假设病人多次访问。我想编写一个查询,根据他们最早的访问返回不同的患者行。例如,请考虑以下行。
patients
-------------
id name
1 Bob
2 Jim
3 Mary
visits
-------------
id patient_id visit_date reference_number
1 1 6/29/14 09f3be26
2 1 7/8/14 34c23a9e
3 2 7/10/14 448dd90a
查询返回的内容是:
id name first_visit_date reference_number
1 Bob 6/29/14 09f3be26
2 Jim 7/10/14 448dd90a
我尝试的内容类似于:
SELECT
patients.id,
patients.name,
visits.visit_date AS first_visit_date,
visits.reference_number
FROM
patients
INNER JOIN (
SELECT
*
FROM
visits
ORDER BY
visit_date
LIMIT
1
) visits ON
visits.patient_id = patients.id
添加LIMIT
会导致查询返回0行,但删除它会导致查询返回重复项。这里的诀窍是什么?我也尝试在INNER JOIN中选择MIN(visit_date)
,但也会返回重复项。
更新
有人建议这个问题是重复的,但对我而言似乎有所不同,因为我在两个单独的表中这样做。另一个问题上接受的答案建议加入y.max_total = x.total
,如果正在加入的表是从中选择的表,则可以使用{{1}}。另外,我需要使用MIN日期返回行中的其他列,而不仅仅是日期本身。
然而,我接受的答案很有效。
答案 0 :(得分:2)
避免使用DISTINCT ON(p.id)
,而是使用普通的NOT EXISTS(...)
代替
SELECT p.id, p.name
, v.first_visit_date, v.reference_number
FROM patients p
JOIN visits v ON p.id = v.patient_id
-- exclude all join-products that are not the first for a patient.
WHERE NOT EXISTS (
SELECT *
FROM visits nx
WHERE nx.patient_id = v.patient_id
AND ( nx.visit_date < v.visit_date
OR (nx.visit_date = v.visit_date AND nx.id < v.id) -- tie-breaker condition
)
);
答案 1 :(得分:1)
使用distinct on
select distinct on (p.id)
p.id,
p.name,
v.visit_date as first_visit_date,
v.reference_number
from
patients p
inner join
visits v on p.id = v.patient_id
order by p.id, v.visit_date
http://www.postgresql.org/docs/current/static/sql-select.html#SQL-DISTINCT
答案 2 :(得分:0)
您希望聚合查询将visits
表的多行减少为每个患者ID一行。 LIMIT有点乱,因为它不是严格的关系,但如果你有足够的决心,你可能会使它工作。如果查询优化器足够好,那么使用LIMIT(适当)的版本之间应该没有性能差异:
SELECT
patients.id,
patients.name,
visits.first_visit_date AS first_visit_date,
visits.reference_number
FROM
patients
INNER JOIN (
SELECT
patient_id,
MIN(visit_date) as first_visit_date
FROM
visits
GROUP BY
patient_id
) visits ON
visits.patient_id = patients.id
我更喜欢带有MIN()的版本,因为它对我来说更清晰。此外,如果它对我来说更清楚,那么它也更有可能让查询优化器更清晰。
答案 3 :(得分:0)
虽然您使用的是PostgreSQL,但为了防止它有用或“鼓舞人心”,这里是T-SQL版本。
SELECT p.id, name, first_visit.visit_date as first_visit_date, v.reference_number as first_visit_reference_number
FROM patients p
INNER JOIN
(
SELECT patient_id, MIN(visit_date) AS visit_date
FROM visits
GROUP BY patient_id
) first_visit ON first_visit.patient_id = p.id
INNER JOIN visits v ON v.patient_id = p.id AND v.visit_date = first_visit.visit_date