2016-09-13 6 views
2

Ich habe folgende Tabelle genannt sample_events:Warum gibt diese Kreuztabellenabfrage doppelte Schlüssel zurück?

Column | Type 
--------+----- 
title | text 
date | date 

mit Werten:

title |  date 
-------+------------ 
ev1 | 2017-01-01 
ev2 | 2017-01-03 
ev3 | 2017-01-02 
ev4 | 2017-12-10 
ev5 | 2017-12-11 
ev6 | 2017-07-28 

Um eine Pivot-Tabelle mit der Anzahl der Ereignisse pro Monat in jedem eindeutigen Jahr habe ich die Kreuztabellen- Funktion zu schaffen, in die Form crosstab(text source_sql, text category_sql):

SELECT * FROM crosstab (
    'SELECT extract(year from date) AS year, 
     extract(month from date) AS month, count(*) 
    FROM sample_events 
    GROUP BY year, month' 
, 
    'SELECT * FROM generate_series(1, 12)' 
) AS (
    year int, jan int, feb int, mar int, 
    apr int, may int, jun int, jul int, 
    aug int, sep int, oct int, nov int, dec int 
) ORDER BY year; 

Ergebnis ist wie folgt und wie erwartet:

year | jan | feb | mar | apr | may | jun | jul | aug | sep | oct | nov | dec 
------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---- 
2017 | 3 |  |  |  |  |  | 1 |  |  |  |  | 2 

Jetzt möchte ich eine Pivot-Tabelle mit der Anzahl der Ereignisse pro Wochentag in jeder einzigartigen Woche des Jahres erstellen. Ich habe versucht, folgende Abfrage:

SELECT * FROM crosstab (
    'SELECT extract(week from date) AS week, 
     extract(dow from date) AS day_of_week, count(*) 
    FROM sample_events 
    GROUP BY week, day_of_week' 
, 
    'SELECT * FROM generate_series(0, 6)' 
) AS (
    week int, sun int, mon int, tue int, 
    wed int, thu int, fri int, sat int 
) ORDER BY week; 

Ergebnis nicht wie erwartet:

week | sun | mon | tue | wed | thu | fri | sat 
------+-----+-----+-----+-----+-----+-----+----- 
    1 |  |  | 1 |  |  |  |  
    1 |  | 1 |  |  |  |  |  
    30 |  |  |  |  |  | 1 |  
    49 | 1 |  |  |  |  |  |  
    50 |  | 1 |  |  |  |  |  
    52 | 1 |  |  |  |  |  |  

Alle sechs Veranstaltungen gibt es aber aus irgendeinem Grund gibt es doppelte Woche Wert. Ich erwartete das Ergebnis wie etwas zu sein:

week | sun | mon | tue | wed | thu | fri | sat 
------+-----+-----+-----+-----+-----+-----+----- 
    1 |  | 1 | 1 |  |  |  |  
    30 |  |  |  |  |  | 1 |  
    49 | 1 |  |  |  |  |  |  
    50 |  | 1 |  |  |  |  |  
    52 | 1 |  |  |  |  |  |  

Fragen

1) Warum Ergebnisse aus dieser Abfrage enthalten doppelte Schlüsselwerte aber die erstere nicht?

2) Wie erstellt man eine Pivot-Tabelle mit Unique Wochenwerte?

Antwort

1

crosstab() erwartet geordneten Eingang. Sie müssen ORDER BY im Eingabe hinzuzufügen:

SELECT * FROM crosstab (
    'SELECT extract(week from date)::int AS week 
     , extract(dow from date)::int AS day_of_week 
     , count(*)::int 
    FROM sample_events 
    GROUP BY week, day_of_week 
    ORDER BY week, day_of_week' 
, 'SELECT generate_series(0, 6)' 
) AS (
    week int, sun int, mon int, tue int, 
    wed int, thu int, fri int, sat int 
); 

Oder nur ORDER BY week.

Genau genommen müssen die Werte des gleichen Schlüssels (week im Beispiel) gruppiert werden (in der Reihenfolge). Schlüssel müssen nicht bestellt werden. Aber der einfachste und billigste Weg, dies zu erreichen, ist ORDER BY (die Tasten zusätzlich sortiert).

Oder kurz:

SELECT * FROM crosstab (
    'SELECT extract(week from date)::int 
     , extract(dow from date)::int 
     , count(*)::int 
    FROM sample_events 
    GROUP BY 1, 2 
    ORDER BY 1, 2' -- or just ORDER BY 1 
, 'SELECT generate_series(0, 6)' 
) AS ... 

Ihr erstes Beispiel mit Monaten geschieht, weil Eingangsdaten in Folge hat Monate zu arbeiten. Dies kann jedoch jedes Mal unterbrochen werden, wenn sich die physische Reihenfolge der Zeilen in Ihrer Tabelle ändert (VACUUM, UPDATE, ...). Sie können sich niemals auf die physische Reihenfolge von Zeilen in einer relationalen Tabelle verlassen.

Weitere Erklärung:

Verwandte Themen