SQL 从每天 table 到日期范围 table 的转换

SQL from per day table to date range table transformation

我需要将以下输入 table 转换为输出 table,其中输出 table 将包含范围而不是每日数据。

输入:

Asin day is_instock
--------------------    
 A1   1      0
 A1   2      0
 A1   3      1
 A1   4      1
 A1   5      0
 A2   3      0
 A2   4      0

输出:

asin start_day end_day is_instock
---------------------------------
 A1      1        2       0
 A1      3        4       1
 A1      5        5       0
 A2      3        4       0

您正在寻找时态数据文献中描述的运算符,并且“最著名”为 PACK。

此运算符未成为 SQL 标准 (SQL:2011) 的一部分,该标准将文献的时间特征引入到语言中,因此您几乎不可能在 SQL product/dialect.

中找到任何支持你的东西

归结为:您必须自己编写算法来进行打包。

这就是所谓的“差距和孤岛”问题。如果您使用该搜索词,您可以找到大量文章和参考资料。

解决方案如下:

/*Data setup*/
DROP TABLE IF EXISTS #Stock
CREATE TABLE #Stock ([Asin] Char(2),[day] int,is_instock bit)

INSERT INTO #Stock
VALUES
 ('A1',1,0)
,('A1',2,0)
,('A1',3,1)
,('A1',4,1)
,('A1',5,0)
,('A2',3,0)
,('A2',4,0);

/*Solution*/
WITH cte_Prev AS (
    SELECT *
        /*Compare previous day's stock status with current row's status. Every time it changes, return 1*/
        ,StockStatusChange = CASE WHEN is_instock = LAG(is_instock) OVER (PARTITION BY [Asin] ORDER BY [day]) THEN 0 ELSE 1 END
    FROM #Stock
)
,cte_Groups AS (
    /*Cumulative sum so everytime stock status changes, add 1 from StockStatusChange to begin the next group*/
    SELECT GroupID = SUM(StockStatusChange) OVER (PARTITION BY [Asin] ORDER BY [day])
        ,*
    FROM cte_Prev
)

SELECT [Asin]
    ,start_day = MIN([day])
    ,end_day = MAX([day])
    ,is_instock
FROM cte_Groups
GROUP BY [Asin],GroupID,is_instock