SQL Server 查询以计算每日“持仓”未结订单

Posted

技术标签:

【中文标题】SQL Server 查询以计算每日“持仓”未结订单【英文标题】:SQL Server query to calculate daily “carrying” open orders 【发布时间】:2017-08-12 11:50:19 【问题描述】:

我在整个网站上进行了搜索,但似乎找不到适合我特定问题的解决方案。有许多接近我正在寻找的东西,但还不足以(至少对于我的编码能力)来建立联系。

我有一个相对简单的表,其中有:

Order_Number Order_Date Fulfilled_Date

还有许多其他字段,但它们与此问题无关。

我需要创建一份报告,显示(按每日细分)在 30 天内“未完成”的订单数量。显然,“空”值表示订单当前未履行,但我真的很纠结如何解决每天有多少未履行订单的问题。

在某些情况下,订单可能在几个月前下达,但仍未完成(可能是由于延期交货状态),因此我需要回顾几乎从开始时的餐桌时间。

另外,对于这个问题,请考虑我没有可用的“日期”或“日期”表,因此无法制作。我可以在临时表中构建一个,但没有永久性的。另外,我只需要担心从“今天”开始的 30 天(getdate()-30)

样本数据:

create table #orders 
(
    order_number varchar(25),
    order_date datetime,
    fulfilled_date datetime
)

insert into #orders (order_number, order_date, fulfilled_date)
values ('HK02411580-92880', '2/22/17 23:06', '2/27/17 23:11'),
       ('HK02411580-93259', '2/22/17 11:22', '2/22/17 16:27'),
       ('HK02411580-93760', '2/22/17 23:46', '2/22/17 23:51'),
       ('HK02411580-94122', '2/23/17 0:06', '2/25/17 0:16'),
       ('HK02411580-94845', '2/23/17 0:42', '2/26/17 0:42'),
       ('HK02411580-94847', '2/23/17 0:42', '2/23/17 0:42'),
       ('HK02411580-94952', '2/23/17 0:46', '2/23/17 0:51'),
       ('BS63719405-53119', '2/24/17 23:44', '2/25/17 23:44'),
       ('BS63719405-53231', '2/24/17 23:48', '2/28/17 23:49'),
       ('BS63719405-53336', '2/24/17 23:54', '2/24/17 23:54'),
       ('BS63719405-53546', '2/25/17 0:04', '2/27/17 0:04'),
       ('BS63719405-53672', '2/25/17 0:09', '2/28/17 0:09'),
       ('UT40057640-11866', '2/26/17 23:06', '3/1/17 23:11'),
       ('UT40057640-11910', '2/26/17 23:07', '3/5/17 23:17'),
       ('UT40057640-13217', '2/27/17 0:11', '2/27/17 0:16'),
       ('UT40057640-13829', '2/27/17 0:41', '2/27/17 0:41'),
       ('UT40057640-93881', '3/1/17 13:28', '3/1/17 13:29'),
       ('UT40057640-94117', '3/1/17 13:38', '3/5/17 13:39'),
       ('SC79933239-74181', '3/3/17 22:02', '3/4/17 22:08'),
       ('SC79933239-76349', '3/3/17 23:32', '3/3/17 23:37'),
       ('SC79933239-76716', '3/3/17 23:51', '3/3/17 23:56'),
       ('SC79933239-77351', '3/4/17 0:18', '3/5/17 0:19'),
       ('SC79933239-77899', '3/4/17 0:41', '3/6/17 0:41'),
       ('SC79933239-77900', '3/4/17 0:41', '3/4/17 0:41'),
       ('FM76423870-59430', '3/6/17 9:54', '3/10/17 9:54'),
       ('FM76423870-59552', '3/6/17 9:59', '3/11/17 9:59'),
       ('FM76423870-59676', '3/6/17 10:03', '3/9/17 10:04'),
       ('FM76423870-59798', '3/6/17 10:09', '3/6/17 10:09'),
       ('IE68709323-78813', '3/20/17 7:01', '3/20/17 7:53'),
       ('IE68709323-78905', '3/20/17 7:09', '3/20/17 7:53'),
       ('RC45792362-15830', '3/20/17 7:59',     NULL),
       ('RC45792362-15831', '3/20/17 7:59',     NULL),
       ('RC45792362-16653', '3/20/17 8:39',     NULL),
       ('RC45792362-24157', '3/20/17 14:52',    NULL),
       ('RC45792362-24163', '3/20/17 14:52', '3/20/17 14:57'),
       ('RC45792362-24223', '3/20/17 14:54',    NULL),
       ('RC45792362-24327', '3/20/17 14:56', '3/20/17 14:59'),
       ('RC45792362-24267', '3/20/17 14:57',    NULL),
       ('RC45792362-27486', '3/20/17 17:32',    NULL),
       ('RC45792362-27607', '3/20/17 17:36', '3/20/17 17:39');

