2012-12-07 7 views
5

Ich habe eine Tabelle mit N Spalten. Nennen wir sie c1, c2, c3, c4, ... cN. Unter mehreren Zeilen möchte ich eine einzelne Zeile mit COUNT DISTINCT(cX) für jedes X in [1, N] bekommen.Wie führe ich die gleiche Aggregation für jede Spalte durch, ohne die Spalten aufzulisten?

Gibt es eine Möglichkeit, dies (in einer gespeicherten Prozedur) zu tun, ohne jeden Spaltennamen manuell in die Abfrage zu schreiben?

Warum?

Wir hatten ein Problem, wo Fehler in Anwendungsserver bedeuten, dass wir gute Spaltenwerte mit später eingefügtem Müll neu schreiben. Um dies zu lösen, speichere ich die Informationsprotokollstruktur, wobei jede Zeile eine logische UPDATE Abfrage darstellt. Wenn dann ein Signal gegeben wird, dass die Aufzeichnung abgeschlossen ist, kann ich feststellen, ob irgendwelche Werte (fälschlicherweise) überschrieben wurden.

Ein Beispiel für einen einzelnen korrekten Datensatz in mehreren Zeilen: Es gibt höchstens einen Wert für jede Spalte.

| id | initialize_time | start_time | end_time | 
| 1 | 12:00am   | NULL  | NULL  | 
| 1 | 12:00am   | 1:00pm  | NULL  | 
| 1 | 12:00am   | NULL  | 2:00pm | 

Reconciled row: 
| 1 | 12:00am   | 1:00pm  | 2:00pm | 

Ein Beispiel für einen unversöhnlichen Datensatz, den ich erkennen soll:

| id | initialize_time | start_time | end_time | 
| 1 | 12:00am   | NULL  | NULL  | 
| 1 | 12:00am   | 1:00pm  | NULL  | 
| 1 | 9:00am   | 1:00pm  | 2:00pm | -- New initialize time => irreconcilable! 
+0

Fragen Sie, wie die Spaltennamen abgerufen werden oder wie die Aggregation durchgeführt wird? –

+0

Ich weiß, wie die Spaltennamen abgerufen werden, aber ich weiß nicht, was zu tun ist, um einen Ausdruck um jeden Spaltennamen in der Abfrage zu erweitern. Ich möchte vermeiden, SELECT COUNT DISTINCT (C1), COUNT DISTINCT (C2), ..., COUNT DISTINCT (CN) FROM ... 'in meiner gespeicherten Prozedur. –

+0

Sie können dies natürlich mit dynamischem SQL tun. Übrigens, wie groß ist X? – dezso

Antwort

3

Sie benötigen dynamischen SQL für das, was bedeutet, dass Sie eine Funktion erstellen oder einen DO Befehl ausführen. Da Sie nicht Werte zurückgeben können direkt von dieser eine plpgsql Funktion es ist:

CREATE OR REPLACE function f_count_all(_tbl text 
          , OUT columns text[], OUT counts bigint[]) 
    RETURNS record LANGUAGE plpgsql AS 
$func$ 
BEGIN 

EXECUTE (
    SELECT 'SELECT 
    ARRAY[' || string_agg('''' || quote_ident(attname) || '''', ', ') || '], 
    ARRAY[' || string_agg('count(' || quote_ident(attname) || ')', ', ') || '] 
    FROM ' || _tbl 
    FROM pg_attribute 
    WHERE attrelid = _tbl::regclass 
    AND attnum >= 1   -- exclude tableoid & friends (neg. attnum) 
    AND attisdropped is FALSE -- exclude deleted columns 
    GROUP BY attrelid 
    ) 
INTO columns, counts; 

END 
$func$; 

Call:

SELECT * FROM f_count_all('myschema.mytable'); 

Returns:

columns  | counts 
--------------+-------- 
{c1, c2, c3,} | {17 1,0} 

Weitere Erläuterungen und Links zu dynamischen SQL und EXECUTE in this related question - oder ein paar mehr hier auf SO, try this serach.

Sehr ähnlich wie diese Frage:
postgresql - count (no null values) of each column in a table

Sie könnten sogar versuchen, eine polymorphe Satzart Rückkehr dynamisch einzelne Spalten zu bekommen, aber das ist ziemlich komplex und fortgeschritten. Wahrscheinlich zu viel Aufwand für Ihren Fall. Mehr in this related answer.

Verwandte Themen