SQL 检测行中的变化

SQL detect change in row

我有来自 sql 附加服务器的数据:

select * from log

我想做的是检查列名称的代码是否有任何变化。因此,如果您从 table 日志中看到数据,则代码更改了 2 次 (B02,B03)。

我想做的是每次代码更改时检索第一个更改的行。在此示例中,第一个更改位于红色框内。所以我想要第 5 行和第 9 行的结果。

我试过像下面的代码那样使用分区:

select a.name,a.code from(
select name,code,row_number() over(partition by code order by name) as rank from log)a
where a.rank=1

得到这样的结果。

但是,我不想检索第一行。因为它是第一个值,所以我不需要它。所以我只想检索列代码指示的更改。如果你知道怎么做,请帮忙。

请注意,我无法使用过滤器 where code <> 'B01' 编写查询,因为在这种情况下,我不知道第一个值是什么。

请假设第一个值是第一个插入 table 的数据。

使用lag获取上一行的值(假设id指定排序)并获取与当前行值不同的行。

create table #log (id int identity(1,1) not null, name nvarchar(100), code nvarchar(100));

insert into #log(name,code) values ('SARUMA','B01'), ('SARUMA','B01'), ('SARUMA','B01'), ('SARUMA','B01');
insert into #log(name,code)  values ('SARUMA','B02'), ('SARUMA','B02'), ('SARUMA','B02'), ('SARUMA','B02');
insert into #log(name,code)  values ('SARUMA','B03'), ('SARUMA','B03');

select name
    ,code
from (
    select l.*
        ,lag(code) over (
            partition by name order by id
            ) as prev_code
    from #log l
    ) l
where prev_code <> code

我认为您原来的 post 非常接近,尽管您希望窗口函数位于 [NAME] 列,而不是代码。请在下面查看我的修改。我还将谓词更改为 >1,因为 1 将是原始记录。

SELECT 
    a.[name]
   ,a.[code] 
FROM (
    SELECT 
        [name]
       ,[code]
       ,ROW_NUMBER() OVER(PARTITION BY [name] order by [name], [code]) AS [rank] 
    FROM log)a
WHERE a.rank>1

注意:您可能不想将 NAME 用作字段,因为它是保留字。此外,RANK 也是一个保留字,您已使用它作为嵌套查询中 ROW_NUMBER 的别名。您可能想为此使用另一个非保留词 - 就个人而言,我为此目的使用 RANKED。

create table #log (name nvarchar(100), code nvarchar(100));

insert into #log values ('SARUMA','B01'), ('SARUMA','B01'), ('SARUMA','B01'), ('SARUMA','B01');
insert into #log values ('SARUMA','B02'), ('SARUMA','B02'), ('SARUMA','B02'), ('SARUMA','B02');
insert into #log values ('SARUMA','B03'), ('SARUMA','B03');

-- remove duplicates
with Singles (name, code) 
AS (
    select distinct name, code from #log
),
-- At first you need an order, in time? By alphanumerical code? Otherwise you cannot decide which is the first item you want to remove
-- So I added an identity ordering, but it is preferable to use a physical column
OrderedSingles (name, code, id) 
AS (
    select *, row_number() over(order by name)
    from Singles
)
-- Now self-join to get the next one, if the index is sequential you can join id = id+1
-- and take the join columns
select distinct ii.name, ii.Code
from OrderedSingles i
inner join OrderedSingles ii 
    on i.Name = ii.Name and i.Code <> ii.Code
where i.id < ii.Id;