2016-04-28 4 views
1

Ich bin in der Lage, eine Abfrage zu machen, um die Anzahl der Kunden, die in einem Geschäft kommen, von 18 bis 24 pro Monat und pro Shop zu erhalten. Ich mache es so:Wie man Vorkommen in mehreren Datumsbereichen in PostgreSQL zählt

select year, month, shop_id, count(birthday) 
from customers 
where birthday 
BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00' 
group by year, month, shop_id; 

Jetzt bin ich ein Problem mit zugleich machen diese Abfrage für mehrere Bereiche.

Im Moment habe ich dieses Datenbankschema:

shop_id | birthday | year | month | 
--------+----------+------+-------- 
567 | 1998-10-10 | 2014 | 10 | 
567 | 1996-10-10 | 2014 | 10 | 
567 | 1985-10-10 | 2014 | 10 | 
234 | 1990-10-10 | 2014 | 10 | 
123 | 1970-01-10 | 2014 | 10 | 
123 | 1974-01-10 | 2014 | 11 | 

Und ich würde so etwas wie dies lernen:

shop_id | year | month | 18 < age < 25 | 26 < age < 35 
--------+------+-------+---------------+------------- 
567 | 2014 | 10 | 2    | 1 
234 | 2014 | 10 | 1    | 0 
123 | 2014 | 10 | 0    | 0 

In der ersten Abfrage, ist es nicht der Fall zu verwalten, wo ein Geschäft hat KEINE Kunden. Wie bekomme ich 0 wenn nicht?

Wie die verschiedenen Datumsbereiche gleichzeitig abfragen?

+0

Verwenden Sie in der Auswahlliste die entsprechenden Ausdrücke, einen für jede Altersgruppe. Z.B. ', count (fall wenn ... dann 1 ende) als 18_age_25, count (fall wenn ...'. – jarlh

+0

alter ab heute? –

Antwort

0

Statt Filter verwenden case-Anweisungen:

select year, month, shop_id, 
count(case when birthday between <range1> then 1 end) RANGE1, 
count(case when birthday between <range2> then 1 end) RANGE2, 
count(case when birthday between <range3> then 1 end) RANGE3 
from customers 
group by year, month, shop_id; 
+1

Vielen Dank! Einfach und effizient. – KillianKemps

0

"Keine Zeilen mit Nullen" ist ein häufiges Problem bei GROUP BY Abfragen. Die Lösung besteht darin, Ihre FROM Tabelle zu machen, die die vollständige Liste hat, und dann eine LEFT JOIN. Da Sie nach Jahr und Monat gruppieren, müssen Sie die vollständige Liste der Jahre und Monate erstellen. Sie können das tun mit generate_series:

SELECT t.t, s.id, COUNT(c.birthday) 
FROM shops s 
CROSS JOIN generate_series('2014-01-01 00:00:00', '2015-01-01 00:00:00', interval '1 month') t(t) 
LEFT OUTER JOIN customers c 
ON  c.shop_id = s.id 
AND  c.birthday 
     BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00' 
AND  c.year = EXTRACT(YEAR FROM t.t) 
AND  c.month = EXTRACT(MONTH FROM t.t) 
GROUP BY t.t, s.id 
ORDER BY s.id, t.t; 

Um Zählungen für zwei Zeiträume zu erhalten, könnten Sie tun, was @ mo2 schon sagt, oder man könnte zweimal der customers Tisch kommen:

SELECT t.t, s.id, COUNT(DISTINCT c1.id), COUNT(DISTINCT c2.id) 
FROM shops s 
CROSS JOIN generate_series('2014-01-01 00:00:00', '2015-01-01 00:00:00', interval '1 month') t(t) 
LEFT OUTER JOIN customers c1 
ON  c1.shop_id = s.id 
AND  c1.birthday 
     BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00' 
AND  c1.year = EXTRACT(YEAR FROM t.t) 
AND  c1.month = EXTRACT(MONTH FROM t.t) 
LEFT OUTER JOIN customers c2 
ON  c2.shop_id = s.id 
AND  c2.birthday 
     BETWEEN '1982-01-01 00:00:00' AND '1992-01-01 00:00:00' 
AND  c2.year = EXTRACT(YEAR FROM t.t) 
AND  c2.month = EXTRACT(MONTH FROM t.t) 
GROUP BY t.t, s.id 
ORDER BY s.id, t.t; 

Beachten Sie, dass in beide Abfragen bin ich SELECT eine volle datetime statt und month. Das ist flexibler, denke ich, aber es sollte leicht zu ändern sein, wenn Sie wollen.

EDIT: Ich erkannte Ihre year und month sind nicht Geburtstag bezogen, sondern etwas anderes, ich denke, das Besuchsdatum? Also habe ich meine Anfrage aktualisiert. Wenn Sie nur einen Monat nach dem anderen überprüfen, können Sie die generate_series entfernen und einfach die Ganzzahlen für Jahr und Monat direkt in die Join-Bedingungen einfügen.

Verwandte Themen