【问题标题】:SQL - SELECT LEFT JOIN removes a row instead of having a NULL value in columnSQL - SELECT LEFT JOIN 删除一行而不是列中的 NULL 值
【发布时间】:2017-10-31 22:33:05
【问题描述】:

我有这个 SQL 查询,它返回下表:

    select tk1.ticketid,tk1.ownergroup,tk1.CHANGEDATE as dateentered 
    from tkstatus as tk1
    where TK1.TICKETID='SR4402' and ownergroup is not null
    ORDER BY  dateentered

TICKETID    OWNERGROUP                 DATEENTERED
SR4402      CONTROLDESK-ESB        2017-05-17 14:01:32
SR4402      IT-ZAŠTITA             2017-05-24 13:11:34
SR4402      IT-PODRŠKA             2017-05-24 13:30:57
SR4402      IT-ZAŠTITA             2017-05-24 13:46:17
SR4402      IT-PODRŠKA             2017-05-24 13:52:52
SR4402      IT-ZAŠTITA             2017-05-24 14:12:32

TKSTATUS 表有整数主列TKSTATUSID,它对每一行都是唯一的,并且每一行都有更大的下一个值。

现在,对于我想要查找该记录何时退出该组的每一行,这意味着这是下一组的时间。 所以基本上对于这张表,我应该再有 6 行,但最后一行应该有该列DATEEXITED NULL,因为它仍在该组中。 所以我写了这个查询:

select tk1.ticketid,tk1.status,tk1.ownergroup,
tk1.CHANGEDATE as dateentered,tk2.changedate as dateexited  
from tkstatus as    tk1
left outer join tkstatus as tk2 on tk2.ticketid=tk1.ticketid
where 
tk2.tkstatusid in (
    SELECT MIN(tk3.TKSTATUSID) 
    FROM TKSTATUS as tk3
    WHERE tk3.TICKETID=tk2.ticketid AND tk3.ownergroup is not null 
    and tk3.ownergroup!=tk1.ownergroup AND tk3.CHANGEDATE>tk1.changedate
)    
AND TK1.TICKETID='SR4402' 
ORDER BY  dateentered

这会返回 5 行而不是 6 行!!! 我希望第 6 行有列 DATEEXITED null

TICKETID      OWNERGROUP          DATEENTERED         DATEEXITED
SR4402     CONTROLDESK-ESB    2017-05-17 14:01:32   2017-05-24 13:11:34
SR4402       IT-ZAŠTITA       2017-05-24 13:11:34   2017-05-24 13:30:57
SR4402       IT-PODRŠKA       2017-05-24 13:30:57   2017-05-24 13:46:17
SR4402       IT-ZAŠTITA       2017-05-24 13:46:17   2017-05-24 13:52:52
SR4402       IT-PODRŠKA       2017-05-24 13:52:52   2017-05-24 14:12:32

我想以某种方式拥有和最后一行这样的

SR4402      IT-ZAŠTITA             2017-05-24 14:12:32   NULL

重要提示:

  1. TKSTATUSIDTKSTATUS 表的主要唯一列

  2. 我之前尝试在 ON 之后的 JOIN 中包含 TKSTATUSID,但随后返回 SQLSTATE 错误 42972,因为在 JOIN 之后我不能拥有 INMIN

所以这不起作用(返回错误)。

 left outer join tkstatus as tk2 on 
      tk2.ticketid=tk1.ticketid
 and  tk2.tkstatusid in (
      SELECT  MIN(tk3.TKSTATUSID)
      FROM    TKSTATUS as tk3
      WHERE   tk3.TICKETID=tk2.ticketid
          AND tk3.ownergroup is not null 
          and tk3.ownergroup!=tk1.ownergroup
          and tk3.CHANGEDATE>tk1.changedate)

【问题讨论】:

  • 您需要将 tk2.tkstatusid 的条件从 where 移到 JOIN 条件中
  • 你能写出你的意思吗?
  • 请检查我更新的问题。我已经尝试将 TKSTATUSID 放入 JOIN 中,但是我遇到了问题,因为对于相同的查询,返回 sqlstate 42972
  • @Dejan Lounis 的回答演示了将 LEAD 与分区一起使用。显然它是在 9.7 版中添加到 DB2 中的。因此,如果可能,强烈建议您使用它。除了更容易阅读之外,它的性能应该比我的答案好得多(这是不支持这些功能的数据库的后备)。
  • @Dejan 为什么您无法使用您之前接受的答案以及非常 similar question

