如何在特定列中找到更改并获取旧值

时间:2017-05-15 11:49:56

标签: sql-server

大家早上好

感谢您在此主题中给予我任何帮助

我有一张与同一Id1同时增长的表格 但有些时候Id2会发生变化,就像历史悠久的公园一样。

我想找到一个查询的最佳方法来检索 id2更改的行和时间

示例,如果表格内容是

Id1  Id2      time
1      1      10:00
1      1      10:30
1      2      10:40
1      2      10:45
1      2      11:00
1      3      11:45
1      3      12:45

查询输出将是

Id1  oldId2  newId2     time
1      1       2       10:40
1      2       3        11:45

我已经完成了存储过程,但我想知道有更快/更清晰的方法来实现这个

提前致谢

3 个答案:

答案 0 :(得分:1)

您可以通过排名函数来实现这一目标。

<强>架构:

CREATE TABLE #TAB (Id1 INT,Id2 INT, timeS TIME  )

INSERT INTO #TAB        
SELECT 1 AS Id1 , 1 Id2, '10:00' AS timeS
UNION ALL
SELECT 1, 1, '10:30'
UNION ALL
SELECT 1, 2, '10:40'
UNION ALL
SELECT 1, 2, '10:45'
UNION ALL
SELECT 1, 2, '11:00'
UNION ALL
SELECT 1, 3, '11:45'
UNION ALL
SELECT 1, 3, '12:45'

现在选择ROW_NUMBER和CTE来检索上一行/下一行值。

;WITH CTE
AS (
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RNO
        ,ID1
        ,ID2
        ,timeS
    FROM (
        SELECT ROW_NUMBER() OVER (PARTITION BY ID2 ORDER BY TIMES) AS SNO
            ,*
        FROM #TAB
        ) A
    WHERE SNO = 1
    )
SELECT C1.Id1
    ,C1.Id2 AS OLD_ID2
    ,C2.Id2 AS NEW_ID2
    ,C2.timeS
FROM CTE C1
LEFT JOIN CTE C2 ON C1.RNO + 1 = C2.RNO
WHERE C2.Id1 IS NOT NULL

<强>结果:

+-----+---------+---------+------------------+
| Id1 | OLD_ID2 | NEW_ID2 |      timeS       |
+-----+---------+---------+------------------+
|   1 |       1 |       2 | 10:40:00.0000000 |
|   1 |       2 |       3 | 11:45:00.0000000 |
+-----+---------+---------+------------------+

注意:如果要将上一行/下一行值转换为当前行,可以使用LEAD LAG函数。但它们仅支持SQL Server 2012+。 以上左连接CTE也适用于较低版本。

答案 1 :(得分:0)

declare @t table (Id1 int, Id2 int, [time] time)
    insert into @t
        select 1, 1, '10:00' union
        select 1, 1, '10:30' union
        select 1, 2, '10:40' union
        select 1, 2, '10:45' union
        select 1, 2, '11:00' union
        select 1, 3, '11:45' union
        select 1, 3, '12:45' 

select Id1, oldId = (select top 1 id2 from @t where Id1=t.Id1 and  Id2 < t.Id2 order by id2, time desc), newId = id2, time = min(time)
from @t t
where id2 > 1
group by Id1, id2

答案 2 :(得分:0)

我对Shakeer Mirza的代码做了一些更改。 起初问题的实际问题是: 我有一张表代表设备历史的表。作为机器内部id(Num_TPA)。 每次出现故障时,机器都会被另一台机器替换,它会保持相同的Num_TPA但Serial_number会发生变化 我需要知道internal_id-&gt; Num_TPA上的历史是什么。新旧serial_number和替换日期

这就是它的结果。

;WITH CTE
AS (
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RNO
        ,[Num_TPA]
        ,[Serial_number]
        ,[Time]
        ,a.SNO
    FROM (
        SELECT ROW_NUMBER() OVER (PARTITION BY [Num_TPA] 
        ORDER BY [Data_Hora_Ficheiro]) AS SNO
            ,*
        FROM tab_values
        ) A
    WHERE SNO > 1
    )
SELECT C1.[Num_TPA]
    ,C1.[Serial_number] AS OLD_ID2
    ,C2.[Serial_number] AS NEW_ID2
    ,C2.[Data_Hora_Ficheiro]
    ,c2.SNO
    ,c2.RNO
FROM tab_values C1
LEFT JOIN CTE C2 ON (
        C1.[Num_TPA] = C2.[Num_TPA]
        AND c1.[Serial_number] != c2.[Serial_number]
        AND C2.[Time] > c1.TIME
        )
WHERE C2.[Num_TPA] IS NOT NULL
    AND SNO = 2

UNION

SELECT C1.[Num_TPA]
    ,C1.[Serial_number] AS OLD_ID2
    ,C2.[Serial_number] AS NEW_ID2
    ,C2.[Data_Hora_Ficheiro]
    ,c2.SNO
    ,c2.RNO
FROM CTE C1
LEFT JOIN CTE C2 ON (
        C1.SNO + 1 = C2.SNO
        AND C1.[Num_TPA] = C2.[Num_TPA]
        )
WHERE C2.[Num_TPA] IS NOT NULL
    AND C2.SNO > 2