使用前一行row_number值计算位置更改

问题描述 投票:0回答:1

我试图计算基于前一行ROW_NUMBER()与当前ROW_NUMBER()相比的位置变化

我的查询是使用带有ROW_NUMBER()OVER ..子句的递归cte,它巧妙地给了我年份结果的行号。

WITH positions AS (
    SELECT 
        [incidents].state_id, [incidents].year_id, MAX(number_of_incidents) AS total_incidents_in_year,
        ROW_NUMBER() OVER(PARTITION BY [incidents].year_id ORDER BY MAX(number_of_incidents) DESC) AS position
    FROM
        [incidents]
    INNER JOIN
        years AS dy ON dy.year_id = [incidents].year_id
    INNER JOIN
        states AS ds on ds.state_id = [incidents].state_id
    GROUP BY
        [incidents].state_id, [incidents].year_id
)

在此之后我的查询然后比较位置以计算行号之间的变化。

SELECT
    ds.state_name, ds.state_id, [before].total_incidents_in_year, dy.year,
    [before].position AS before_position, [after].position AS after_position,
    ([before].position - [after].position) AS change
FROM
    positions AS [before]
LEFT JOIN 
    positions AS [after] ON [before].position = [after].position + 1 AND [before].state_id = [after].state_id AND [before].year_id = [after].year_id
INNER JOIN
    years AS dy ON dy.year_id = [before].year_id
INNER JOIN
    states AS ds on ds.state_id = [before].state_id
ORDER BY
    [before].year_id ASC, [before].total_incidents_in_year DESC

不幸的是,这不起作用,因为[after]位置始终为null。

这有点难以解释所以我已经包含了一个sqlfiddle链接:http://www.sqlfiddle.com/#!18/c7e57e/1

--

这个图像直观地解释了我想要实现的My envisioned output

2011年明尼苏达州排名第一,2012年明尼苏达排名第3,变化为+2

2011年爱荷华州排名第6,2012年爱荷华州排名第4,变化为-2

2011年南达科他州位居第5位,2012年南达科他州排名第5,变化为0

谢谢

row-number sql-server-2017 recursive-cte
1个回答
1
投票

弄清楚了。

我错误地尝试加入ROW_NUMBER(),这会导致不匹配的连接,因为行号不一定与状态ID正确对齐。

在改变它以加入year之后,这是计算年度变化的正确方法,这一切都汇集在一起​​。

WITH positions AS (
    SELECT 
        [incidents].state_id, dy.year, MAX(number_of_incidents) AS total_incidents_in_year,
        ROW_NUMBER() OVER(PARTITION BY dy.year ORDER BY MAX(number_of_incidents) DESC) AS position
    FROM
        [incidents]
    INNER JOIN
        years AS dy ON dy.year_id = [incidents].year_id
    INNER JOIN
        states AS ds on ds.state_id = [incidents].state_id
    GROUP BY
        [incidents].state_id, dy.year
)
SELECT
    ds.state_name, ds.state_id, [before].total_incidents_in_year, dy.year,
    [before].position AS before_position,
    ([before].position - [after].position) AS change
FROM
    positions AS [before]
LEFT JOIN 
    positions AS [after] ON [before].state_id = [after].state_id AND [before].year = [after].year + 1
INNER JOIN
    years AS dy ON dy.year = [before].year
INNER JOIN
    states AS ds on ds.state_id = [before].state_id
ORDER BY
    [before].year ASC, [before].total_incidents_in_year DESC

http://www.sqlfiddle.com/#!18/c7e57e/11

© www.soinside.com 2019 - 2024. All rights reserved.