SQL 服务器 - 合并时合并重复键上的数据

SQL Server - coalesce data on duplicate keys when MERGE-ing

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

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

请注意,我已经更改了所有字段和 table 名称

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 查询结果

如果我们只取 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);

您可以使用 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);