【问题标题】:LEFT JOIN match. If no match, need to match on most recent date左连接匹配。如果没有匹配,需要在最近的日期匹配
【发布时间】:2021-04-01 14:59:55
【问题描述】:

我当前的 SQL 代码:

SELECT 
    [Date], [Count]
FROM
    Calendar_Table pdv
LEFT JOIN
    (SELECT 
         COUNT([FILE NAME]) AS [Count], [CLOSE DT]
     FROM 
         Production_Table
     GROUP BY 
         [CLOSE DT]) [Group] ON [pdv].[Date] = [Group].[CLOSE DT]
ORDER BY 
    [Date]

请看下面的代码。 Calendar_Table 是一个简单的表格,每个日期一行。 Production_Table 提供每天销售的产品。如果左连接产生NULL,请产生最近的非NULL 值。

当前输出:

Date       | Count
-----------+--------
9/4/2019   | NULL
9/5/2019   | 1
9/6/2019   | 4
9/7/2019   | NULL
9/8/2019   | 7
9/9/2019   | 11
9/10/2019  | NULL
9/11/2019  | 14
9/12/2019  | NULL
9/13/2019  | 19

期望的输出:

Date       | Count
-----------+--------
9/4/2019   | 0
9/5/2019   | 1
9/6/2019   | 4
9/7/2019   | 4
9/8/2019   | 7
9/9/2019   | 11
9/10/2019  | 11
9/11/2019  | 14
9/12/2019  | 14
9/13/2019  | 19

【问题讨论】:

  • 请分享表定义和一些示例数据..

标签: sql sql-server datetime gaps-and-islands lateral-join


【解决方案1】:

一种选择是横向连接:

select c.date, p.*
from calendar_table c
outer apply (
    select top (1) count(file_name) as cnt, close_dt
    from production_table p
    where p.close_dt <= c.date 
    group by p.close_dt
    order by p.close_dt desc
) p

作为替代方案,我们可以使用 equi-join 来获得匹配的日期,就像在您的原始查询中一样,然后使用窗口函数填补空白。基本思想是建立每次匹配时重置的组。

select date, coalesce(max(cnt) over(partition by grp), 0) as cnt
from (
    select c.date, p.cnt,
        sum(case when p.close_dt is null then 0 else 1 end) over(order by c.dt) as grp
    from calendar_table c
    left join (
        select close_dt, count(file_name) as cnt
        from production_table p
        group by close_dt
    ) p on p.close_dt = c.date
) t

根据您的数据,一种或另一种解决方案的效果可能更好。

【讨论】:

  • 我相信 Itzik Ben-Gan 展示了一种不涉及自连接的更有效的方法:The Last non NULL Puzzle
  • @VladimirBaranov:这几乎是答案中第二个查询的方法。请注意,这两个查询中都没有自联接(我们有两个不同的表)。
猜你喜欢
  • 2021-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-07
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
相关资源
最近更新 更多