Oracle SQL 遍历日期范围
Oracle SQL Loop through Date Range
我正在尝试编写执行以下操作的查询:
- 从访问 table
中获取 Start_Date 和 End_Date
- 对于日期范围内的每个日期,搜索相遇 table
查看某位提供者是否在该日期看过患者
- 生成一个 table 来显示每个日期以及在该日期看到患者的人
日期。
- 备注:
- 该患者可能没有在该日期出现,这应该导致 NULL 或类似的结果
- 可能有不止一位提供者在某个日期看过患者,因此该日期的行数应该不止一行。
简化示例:
Start_Date:2015 年 1 月 1 日
End_Date:2015 年 1 月 4 日
期望的输出:
╔══════╦══════════╦═══════╦═══════╗
║ ID ║ DATE ║ NAME ║ TYPE ║
╠══════╬══════════╬═══════╬═══════╣
║ 2222 ║ 1-Jan-15 ║ Smith ║ Note ║
║ 2222 ║ 2-Jan-15 ║ Jones ║ Note ║
║ 2222 ║ 2-Jan-15 ║ Smith ║ Order ║
║ 2222 ║ 3-Jan-15 ║ NULL ║ ║
║ 2222 ║ 4-Jan-15 ║ Jones ║ Note ║
╚══════╩══════════╩═══════╩═══════╝
这是我目前所知道的。这会生成这些特定提供者何时看到患者的列表,但对于那些未看到患者的日期,它不会产生 NULL。
SELECT V.VISIT_ID, ET.ENCOUNTER_TRANSACTION_DATE, P.NAME_LAST, ETT.ENC_TRANS_TYPE_NAME
FROM VISIT V
RIGHT OUTER JOIN ENCOUNTER_TRANSACTION ET ON V.VISIT_ID = ET.VISIT_ID AND V.INSTITUTION_ID = ET.INSTITUTION_ID
INNER JOIN ENCOUNTER_TRANSACTION_TYPE ETT ON ET.ENCOUNTER_TYPE_ID = ETT.ENCOUNTER_TRANSACTION_TYPE_ID
INNER JOIN LOCAL_PROVIDER LP ON ET.ORDERING_PROVIDER_ID = LP.LOCAL_PROVIDER_ID
INNER JOIN PERSON_IDENTIFIER I ON I.IDENTIFIER = LP.PROVIDER_NUMBER AND I.IDENTIFIER_SYS_ID = LP.PROVIDER_NUMBER_SYS_ID
INNER JOIN PERSON P ON P.PERSON_ID = I.PERSON_ID
WHERE
V.INSTITUTION_ID = 1 AND
V.END_DATE IS NOT NULL AND
V.VOIDED_YN = 'N' AND
V.CARE_SETTING_CODE = 'I' AND
V.PATIENT_TEAM_ID IN (16, 17, 18) AND
V.START_DATE >= (TRUNC(ADD_MONTHS(CURRENT_DATE, -1),'mon')) AND
V.START_DATE <= (LAST_DAY(ADD_MONTHS(CURRENT_DATE, -1))) AND
I.IDENTIFIER IN (
'1234', --Smith
'4321', --Jones
)
ORDER BY V.VISIT_ID ASC, ET.ENCOUNTER_TRANSACTION_DATE ASC;
当前输出(缺少 03-JAN-15 的 NULL 行):
╔══════╦══════════╦═══════╦═══════╗
║ ID ║ DATE ║ NAME ║ TYPE ║
╠══════╬══════════╬═══════╬═══════╣
║ 2222 ║ 1-Jan-15 ║ Smith ║ Note ║
║ 2222 ║ 2-Jan-15 ║ Jones ║ Note ║
║ 2222 ║ 2-Jan-15 ║ Smith ║ Order ║
║ 2222 ║ 4-Jan-15 ║ Jones ║ Note ║
╚══════╩══════════╩═══════╩═══════╝
以下是获取日期范围的方法:
SELECT DATE'2015-01-01' + LEVEL - 1
FROM dual
CONNECT BY DATE'2015-01-01' + LEVEL - 1 < DATE'2015-02-01';
以上将获取2015年1月1日至2015年1月31日范围内的所有日期。
使用上述方法,您可以做的是插入开始日期和结束日期并创建 CTE,然后对日期使用外部联接:
WITH dr AS (
SELECT DATE'2015-01-01' + LEVEL - 1 AS transaction_date
FROM dual
CONNECT BY DATE'2015-01-01' + LEVEL - 1 < DATE'2015-01-04'
)
SELECT V.VISIT_ID, dr.transaction_date
, P.NAME_LAST, ETT.ENC_TRANS_TYPE_NAME
...
ENCOUNTER_TRANSACTION ET RIGHT JOIN dr
ON ET.ENCOUNTER_TRANSACTION_DATE = dr.transaction_date
UPDATE 我花了一些时间,我想我明白了如何将上述内容整合到您的查询中。我真的没有 SQL Fiddle 的样本数据(无论如何你有很多表格)。这是您可以开始的地方,这应该获得所有适当的访问加上访问日期范围内的每个日期(假设没有访问超过 30 天 - 相应地调整):
WITH dr AS (
SELECT LEVEL AS dd FROM dual
CONNECT BY LEVEL <= 30 -- I'm assuming a max date range of 30; increase as you see fit
)
SELECT v.visit_id, v.start_date - 1 + dr.dd AS encounter_transaction_date
, p.name_last, ett.enc_trans_type_name
FROM visit v CROSS JOIN dr
WHERE v.start_date - 1 + dr.dd < TRUNC(v.end_date) + 1
AND v.institution_id = 1
AND v.end_date IS NOT NULL
AND v.voided_yn = 'N'
AND v.care_setting_code = 'I'
AND v.patient_team_id IN (16,17,18)
AND v.start_date >= TRUNC(ADD_MONTHS(CURRENT_DATE, -1), 'MONTH')
AND v.end_date < TRUNC(CURRENT_DATE, 'MONTH');
然后我认为你的外部连接应该是从那里开始的 LEFT JOIN(至少,如果我理解正确的话我可能不会:
WITH dr AS (
SELECT LEVEL AS dd FROM dual
CONNECT BY LEVEL <= 30 -- I'm assuming a max date range of 30; increase as you see fit
)
SELECT v.visit_id, v.start_date - 1 + dr.dd AS encounter_transaction_date
FROM visit v CROSS JOIN dr
LEFT JOIN encounter_transaction et
ON v.visit_id = et.visit_id
AND v.institution_id = et.institution_id
AND TRUNC(v.start_date - 1 + dr.dd) = et.encounter_transaction_date
LEFT JOIN encounter_transaction_type ETT
ON et.encounter_type_id = ett.encounter_transaction_type_id
LEFT JOIN local_provider lp
ON et.ordering_provider_id = lp.local_provider_id
LEFT JOIN person_identifier i
ON i.identifier = lp.provider_number
AND i.identifier_sys_id = lp.provider_number_sys_id
AND i.identifier IN (
'1234', --Smith
'4321' --Jones ** you had an extra comma here!
)
LEFT JOIN person p
ON p.person_id = i.person_id
WHERE v.start_date - 1 + dr.dd < TRUNC(v.end_date) + 1
AND v.institution_id = 1
AND v.end_date IS NOT NULL
AND v.voided_yn = 'N'
AND v.care_setting_code = 'I'
AND v.patient_team_id IN (16,17,18)
AND v.start_date >= TRUNC(ADD_MONTHS(CURRENT_DATE, -1), 'MONTH')
AND v.start_date < TRUNC(CURRENT_DATE, 'MONTH');
我正在尝试编写执行以下操作的查询:
- 从访问 table 中获取 Start_Date 和 End_Date
- 对于日期范围内的每个日期,搜索相遇 table 查看某位提供者是否在该日期看过患者
- 生成一个 table 来显示每个日期以及在该日期看到患者的人 日期。
- 备注:
- 该患者可能没有在该日期出现,这应该导致 NULL 或类似的结果
- 可能有不止一位提供者在某个日期看过患者,因此该日期的行数应该不止一行。
简化示例:
Start_Date:2015 年 1 月 1 日
End_Date:2015 年 1 月 4 日
期望的输出:
╔══════╦══════════╦═══════╦═══════╗
║ ID ║ DATE ║ NAME ║ TYPE ║
╠══════╬══════════╬═══════╬═══════╣
║ 2222 ║ 1-Jan-15 ║ Smith ║ Note ║
║ 2222 ║ 2-Jan-15 ║ Jones ║ Note ║
║ 2222 ║ 2-Jan-15 ║ Smith ║ Order ║
║ 2222 ║ 3-Jan-15 ║ NULL ║ ║
║ 2222 ║ 4-Jan-15 ║ Jones ║ Note ║
╚══════╩══════════╩═══════╩═══════╝
这是我目前所知道的。这会生成这些特定提供者何时看到患者的列表,但对于那些未看到患者的日期,它不会产生 NULL。
SELECT V.VISIT_ID, ET.ENCOUNTER_TRANSACTION_DATE, P.NAME_LAST, ETT.ENC_TRANS_TYPE_NAME
FROM VISIT V
RIGHT OUTER JOIN ENCOUNTER_TRANSACTION ET ON V.VISIT_ID = ET.VISIT_ID AND V.INSTITUTION_ID = ET.INSTITUTION_ID
INNER JOIN ENCOUNTER_TRANSACTION_TYPE ETT ON ET.ENCOUNTER_TYPE_ID = ETT.ENCOUNTER_TRANSACTION_TYPE_ID
INNER JOIN LOCAL_PROVIDER LP ON ET.ORDERING_PROVIDER_ID = LP.LOCAL_PROVIDER_ID
INNER JOIN PERSON_IDENTIFIER I ON I.IDENTIFIER = LP.PROVIDER_NUMBER AND I.IDENTIFIER_SYS_ID = LP.PROVIDER_NUMBER_SYS_ID
INNER JOIN PERSON P ON P.PERSON_ID = I.PERSON_ID
WHERE
V.INSTITUTION_ID = 1 AND
V.END_DATE IS NOT NULL AND
V.VOIDED_YN = 'N' AND
V.CARE_SETTING_CODE = 'I' AND
V.PATIENT_TEAM_ID IN (16, 17, 18) AND
V.START_DATE >= (TRUNC(ADD_MONTHS(CURRENT_DATE, -1),'mon')) AND
V.START_DATE <= (LAST_DAY(ADD_MONTHS(CURRENT_DATE, -1))) AND
I.IDENTIFIER IN (
'1234', --Smith
'4321', --Jones
)
ORDER BY V.VISIT_ID ASC, ET.ENCOUNTER_TRANSACTION_DATE ASC;
当前输出(缺少 03-JAN-15 的 NULL 行):
╔══════╦══════════╦═══════╦═══════╗
║ ID ║ DATE ║ NAME ║ TYPE ║
╠══════╬══════════╬═══════╬═══════╣
║ 2222 ║ 1-Jan-15 ║ Smith ║ Note ║
║ 2222 ║ 2-Jan-15 ║ Jones ║ Note ║
║ 2222 ║ 2-Jan-15 ║ Smith ║ Order ║
║ 2222 ║ 4-Jan-15 ║ Jones ║ Note ║
╚══════╩══════════╩═══════╩═══════╝
以下是获取日期范围的方法:
SELECT DATE'2015-01-01' + LEVEL - 1
FROM dual
CONNECT BY DATE'2015-01-01' + LEVEL - 1 < DATE'2015-02-01';
以上将获取2015年1月1日至2015年1月31日范围内的所有日期。
使用上述方法,您可以做的是插入开始日期和结束日期并创建 CTE,然后对日期使用外部联接:
WITH dr AS (
SELECT DATE'2015-01-01' + LEVEL - 1 AS transaction_date
FROM dual
CONNECT BY DATE'2015-01-01' + LEVEL - 1 < DATE'2015-01-04'
)
SELECT V.VISIT_ID, dr.transaction_date
, P.NAME_LAST, ETT.ENC_TRANS_TYPE_NAME
...
ENCOUNTER_TRANSACTION ET RIGHT JOIN dr
ON ET.ENCOUNTER_TRANSACTION_DATE = dr.transaction_date
UPDATE 我花了一些时间,我想我明白了如何将上述内容整合到您的查询中。我真的没有 SQL Fiddle 的样本数据(无论如何你有很多表格)。这是您可以开始的地方,这应该获得所有适当的访问加上访问日期范围内的每个日期(假设没有访问超过 30 天 - 相应地调整):
WITH dr AS (
SELECT LEVEL AS dd FROM dual
CONNECT BY LEVEL <= 30 -- I'm assuming a max date range of 30; increase as you see fit
)
SELECT v.visit_id, v.start_date - 1 + dr.dd AS encounter_transaction_date
, p.name_last, ett.enc_trans_type_name
FROM visit v CROSS JOIN dr
WHERE v.start_date - 1 + dr.dd < TRUNC(v.end_date) + 1
AND v.institution_id = 1
AND v.end_date IS NOT NULL
AND v.voided_yn = 'N'
AND v.care_setting_code = 'I'
AND v.patient_team_id IN (16,17,18)
AND v.start_date >= TRUNC(ADD_MONTHS(CURRENT_DATE, -1), 'MONTH')
AND v.end_date < TRUNC(CURRENT_DATE, 'MONTH');
然后我认为你的外部连接应该是从那里开始的 LEFT JOIN(至少,如果我理解正确的话我可能不会:
WITH dr AS (
SELECT LEVEL AS dd FROM dual
CONNECT BY LEVEL <= 30 -- I'm assuming a max date range of 30; increase as you see fit
)
SELECT v.visit_id, v.start_date - 1 + dr.dd AS encounter_transaction_date
FROM visit v CROSS JOIN dr
LEFT JOIN encounter_transaction et
ON v.visit_id = et.visit_id
AND v.institution_id = et.institution_id
AND TRUNC(v.start_date - 1 + dr.dd) = et.encounter_transaction_date
LEFT JOIN encounter_transaction_type ETT
ON et.encounter_type_id = ett.encounter_transaction_type_id
LEFT JOIN local_provider lp
ON et.ordering_provider_id = lp.local_provider_id
LEFT JOIN person_identifier i
ON i.identifier = lp.provider_number
AND i.identifier_sys_id = lp.provider_number_sys_id
AND i.identifier IN (
'1234', --Smith
'4321' --Jones ** you had an extra comma here!
)
LEFT JOIN person p
ON p.person_id = i.person_id
WHERE v.start_date - 1 + dr.dd < TRUNC(v.end_date) + 1
AND v.institution_id = 1
AND v.end_date IS NOT NULL
AND v.voided_yn = 'N'
AND v.care_setting_code = 'I'
AND v.patient_team_id IN (16,17,18)
AND v.start_date >= TRUNC(ADD_MONTHS(CURRENT_DATE, -1), 'MONTH')
AND v.start_date < TRUNC(CURRENT_DATE, 'MONTH');