2017-05-09 2 views
1

Problem

ich eine PostgreSQL 9.6 Datenbank mit einer Tabelle haben die gemäß einem EAV-Modell mit verschiedenen Arten von Werten. Ein Beispiel Auszug sieht wie folgt aus:PostgreSQL Kreuztabellen- mit dynamischen Spaltennamen und mehrere Eingabespalten

name |arrivalTime | boolValue | intValue | floatValue | stringValue 
------+------------+-----------+----------+------------+------------ 
a1 | 10:00:00 | true |   |   | 
c3 | 10:00:00 |   | 12  |   | 
d4 | 10:00:00 |   |   |   | hello 
e5 | 15:00:00 |   |   | 45.67 | 
c3 | 15:00:00 |   | 45  |   | 
b2 | 20:00:00 |   |   | 4.567 | 
a1 | 20:00:00 | false |   |   | 
d4 | 22:00:00 |   |   |   | bye 
b2 | 22:00:00 |   |   | 12.34 | 

Leere Zellen null Werte in der Datenbank repräsentieren.

Jetzt möchte ich eine Pivot-Tabelle erhalten, waren die neuen Spalten die arrivalTime und der Inhalt name. Für das Beispiel von oben es sollte wie folgt aussehen:

arrivalTime | a1 | b2 | c3 | d4 | e5 
------------+-------+-------+-------+-------+------- 
    10:00:00 | true |  | 12 | hello | 
    15:00:00 |  |  | 45 |  | 45.67 
    20:00:00 | false | 4.567 |  |  | 
    22:00:00 |  | 12.34 |  | bye | 

Als Eingang zur Abfrage zum Abrufen dieses Ergebnisses erhalte ich ein Muster, welches die name s passend und eine Start- und Endzeit den Bereich des arrivalTime angeben.

Eigenschaften der ursprünglichen Tabelle:

  • Die Einträge in der Namensspalte sind flüchtig, das heißt neue Namen kommen in und alte Namen regelmäßig verschwinden.
  • Jede Kombination von name und arrivalTime ist einzigartig.
  • Jede name und arrivalTime Kombination hat genau einen Eintrag in einer der Wertspalten.

Ideen

Ich habe es schon einige Überlegungen:

Beispiel Tabelle

Hier ist die SQL-Code der Beispieltabelle zu erstellen:

CREATE TABLE IF NOT EXISTS playTable (
    name TEXT NOT NULL, 
    arrivalTime TIME NOT NULL, 
    floatValue REAL NULL, 
    intValue INT NULL, 
    boolValue BOOLEAN NULL, 
    stringValue TEXT NULL, 
    PRIMARY KEY (name, arrivalTime), 
    CONSTRAINT single_value CHECK(
    (boolValue IS NOT NULL)::INT + 
    (intValue IS NOT NULL)::INT + 
    (floatValue IS NOT NULL)::INT + 
    (stringValue IS NOT NULL)::INT = 1 
) 
); 

Und die Werte einfügen:

INSERT INTO playTable (name, arrivalTime, boolValue) VALUES ('a1', '10:00:00', true); 
INSERT INTO playTable (name, arrivalTime, intValue) VALUES ('c3', '10:00:00', 12); 
INSERT INTO playTable (name, arrivalTime, stringValue) VALUES ('d4', '10:00:00', 'hello'); 
INSERT INTO playTable (name, arrivalTime, floatValue) VALUES ('e5', '15:00:00', 45.67); 
INSERT INTO playTable (name, arrivalTime, intValue) VALUES ('c3', '15:00:00', 45); 
INSERT INTO playTable (name, arrivalTime, floatValue) VALUES ('b2', '20:00:00', 4.567); 
INSERT INTO playTable (name, arrivalTime, boolValue) VALUES ('a1', '20:00:00', false); 
INSERT INTO playTable (name, arrivalTime, stringValue) VALUES ('d4', '22:00:00', 'bye'); 
INSERT INTO playTable (name, arrivalTime, floatValue) VALUES ('b2', '22:00:00', 12.34); 

Pivot-Tabelle, nicht dynamische

klin Provid Ed den Ausgangspunkt der Lösung, ich denke:

Was fehlt von dieser Lösung ist der dynamische Aspekt. Als Eingabe wird ein LIKE Muster für name geliefert und der Bereich (d. H. Min- und Max-Wert) von arrivalTime. Dies macht das Argument von as ct(...) dynamisch.

Antwort

1

Verwenden Sie coalesce() für vier letzte Spalten. Sie haben die Spalten text zu werfen, dies zu tun:

select * 
from crosstab(
    $ct$ 
     select 
      arrivaltime, name, 
      coalesce(boolvalue::text, intvalue::text, floatvalue::text, stringvalue) 
     from my_table 
     order by 1, 2 
    $ct$, 
    $ct$ 
     select distinct name 
     from my_table 
     order by 1 
    $ct$) 
as ct("arrivalTime" time, "a1" text, "b2" text, "c3" text, "d4" text, "e5" text); 

arrivalTime | a1 | b2 | c3 | d4 | e5 
-------------+-------+-------+----+-------+------- 
10:00:00 | true |  | 12 | hello | 
15:00:00 |  |  | 45 |  | 45.67 
20:00:00 | false | 4.567 | |  | 
22:00:00 |  | 12.34 | | bye | 
(4 rows) 

I arrivalTime time verwendet habe, weil das Format der Beispieldaten, um es zu timestamp zu ändern.

+0

Ich spielte mit der Lösung herum und erweiterte meine Frage ein wenig. Ich habe Ihren Code von 'coalesce' in' concat' geändert. Dies funktioniert gut und wichtige Hürden sind genommen, aber ich bin noch nicht im Ziel: Noch fehlt die Möglichkeit, in das Muster unter Angabe der 'name' und der' arrivalTime' Bereich. Dies macht das Argument von 'as ct (...)' dynamisch. – user711270

+0

user711270 Sie benötigen irgendeine Art von Programmiersprache, die SQL-Abfragen für Sie generiert, wobei auf Eingabemuster geachtet wird. Wenn Sie SQL verwenden, verwenden Sie nur plpgsql, um solche dynamischen Abfragen zu erstellen. –

Verwandte Themen