【问题标题】:SQL - Building iteration tableSQL - 构建迭代表
【发布时间】:2023-01-28 02:15:06
【问题描述】:

我对表的迭代有疑问。库存中有状态产品 (test_product) 和操作:添加或从库存中删除。

product action operation_date number total
test_product add 2023-01-03 4 4
test_product remove 2023-01-05 -3 1
test_product remove 2023-01-07 -1 0

有一天我们会添加或删除产品、产品数量和总数。

我想计算天数,在某个时期总人数是0,比方说从2023-01-012023-01-10起始值为 total 的列是 0

在我看来,我有这样的表格:

calendar_day product action operation_day number total
2023-01-01 0
2023-01-02 0
2023-01-03 test_product add 2023-01-03 4 4
2023-01-04 4
2023-01-05 test_product remove 2023-01-05 -3 1
2023-01-06 1
2023-01-07 test_product remove 2023-01-07 -1 0
2023-01-08 0
2023-01-09 0
2023-01-10 0

0天数是技术操作,现在不重要了。问题是建表。

我试过这样的事情:

GO
DECLARE @PRODUCT AS VARCHAR(30)
SET @PRODUCT = 'test_product'
DECLARE @TOTAL AS INT
SET @TOTAL = 0
DECLARE @STOP_DATE AS DATE;
SET @STOP_DATE = CAST('2023-01-10' AS DATE)
DECLARE @UP_DATE AS DATE;
SET @UP_DATE = CAST('2023-01-01' AS DATE);
WHILE @STOP_DATE >= @UP_DATE
BEGIN  
SELECT
@UP_DATE AS calendar_day,
CASE
WHEN operation_date = @UP_DATE THEN operation_date
ELSE ''
END AS operation_date,
number,
@TOTAL+number AS total
FROM stock
JOIN products ON products.id = stock.product_id
WHERE products.name = @PRODUCT
AND stock.operation_date >= @UP_DATE
AND stock.operation_date <= @UP_DATE
SET @UP_DATE = DATEADD(DAY, 1, @UP_DATE)
END

但是我得到了分离结果,其中 7 个是空的而且速度太慢,因为我们现在有 9000 个项目。

你能帮助我吗?

【问题讨论】:

  • 你使用什么数据库管理系统?
  • 我正在使用 MS SQL

标签: sql sql-server gaps-and-islands


【解决方案1】:

您可以分两步完成此任务:

  • 用递归查询构建一个日历表,停止在calen_date &lt; '2023-10-01'
  • 左加入日历表和您的产品表
  • 为每个非空值后跟空值计算分区
  • 将每个分区的最大值分配给总计
WITH calendar AS (
    SELECT CAST('2023-01-01' AS DATE) AS calendar_day
    UNION ALL 
    SELECT DATEADD(DAY, 1, calendar_day) FROM calendar WHERE calendar_day < '2023-01-10'
), product_and_calend AS (
    SELECT *, 
           COUNT(CASE WHEN total IS NOT NULL THEN 1 END) OVER(ORDER BY calendar_day) AS num_nulls
    FROM      calendar     c
    LEFT JOIN test_product p
           ON c.calendar_day = p.operation_date
)
SELECT calendar_day, product, action_, operation_date, number,
       COALESCE(MAX(total) OVER(PARTITION BY num_nulls), 0) AS total
FROM product_and_calend

输出:

calendar_day product action operation_day number total
2023-01-01 0
2023-01-02 0
2023-01-03 test_product add 2023-01-03 4 4
2023-01-04 4
2023-01-05 test_product remove 2023-01-05 -3 1
2023-01-06 1
2023-01-07 test_product remove 2023-01-07 -1 0
2023-01-08 0
2023-01-09 0
2023-01-10 0

查看演示 here

【讨论】:

  • 我在这里有点困惑 SELECT DATEADD(MONTH, 1, calendar_day) FROM calendar WHERE calendar_day &lt; '2023-10-01' 但我知道你没有注意到你在日期中使用了月份而不是日期 :) 但是,非常感谢你!
  • 我意识到月-日倒置,这就是为什么我不明白为什么我首先得到所有空值,尽管我已经切换了它们并假设您使用的是标准日期。
  • SELECT DATEADD(DAY, 1, calendar_day) FROM calendar WHERE calendar_day &lt; '2023-01-10'修复了它
  • 所以你要去几天而不是几个月,我明白了。让我相应地调整答案。
  • 好的,现在我看到了完美的 sql ;)再次感谢你
猜你喜欢
  • 2017-04-03
  • 2020-05-03
  • 1970-01-01
  • 2016-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多