【问题标题】:Update a column with the value from previous row based on conditions根据条件使用上一行的值更新列
【发布时间】:2018-11-14 10:36:07
【问题描述】:

我有一个表,我需要在其中找到满足几个条件的值,如果满足这些条件,我需要为每一列分配相同的值

 Table 
  ID       Name   Salary  rownum
  1         Jon    500     1
  1         Jim    600     2 
  1         Jack   700     3
  1         Bob    1000    4
  2         Adam    500    1
  2         Aron    600    2 
  2         James   900    3
  2         Jay     1000   4

第一个条件是我需要相同的 ID,然后在 ID 内,如果差异小于或等于 100,我需要将第一行与第二行进行比较。我只能将 Rownum 1 与 2 和 2 进行比较与 3 依此类推。在确定是否满足条件后,我需要将工资值更新为 Rownum 1 存在的值,直到满足条件并保持名称相同。

预期输出

 Table 
  ID       Name   Salary  rownum
  1         Jon    500     1
  1         Jim    500     2 
  1         Jack   500     3
  1         Bob    1000    4
  2         Adam    500    1
  2         Aron    500    2 
  2         James   900    3  
  2         Jay     900    4                 

Jim 的工资为 600,与 Jon 的工资相差

【问题讨论】:

    标签: sql sql-server tsql sql-server-2014 gaps-and-islands


    【解决方案1】:

    试试这个:

    如果 "left join self + where Salary + 100 * (jointable.rownum - rownum) = jointable.Salary 的数据不为空”然后更新薪水

    update T
    set Salary = NewSalary
    from (
      select T2.*,T1.Salary NewSalary,(T2.rownum - T1.rownum) fd
      from [Table] T1
      left join [Table] T2 on T1.ID = T2.ID
        and T1.rownum <> T2.rownum
        and (T2.rownum - T1.rownum) > 0 
        and T1.[Salary] + 100 * (T2.rownum - T1.rownum) = T2.[Salary] 
      where T2.id is not null
    ) T ;  
    

    | ID |  Name | Salary | rownum |
    |----|-------|--------|--------|
    |  1 |   Jon |    500 |      1 |
    |  1 |   Jim |    500 |      2 |
    |  1 |  Jack |    500 |      3 |
    |  1 |   Bob |   1000 |      4 |
    |  2 |  Adam |    500 |      1 |
    |  2 |  Aron |    500 |      2 |
    |  2 | James |    900 |      3 |
    |  2 |   Jay |    900 |      4 |
    

    SQL Fiddle DEMO LINK

    【讨论】:

    • 我认为您基于数学的逻辑是错误的。可能有四行,如 10、80、190、200,其中显然 200 需要用 190 更新,而 190 不需要更新。也可能有三个连续的行,如 0,800,700。这里 700 不需要更新 AFAIK。
    • 感谢 IT Weihan 提供解决方案,这有助于我了解解决方案应该如何应用
    【解决方案2】:

    您的问题并不像看起来那么简单,因为与当前行(例如 750)相比,前一行可能具有更大的值(例如 800)。 也有可能存在更多的岛屿和缝隙,而不仅仅是一个。

    以下是我的解决方案。另请参阅 working demo

    ; with cte as 
    (
        select *
        , toUpdate= case 
                        when 
                            salary - lag( salary) over( partition by Id order by rownum asc) between 0 and 100 
                        then 
                            1 
                        else 
                            0 
                    end
    from t
    )
    
    update t5 
    set t5.salary=t4.newsalary
    from t t5 
    join
    (
        select 
        t1.*, 
        rn=row_number () over( partition by t1.id, t1.rownum order by t3.rownum desc), 
        newsalary=t3.salary 
        from cte t1 
            outer apply
                (
                    select *  
                        from cte t2 
                    where t2.id=t1.id 
                        and t2.rownum<t1.rownum 
                        and t2.toUpdate=0
                  ) t3
        )t4 
    on t4.rn=1 and t4.toUpdate=1 and t5.id=t4.id and t5.rownum=t4.rownum
    
    select * from t
    

    【讨论】:

    • 感谢您提供解决方案,真的很有帮助!
    猜你喜欢
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 2022-01-07
    • 2020-02-20
    • 2010-12-17
    • 1970-01-01
    相关资源
    最近更新 更多