如何使用同一表中同一列的其他值更新列中的特定值? - SQL Server

时间:2016-11-01 18:31:42

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

所以我想说我有一个表“Stuff”。 它有3列。

Table Details

因此,对于经理和该经理下的员工,工作代码应该是相同的(就像在jobcode = 000的地方)。这是正常情况。 但是在某些情况下,经理会将“ABC”作为工作代码。 在这些情况下,我需要将“ABC”替换为该经理下最近员工的工作代码值。 例如,对于经理A1,我需要用234取代他的ABC工作代码,考虑到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')

1 个答案:

答案 0 :(得分: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&#39;并且行号返回的作业代码不同,因此您只更新一组特定的行。

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

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