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;
我有来自 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;