2010-03-19 16 views
6

J'essaie de créer une vue de type tableau croisé dynamique dans postgresql et suis presque là! Voici la requête de base:façon correcte de créer un tableau croisé dynamique dans postgresql en utilisant 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'; 

Et les données:

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 

Ce que je suis en train de faire est la suivante:

acc  | species     | phylum 
AJ012531 | Paromalostomum fusculum | Platyhelminthes 

Je suis en train de le faire avec CASE QUAND , donc j'ai aussi loin que le suivant:

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'; 

Ce qui me donne la sortie:

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

Maintenant, je sais que je dois groupe par acc à un moment donné, donc j'essayer

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; 

Mais je reçois le

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

Tous les exemples précédents que j'ai pu trouver utilisent quelque chose comme SUM() autour des instructions CASE, donc je suppose que c'est la fonction d'agrégat. J'ai essayé d'utiliser FIRST():

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; 

mais obtenir l'erreur:

ERROR: function first(character varying) does not exist 

Quelqu'un peut-il offrir des conseils?

+0

Pourriez-vous s'il vous plaît afficher les résultats de cette requête: ' SELECT * FROM acc2tax_node O acc acc = 'AJ012531''? – Quassnoi

Répondre

5

Utilisez MAX() ou MIN() et non FIRST(). Dans ce scénario, vous aurez toutes les valeurs NULL dans la colonne pour chaque valeur de groupe à l'exception, au plus, d'une valeur non nulle. Par définition, il s'agit à la fois du MIN et du MAX de cet ensemble de valeurs (tous les NULL sont exclus).

+0

Cela fonctionne parfaitement, merci. Pour une raison quelconque, j'ai supposé que MAX() ne fonctionnerait pas parce que j'utilisais des valeurs de chaîne. – 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

S'il vous plaît excusez mes terribles tentatives de mise en forme :-) – mojones

0

plus d'informations à la demande (dans une réponse plutôt qu'un commentaire pour belle mise en forme):

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 a un couple de fonctions pour les requêtes de pivot, consultez cet article à Postgresonline. Vous pouvez trouver ces fonctions dans le contrib.

+0

Oui, je soupçonne que la bonne façon de le faire est avec scrosstab. Je voudrais toujours comprendre ce que je fais mal ici pour ma propre éducation. – mojones

0

Exécuter:

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

Comme Matthew Wood a souligné, utilisez MIN() ou MAX(), non 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;