TSQL - 计算从昨天到今天的值之间的差异,SELF JOIN 问题
TSQL - Calculate difference between values from yesterday to today, SELF JOIN question
我已经将各种在线答案的代码拼凑在一起以获得我想要的结果,但是,我不明白它为什么起作用,我想知道 JOIN 在它说 RowNum + 1 的地方实际上做了什么。
原题是计算一个值从昨天到今天的百分比差。我对自我加入有点模糊,但我确实理解自我加入。当我添加 RowNum 列时,这让我很困惑。
问题
请问 T2.RowNum = T1.RowNum + 1 在自连接中做什么?
IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1
CREATE TABLE #T1 (
ProductTotal int
,CountDate date
)
INSERT INTO #t1
VALUES
(893911,'20200815')
,(888970,'20200816')
,(899999,'20200817')
WITH cte AS (
SELECT
ROW_NUMBER() OVER(ORDER BY CountDate) AS RowNum
,ProductTotal
,CountDate
FROM #t1
WHERE CountDate > CAST(GETDATE () - 2 AS DATE)
)
SELECT
t1.RowNum
,t1.ProductTotal
,CAST(((t1.ProductTotal - t2.ProductTotal) * 1.0 / t2.ProductTotal) * 100 AS DECIMAL(10,2)) AS ProductDiff
,t1.CountDate
FROM cte AS t1
LEFT JOIN cte t2 ON T2.RowNum = T1.RowNum + 1
假设您每天都有值,更好的方法是使用 lag()
:
SELECT ProductTotal, CountDate,
(ProductTotal - prev_ProductTotal) * 1.0 / ProductTotal
FROM (SELECT t.*,
LAG(ProductTotal) OVER (ORDER BY CountDate) as prev_ProductTotal
FROM #t1 t
) t
WHERE CountDate > CAST(GETDATE () - 1 AS DATE)
请注意,正如我评论的那样,我完全同意 Gordon 的观点,LAG
(或 LEAD
)是这里的正确答案。解释你在评论中提出的问题 “我不明白 T2.RowNum = T1.RowNum + 1 是如何工作的”:
JOIN
returns 行,其中 ON
中的表达式为真。由于您有 INNER JOIN
,因此仅显示 JOIN
两侧的表达式计算结果为 True 的行。对于 LEFT JOIN
之前返回的任何先前内容都不会“丢失”。 (还有其他类型的联接。)
对于T2.RowNum = T1.RowNum + 1
,这是基础数学。 2
匹配到 1
(1+1
),3
匹配到 2
(2+1
)... 100
是匹配到 99
(99 + 1
)。因此,根据 CTE 中定义的 ROW_NUMBER
顺序,来自 T1
的数据与“之后”的行相匹配。在这种情况下,这将是 CountDate
的“下一个”值按升序排列的行。
我已经将各种在线答案的代码拼凑在一起以获得我想要的结果,但是,我不明白它为什么起作用,我想知道 JOIN 在它说 RowNum + 1 的地方实际上做了什么。
原题是计算一个值从昨天到今天的百分比差。我对自我加入有点模糊,但我确实理解自我加入。当我添加 RowNum 列时,这让我很困惑。
问题
请问 T2.RowNum = T1.RowNum + 1 在自连接中做什么?
IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1
CREATE TABLE #T1 (
ProductTotal int
,CountDate date
)
INSERT INTO #t1
VALUES
(893911,'20200815')
,(888970,'20200816')
,(899999,'20200817')
WITH cte AS (
SELECT
ROW_NUMBER() OVER(ORDER BY CountDate) AS RowNum
,ProductTotal
,CountDate
FROM #t1
WHERE CountDate > CAST(GETDATE () - 2 AS DATE)
)
SELECT
t1.RowNum
,t1.ProductTotal
,CAST(((t1.ProductTotal - t2.ProductTotal) * 1.0 / t2.ProductTotal) * 100 AS DECIMAL(10,2)) AS ProductDiff
,t1.CountDate
FROM cte AS t1
LEFT JOIN cte t2 ON T2.RowNum = T1.RowNum + 1
假设您每天都有值,更好的方法是使用 lag()
:
SELECT ProductTotal, CountDate,
(ProductTotal - prev_ProductTotal) * 1.0 / ProductTotal
FROM (SELECT t.*,
LAG(ProductTotal) OVER (ORDER BY CountDate) as prev_ProductTotal
FROM #t1 t
) t
WHERE CountDate > CAST(GETDATE () - 1 AS DATE)
请注意,正如我评论的那样,我完全同意 Gordon 的观点,LAG
(或 LEAD
)是这里的正确答案。解释你在评论中提出的问题 “我不明白 T2.RowNum = T1.RowNum + 1 是如何工作的”:
JOIN
returns 行,其中 ON
中的表达式为真。由于您有 INNER JOIN
,因此仅显示 JOIN
两侧的表达式计算结果为 True 的行。对于 LEFT JOIN
之前返回的任何先前内容都不会“丢失”。 (还有其他类型的联接。)
对于T2.RowNum = T1.RowNum + 1
,这是基础数学。 2
匹配到 1
(1+1
),3
匹配到 2
(2+1
)... 100
是匹配到 99
(99 + 1
)。因此,根据 CTE 中定义的 ROW_NUMBER
顺序,来自 T1
的数据与“之后”的行相匹配。在这种情况下,这将是 CountDate
的“下一个”值按升序排列的行。