所需的输出将是(例如):

 Date          Carry Over Orders
 ---------     -----------------
 2/22/2017     1 (3 orders...2 fulfilled and one left over  or "carried over")
 2/23/2017     3 (2 orders fulfilled that day, but 2 additional carried over)
 2/24/2017     5 (1 order fulfilled that day, but 2 additional carried over)
 2/25/2017     5 (2 orders fulfilled from prior dates but 2 new orders carried over)

 Etc...

我希望我解释得对...当我开始走这条路时似乎很简单,但它只是没有在大脑中点击正确...

非常感谢任何帮助。

服务器版本:SQL Server 2008

还要添加一项:对于没有订单的日期,我仍然需要考虑它们...我希望必须根据开始日期编写某种临时日期表并向后工作 30 天。 .除非有更好的方法。

澄清:在结果集中,“结转订单”本质上是在该特定日期内未履行的订单的累计总数。

逻辑澄清:

在 22 日,总共有 3 个订单...其中 2 个已完成(如果您愿意,也可以发货),1 个未完成。这使得 1 个未完成的订单进入 23 日。

23 日总共有 4 个订单。其中 2 条当天实现,2 条没有实现。前一天的订单仍未完成,因此“结转”订单总数达到 3 个。

24 日我们还有另外 3 个订单。 1 那天完成了,2 没有完成。总结转现在是 5

在 25 日,我们有 2 个当天未完成的新订单,但之前有 2 个订单(一个来自 23 日,一个来自 24 日)。 Carr-over 订单(或未完成的订单)总数保持在 5 个。

希望这能帮助更多

为了帮助解决这个问题,我创建了一个 rextester(因为 sqlfiddle 似乎坏了) rextester sandbox

【问题讨论】:

第二列的1、3、5、5分别代表什么? 抱歉...这些将是当天未完成的订单总数。 为什么 2/22/2017 没有完成订单? 需要“未完成”的订单。 2/22(开始)有 2 个订单已完成,但 1 个订单未完成,因此将被视为结转 您可能想澄清您所说的结转订单的含义。 【参考方案1】:

这应该会给你想要的输出。此查询假定您有一个不同的日期列表来查询。

您最麻烦的部分,即结转部分,使用了引用两个数据集的FROM 语句。这与JOIN 不同,它是通过引用两个表并用, 分隔它们来完成的。这将反过来创建一个查询,其中dates_table 中的每个日期都从orders 表中分配了整个数据集。为了确定结转,使用WHERE 语句过滤复制的订单表,并使用GROUP BY 计算每个过滤后的订单。之后使用LEFT JOIN 将结果按日期拉到date_table。如果您需要更多解释,请随时发表评论。

SQL with Dates Table这个表在下面的查询中被命名为dates_table

SELECT 
    dates.date,
    iif(carry_over.count IS NULL, 0, carry_over.count) AS carry_over,
    iif(fulfilled.count IS NULL, 0, fulfilled.count) AS fulfilled,
    iif(not_fulfilled.count IS NULL, 0, not_fulfilled.count) AS not_fulfilled

