将特定行转换为列的SQL查询

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

假设数据

ID          Date                    Mode
1           2019-09-20 09:28      IN
2           2019-09-20 19:00      IN
3           2019-09-20 19:00      IN
4           2019-09-20 19:00      IN
5           2019-09-20 19:01      IN
6           2019-09-20 19:01      IN
7           2019-09-20 19:01      Out
8           2019-09-20 20:28      IN
9           2019-09-20 20:35      IN
10          2019-09-20 20:50      Out
11          2019-09-20 20:55      Out
12          2019-09-20 21:30      IN

转换为从最小入住到最大退房的期间的行

我使用迭代来获得期望的结果,但想要优化查询(设置基准或CTE)以提高性能,

这就是我想要的

ID      DateIN              ID          DateOut
01      2019-09-20 09:28    07          2019-09-20 19:01
08      2019-09-20 20:28    11          2019-09-20 20:55
sql sql-server sql-server-2008 gaps-and-islands
1个回答
1
投票

这是一个基于孤岛的问题。

首先,可以使用以下查询生成连续记录组:

SELECT [Mode], MIN(id) min_id, MAX(id) max_id, MIN([Date]) min_date, MAX([Date]) max_date
FROM (
    SELECT
        id,
        [Date],
        [Mode],
        ROW_NUMBER() OVER(ORDER BY [Date]) rn1,
        ROW_NUMBER() OVER(PARTITION BY [Mode] ORDER BY [Date]) rn2
    FROM mytable
) x
GROUP BY [Mode], (rn1 - rn2)

这产生了:

模式| min_id | max_id | min_date | max_date:--- | -----:| -----:| :--------------- | :---------------IN | 1 | 6 | 2019-09-20 09:28 | 2019-09-20 19:01出| 7 | 7 | 2019-09-20 19:01 | 2019-09-20 19:01IN | 8 | 9 | 2019-09-20 20:28 | 2019-09-20 20:35出| 10 | 11 | 2019-09-20 20:50 | 2019-09-20 20:55IN | 12 | 12 | 2019-09-20 21:30 | 2019-09-20 21:30

然后,您可以将此查询转换为cte并对其进行自我联接以生成预期的结果集:

WITH cte AS (
    SELECT [Mode], MIN(id) min_id, MAX(id) max_id, MIN([Date]) min_date, MAX([Date]) max_date
    FROM (
        SELECT
            id,
            [Date],
            [Mode],
            ROW_NUMBER() OVER(ORDER BY [Date]) rn1,
            ROW_NUMBER() OVER(PARTITION BY [Mode] ORDER BY [Date]) rn2
        FROM mytable
    ) x
    GROUP BY [Mode], (rn1 - rn2)
)
SELECT c1.min_id IdIn, c1.min_date DateIN, c2.max_id IdOut, c2.max_date DateOut
FROM cte c1
INNER JOIN cte c2 
    ON  c1.mode = 'IN'
    AND c2.mode = 'Out'
    AND c2.min_id = c1.max_id + 1

输出:

IdIn | DateIN | IdOut |约会---: :--------------- | ----:| :---------------1 | 2019-09-20 09:28 | 7 | 2019-09-20 19:018 | 2019-09-20 20:28 | 11 | 2019-09-20 20:55

Demo on DB Fiddle

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