Postgres - كيفية إرجاع الصفوف ذات العدد 0 للبيانات المفقودة؟
-
19-08-2019 - |
سؤال
لقد قمت بتوزيع البيانات بشكل غير متساو (تاريخ الكتابة) لبضع سنوات (2003-2008).أريد الاستعلام عن البيانات لمجموعة معينة من تاريخ البدء والانتهاء، وتجميع البيانات حسب أي من الفواصل الزمنية المدعومة (اليوم، الأسبوع، الشهر، الربع، السنة) في PostgreSQL 8.3 (http://www.postgresql.org/docs/8.3/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC).
المشكلة هي أن بعض الاستعلامات تعطي النتائج مستمرة خلال الفترة المطلوبة ، كما هي:
select to_char(date_trunc('month',date), 'YYYY-MM-DD'),count(distinct post_id)
from some_table where category_id=1 and entity_id = 77 and entity2_id = 115
and date <= '2008-12-06' and date >= '2007-12-01' group by
date_trunc('month',date) order by date_trunc('month',date);
to_char | count
------------+-------
2007-12-01 | 64
2008-01-01 | 31
2008-02-01 | 14
2008-03-01 | 21
2008-04-01 | 28
2008-05-01 | 44
2008-06-01 | 100
2008-07-01 | 72
2008-08-01 | 91
2008-09-01 | 92
2008-10-01 | 79
2008-11-01 | 65
(12 rows)
لكن بعضها يفتقد بعض الفواصل الزمنية لعدم وجود بيانات، مثل هذه:
select to_char(date_trunc('month',date), 'YYYY-MM-DD'),count(distinct post_id)
from some_table where category_id=1 and entity_id = 75 and entity2_id = 115
and date <= '2008-12-06' and date >= '2007-12-01' group by
date_trunc('month',date) order by date_trunc('month',date);
to_char | count
------------+-------
2007-12-01 | 2
2008-01-01 | 2
2008-03-01 | 1
2008-04-01 | 2
2008-06-01 | 1
2008-08-01 | 3
2008-10-01 | 2
(7 rows)
حيث تكون مجموعة النتائج المطلوبة هي:
to_char | count
------------+-------
2007-12-01 | 2
2008-01-01 | 2
2008-02-01 | 0
2008-03-01 | 1
2008-04-01 | 2
2008-05-01 | 0
2008-06-01 | 1
2008-07-01 | 0
2008-08-01 | 3
2008-09-01 | 0
2008-10-01 | 2
2008-11-01 | 0
(12 rows)
عدد 0 للإدخالات المفقودة.
لقد رأيت مناقشات سابقة حول Stack Overflow لكنها لم تحل مشكلتي على ما يبدو، نظرًا لأن فترة التجميع الخاصة بي هي واحدة من (يوم، أسبوع، شهر، ربع سنة، سنة) وتم تحديد وقت التشغيل بواسطة التطبيق.لذا فإن نهجًا مثل الانضمام الأيسر مع جدول تقويم أو جدول تسلسل لن يساعد في التخمين.
الحل الحالي لهذا هو ملء هذه الفجوات في Python (في تطبيق Turbogears) باستخدام وحدة التقويم.
هل هناك طريقة أفضل للقيام بذلك.
المحلول
يمكنك إنشاء قائمة من كل الأيام الأولى من العام الماضي (ويقول) مع
select distinct date_trunc('month', (current_date - offs)) as date
from generate_series(0,365,28) as offs;
date
------------------------
2007-12-01 00:00:00+01
2008-01-01 00:00:00+01
2008-02-01 00:00:00+01
2008-03-01 00:00:00+01
2008-04-01 00:00:00+02
2008-05-01 00:00:00+02
2008-06-01 00:00:00+02
2008-07-01 00:00:00+02
2008-08-01 00:00:00+02
2008-09-01 00:00:00+02
2008-10-01 00:00:00+02
2008-11-01 00:00:00+01
2008-12-01 00:00:00+01
وبعد ذلك يمكنك الانضمام مع هذه السلسلة.
نصائح أخرى
هذا السؤال قديم.ولكن بما أن زملائي المستخدمين اختاروه كنسخة رئيسية لنسخة مكررة جديدة، فأنا أقوم بإضافة إجابة مناسبة.
الحل المناسب
SELECT *
FROM (
SELECT day::date
FROM generate_series(timestamp '2007-12-01'
, timestamp '2008-12-01'
, interval '1 month') day
) d
LEFT JOIN (
SELECT date_trunc('month', date_col)::date AS day
, count(*) AS some_count
FROM tbl
WHERE date_col >= date '2007-12-01'
AND date_col <= date '2008-12-06'
-- AND ... more conditions
GROUP BY 1
) t USING (day)
ORDER BY day;
يستخدم
LEFT JOIN
, ، بالطبع.generate_series()
يمكن أن ينتج جدولًا للطوابع الزمنية بسرعة وبسرعة كبيرة.بشكل عام، يكون التجميع أسرع قبل تنضم.لقد قدمت مؤخرًا حالة اختبار على sqlfiddle.com في هذه الإجابة ذات الصلة:
يلقي
timestamp
لdate
(::date
) للتنسيق الأساسي.لمزيد من الاستخدامto_char()
.GROUP BY 1
هو اختصار بناء الجملة للإشارة إلى عمود الإخراج الأول.ممكن ان يكونGROUP BY day
كذلك، ولكن قد يتعارض ذلك مع عمود موجود يحمل نفس الاسم.أوGROUP BY date_trunc('month', date_col)::date
ولكن هذا طويل جدًا بالنسبة لذوقي.يعمل مع وسيطات الفاصل الزمني المتاحة ل
date_trunc()
.count()
لا تنتج أبداNULL
(0
لعدم وجود صفوف)، ولكنLEFT JOIN
يفعل.
لكي ترجع0
بدلاً منNULL
في الخارجSELECT
, ، يستخدمCOALESCE(some_count, 0) AS some_count
. الدليل.ل حل أكثر عمومية أو فترات زمنية تعسفية خذ بعين الاعتبار هذه الإجابة ذات الصلة الوثيقة:
هل يمكن إنشاء جدول مؤقت في وقت التشغيل واليسار الانضمام على ذلك. ويبدو أن تجعل اكثر احساسا.