【问题标题】:SQL Join BETWEEN Dates Counting IssueSQL Join BETWEEN 日期计数问题
【发布时间】:2019-05-22 09:57:32
【问题描述】:

很难解释的问题,所以请多多包涵。

我有两张桌子:

1) 按日期细分以及当天是否在 Basic (Y/N)

ID      Date        Basic_Days
5423    2019-02-03  1
5423    2019-02-04  0
5423    2019-02-05  1
5423    2019-02-06  1
5423    2019-02-07  1
5423    2019-02-08  1
5423    2019-02-09  0
5423    2019-02-10  0
5423    2019-02-11  0
5423    2019-02-12  0
5423    2019-02-13  0
5423    2019-02-14  1
5423    2019-02-15  1
5423    2019-02-16  1

2) 按订单划分的不同日期时间段

EPI_Start_Date  EPI_End_Date     ID     EPI_ORDER
2019-02-03      2019-02-04       5423   1
2019-02-04      2019-02-15       5423   2
2019-02-15      2019-02-16       5423   3

我正在尝试做的是将各个天归因于它们各自的 EPI_ORDER,但不重复计算天数。

理想的输出是:

Basic_Days  EPI_Start_Date  EPI_End_Date    ID      EPIORDER
1           2019-02-03      2019-02-04      5423    1
5           2019-02-04      2019-02-15      5423    2
2           2019-02-15      2019-02-16      5423    3

到目前为止我所做的尝试:

我已经开始的查询几乎让我到达那里。但我想要一种正确处理最后日期的方法。

SELECT 
 SUM(CAST(p.Basic_Days AS int)) AS Basic_Days
, x.EPI_Start_Date
, x.EPI_End_Date
, p.ID
, x.EPIORDER


FROM *SNIP* AS x

    INNER JOIN *SNIP* table leapfrog join here, unnecessary for display purposes AS cc

    INNER JOIN *SNIP* AS p 
    ON  p.ID = cc.ID

    AND (   (p.[Date] BETWEEN x.EPI_Start_Date AND x.EPI_End_Date) 

        AND (p.[Date] <> x.EPI_End_Date) ) --this was my effort into not counting the last day on each, but it doesn't work for the very final day, where I DO want it.


WHERE p.ID = '5423' --testing

GROUP BY  EPI_Start_Date
        , EPI_End_Date
        , x.EPIORDER
        , ID

我的实际输出给了我:

Basic_Days  EPI_Start_Date  EPI_End_Date    ID      EPIORDER
1           2019-02-03      2019-02-04      5423    1
5           2019-02-04      2019-02-15      5423    2
1           2019-02-15      2019-02-16      5423    3

您可以看到最后一行只有 1 个 Basic_Days。但我希望它是 2 Basic_Days。

我觉得我并不太远,但我只需要调整我的 Join 中的 AND 语句。

任何帮助表示赞赏!希望我已经解释得足够好,可以理解吗?

【问题讨论】:

  • 请在代码问题中给出minimal reproducible example--剪切&粘贴&运行代码;具有期望和实际输出的示例输入(包括逐字错误消息);明确的规范和解释。这包括您可以提供的最少代码,即您显示的代码可以通过您显示的代码扩展为不正常。 (调试基础。)

标签: sql tsql join


【解决方案1】:

将您的 BETWEEN 更改为

p.[Date] >= x.EPI_Start_Date AND  p.[Date] < x.EPI_End_Date

BETWEEN 两端都包含,也就是说它的行为是这样的,它会加倍计算你的天数:

--don't want the end date compare to be <=
p.[Date] >= x.EPI_Start_Date AND  p.[Date] <= x.EPI_End_Date

你也可以删除(p.[Date] &lt;&gt; x.EPI_End_Date)

最后,我想指出您的理想输出不一致 - 对于您的大多数理想输出,您说过您不希望结束日期的记录包含在该波段中,然后突然对于最后一张唱片,你确实想要它在乐队里。可以制作一个处理这个问题的查询,但它是不一致的数据建模,有 2 行不包含在其带中的值,然后一行突然包含一个值,另一行不包含“只是因为没有另一个乐队”-决定这是否真的是您想要的,因为下次您运行该报告时,“15 日和 16 日之间的基本天数”将从 2 下降到 1,只是因为另一个已添加波段(例如从 16 到 21)..

这样的事情会虚假地将最后一行包含在错误的带中“仅仅因为它是最后一行”:

INNER JOIN (SELECT t.*, MAX(EPI_END_DATE) OVER(PARTITION BY ID) as max_end_date FROM date_ranges_table) x
ON 
  p.ID = x.ID AND
  p.[Date] >= x.EPI_Start_Date AND (p.[Date] < x.EPI_End_Date OR p.Date = x.max_end_date)

【讨论】:

  • 我明白你的逻辑,但我仍然得到相同的结果。基本天数 1,5,1 而不是 1,5,2。
  • 谢谢。但不一致的理想输出是我的目标。我需要以不同的方式处理最后一个条目。如果在原始问题中不清楚,请道歉:)
  • 你真的应该把它放在另一个乐队里。它属于“16 到 21”波段,而不是“15 到 16”波段。将另一行添加到您的表中,或者通过将数据写入具有高端日期的表中,或者实际上使用SELECT * FROM date_ranges UNION ALL SELECT ID, MAX(end_date), '9999-12-31', MAX(epi_order)+1 FROM date_ranges GROUP BY id。如果您要根据此报告向某人等付款,那么有人会想知道为什么当报告分组分配发生变化时,支付的金额与下个月的工作天数等不一致
  • 总共有8天要分配。使用我目前的方法,实际上只有 7 个被计算在内。日期带已设置且无法调整,因此我无法为空闲日创建额外的带。就目前而言,16 日这一天不会在任何地方登陆。
  • 那是因为它不属于您声明的日期范围内的任何地方.. 但我已经编辑了帖子以说明如何将其破解到最后一个乐队
猜你喜欢
  • 1970-01-01
  • 2020-05-17
  • 2012-09-23
  • 1970-01-01
  • 2021-11-24
  • 2017-01-01
  • 2017-09-29
  • 1970-01-01
  • 2011-03-25
相关资源
最近更新 更多