2010-03-19 4 views
6

Ich versuche, eine Pivot-Tabelle Typ Ansicht in Postgresql zu erstellen und bin fast da! Hier ist die grundlegende Abfrage:richtige Weise zum Erstellen einer Pivot-Tabelle in Postgresql mit CASE WHEN

select 
acc2tax_node.acc, tax_node.name, tax_node.rank 
from 
tax_node, acc2tax_node 
where 
tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531'; 

Und die Daten:

acc |   name   |  rank  
----------+-------------------------+-------------- 
AJ012531 | Paromalostomum fusculum | species 
AJ012531 | Paromalostomum   | genus 
AJ012531 | Macrostomidae   | family 
AJ012531 | Macrostomida   | order 
AJ012531 | Macrostomorpha   | no rank 
AJ012531 | Turbellaria    | class 
AJ012531 | Platyhelminthes   | phylum 
AJ012531 | Acoelomata    | no rank 
AJ012531 | Bilateria    | no rank 
AJ012531 | Eumetazoa    | no rank 
AJ012531 | Metazoa     | kingdom 
AJ012531 | Fungi/Metazoa group  | no rank 
AJ012531 | Eukaryota    | superkingdom 
AJ012531 | cellular organisms  | no rank 

Was ich versuche zu bekommen, ist die folgende:

acc  | species     | phylum 
AJ012531 | Paromalostomum fusculum | Platyhelminthes 

Ich versuche, dies zu tun mit CASE WHEN Ich bin also soweit wie folgt:

select 
acc2tax_node.acc, 
CASE tax_node.rank WHEN 'species' THEN tax_node.name ELSE NULL END as species, 
CASE tax_node.rank WHEN 'phylum' THEN tax_node.name ELSE NULL END as phylum 
from 
tax_node, acc2tax_node 
where 
tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531'; 

die mir die Ausgabe gibt:

acc |   species   |  phylum  
----------+-------------------------+----------------- 
AJ012531 | Paromalostomum fusculum | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | Platyhelminthes 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 

Jetzt an einem gewissen Punkt von acc müssen Gruppe Ich weiß, dass ich, so dass ich versuchen

select 
acc2tax_node.acc, 
CASE tax_node.rank WHEN 'species' THEN tax_node.name ELSE NULL END as sp, 
CASE tax_node.rank WHEN 'phylum' THEN tax_node.name ELSE NULL END as ph 
from 
tax_node, acc2tax_node 
where 
tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531' 
group by acc2tax_node.acc; 

Aber ich bekomme die gefürchtete

ERROR: column "tax_node.rank" must appear in the GROUP BY clause or be used in an aggregate function 

Alle vorherigen Beispiele, die ich finden konnte, verwenden so etwas wie SUM() um die CASE-Anweisungen, also denke ich, dass das die Aggregatfunktion ist. Ich habe mit FIRST() versucht:

select 
acc2tax_node.acc, 
FIRST(CASE tax_node.rank WHEN 'species' THEN tax_node.name ELSE NULL END) as sp, 
FIRST(CASE tax_node.rank WHEN 'phylum' THEN tax_node.name ELSE NULL END) as ph 
from tax_node, acc2tax_node where tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531' group by acc2tax_node.acc; 

aber den Fehler:

ERROR: function first(character varying) does not exist 

Kann jemand irgendwelche Hinweise anbieten?

+0

Könnten Sie bitte die Ergebnisse dieser Abfrage schreiben: ' SELECT * FROM acc2tax_node WHERE acc = 'AJ012531''? – Quassnoi

Antwort

5

Verwenden Sie MAX() oder MIN(), nicht FIRST(). In diesem Szenario haben Sie alle NULL in der Spalte für jeden Gruppenwert mit Ausnahme von höchstens einem mit einem Wert ungleich Null. Per Definition ist dies sowohl der MIN als auch der MAX dieser Menge von Werten (alle Nullen sind ausgeschlossen).

+0

Das funktioniert perfekt, danke. Aus irgendeinem Grund nahm ich an, dass MAX() nicht funktionieren würde, weil ich String-Werte verwendete. – mojones

0
SELECT atn.acc, ts.name AS species, tp.name AS phylum 
FROM acc2tax_node atn 
LEFT JOIN 
     tax_node ts 
ON  ts.taxid = atn.taxid 
     AND ts.rank = 'species' 
LEFT JOIN 
     tax_node tp 
ON  tp.taxid = atn.taxid 
     AND tp.rank = 'phylum' 
WHERE atn.acc = 'AJ012531 ' 
+0

Bitte entschuldigen Sie meine schrecklichen Formatierungsversuche :-) – mojones

0

Weitere Informationen wie gewünscht (in einer Antwort eher als ein Kommentar für nette Formatierung):

SELECT * FROM acc2tax_node WHERE acc = 'AJ012531'; 

    acc | taxid 
----------+-------- 
AJ012531 | 66400 
AJ012531 | 66399 
AJ012531 | 39216 
AJ012531 | 39215 
AJ012531 | 166235 
AJ012531 | 166384 
AJ012531 | 6157 
AJ012531 | 33214 
AJ012531 | 33213 
AJ012531 | 6072 
AJ012531 | 33208 
AJ012531 | 33154 
AJ012531 | 2759 
AJ012531 | 131567 
2

PostgreSQL hat ein paar Funktionen für Pivot-Abfragen finden Sie diesen Artikel zu Postgresonline. Sie finden diese Funktionen in der contrib.

+0

Ja, ich vermute, dass der richtige Weg das mit scrosstab ist. Ich möchte immer noch herausfinden, was ich hier falsch mache für meine eigene Ausbildung. – mojones

0

Execute:

SELECT report.* FROM crosstab(
select 
acc2tax_node.acc, tax_node.name, tax_node.rank 
from 
tax_node, acc2tax_node 
where 
tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531'; 
) AS report(species text, enus text, family text, ...) 
0

Als Matthew Wood darauf hingewiesen, verwenden MIN() oder MAX(), nicht FIRST():

SELECT 
    an.acc, 
    MAX(
     CASE tn.rank 
      WHEN 'species' THEN tn.name 
      ELSE NULL 
     END 
    ) AS species, 
    MAX(
     CASE tn.rank 
      WHEN 'phylum' THEN tn.name 
      ELSE NULL 
     END 
    ) AS phylum 
FROM tax_node tn, 
    acc2tax_node an 
WHERE tn.taxid = an.taxid 
    and an.acc = 'AJ012531' 
GROUP by an.acc;