【问题标题】:Updating table without replacing values that already exist in the original table with null values from the temporary table更新表而不用临时表中的空值替换原始表中已经存在的值
【发布时间】:2015-09-09 08:18:04
【问题描述】:

我有一个名为“学生”的原始表,如下所示:

idstudent    studentname    studentclass
101          adam           A
102          brian          NULL
103          charlie        C 
104          danny          D

然后,我有一个临时表名“student_temp”,如下所示:

idstudent    studentname    studentclass
101          adam           A
102          brian          B
103          NULL           C
105          edward         E

如果我在 SQL Server Management Studio 2008 R2 上运行此查询:

USE [StudentDatabase]
GO

UPDATE stu
SET [studentname] = tmp.[studentname]
  , [studentclass] = tmp.[studentclass]

FROM [StudentDatabase].[dbo].[student] stu
INNER JOIN [StudentDatabase].[dbo].[student_temp] tmp  
    ON stu.[idstudent] = tmp.[idstudent]
GO

INSERT INTO student
SELECT 
    tmp.[idstudent]
  , tmp.[studentname]
  , tmp.[studentclass]

FROM [StudentDatabase].[dbo].[student] stu
RIGHT OUTER JOIN [StudentDatabase].[dbo].[student_temp] tmp 
    ON  stu.[idstudent] = tmp.[idstudent]
WHERE stu.[idstudent] IS NULL

'student'表的结果会是这样的:

idstudent    studentname    studentclass
101          adam           A
102          brian          B
103          NULL           C
104          danny          D
105          edward         E

但我想要的是,结果会是这样的:

idstudent    studentname    studentclass
101          adam           A
102          brian          B
103          charlie        C
104          danny          D
105          edward         E

注意idstudent=103student 表中已经有studentname 值“charlie”。但它被student_temp表中的记录替换为NULL

有没有办法解决这个问题?

【问题讨论】:

  • 如果两个表的非空值不相等,应该首选哪一个?
  • 首选的是student_temp表

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


【解决方案1】:

WHERE 子句中使用条件忽略NULL

UPDATE stu
SET [studentname] = tmp.[studentname]
  , [studentclass] = tmp.[studentclass]

FROM [StudentDatabase].[dbo].[student] stu
INNER JOIN [StudentDatabase].[dbo].[student_temp] tmp  
    ON stu.[idstudent] = tmp.[idstudent]
WHERE tmp.[studentname] IS NOT NULL

【讨论】:

    【解决方案2】:

    这整个事情通常应该用MERGECOALESCE来完成:

    MERGE INTO student t
    USING student_temp s
    ON t.idstudent = s.idstudent
    WHEN MATCHED THEN UPDATE SET
      studentname = COALESCE(t.studentname,s.studentname),
      studentclass = COALESCE(t.studentclass,s.studentclass)
    WHEN NOT MATCHED THEN INSERT (idstudent,studentname,studentclass)
    VALUES (s.idstudent,s.studentname,s.studentclass);
    

    如果两个表都具有非空值,则当前有利于现有数据。如果您希望用 student_temp 中的新值覆盖,请反转 COALESCE 表达式中的值顺序。

    所以,更喜欢来自student_temp 的值:

    MERGE INTO student t
    USING student_temp s
    ON t.idstudent = s.idstudent
    WHEN MATCHED THEN UPDATE SET
      studentname = COALESCE(s.studentname,t.studentname),
      studentclass = COALESCE(s.studentclass,t.studentclass)
    WHEN NOT MATCHED THEN INSERT (idstudent,studentname,studentclass)
    VALUES (s.idstudent,s.studentname,s.studentclass);
    

    【讨论】:

    • Msg 156, Level 15, State 1, Line 1 Incorrect syntax near the keyword 'INTO'. 出现错误
    【解决方案3】:

    试试这个:

    UPDATE stu
    SET [studentname] = CASE WHEN tmp.[studentname] IS NOT NULL THEN tmp.[studentname] ELSE stu.studentname END
      , [studentclass] = CASE WHEN tmp.[studentclass] IS NOT NULL THEN tmp.[studentclass] ELSE stu.studentclass END
    
    FROM [student] stu
    INNER JOIN [student_temp] tmp  
        ON stu.[idstudent] = tmp.[idstudent]
    GO
    
    INSERT INTO student
    SELECT 
        tmp.[idstudent]
      , tmp.[studentname]
      , tmp.[studentclass]
    
    FROM [student] stu
    RIGHT OUTER JOIN [student_temp] tmp 
        ON  stu.[idstudent] = tmp.[idstudent]
    WHERE stu.[idstudent] IS NULL
    

    【讨论】:

    • 那些CASE 表达式是一种非常冗长的方式来做与COALESCE 相同的事情。
    猜你喜欢
    • 1970-01-01
    • 2018-10-13
    • 2011-05-16
    • 2021-01-23
    • 2015-05-24
    • 1970-01-01
    • 2021-01-04
    • 2013-11-01
    • 2023-03-26
    相关资源
    最近更新 更多