FROM dates_table AS dates

/* Fulfilled that day */
LEFT JOIN 
(
    SELECT 
        dateadd(d, datediff(d,0, fulfilled_date), 0) AS date, 
        COUNT(dateadd(d, datediff(d,0, fulfilled_date), 0)) AS count
    FROM orders
    GROUP BY dateadd(d, datediff(d,0, fulfilled_date), 0)
) AS fulfilled
    ON dates.date = fulfilled.date

/* Not Fulfilled that day */
LEFT JOIN 
(
    SELECT 
        dateadd(d, datediff(d,0, order_date), 0) AS date, 
        COUNT(dateadd(d, datediff(d,0, order_date), 0)) AS count
    FROM orders
    WHERE (dateadd(d, datediff(d,0, order_date), 0) <> dateadd(d, datediff(d,0, fulfilled_date), 0)) OR fulfilled_date IS NULL
    GROUP BY dateadd(d, datediff(d,0, order_date), 0)
) AS not_fulfilled
    ON dates.date = not_fulfilled.date

/* Carry Over */
LEFT JOIN 
(
    SELECT
        full_data.date,
        COUNT(full_data.order_date) AS count

    FROM
    (
        SELECT 
            dates.date AS date,
            order_dates.order_date AS order_date,
            order_dates.fulfilled_date AS fulfilled_date

        FROM dates_table AS dates,

        /* Allocate all dates to key of dates, filter out what is relevant in where */
        (
            SELECT 
                dateadd(d, datediff(d,0, order_date), 0) AS order_date,
                iif(fulfilled_date IS NULL, NULL, dateadd(d, datediff(d,0, fulfilled_date), 0)) AS fulfilled_date
            FROM orders
        ) AS order_dates

    ) AS full_data

    /* Determines what is carry over */
    WHERE (full_data.date < full_data.fulfilled_date OR full_data.fulfilled_date IS NULL) AND full_data.date >= full_data.order_date
    GROUP BY full_data.date

) AS carry_over
    ON dates.date = carry_over.date

rextester

编辑:为最终查询添加了字段名称,因为它们之前都被标记为 count

编辑:假设您有一个日期表和订单表的#,添加了另一个查询

编辑:删除了没有 date_table 的查询,现在在 order_date 上完成了carry_over 的计数,因为不计算空值,对于已完成的那一天数字现在提取fulfilled_date 而不是 order_date

【讨论】:

这绝对给了我数据..我需要使用日期表,因为我确实需要显示连续的日期......所以如果某一天没有订单,会有仍然是“待定”订单或“结转”订单...您对如何整合该部分有建议吗? 假设您有一个日期表,我将发布另一个 sql 查询。 @Buckwheattb 我已经更新了我的答案。这就是你要找的东西吗? 我也可以像你那样使用我的空间,这样占用的空间会少很多 @DavidLee 这很接近,但是当查询命中没有活动的日期(订单表中缺少日期范围)时,它似乎分开了......我制作了一个从 2 开始的日期表/20 到 3/21 作为测试。答案集在早期看起来不错,但是一旦进入无订单时期(特别是 3/6 到 3/20 时期),结果就消失了……另一件事……在“未完成”天”部分,我进行了更改以适应“NULL”履行日期...“isnull(dateadd(d,datediff(d,0,fulfilled_date),0),'1/1/2050')”这有意义吗?

以上是关于SQL Server 查询以计算每日“持仓”未结订单的主要内容,如果未能解决你的问题,请参考以下文章

如何推断 SQL Server 中的日期以计算每日计数?

用于 Google BigQuery 的 SQL 查询以计算会话和浏览量

查询以计算 Sql Server 视图中的列数

SQL Server - 查询以根据每年的最后一个值计算加权平均值

SQL Server查询以获得结果

如何避免两次编写 SQL Server 查询以避免重复?