按任意开始和结束日期对订单表进行分区

Posted

技术标签:

【中文标题】按任意开始和结束日期对订单表进行分区【英文标题】:Partition Orders table by arbitrary start and end day-of-month 【发布时间】:2020-08-12 05:25:14 【问题描述】:

鉴于以下相当标准的订单表:

CREATE TABLE [dbo].[orders](
    [bill_product_id] [int] IDENTITY(1,1) NOT NULL,
    [Bill_date] [datetime] NULL,
    [TenantId] [int] NULL,
    [Product_type] [int] NULL,
    [Quantity] [int] NULL,
    [Customer_cost] [numeric](18, 10)
)

以下查询为我提供表orders 中有记录的每个月的开始日期和结束日期

SELECT distinct DATEADD(DAY,1,EOMONTH(bill_date,-1)) as start_date,
       EOMONTH(bill_date) as end_date
    FROM orders

示例结果集:

开始日期结束日期


2020-07-01 2020-07-31

2020-08-01 2020-08-31

现在我们需要更改“结算周期”,因此我们需要从每月 26 日开始结算周期,而不是从每月 1 日开始,到每月最后一天结束,月底是下个月的第 25 天(不要问)。

我确定我可以根据开始日期确定 end_date,但我不确定将数据划分为月份的 26 日至 25 日的最佳方式。请提出一个有效的方法来做到这一点。

【问题讨论】:

【参考方案1】:

也许你可以使用DATEFROMPARTS

DECLARE @bill_date DATE = '2020-08-12'

SELECT DATEFROMPARTS(YEAR(@bill_date), MONTH(@bill_date), 26)
      ,DATEFROMPARTS(YEAR(@bill_date), MONTH(@bill_date) + 1, 25)

但你的方式也是有效的,可以加强。


正如你所指出的,它应该是:

SELECT DATEFROMPARTS(YEAR(@bill_date), MONTH(@bill_date) - (CASE WHEN DAY(@bill_date) >= 26 then 0 else 1 end) , 26);

为了确保小于26 的日期保持在当前间隔内,而不是像我原来的解决方案中那样的下一个。

【讨论】:

这给出了从 8 月 26 日开始的 next 间隔。我尝试从两个“月份”部分中减去 1,但如果给出的日期是“2020-”,这将不起作用07-30' - 计算到 6 月 26 日,应该是 7 月 26 日 对于2020-07-30,我得到2020-07-262020-08-25。这不是你需要的吗? 是的,但如果给定 '2020-08-12',相同的函数会返回未来的日期 - 而不是当前的时间间隔。但是 DATEFROMPARTS 帮我找到了真正的解决方案: SELECT DATEFROMPARTS(YEAR(@bill_date), MONTH(@bill_date) - (CASE WHEN DAY(@bill_date) >= 26 then 0 else 1 end) , 26); @Black 我现在明白逻辑了 :-)【参考方案2】:

感谢@gotqn,我可以按如下方式使用 DATEFROMPARTS

 SELECT DATEFROMPARTS(YEAR(@bill_date),  
         MONTH(@bill_date) - (CASE WHEN DAY(@bill_date) >= 26 then 0 else 1 end), 
         26) as start_date
        ,DATEFROMPARTS(YEAR(@bill_date),  
         MONTH(@bill_date) + (CASE WHEN DAY(@bill_date) >= 26 then 1 else 0 end),
         25) as end_date

【讨论】:

【参考方案3】:

您可以减去 26 天并使用 datefromparts():

SELECT DISTINCT DATEFROMPARTS(YEAR(yyyymm_start), MONTH(yyyymm_start), 26) as start_date,
       DATEFROMPARTS(YEAR(yyyymm_end), MONTH(yyymm_end), 25) as end_date
FROM orders o CROSS APPLY
     (VALUES (DATEADD(DAY, -26, BILL_DATE),
              DATEADD(MONTH, 1, DATEADD(DAY, -26, BILL_DATE))
             )
     ) as v(yyyymm_start, yyyymm_end)

【讨论】:

【参考方案4】:

只需使用 dateadd 即可“移动”您的计费周期。

我假设然后你查询

  declare @billDate date = '2020-07-16'
 SELECT distinct DATEADD(DAY,1,EOMONTH(@billDate)) as start_date,
       EOMONTH(@billDate) as end_date, 'Original' as query
    --FROM orders


 SELECT distinct DATEADD(DAY,26,EOMONTH(@billDate,-1)) as start_date,
       dateadd(day,25,EOMONTH(@billDate) )as end_date, 'Modified' as query
    --FROM orders

会导致

start_date end_date   query
---------- ---------- -------- 
2020-07-01 2020-07-31 Original
         
start_date end_date   query
---------- ---------- -------- 
2020-07-26 2020-08-25 Modified

【讨论】:

这与@gotqn 的原始答案有相同的问题,即对于 '2020-08-10' 它返回 future 间隔 2020-08-26 到 2020-09- 25 已修复,在 eomonth 函数中添加了 -1 没有。现在它返回值“2020-07-30”的错误(先前)间隔 请张贴给定账单日期的预计开始/结束日期 这一切都在原始帖子中,也在@gotqn 的答案中。不用担心,它已经被正确回答了

以上是关于按任意开始和结束日期对订单表进行分区的主要内容,如果未能解决你的问题,请参考以下文章

制作一个接受开始日期和结束日期的 UDF。并返回

Woocommerce 集团订单总额按自定义字段日期

在 MVC4 视图中按类别对订单进行分组

两个日期之间每天未结订单的 SQL 计数

每年年初获取有效订单

获取按月顺序显示的特定日期之间的所有订单