【问题标题】:[SQL][DB2] Returns 0 when no records[SQL][DB2] 无记录时返回 0
【发布时间】:2020-05-25 12:27:46
【问题描述】:

以下查询返回每月的交易数量。 我希望查询在 TV_TRANSACTION 表中没有交易(无记录)的月份返回 0。

WITH
msc (num) AS
(VALUES (TIMESTAMP('2019-10-01 00:00:00.001'))
UNION ALL
SELECT num + 1 MONTH
FROM msc
WHERE num < current timestamp - 1 MONTH
)
SELECT SUBSTR(CHAR(num),1,7), 
count(case when t.STATUS = 44 and t.TRANSACTION_TYPE = 0 then 1 else 0 end) FROM TV_TRANSACTION t
join TB_INSTALLATION i on t.INSTALLATION_ID = i.INSTALLATION_ID
right join msc mc on SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) = SUBSTR(CHAR(mc.num),1,7)
where i.IB24_VERSION = 2
and date(t.REGISTRATION_DATE) >= '2019-10-01'
and t.STATUS = 44
and t.TRANSACTION_TYPE = 0
and SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) >= SUBSTR(CHAR(i.IB24_VERSION_UPDATE_DATE),1,7)
group by SUBSTR(CHAR(mc.num),1,7)

此时查询返回结果

2020-02 | 1552
2020-03 | 6981
2020-04 | 16439
2020-05 | 5

如何修改查询以获得这样的结果?:

2019-10 | 0
2019-11 | 0
2019-12 | 0
2020-01 | 0    
2020-02 | 1552
2020-03 | 6981
2020-04 | 16439
2020-05 | 5

【问题讨论】:

  • 您需要以某种方式从月份列表开始;也许来自日历表。
  • RIGHT JOIN 会自动转换为 INNER JOIN,因为您的 WHERE 子句包含左表中的列。这就是问题所在。解决方案:WHERE改为AND
  • @GordonLinoff, msc 表返回月份列表
  • 你把WHERE改成AND了吗?

标签: sql date join db2 recursive-query


【解决方案1】:

CTE 开始连接,并为其他表使用LEFT 连接,包括 ON 子句中的所有条件,而不是 WHERE 子句:

WITH msc(num) AS (
  VALUES (TIMESTAMP('2019-10-01 00:00:00.001'))
  UNION ALL
  SELECT num + 1 MONTH
  FROM msc
  WHERE num < current timestamp - 1 MONTH
)
SELECT 
  SUBSTR(CHAR(num),1,7), 
  COUNT(CASE WHEN t.STATUS = 44 AND t.TRANSACTION_TYPE = 0 THEN 1 END) 
FROM msc mc
LEFT JOIN TV_TRANSACTION t 
ON    SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) = SUBSTR(CHAR(mc.num),1,7)
  AND date(t.REGISTRATION_DATE) >= '2019-10-01'
  AND t.STATUS = 44
  AND t.TRANSACTION_TYPE = 0
LEFT JOIN TB_INSTALLATION i 
ON    t.INSTALLATION_ID = i.INSTALLATION_ID
  AND i.IB24_VERSION = 2
  AND SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) >= SUBSTR(CHAR(i.IB24_VERSION_UPDATE_DATE),1,7)
GROUP BY SUBSTR(CHAR(mc.num),1,7)

我还从COUNT()CASE 表达式中删除了ELSE 部分。

【讨论】:

    【解决方案2】:

    已经评论说您需要将条件放在连接中而不是 where 子句中。此外,如果您从日期表开始,然后使用left joins 带来附加表,则逻辑要简单得多。

    据我所知,其他修复优化是可能的:

    • 您可以在 cte 中使用日期而不是时间戳

    • 使用半开区间过滤比使用字符串函数更有效(这使得这些谓词 SARGeable,意味着它们可以利用索引)

    • count() 中不需要条件逻辑,因为它已经匹配连接条件

    • count() 考虑0(它仅忽略null 值)-大概,您只想计算每个日期在两个表中可用的记录数,因此从第二个开始计算任何记录left join就够了

    • 我将 cte 重命名为对我更有意义的名称

    这应该(足够接近)你想要的:

    with all_dates (dt) as
        (values (date('2019-10-01''))
        union all
        select num + 1 month from msc where num < current timestamp 
    )
    select 
        d.dt,
        count(i.installation_id) no_matches 
    from  all_dates d
    left join tv_transaction t
        on  t.registration_date >= d.dt
        and t.registration_date < d.dt + 1 day
        and t.status = 44
        and t.transaction_type = 0
    left join tb_installation i 
        on  i.installation_id = t.installation_id
        and i.ib24_version = 2
        and i.ib24_version_update_date <= d.dt
    group by d.dt
    

    【讨论】:

      【解决方案3】:

      谢谢你们。我已经修改了下面的查询,看起来它可以工作了

      WITH
      msc (num) AS
      (VALUES (TIMESTAMP('2018-10-01 00:00:00.001'))
      UNION ALL
      SELECT num + 1 MONTH
      FROM msc
      WHERE num < current timestamp - 1 MONTH
      )
      SELECT substr(char(mc.num),1,7), 
      count(case when t.STATUS = 44 and t.TRANSACTION_TYPE = 0 then 1 end) FROM TV_TRANSACTION t
      join TB_INSTALLATION i on t.INSTALLATION_ID = i.INSTALLATION_ID and i.IB24_VERSION = 2
      right join msc mc on SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) = substr(char(mc.num),1,7) and date(t.REGISTRATION_DATE) >= '2019-10-01' and t.STATUS = 44 and t.TRANSACTION_TYPE = 0
      and SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) >= SUBSTR(CHAR(i.IB24_VERSION_UPDATE_DATE),1,7)
      group by substr(char(mc.num),1,7)
      

      【讨论】:

      • 虽然从不使用右连接(左连接的概念总是更容易可视化),但如果您将 TV_TRANSACTION 的连接更改为 TB_INSTALLATION 也改为右连接,您的代码就可以工作。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-20
      • 2019-01-07
      • 1970-01-01
      相关资源
      最近更新 更多