我的查询有问题
我有2张桌子:
1) Patient
*id: number
*name: varchar
2) Patient_coverage_list:
*item_id: number
*patient_id: number
*group_id: number
*start_date: date
*end_date: date
例如:
Patient
id | Name
1 | Mat
2 | Michael
patient_coverage_list
item_id | patient_id | group_id | start_date | end_date
1 | 1 | 12 | 2012-12-12 | 2015-12-12
2 | 1 | 12 | 2008-12-12 | 2009-12-12
3 | 1 | 12 | 2017-12-12 | 2018-12-12
4 | 1 | 15 | 2020-12-12 | 2021-12-12
5 | 2 | 12 | 2016-12-12 | 2019-12-12
6 | 2 | 11 | 2017-12-12 | 2018-12-12
7 | 2 | 12 | 2021-12-12 | 2022-12-12
我必须选择group_id等于12的所有Patient_coverage_list并使用带日期的过滤器,但是必须排除过滤器,例如:
方案1: 如果当前日期是2018-05-05,并且Patient_coverage_list看起来像这样,则显示的是介于start_date和end_date之间的行:
patient_coverage_list
item_id | patient_id | group_id | start_date | end_date
1 | 1 | 12 | 2012-12-12 | 2015-12-12
2 | 1 | 12 | 2008-12-12 | 2009-12-12
3 | 1 | 12 | 2017-12-12 | 2018-12-12
4 | 1 | 15 | 2020-12-12 | 2021-12-12
您显示的患者是:
3|1| 12 | 2017-12-12 | 2018-12-12
方案2: 如果当前日期是2018-05-05,并且Patient_coverage_list看起来像这样, 如果当前日期在开始日期和结束日期之间,则显示下一个日期在该日期之间:
patient_coverage_list
item_id | patient_id | group_id | start_date | end_date
1 | 1 | 12 | 2012-12-12 | 2015-12-12
2 | 1 | 12 | 2008-12-12 | 2009-12-12
4 | 1 | 15 | 2020-12-12 | 2021-12-12
您显示的患者是:
4 | 1 | 15 | 2020-12-12 | 2021-12-12
方案3: 如果当前日期是2018-05-05,并且Patient_coverage_list看起来像这样, 如果当前时间在start_date和end_date之间,并且没有下一个日期,则显示带有最后日期的行:
patient_coverage_list
item_id | patient_id | group_id | start_date | end_date
1 | 1 | 12 | 2012-12-12 | 2015-12-12
2 | 1 | 12 | 2008-12-12 | 2009-12-12
您显示的患者是:
1 | 1 | 12 | 2012-12-12 | 2015-12-12
我创建了一个查询,但我认为它会更好:
SELECT * FROM(
SELECT pa.id, pa.name, pel.item_id, pel.patient_id, pel.group_id, pel.start_date, pel.end_date
FROM patient pa
JOIN patient_coverage_list pel ON pel.patient_id = pa.id
WHERE pel.group_id = $1
AND pel.item_id IN (SELECT peli.item_id
FROM patient_coverage_list peli
WHERE peli.patient_id = pel.patient_id
AND peli.start_date < peli.end_date
AND now() > peli.start_date
AND now() < peli.end_date
ORDER BY peli.end_date ASC
LIMIT 1)
UNION ALL
SELECT pa.id, pa.name, pel.item_id, pel.patient_id, pel.group_id, pel.start_date, pel.end_date
FROM patient pa
JOIN patient_coverage_list pel ON pel.patient_id = pa.id
WHERE pel.group_id = $1
AND NOT (now() > pel.start_date AND now() < pel.end_date)
AND pel.start_date < pel.end_date
AND pel.item_id in (SELECT peli.item_id
FROM seligibility.patient_eligibility_list peli
WHERE peli.patient_id = pel.patient_id
AND peli.start_date > now()
ORDER BY peli.start_date DESC LIMIT 1)
AND pel.patient_id NOT IN (SELECT peli.patient_id
FROM seligibility.patient_eligibility_list peli
WHERE peli.patient_id = pel.patient_id
AND peli.start_date < peli.end_date
AND now() > peli.start_date
AND now() < peli.end_date
ORDER BY peli.end_date ASC LIMIT 1)
UNION ALL
SELECT pa.id, pa.name, pel.item_id, pel.patient_id, pel.group_id, pel.start_date, pel.end_date
FROM patient pa
JOIN patient_coverage_list pel ON pel.patient_id = pa.id
WHERE pel.group_id = $1
AND pel.start_date < pel.end_date
AND pel.item_id IN (SELECT peli.item_id
FROM seligibility.patient_eligibility_list peli
WHERE peli.patient_id = pel.patient_id
AND now() > peli.end_date
ORDER BY peli.end_date DESC LIMIT 1)
AND pel.patient_id NOT IN (SELECT peli.patient_id
FROM seligibility.patient_eligibility_list peli
WHERE peli.patient_id = pel.patient_id
AND peli.start_date < peli.end_date
AND now() > peli.start_date
AND now() < peli.end_date
ORDER BY peli.end_date ASC LIMIT 1)
AND pel.patient_id NOT IN (SELECT peli.patient_id
FROM seligibility.patient_eligibility_list peli
WHERE peli.patient_id = pel.patient_id
AND peli.start_date > now()
ORDER BY peli.start_date DESC LIMIT 1)) AS patient ORDER BY patient.id
答案 0 :(得分:0)
没有理由将如此多的选择嵌套在一起。给定的方案看起来非常简单。因此,让我们从一个接一个地开始,可能在这个答案下面说明你的意思。
方案1:这似乎很简单。完全不需要从patient_coverage_list
进行嵌套SELECT:
SELECT *
FROM patient AS pa
JOIN patient_coverage_list AS pel ON pel.patient_id = pa.id
WHERE pel.group_id = $1
AND pel.end_date > CURRENT_DATE -- use CURRENT_DATE instead of NOW() if making date comparisons
AND pel.start_date < CURRENT_DATE
ORDER BY pel.end_date ASC
LIMIT 1;
方案2:根据您的示例,您实际上是在start_date
之后搜索最低的CURRENT_DATE
:
SELECT *
FROM patient AS pa
JOIN patient_coverage_list AS pel ON pel.patient_id = pa.id
WHERE pel.group_id = $1
AND pel.start_date > CURRENT_DATE
ORDER BY pel.start_date ASC
LIMIT 1;
请注意,您不需要从上一个查询中过滤出结果,因为该数据集永远不会与该数据集相交(请参见start_date和CURRENT_DATE
的比较)。
场景3:在这里,我们需要帮助我们解决嵌套查询,该查询告诉我们end_date
之后是否有CURRENT_DATE
条目。如果存在,由于AND
的关系,查询返回空集,否则返回最高end_date
的条目:
SELECT *
FROM patient AS pa
JOIN patient_coverage_list AS pel ON pel.patient_id = pa.id
WHERE pel.group_id = $1
AND NOT EXISTS ( SELECT *
FROM patient_coverage_list AS pel1
WHERE pel1.group_id = $1 -- important if you want to make comparison within the same group_id
AND pel1.end_date > CURRENT_DATE
)
ORDER BY pel.end_date DESC -- you don't mention what is meant by the "last date", if you meant start_date or end_date
LIMIT 1;
请注意,最好使用WHERE EXISTS (SELECT * FROM ... WHERE ...)
而不是WHERE id IN (SELECT id FROM ...)
,以便RDBMS不需要创建嵌套SELECT
的数据集,然后将其与外部{{ 1}}。明智地使用嵌套的SELECT。