2016-04-12 9 views
1

Ich habe eine Tabelle mit einer Reihe von booleschen Spalten. Ich möchte diese Spalten nach der Anzahl der wahren Werte ordnen, die jeder hat. mitRang Spalten durch ihre Anzahl von Werten

fand ich eine Möglichkeit, die Anzahl der wahren Werte in einer Spalte zu zählen:

SELECT count(CASE WHEN col1 THEN 1 ELSE null END) as col1, 
     count(CASE WHEN col2 THEN 1 ELSE null END) as col2 
     .... 
FROM my_table; 

aber dieser Ansatz hat zwei Probleme:

  1. Ich habe die Namen der Spalten manuell eingeben
  2. ich dann das Ergebnis und Ordnung

gibt es von Wert transponieren aw um die ganze Operation eine Abfrage zu machen?

+0

Wahrscheinlich wird 'Kreuztabellen 'damit umgehen. Bitte geben Sie http://sqlfiddle.com Beispieldaten und das gewünschte Resultset – lad2025

+0

@ lad2025 mit 'Kreuztabelle' an. Sie müssen auch die Namen der Spalten manuell eingeben. Es sei denn, Sie verwenden eine dynamische Aussage, die im Grunde genommen die gleiche ist wie das Erstellen der OP (soweit es das Ergebnis betrifft). –

+1

Bearbeiten Sie Ihre Frage und geben Sie Ihre gewünschten Ergebnisse an. –

Antwort

0

Wenn ich richtig verstehe, können Sie dies mit einem riesigen union all tun:

select c.* 
from ((select 'col1' as which, sum(case when col1 then 1 else 0 end) as cnt from t 
    ) union all 
     (select 'col2' as which, sum(case when col2 then 1 else 0 end) as cnt from t 
    ) union all 
     . . . 
    ) c 
order by cnt desc; 

Obwohl Sie immer noch die Ergebnisse geben müssen, das die Umstellungen nicht umgehen.

1

Dies ist eigentlich kein Kreuztabellenauftrag (oder "Pivot" in anderen RDBMS), aber die umgekehrte Operation, ein Counter-Kreuztabellen, wenn Sie so wollen. Eine elegante Technik ist ein VALUES Ausdruck in einem LATERAL Join.

Die grundlegende Abfrage kann wie folgt aussehen, was kümmert um:

  1. ich Wert das Ergebnis und haben, um dann transponieren
SELECT c.col, c.ct 
FROM (
    SELECT count(col1 OR NULL) AS col1 
     , count(col2 OR NULL) AS col2 
      -- etc. 
    FROM tbl 
    ) t 
    , LATERAL (
    VALUES ('col1', col1) 
     , ('col2', col2) 
      -- etc. 
    ) c(col, ct) 
ORDER BY 2 

Das war der einfache Teil. Ihre andere Anfrage ist härter:

  1. Ich habe manuell die Namen der Spalten eingeben

Diese Funktion nimmt Ihre Tabellennamen und ruft Metadaten aus dem Systemkatalog pg_attribute. Es ist eine dynamische Umsetzung der obigen Abfrage, sicher vor SQL-Injection:

CREATE OR REPLACE FUNCTION f_true_ct(_tbl regclass) 
    RETURNS TABLE (col text, ct bigint) AS 
$func$ 
BEGIN 
    RETURN QUERY EXECUTE (
    SELECT format(' 
     SELECT c.col, c.ct 
     FROM (SELECT %s FROM tbl) t 
      , LATERAL (VALUES %s) c(col, ct) 
     ORDER BY 2 DESC' 
    , string_agg (format('count(%1$I OR NULL) AS %1$I', attname), ', ') 
    , string_agg (format('(%1$L, %1$I)', attname), ', ') 
    ) 
    FROM pg_attribute 
    WHERE attrelid = _tbl    -- valid, visible, legal table name 
    AND attnum >= 1     -- exclude tableoid & friends 
    AND NOT attisdropped   -- exclude dropped columns 
    AND atttypid = 'bool'::regtype -- only character types 
    ); 
END 
$func$ LANGUAGE plpgsql; 

Call:

SELECT * FROM f_true_ct('tbl'); -- table name optionally schema-qualified 

Ergebnis:

col | ct 
------+--- 
col1 | 3 
col3 | 2 
col2 | 1 

Werke für jede Tabelle alle Rang boolean Spalten nach ihrer Anzahl von true Werte.

die Funktionsparameter zu verstehen, lesen Sie:

Verwandte Antworten mit mehr Erklärung:

+0

'LATERAL und VALUES' :) Ich frage mich immer, warum Leute' SELECT * 'Verhalten simulieren wollen – lad2025

Verwandte Themen