【问题标题】:How to update specific values in a column with other values from same column in the same table? - SQL Server如何使用同一表中同一列中的其他值更新列中的特定值? - SQL 服务器
【发布时间】:2017-03-14 23:08:56
【问题描述】:

假设我有一个表“东西”。 它有 3 列。

因此,经理和该经理下属的员工的工作代码应该相同(就像 jobcode= 000 一样)。那是正常的情况。 但是在某些情况下,经理将“ABC”作为工作代码。 在这些情况下,我需要将“ABC”替换为该经理下一位最近员工的工作代码值。 例如,对于经理 A1,我需要将他的工作代码 ABC 替换为 234,考虑到 B1 是他最近的员工。 对于经理 A,他的工作代码 ABC 将被替换为 121,因为 B 是他手下唯一的员工。

我写了这个查询,但它似乎不起作用。

Update X

Set X.JobCode=Y.JobCode

FROM STUFF X

INNER JOIN STUFF Y

ON X.MGRCODE=Y.MGRCODE

AND X.JOBCODE = 'ABC"

AND Y.JOBCODE = ( SELECT TOP 1 JOBCODE FROM STUFF WHERE EMPCODE<>Y.MGRCODE AND
Y.MGRCODE IN (SELECT MGRCODE FROM STUFF WHERE EMPCODE=MGRCODE AND JOBCODE='ABC')

【问题讨论】:

  • 什么版本的sql server?为此,您可以使用LEAD 或带有ROW_NUMBER 的CTE。此外,当使用TOP 时,您需要一个ORDER BY 来使其具有确定性
  • SQL Server 2008 R2。是的,我在 order by 子句中使用了一个更新日期。我想知道是否有任何方法可以通过简单的查询和连接来做到这一点?

标签: sql sql-server sql-server-2008 tsql join


【解决方案1】:
;WITH cteJobCodeRowNum AS (
    SELECT
       ManagerCode
       ,JobCode
       ,ROW_NUMBER() OVER (PARTITION BY ManagerCode ORDER BY UpdateDate DESC) as RowNumber
    FROM
       @Table
)

UPDATE t
    SET JobCode = r.JobCode
FROM
    @Table t
    INNER JOIN cteJobCodeRowNum r
    ON t.EmpCode = r.ManagerCode
    AND r.RowNumber = 1
    AND t.JobCode <> r.JobCode
WHERE
    t.JobCode = 'ABC'

使用分区窗口函数生成行号以选择所需的作业代码。按ManagerCode 分区并按UpdateDate 降序排列。然后基于EmpCode = ManagerCode 将该公用表表达式(或派生表,如果嵌套它)加入到您的表中,以更新经理记录。然后,您还可以将其限制为仅当经理的工作代码为“ABC”并且行号返回的工作代码不同时,您只更新一组特定的行。

另一种类似的方法是通过使用相关的交叉应用来创建自己的行号,例如:

UPDATE t1
    SET JobCode = NewJobCode
FROM
    @Table t1
    CROSS APPLY (SELECT TOP 1 JobCode as NewJobCode FROM @Table t2 WHERE t1.EmpCode = t2.ManagerCode ORDER BY t2.UpdateDate DESC) n
WHERE
    t1.JobCode = 'ABC'
    AND t1.JobCode <> n.NewJobCode

下面是窗口函数方法的完整工作示例:

DECLARE @Table AS TABLE (JobCode CHAR(3), EmpCode VARCHAR(2), ManagerCode VARCHAR(2), UpdateDate DATETIME)
INSERT INTO @Table (JobCode, EmpCode, ManagerCode, UpdateDate)
VALUES ('ABC','A','A',GETDATE()-1),('121','B','B',GETDATE()-1)
,('ABC','A1','A1',GETDATE()-1)
,('234','B1','A1',GETDATE()+1)
,('342','C1','A1',GETDATE()-1)
,('000','A2','A2',GETDATE()-1)
,('000','B2','B2',GETDATE()-1)

SELECT *
FROM
    @Table

;WITH cteJobCodeRowNum AS (
    SELECT
       ManagerCode
       ,JobCode
       ,ROW_NUMBER() OVER (PARTITION BY ManagerCode ORDER BY UpdateDate DESC) as RowNumber
    FROM
       @Table
)

UPDATE t
    SET JobCode = r.JobCode
FROM
    @Table t
    INNER JOIN cteJobCodeRowNum r
    ON t.EmpCode = r.ManagerCode
    AND r.RowNumber = 1
    AND t.JobCode <> r.JobCode
WHERE
    t.JobCode = 'ABC'


SELECT *
FROM
    @Table

【讨论】:

  • 嗯这种工作。 cte 解决方案非常好。谢谢你:)
猜你喜欢
  • 2015-05-19
  • 2012-04-20
  • 2016-10-14
  • 2012-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多