PostgreSQL中多个表的多个和/计数

时间:2011-07-27 19:10:12

标签: sql postgresql join count sum

我在这个网站上搜索了几个建议,但我还没有完全掌握我所追求的内容。我怀疑只是一个语法/标点符号问题,我只是缺少。

我使用phpPgAdmin处理数据库,该数据库跟踪与正在研究的狒狒群体相关的大量信息。我正在尝试查询,为每个狒狒确定我们为他们收集了多少不同类型的组织样本,以及我们为每个样本分别提供了多少不同类型的DNA样本有三个表格与我的问题:

表:“传记”有关于该组中所有动物的基本信息,尽管这个名字是我关心的。

name | birth
-----+-----------
A21  | 1968-07-01
AAR  | 2002-03-30
ABB  | 1998-09-10
ABD  | 2005-03-15
ABE  | 1986-01-01

表:“babtissue”跟踪多年来收集的不同组织的信息,包括以下三列。此表中的某些行代表我们不再拥有的组织样本,但仍然在数据库的其他位置引用,因此“avail”列可帮助我们筛选我们仍然存在的样本。

name | sample_type | avail
-----+-------------+------
A21  | BLOOD       | Y
A21  | BLOOD       | Y
A21  | TISSUE      | N
ABB  | BLOOD       | Y
ABB  | TISSUE      | Y

表:“dna”类似于babtissue。

name | sample_type | avail
-----+-------------+------
ABB  | GDNA        | N
ABB  | WGA         | Y
ACC  | WGA         | N
ALE  | GDNA        | Y
ALE  | GDNA        | Y

总而言之,我正在尝试编写一个将从传记中返回每个名字的查询,并在一列中告诉我我为每个人准备了多少'BLOOD','TISSUE','GDNA'和'WGA'样本。有点像...

name | bloodsamps | tissuesamps | gdnas | wgas | avail
-----+------------+-------------+-------+------+------
A21  | 2          | 0           | 0     | 0    | ?
AAR  | 0          | 0           | 0     | 0    | ?
ABB  | 1          | 1           | 0     | 1    | ?
ACC  | 0          | 0           | 0     | 0    | ?
ALE  | 0          | 0           | 2     | 0    | ?

(对于上面奇怪的格式表示道歉,我不太熟悉这种写作方式)

我尝试过的最新版本的查询:

select b.name,  
sum(case when t.sample_type='BLOOD' and t.avail='Y' then 1 else 0 end) as bloodsamps,   
sum(case when t.sample_type='TISSUE' and t.avail='Y' then 1 else 0 end) as tissuesamps,   
sum(case when d.sample_type='GDNA' and d.avail='Y' then 1 else 0 end) as gdnas,  
sum(case when d.sample_type='WGA' and d.avail='Y' then 1 else 0 end) as wgas  
from biograph b  
left join babtissue t on b.name=t.name  
left join dna d on b.name=d.name  
where b.name is not NULL  
group by b.name  
order by b.name  

我这样做时没有收到任何错误,但我知道它给我的数字是错的 - 太高了。我认为这与我使用多个连接有关,而且我的连接语法需要改变。

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

这些数字太高,因为您加入babtissue,然后加入dna,这会导致重复。

您可以尝试分解它。我不知道这种语法是否适用于您的数据库,但我相信它符合ANSI标准,所以请试一试......

SELECT
    SQ.name,
    SUM(CASE WHEN T.sample_type = 'BLOOD' AND T.avail = 'Y' THEN 1 ELSE 0 END) AS bloodsamps,
    SUM(CASE WHEN T.sample_type = 'TISSUE' AND T.avail = 'Y' THEN 1 ELSE 0 END) AS tissuesamps,
    SQ.gdnas,
    SQ.wgas
FROM
    (
    SELECT
        B.name,
        SUM(CASE WHEN D.sample_type = 'GDNA' AND T.avail = 'Y' THEN 1 ELSE 0 END) AS gdnas,
        SUM(CASE WHEN D.sample_type = 'WGA' AND T.avail = 'Y' THEN 1 ELSE 0 END) AS wgas
    FROM
        biograph B
    LEFT JOIN dna D ON D.name = B.name
    GROUP BY
        B.name
    ) AS SQ
LEFT JOIN babtissue T on T.name = SQ.name
WHERE SQ.name is not NULL
GROUP BY SQ.name, SQ.gdnas, SQ.wgas
ORDER BY SQ.name

名称真的可以为NULL吗?

答案 1 :(得分:1)

我不知道“avail”列,但这应该会为您提供您正在寻找的其他列:

SELECT  b.name,
        COALESCE (t.bloodsamps,  0) AS bloodsamps,
        COALESCE (t.tissuesamps, 0) AS tissuesamps
        COALESCE (d.gdnas, 0) AS gdnas 
        COALESCE (d.wgas,  0) AS wgas
    FROM biograph b
    LEFT JOIN (
        SELECT  name,
                SUM(CASE WHEN sample_type = 'BLOOD'  THEN 1 ELSE 0 END) AS bloodsamps,
                SUM(CASE WHEN sample_type = 'TISSUE' THEN 1 ELSE 0 END) AS tissuesamps
            FROM babtissue
            WHERE avail = 'Y'
            GROUP BY name
        ) t
        ON (t.name = b.name)
    LEFT JOIN (
        SELECT  name,
                SUM(CASE WHEN sample_type = 'GDNA' THEN 1 ELSE 0 END) AS gdnas,
                SUM(CASE WHEN sample_type = 'WGA'  THEN 1 ELSE 0 END) AS wgas
            FROM dna
            WHERE avail = 'Y'
            GROUP BY name
        ) d
        ON (d.name = b.name)
;