2010-03-19 38 views
6

Tôi đang cố gắng tạo chế độ xem dạng bảng tổng hợp trong postgresql và gần như ở đó! Dưới đây là các truy vấn cơ bản:cách chính xác để tạo bảng tổng hợp trong postgresql bằng cách sử dụng 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'; 

Và dữ liệu:

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 

Những gì tôi đang cố gắng để có được như sau:

acc  | species     | phylum 
AJ012531 | Paromalostomum fusculum | Platyhelminthes 

Tôi cố gắng để làm điều này với CASE KHI , vì vậy tôi đã có được như sau như sau:

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

nào mang lại cho tôi kết quả:

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

Bây giờ tôi biết rằng tôi phải nhóm bằng acc tại một số điểm, vì vậy tôi cố gắng

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; 

Nhưng tôi nhận được sợ hãi

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

Tất cả các ví dụ trước tôi đã có thể tìm thấy sử dụng một cái gì đó giống như SUM() xung quanh các câu lệnh CASE, vì vậy tôi đoán đó là hàm tổng hợp. Tôi đã cố gắng sử dụng 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; 

nhưng nhận được lỗi:

ERROR: function first(character varying) does not exist 

bất cứ ai có thể đưa ra bất kỳ gợi ý?

+0

Ông có thể xin vui lòng gửi kết quả của truy vấn này: ' CHỌN * TỪ acc2tax_node WHERE acc = 'AJ012531''? – Quassnoi

Trả lời

5

Sử dụng MAX() hoặc MIN(), không phải FIRST(). Trong trường hợp này, bạn sẽ có tất cả các NULL trong cột cho mỗi giá trị nhóm ngoại trừ, nhiều nhất, một với một giá trị không null. Theo định nghĩa, đây là cả MIN và MAX của tập hợp các giá trị đó (tất cả các null đều bị loại trừ).

+0

Điều đó hoạt động hoàn hảo, cảm ơn bạn. Đối với một số lý do tôi giả định rằng MAX() sẽ không hoạt động vì tôi đã sử dụng các giá trị chuỗi. – 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

Hãy tha thứ cho những nỗ lực khủng khiếp của tôi ở định dạng :-) – mojones

0

Thêm thông tin theo yêu cầu (trong bài trả lời chứ không phải là một lời nhận xét để định dạng đẹp):

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 không có một vài chức năng cho các truy vấn trục, xem bài viết này tại Postgresonline. Bạn có thể tìm thấy các chức năng này trong contrib.

+0

Có, tôi nghi ngờ rằng cách chính xác để làm điều này là với scrosstab. Tôi vẫn muốn tìm ra những gì tôi đang làm sai ở đây vì sự giáo dục của chính tôi. – 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

Như Matthew Gỗ chỉ ra, sử dụng MIN() hoặc MAX(), không 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; 
Các vấn đề liên quan