SQL Server MERGE + присоединение к другим таблицам

Я использую оператор MERGE в проекте базы данных для заполнения справочных данных из статического набора значений, например следующего ниже:

    MERGE INTO dbo.[User] AS TARGET
USING (VALUES
    ('[email protected]', 'My Name'))
AS SOURCE(UserName, FullName)
ON SOURCE.UserName = TARGET.UserName
WHEN NOT MATCHED BY TARGET THEN
    INSERT (UserId, UserName, FullName)
    VALUES (NEWID(), UserName, FullName);

Проблема возникает, когда я хочу заполнить дополнительную таблицу на основе содержимого других таблиц. Например, моя таблица UserPermission содержит идентификатор пользователя и идентификатор роли, и я хотел бы, чтобы мое статическое значение было примерно таким ('[email protected]', 'Admin') и имело возможность присоединиться к Пользователю и Разрешению, чтобы получить Значения ID для INSERTing. Не знаю, где это сделать...

Редактировать:

Таблица пользователей (ID, имя пользователя) 1, Джон Смит 2, Марк Валерг

Таблица ролей (ID, имя роли) 1, администратор 2, пользователь 3, гость

Таблица ролей пользователей (идентификатор пользователя, идентификатор роли)

Я хочу, чтобы SQL для оператора MERGE корректировал таблицу User-Role, чтобы я мог указать что-то вроде:

USING(VALUES
 ('John Smith', 'Administrator'),
 ('Mark Wahlburg', 'User')

и он присоединится, чтобы определить идентификаторы, вставить комбинации, которых не существует (и, возможно, удалить те, которые существуют, но не находятся в MERGE.

Решение:

WITH CTE AS
(
   SELECT UserId, RoleId
   FROM (VALUES
      ('John Smith', 'Administrator'),
      ('Mark Wahlburg', 'User'))
      AS SOURCE(UserName, RoleName)
   INNER JOIN User ON SOURCE.UserName = User.UserName
   INNER JOIN Role ON SOURCE.RoleName = Role.RoleName
)
MERGE INTO UserRole AS TARGET
USING CTE
ON CTE.UserId = TARGET.UserID AND CTE.RoleId = TARGET.UserId
WHEN NOT MATCHED BY TARGET THEN
  INSERT(UserId, RoleId)
  VALUES(UserId, RoleId)

person Rich    schedule 09.05.2012    source источник
comment
Просто любопытно, почему вы используете здесь MERGE вместо гораздо более простого INSERT ... SELECT? Я не говорю, что вы не можете сделать это с помощью MERGE, но это кажется излишним для такой тривиальной операции.   -  person Aaron Bertrand    schedule 09.05.2012
comment
@AaronBertrand, это упрощенный пример, обычно у меня есть несколько строк и я использую возможности UPDATE и DELETE MERGE. Я пытался изолировать проблему.   -  person Rich    schedule 09.05.2012
comment
Проблема в вашем предложении USING. У вас просто есть жестко запрограммированные значения; вам нужно, чтобы он фактически использовал SELECT, если вам нужно извлечь эти значения из таблицы. Также есть несколько довольно умных людей, которые могут помочь решить ваши проблемы, но они гораздо больше заинтересованы в решении вашей реальной проблемы - упрощение ее просто приводит к ненужным вопросам, подобным тому, который я задал.   -  person Aaron Bertrand    schedule 09.05.2012
comment
Я не вижу причин для того, чтобы не изменить вставку, удалив строку «значения (...)» на «выбрать», которая включает ваши статические поля, а также присоединяется к другим таблицам для поиска соответствующих идентификаторов.   -  person Chris Moutray    schedule 09.05.2012
comment
Эти значения должны быть жестко закодированы, но проблема в том, что я не хочу вставлять эти конкретные значения, а вместо этого идентификаторы из других таблиц на основе жестко закодированных значений. Пример тот, который работает сейчас. Проблема заключается в том, чтобы сделать следующий шаг, который описан позже.   -  person Rich    schedule 09.05.2012
comment
Поля ID должны быть известны до INSERT, чтобы предложение ON соответствовало источнику и цели MERGE, чтобы определить, должно ли MERGE обновлять, вставлять или удалять.   -  person Rich    schedule 09.05.2012
comment
Вам нужно лучше указать, какие жестко закодированные значения вы хотите использовать, а какие — нет. Можете ли вы показать некоторые фактические образцы данных до и после и как вы хотите, чтобы слияние фактически повлияло на данные? Вы пытаетесь сделать это для всех значений в таблице имен пользователей или для конкретных? Если конкретно, то как вы указываете? Детали, детали, детали.   -  person Aaron Bertrand    schedule 09.05.2012
comment
Может ли пользователь принадлежать к нескольким ролям?   -  person Aaron Bertrand    schedule 10.05.2012


Ответы (1)


Merge поддерживает CTE, поэтому, возможно, вы можете использовать его в качестве источника, комбинируя свои статические данные и выполняя любые объединения внутри CTE.

person Chris Moutray    schedule 09.05.2012
comment
В этом была хитрость. Мой опыт работы с CTE и конструкторами табличных значений был немного слабым, поэтому я не знал, где их можно использовать (и использовать вместе). - person Rich; 10.05.2012