标签: sql select null db2 left-join


【解决方案1】:

您误解了 OUTER JOIN 的工作原理。 JOIN 条件将包括 OUTER 表中缺失的行。

left outer join tkstatus as tk2 on tk2.ticketid=tk1.ticketid

因此,如果您在给定的 tk1 行中缺少任何 tk2 行,tk1 仍将包括在内,但该行的所有 tk2 值将是 NULL

您已经表明情况并非如此,这表明没有必要使用 OUTER JOIN。

请注意,WHERE 子句实际上是在联接 之后应用的过滤器。如果您按如下方式更改 SELECT 列并注释掉 WHERE 子句,您应该会发现问题。

SELECT  tk1.ticketid, tk1.status, tk1.ownergroup,
        tk1.CHANGEDATE as dateentered,
        tk2.changedate as dateexited,
        tk2.tkstatusid,
        (
        SELECT  MIN(tk3.TKSTATUSID) 
        FROM    TKSTATUS as tk3
        WHERE   tk3.TICKETID=tk2.ticketid
            AND tk3.ownergroup is not null 
            and tk3.ownergroup!=tk1.ownergroup
            AND tk3.CHANGEDATE>tk1.changedate
        ) as MinTk3StatusId
 /* Rest of your query. .... Spelt out because apparently it wasn't obvious enough! */

您的 WHERE 子句要求 tk2.tkstatusid 等于子查询返回的值。 (请注意,使用IN 是没有意义的,因为子查询只返回一个聚合值。)

您无疑会发现,对于被 WHERE 子句过滤掉的行,最后两列并不相同。

实际上,我想我已经弄清楚你想要做什么了。它看起来像一个自连接来确定选择中下一个项目的 ChangeDate。通过使用子查询列可以显着简化您的查询,如下所示。

select  tk1.ticketid, tk1.status, tk1.ownergroup,
        tk1.CHANGEDATE as dateentered,
        (
        SELECT  MIN(tk2.CHANGEDATE) 
        FROM    TKSTATUS as tk2
        WHERE   tk2.TICKETID=tk1.ticketid 
            /*Hopefully I've got this logic correct*/
            AND tk2.ownergroup != tk1.OwnerGroup
            and tk2.CHANGEDATE > tk1.changedate
        ) AS DateExited
from    TkStatus tk1
where   tk1.TICKETID = 'SR4402'

但是,使用“窗口或排名”功能会更有效。我不知道 DB2 是否支持这一点或者它会使用什么语法。但是,如果我提出的解决方案不够快,请随时进一步调查。

【讨论】:

  • 嗨,这不起作用我仍然有 5 行结果。 TKSTATUSID 是我正在谈论的此表的主唯一键,并且始终填充 TKSTATUSID
  • 您能否再次检查一下,因为这与您的建议不符?谢谢
  • @Dejan 当我没有您的数据时,我很难检查。 ;) 由于您已指出始终填充 tk2.tkstatusid,因此问题略有不同。但是您仍然误解了 OUTER JOINS。我会更新我的答案。
  • tkstatusid 总是被填充,因为它是 tkstatus 中的唯一列,我将更新我的问题
  • 嗨,克雷格,在您的第一个 SQL 查询中,TK2 定义在哪里?我看不到您定义了什么是 TK2,您可以检查一下吗?谢谢
【解决方案2】:

您的问题是加入后的 where 语句。我不知道您是否必须使用连接,但如果您想使用潜在客户产生结果,您可以简单地使用:

select ticketid,ownergroup,CHANGEDATE as dateentered, 
lead(CHANGEDATE) over (partition by TICKETID order by CHANGEDATE) as dateexited
from tkstatus as tk1
where TK1.TICKETID='SR4402' and ownergroup is not null
ORDER BY dateentered

【讨论】:

    猜你喜欢
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 2016-09-14
    • 2014-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多