SQL Server-合并时在重复键上合并数据

时间:2018-10-11 18:15:09

标签: sql-server tsql sql-merge

我偶然发现了一个令人烦恼的情况,即我的源查询结果具有重复的键且数据不同。不幸的是,我需要回填所有NULL。 我尝试使用MERGE,但遇到关键错误。

MySQL(我无法转换)中的等效查询为:

请注意,我更改了所有字段和表名

INSERT INTO user_brief (name, high_score, colour)
SELECT
  u.name,
  h.high_score,
  p.colour,
FROM foo_table AS f
    LEFT JOIN users AS u       ON f.user_id = u.id
    LEFT JOIN high_scores AS h ON f.user_id = h.id
    LEFT JOIN preferences AS p ON f.user_id = p.id
ON DUPLICATE KEY
UPDATE
    name        = COALESCE(user_brief.name,             VALUES(name)),
    high_score  = COALESCE(user_brief.high_score,       VALUES(high_score)),
    colour      = COALESCE(user_brief.colour,           VALUES(colour));

选择查询结果

如果仅使用SELECT,您将获得以下结果:

name | high_score  | color
---------------------------
foo  | NULL        | brown
foo  | 40          | NULL
bar  | 29          | blue
...

所需结果

name | high_score | color
---------------------------
foo  | 40         | brown
bar  | 29         | blue
...

如您所见,它已经变平了(不确定这是否是正确的术语),它为name键控记录的每一列取了第一个非空值。


我尝试的MERGE解决方案(但出现关键错误):

MERGE INTO user_brief AS target
USING (SELECT
      u.name,
      h.high_score,
      p.colour,
    FROM foo_table AS f
        LEFT JOIN users AS u       ON f.user_id = u.id
        LEFT JOIN high_scores AS h ON f.user_id = h.id
        LEFT JOIN preferences AS p ON f.user_id = p.id) AS source
    ON target.name = source.name
WHEN MATCHED THEN
    UPDATE SET 
        target.name       = COALESCE(source.name,       target.name),
        target.high_score = COALESCE(source.high_score, target.high_score),
        target.colour     = COALESCE(source.colour,     target.colour)
WHEN NOT MATCHED BY TARGET THEN
    INSERT (name, high_score, colour)
    VALUES (source.name, source.high_score, source.colour);

1 个答案:

答案 0 :(得分:1)

您可以使用GROUP BY来拼合源代码:

WITH source AS (
    SELECT
      u.name,
      high_score = MIN(h.high_score),
      colour = MIN(p.colour)
    FROM foo_table AS f
        LEFT JOIN users AS u       ON f.user_id = u.id
        LEFT JOIN high_scores AS h ON f.user_id = h.id
        LEFT JOIN preferences AS p ON f.user_id = p.id
    GROUP BY u.name
)
MERGE INTO user_brief AS target
USING source
  ON target.name = source.name
WHEN MATCHED THEN
    UPDATE SET 
        target.name       = COALESCE(source.name,       target.name),
        target.high_score = COALESCE(source.high_score, target.high_score),
        target.colour     = COALESCE(source.colour,     target.colour)
WHEN NOT MATCHED BY TARGET THEN
    INSERT (name, high_score, colour)
    VALUES (source.name, source.high_score, source.colour);