SQL Server - объединять данные о повторяющихся ключах при MERGE-ing

Я наткнулся на раздражающую ситуацию, когда результаты моего исходного запроса содержат повторяющиеся ключи с разными данными. К сожалению, мне нужно заполнить все 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);

person Stefan Collier    schedule 11.10.2018    source источник


Ответы (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);
person Lukasz Szozda    schedule 11.10.2018
comment
Это кажется очень хорошим и дерзким решением. завтра попробую! Спасибо - person Stefan Collier; 11.10.2018