SQL嵌套查询,平均值
我是SQL新手。 我有三个标签:医生、病人和就诊。 这样,每次“就诊”都会联系到前来就诊的患者。 这些字段是: 医生(did、dname、专科、诊所) 患者(pid、pname、bmi、性别) 访问(did、pid、vdate、费用) 我需要找到医生的id,他的病人的平均bmi是最大的。以及平均计算需要考虑的因素 每个患者的医生一次,即使患者多次就诊 我写了这个查询:SQL嵌套查询,平均值,sql,postgresql,nested,average,Sql,Postgresql,Nested,Average,我是SQL新手。 我有三个标签:医生、病人和就诊。 这样,每次“就诊”都会联系到前来就诊的患者。 这些字段是: 医生(did、dname、专科、诊所) 患者(pid、pname、bmi、性别) 访问(did、pid、vdate、费用) 我需要找到医生的id,他的病人的平均bmi是最大的。以及平均计算需要考虑的因素 每个患者的医生一次,即使患者多次就诊 我写了这个查询: SELECT V.did FROM Visit V NATURAL JOIN Patient P GROUP BY V.did
SELECT V.did
FROM Visit V NATURAL JOIN Patient P
GROUP BY V.did
HAVING AVG(P.bmi) >= ALL
(SELECT AVG(P.bmi)
FROM Patient P NATURAL JOIN Visit V
GROUP BY V.did)
ORDER BY did ASC
我的问题是,对于每个医生,我需要在平均计算中只考虑医生的每个患者一次,即使患者多次就诊,并且在我的查询中,我会根据患者在同一位医生中就诊的次数反复计算患者。
如何更改查询以满足需求?请勿使用
自然加入!列出JOIN
键!这只是预防未来问题的好建议
如果您只需要一名医生,即使是在打领带的情况下,那么聚合、orderby
,以及某种版本的LIMIT
会满足您的需求
在标准SQL中,如下所示:
SELECT V.did
FROM Visit V JOIN
Patient P
USING (pid)
GROUP BY V.did
ORDER BY AVG(P.bmi) DESC
FETCH FIRST 1 ROW ONLY;
NATURAL JOIN
最大的问题是它没有使用正确声明的外键
关系。相反,它只依赖于具有相同名称的列。第二个大问题是键隐藏在查询中。因此,JOIN
可能没有达到预期的效果,并且可能没有行或笛卡尔积,而且调试非常困难
查找患者平均bmi最大的医生id
您的基本查询将如下所示(Gordon Linoff已经评论说,自然连接通常应该避免):
然后,你需要用领带筛选顶级医生。实际的解决方案取决于您的RDMBS
在Oracle中:
select d.did, d.dname, avg(p.bmi) avg_pmi
from doctor d
inner join visit on v.did = d.did
inner join patient p on p.pid = v.pid
group by d.did, d.dname
order by avg_pmi desc
fetch first 1 row with ties
在SQL Server中:
select top (1) with ties d.did, d.dname, avg(p.bmi) avg_pmi
from doctor d
inner join visit on v.did = d.did
inner join patient p on p.pid = v.pid
group by d.did, d.dname
order by avg_pmi desc
在其他系统中,如MySQL或Postgres,不支持带ties的,
,通常可以使用窗口功能:
select did, dname, avg_pmi
from (
select t.*, rank() over(order by avg_pmi desc) rn
from (
select d.did, d.dname, avg(p.bmi) avg_pmi
from doctor d
inner join visit on v.did = d.did
inner join patient p on p.pid = v.pid
group by d.did, d.dname
) t
) t
where rn = 1
用你正在使用的数据库标记你的问题。忘记自然连接结构。不要偷懒,指定连接条件。此外,如果稍后将一列添加到其中一个表中,并且与另一个表中的一列同名,则连接条件也会突然包括这些列。
select did, dname, avg_pmi
from (
select t.*, rank() over(order by avg_pmi desc) rn
from (
select d.did, d.dname, avg(p.bmi) avg_pmi
from doctor d
inner join visit on v.did = d.did
inner join patient p on p.pid = v.pid
group by d.did, d.dname
) t
) t
where rn = 1