【问题标题】:SQL detect change in rowSQL 检测行中的变化
【发布时间】:2018-02-17 10:31:24
【问题描述】:

我有来自 sql server 的数据:

select * from log

我想做的是检查列名的代码是否有任何更改。因此,如果您从表日志中查看数据,则代码更改了 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' 编写查询,因为在这种情况下,我不知道第一个值是什么。

请假设第一个值是最先插入到表中的数据。

【问题讨论】:

  • 你可以用哪一栏来表示顺序?根据您发布的内容,无法确定顺序。
  • 如果您发布示例数据的文本而不是图像,您会做得更好。

标签: sql sql-server partition


【解决方案1】:

使用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

【讨论】:

    【解决方案2】:
    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;
    

    【讨论】:

      【解决方案3】:

      我认为您的原始帖子非常接近,尽管您希望窗口函数位于 [NAME] 列上,而不是代码上。请在下面查看我的修改。我还将谓词更改为&gt;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。

      【讨论】:

        猜你喜欢
        • 2014-05-07
        • 2018-04-29
        • 1970-01-01
        • 1970-01-01
        • 2021-06-17
        • 2021-06-07
        相关资源
        最近更新 更多