【问题标题】:How can I get both the rows that fit into a date range, and the single most recent row prior to the given date range per ID?如何获取适合日期范围的行和每个 ID 给定日期范围之前的最近一行?
【发布时间】:2021-12-03 01:49:17
【问题描述】:

我想提供一个日期范围的查询,例如 11/01/2021 - 11/30/2021。从那里我想获取该日期范围内的所有相关行,这非常简单 - 只需一个简单的选择,其中包含基于 to 和 from 日期的 where 子句。但在此之后,我想获取日期范围之前的最新行(如果存在),用于出现在日期范围内的外键 ID。

举个例子,

ID FK ID Date
1 101 09/05/2021
2 101 10/29/2021
3 101 11/05/2021
4 201 11/20/2021
5 301 08/13/2021
6 401 11/01/2021
7 401 11/23/2021

如果我输入的日期范围是 2021 年 11 月 1 日 - 2021 年 11 月 30 日,我希望得到以下结果

ID FK ID Date
2 101 10/29/2021
3 101 11/05/2021
4 201 11/20/2021
6 401 11/01/2021
7 401 11/23/2021

我的第一个想法是 UNION,其中第二个查询获取日期范围之前的最大日期,并与第一个查询联合,该查询具有给定日期范围内的所有值。但我认为这会因上表中的 ID 5 之类的值而失败 - 因为第二个查询没有限制它需要相同的 FK ID 存在于第一个表中。也许我只是想不通,但我想不出任何办法以这种方式限制工会?

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    您可以使用 cte 选择范围内的行并添加更多相对于此 cte 的行

    with cte as (
      SELECT *
      FROM tb
      WHERE [Date] >= '11/1/2021' AND [Date] <= '11/30/2021'
    )
    select * 
    from cte
    union all
    select *
    from (
      select top(1) with ties *
      from tb
      where exists (select 1 from cte where cte.fk_id = tb.fk_id)
         and [Date] < '11/1/2021'
      order by row_number() over(partition by fk_id order by [date] desc)
    ) t
    order by id;
    

    db<>fiddle

    【讨论】:

    • 这个解决方案几乎可以工作,但是由于某种原因,使用top(1) 只会返回具有最高日期的单行,而不管 fk_id 是什么。我通过删除top(1) with ties 并在存在条件and [Date] = (select max([Date]) from tb tb2 where tb2.FK_ID = tb.FK_ID and [Date] &lt; '11/1/2021') 之后添加此条件来使其工作。我真的不喜欢我不得不使用子查询,但仍然可以改进。
    • @ryan.kom, partition by fk_id 不见了,我的错。查看修改后的版本。
    【解决方案2】:

    以下查询产生您想要的输出

    WITH cte AS(
      SELECT ID,FK_ID,[DATE]
      FROM tb
      WHERE [DATe] >= '11/1/2021' AND [Date] <= '11/30/2021')
    SELECT * 
    FROM cte    
    UNION ALL  
    SELECT ID,FK_ID,[DATE]
    FROM
        (SELECT *,
           CASE WHEN LEAD([Date]) over(ORDER BY ID) >= '11/1/2021' AND LEAD([Date]) over(ORDER BY ID) <= '11/30/2021' THEN 1 ELSE 0 END AS rnk
         FROM tb) t
      WHERE rnk = 1 AND [DATe] < '11/1/2021' AND FK_ID IN (SELECT FK_ID FROM cte)
    ORDER BY ID
    

    db<>fiddle中的演示

    【讨论】:

    • 这个非常接近,但是需要排除ID 5的原因是因为FK ID 301在日期范围内不存在。所以基本上,条件是我只得到日期范围之前的最新行,如果日期范围内至少存在一行
    • 即给出 FK_ID 在接受日期列表中的最后日期。我编辑了答案。
    猜你喜欢
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 2022-12-18
    • 2020-07-06
    • 2017-12-20
    • 1970-01-01
    相关资源
    最近更新 更多