Oracle SQL-从子查询返回多列

时间:2019-05-08 11:08:37

标签: sql oracle join subquery

让我们在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不够先进,无法重构“较新的” ”样式加入到现有代码中。

3 个答案:

答案 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'