MySQL / دليل حلول تحريري
ONLY_FULL_GROUP_BY: إصلاح معنى التقرير
احسم غموض التجميع دون تعطيل الوضع أوإخفاء القيم الاعتباطية.
قاعدة معرفة للقراءة فقط · بلا تعليقات عامة
تعرّف على الأعراض
تشير ERROR 1055 (42000) إلى تعبير غير مجمع لا يعتمد وظيفياً على المجموعة. وقد تظهر ERROR 1140 (42000) عند خلط التجميع وأعمدة غير مرتبطة دون GROUP BY.
قد يبدو تقرير قديم صحيحاً بعد تعطيل الوضع لكنه يختار حالة أواسماً اعتباطياً. ولا تجعل ORDER BY هذه القيمة أحدث صف مرتبط.
افهم الأسباب المحتملة
- قد تضم المجموعة قيماً متعددة للعمود المختار. للعميل 1 طلبان بحالتي paid و new، فلا يحدد customer_id حالة واحدة.
- قد يكرر ربط التفاصيل إجماليات الآباء. ولا يصلح علاج خطأ التجميع وحده مستوى مدخل خاطئاً أومجتمع تجميع غير مناسب.
افحص الوضع وحدد مستوى الصف
يستهدف الدليل MySQL8.4 مع تفعيل ONLY_FULL_GROUP_BY. تعد SELECT @@SESSION.sql_mode فحصاً للقراءة. اكتب مستوى النتيجة: صف لكل عميل أم زوج عميل وحالة أم طلب. يتحدد الإصلاح بالإجابة لا بمجرد إخفاء الخطأ.
اجمع كل فئة يحتاجها التقرير
تطابق البيانات المستقلة الطلبات الثلاثة في الدورة. يلائم التجميع حسب العميل والحالة تقرير قيمة كل حالة لكل عميل. أعمدة الفئات المختارة مفاتيح مجموعة صريحة، فلا غموض ولا تغيير لوضع SQL.
WITH sample_orders AS (
SELECT 101 AS id,1 AS customer_id,'paid' AS status,25.00 AS total
UNION ALL SELECT 102,1,'new',30.00
UNION ALL SELECT 103,2,'paid',10.00
)
SELECT customer_id,status,SUM(total) AS amount
FROM sample_orders GROUP BY customer_id,status
ORDER BY customer_id,status;
customer_id | status | amount
1 | new | 30.00
1 | paid | 25.00
2 | paid | 10.00
للعميل 1 قيمة new مقدار 30.00 و paid مقدار 25.00 وللعميل 2 paid مقدار 10.00. ينتج ثلاث مجموعات عن قصد. إضافة الحالة قرار معنوي وليست إصلاحاً عاماً إن كان المطلوب صفاً واحداً للعميل.
اجمع حقيقة محددة لصف واحد لكل عميل
إن كان المطلوب القيمة المدفوعة لكل عميل فاستخدم تجميعاً شرطياً بدلاً من حالة عشوائية. وإن كانت حالة أحدث طلب فرتب الطلبات بالوقت ورقم فريد واختر الأول عبر استعلام فرعي؛ فـ MAX(status) أكبر نص لا الأحدث. لا تلائم ANY_VALUE إلا قبول أي قيمة فعلاً مع توثيق اعتباطيتها.
WITH sample_orders AS (
SELECT 1 AS customer_id,'paid' AS status,25.00 AS total
UNION ALL SELECT 1,'new',30.00
UNION ALL SELECT 2,'paid',10.00
)
SELECT customer_id,
SUM(CASE WHEN status='paid' THEN total ELSE 0 END) AS paid_value
FROM sample_orders GROUP BY customer_id ORDER BY customer_id;
customer_id | paid_value
1 | 25.00
2 | 10.00
النتيجة 1/25.00 و 2/10.00. تسهم CASE بصفر للطلب الجديد وبالمبلغ للمدفوع. ولا يظهر عميل دون صف مدخل إلا بربط customers أيسر إن كان التقرير يحتاج عرضه بصفر.
استخدم اعتماداً وظيفياً حقيقياً وإجماليات سليمة
قد يجعل تجميع المفتاح الأساسي اسم العميل معتمداً وظيفياً في MySQL، ولا يثبت تجميع اسم غير فريد ذلك. احفظ المفاتيح ولا تستنتج الهوية من مصادفات العينة. وقبل جمع إجماليات مربوطة تحقق من تكرار الطلب مع بنوده واجمع التفاصيل مسبقاً أوعلى المستوى الصحيح.
تحقق من نجاح الإصلاح
نفذ القراءة المصححة مع الوضع الأصلي. تحقق من المجموعات والمبالغ ثم اختبر تعادلاً اصطناعياً وعميلاً بعدة حالات وقيمة مفقودة. طابق الإجماليات مع مجتمع المدفوع المحسوب مستقلاً ولا تكتف باختفاء ERROR1055.
امنع تكرار المشكلة
- أبق ONLY_FULL_GROUP_BY مفعلاً في التطوير والنشر ووثق مستوى كل تقرير وراجع NULL وتضاعف الربط. تحقق من MariaDB مستقلاً فقد تختلف معرفة الاعتماد الوظيفي وسلوك التجميع.