让我们在Oracle中进行简单查询:
SELECT
CASE.ID,
CASE.TYPE,
CASE.DATE_RAISED
FROM
CASE
WHERE
CASE.DATE_RAISED > '2019-01-01'
现在让我们说另一个表EVENT,其中包含可能与每种情况关联的多个事件(通过EVENT.CASE_ID链接)。或根本不存在。我想报告每种情况下最早的将来事件-如果不存在,则返回NULL。我可以使用SELECT子句中的子查询来做到这一点,如下所示:
SELECT
CASE.ID,
CASE.TYPE,
CASE.DATE_RAISED,
(
SELECT
MIN(EVENT.DATE)
FROM
EVENT
WHERE
EVENT.CASE_ID = CASE.ID
AND EVENT.DATE >= CURRENT_DATE
) AS MIN_EVENT_DATE
FROM
CASE
WHERE
CASE.DATE_RAISED > '2019-01-01'
这将返回如下表:
Case ID Case Type Date Raised Min Event Date
76 A 03/01/2019 10/05/2019
43 B 02/02/2019 [NULL]
89 A 29/01/2019 08/07/2019
90 A 04/03/2019 [NULL]
102 C 15/04/2019 20/05/2019
请注意,如果不存在任何符合条件的事件,则仍返回该行,但没有值。这是因为子查询在SELECT子句中。这样就可以了。
但是,我的问题是,如果我想从EVENT表中返回多个列-同时仍保留EVENT表中没有匹配行的可能性。上面的代码仅将EVENT.DATE作为单个子查询结果返回到主查询的ONE列。但是,如果我还想返回EVENT.ID或EVENT.TYPE,该怎么办?同时仍然允许它们为NULL(如果找不到CASE的匹配记录)?
我想我可以在SELECT子句中使用多个子查询:每个子查询仅返回一个列。但这似乎效率极低,因为每个子查询都基于相同的条件(其CASE ID与主查询的ID匹配的最小日期EVENT;如果未找到此类事件,则为NULL)。
我怀疑一些巧妙的连接将是答案-尽管我一直在努力准确地了解哪些连接。
请注意,上面的示例是我的实际代码的简化版本,其中已经包含“旧样式” Oracle格式的多个联接,例如:
WHERE
CASE.ID(+) = EVENT.CASE_ID
之所以如此是有原因的-因此,请回答此问题的任何人,请您以这种编码方式演示任何解决方案,因为我的SQL不够先进,无法重构“较新的” ”样式加入到现有代码中。
答案 0 :(得分:3)
您可以使用join
和窗口函数。例如:
select c.*, e.*
from c left join
(select e.*,
row_number() over (partition by e.case_id order by e.date desc) as seqnum
from events e
) e
on e.case_id = c.id and e.seqnum = 1;
where c.date_raised > date '2019-01-01'; -- assuming the value is a date
答案 1 :(得分:1)
这是您的意思吗?我只是用旧的Oracle连接语法和您的代码样式重写了戈登的答案。
SELECT
CASE.ID,
CASE.TYPE,
CASE.DATE_RAISED,
MIN_E.DATE AS MIN_EVENT_DATE
FROM
CASE,
(SELECT EVENT.*,
ROW_NUMBER() OVER (PARTITION BY EVENT.CASE_ID ORDER BY EVENT.DATE DESC) AS SEQNUM
FROM
EVENT
WHERE
EVENT.DATE >= CURRENT_DATE
) MIN_E
WHERE
CASE.DATE_RAISED > DATE '2019-01-01'
AND MIN_E.CASE_ID (+) = CASE.ID
AND MIN_E.SEQNUM (+) = 1;
答案 2 :(得分:0)
使用您想要的列创建对象类型并从子查询中返回它。您的查询将类似于
SELECT
CASE.ID,
CASE.TYPE,
CASE.DATE_RAISED,
(
SELECT
t_your_new_type ( MIN(EVENT.DATE) , min ( EVENT.your_another_column ) )
FROM
EVENT
WHERE
EVENT.CASE_ID = CASE.ID
AND EVENT.DATE >= CURRENT_DATE
) AS MIN_EVENT_DATE
FROM
CASE
WHERE
CASE.DATE_RAISED > '2019-01-01'