استعلام Oracle SQL لتلخيص الإحصائيات باستخدام GROUP BY
سؤال
لدي جدول أوراكل يحتوي على بيانات تبدو كما يلي:
ID BATCH STATUS
1 1 0
2 1 0
3 1 1
4 2 0
إنه، بطاقة تعريف هو المفتاح الأساسي، وسيكون هناك صفوف متعددة لكل "دفعة"، وسيكون لكل صف رمز الحالة في الملف حالة عمود.هناك مجموعة من الأعمدة الأخرى، لكن هذه هي الأهم.
أحتاج إلى كتابة استعلام يلخص رموز الحالة لكل حزمة;هناك ثلاث قيم محتملة يمكن إدراجها في عمود الحالة، 0 و1 و2، وأرغب في أن يبدو الناتج كما يلي:
BATCH STATUS0 STATUS1 STATUS2
1 2 1 0
2 1 0 0
ستكون هذه الأرقام تهمًا.للدفعة 1، هناك
- 2 سجلات حيث حالة تم ضبطه على 0
- 1 سجل حيث حالة تم ضبطه على 1، و
- لا توجد سجلات حيث حالة تم ضبطه على 0.
بالنسبة للدفعة 2، هناك
- 1 سجل حيث حالة تم ضبطه على 0، و
- لا توجد سجلات حيث حالة تم ضبطه على 1 أو 2.
هل هناك طريقة يمكنني من خلالها القيام بذلك في استعلام واحد، دون الحاجة إلى إعادة كتابة الاستعلام لكل رمز حالة؟أي.يمكنني بسهولة كتابة استعلام مثل هذا وتشغيله ثلاث مرات:
SELECT batch, COUNT(status)
FROM table
WHERE status = 0
GROUP BY batch
يمكنني تشغيل ذلك، ثم تشغيله مرة أخرى حيث الحالة = 1، ومرة أخرى حيث الحالة = 2، ولكنني آمل أن أفعل ذلك في استعلام واحد.
إذا كان يحدث فرقا، بصرف النظر عن حالة العمود هناك آخر العمود الذي قد أرغب في تلخيصه بنفس الطريقة - سبب آخر لعدم رغبتي في تنفيذ عبارة SELECT بعد عبارة SELECT ودمج كل النتائج.
المحلول
select batch
, count(case when status=1 then 1 end) status1
, count(case when status=2 then 1 end) status2
, count(case when status=3 then 1 end) status3
from table
group by batch;
يُطلق على هذا غالبًا اسم الاستعلام "المحوري"، وقد كتبت مقالًا حول كيفية إنشاء هذه الاستعلامات ديناميكيًا على مدونتي.
الإصدار الذي يستخدم DECODE (خاص بـ Oracle ولكنه أقل تفصيلاً):
select batch
, count(decode(status,1,1)) status1
, count(decode(status,2,1)) status2
, count(decode(status,3,1)) status3
from table
group by batch;
نصائح أخرى
select batch,
sum(select case when status = 0 then 1 else 0 end) status0,
sum(select case when status = 1 then 1 else 0 end) status1,
sum(select case when status = 2 then 1 else 0 end) status2
from table
group by batch
select batch,
sum((decode(status,0,1,0)) status0,
sum((decode(status,1,1,0)) status1,
sum((decode(status,2,1,0)) status2,
from table
group by batch
يسأل OP عما إذا كان هناك أي فائدة أداء لنهج واحد (SUM) على الآخر (COUNT).يُظهر إجراء اختبار بسيط على جدول يحتوي على 26 ألف صف أن أسلوب COUNT أسرع بشكل ملحوظ.YMMV.
DECLARE
CURSOR B IS
select batch_id
FROM batch
WHERE ROWNUM < 2000;
v_t1 NUMBER;
v_t2 NUMBER;
v_c1 NUMBER;
v_c2 NUMBER;
v_opn INTEGER;
v_cls INTEGER;
v_btc VARCHAR2(100);
BEGIN
-- Loop using SUM
v_t1 := dbms_utility.get_time;
v_c1 := dbms_utility.get_cpu_time;
FOR R IN B LOOP
FOR R2 IN (SELECT batch_type_code
, SUM(decode(batch_status_code, 'CLOSED', 1, 0)) closed
, SUM(decode(batch_status_code, 'OPEN', 1, 0)) OPEN
, SUM(decode(batch_status_code, 'REWORK', 1, 0)) rework
FROM batch
GROUP BY batch_type_code) LOOP
v_opn := R2.open;
v_cls := R2.closed;
END LOOP;
END LOOP;
v_t2 := dbms_utility.get_time;
v_c2 := dbms_utility.get_cpu_time;
dbms_output.put_line('For loop using SUM:');
dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
-- Loop using COUNT
v_t1 := dbms_utility.get_time;
v_c1 := dbms_utility.get_cpu_time;
FOR R IN B LOOP
FOR R2 IN (SELECT batch_type_code
, COUNT(CASE WHEN batch_status_code = 'CLOSED' THEN 1 END) closed
, COUNT(CASE WHEN batch_status_code = 'OPEN' THEN 1 END) OPEN
, COUNT(CASE WHEN batch_status_code = 'REWORK' THEN 1 END) rework
FROM batch
GROUP BY batch_type_code) LOOP
v_opn := R2.open;
v_cls := R2.closed;
END LOOP;
END LOOP;
v_t2 := dbms_utility.get_time;
v_c2 := dbms_utility.get_cpu_time;
dbms_output.put_line('For loop using COUNT:');
dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
END;
/
أدى هذا إلى الإخراج التالي:
For loop using SUM:
CPU seconds used: 40
Elapsed time: 40.09
For loop using COUNT:
CPU seconds used: 33.26
Elapsed time: 33.34
كررت الاختبار عدة مرات للتخلص من أي آثار للتخزين المؤقت.لقد قمت أيضًا بتبديل عبارات التحديد.وكانت النتائج مماثلة في جميع المجالات.
يحرر:هذا هو نفس أداة الاختبار التي استخدمتها للإجابة سؤال مماثل مع.