Подтвердить что ты не робот

Что такое ИСПОЛЬЗОВАНИЕ в синтаксисе MERGE SQL Server 2008?

Якоб задал идеальный вопрос: дать мне синтаксис MERGE.

Каждый ответ там сразу переходит в самый сложный случай, о котором они могут подумать; скрывая синтаксис с посторонней путаницей.

Марк дал ответ:

MERGE 
   member_topic AS target
USING 
   someOtherTable AS source
ON 
   target.mt_member = source.mt_member 
   AND source.mt_member = 0 
   AND source.mt_topic = 110
WHEN MATCHED THEN 
   UPDATE SET mt_notes = 'test'
WHEN NOT MATCHED THEN 
   INSERT (mt_member, mt_topic, mt_notes) VALUES (0, 110, 'test')
; 

Глядя на этот ответ, я так же смущен, как Джейкоб:

У меня нет someOtherTable

Марк предположил, что someOtherTable является фиктивным значением-заполнителем - не имеет значения, что у вас нет этой таблицы.

Я пытаюсь это сделать, и SQL Server жалуется

Недопустимое имя объекта 'someOtherTable'.

Это оставляет мне попытку понять, что означает USING in USING foo, если это не важно (кроме действительно важных).

Что используется USING при использовании foo при использовании синтаксиса MERGE SQL Server 2008?


Бонусный вопрос

Что такое синтаксис UPSERT с помощью MERGE:

IF (rowExists)
   UPDATE Users SET Firstname='Ian', LastName='Boyd' WHERE Username='iboyd'
ELSE
   INSERT INTO Users (UserGUID, Username, FirstName, LastName, AuthenticationMethod)
   VALUES ('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}', 'iboyd', 'Ian', 'Boyd', 'Windows')

становится (точный код, который я пробовал):

begin transaction

    MERGE 
       Users
    USING 
       foo
    ON  
       Users.UserName = foo.UserName
    WHEN MATCHED THEN
        UPDATE SET Firstname = foo.FirstName, Lastname = foo.LastName
    WHEN NOT MATCHED THEN
        INSERT (UserGUID, Username, FirstName, LastName, AuthenticationMethod)
        VALUES ('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}', 'iboyd', 'Ian', 'Boyd', 'Windows')
    ; --A MERGE statement must be terminated by a semi-colon (;).

rollback

Msg 208, Level 16, State 1, Line 3
Invalid object name 'foo'.

?

С таблицей Users, содержащей столбцы:

UserGUID uniqueidentifier
Username varchar(50)
FirstName varchar(50)
LastName varchar(50)
AuthenticationMethod varchar(50)

Update:

USING <table_source> 

Где table_source:

table_or_view_name [ [ AS ] table_alias ] [ <tablesample_clause> ] 
    [ WITH ( table_hint [ [ , ]...n ] ) ] 
| rowset_function [ [ AS ] table_alias ] 
    [ ( bulk_column_alias [ ,...n ] ) ] 
| user_defined_function [ [ AS ] table_alias ]
| OPENXML <openxml_clause> 
| derived_table [ AS ] table_alias [ ( column_alias [ ,...n ] ) ] 
| <joined_table> 
| <pivoted_table> 
| <unpivoted_table> 

Где joined_table:

undefined

Где pivoted_table:

undefined

Где unpivoted_table:

undefined

4b9b3361

Ответ 1

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

В вашем вопросе указывается грамматика. Чтобы слить из другой таблицы или просмотра, используйте

MERGE 
   Users
USING SomeOtherTableName AS foo /*Alias is optional*/
ON /* ... */

Или вы можете использовать <unpivoted_table>, например

MERGE 
   Users
USING master..spt_values
UNPIVOT (X FOR Y IN ([high],[low])) AS foo 
ON  
   Users.Username = foo.Y 
WHEN MATCHED THEN
    UPDATE SET FirstName = foo.Y
WHEN NOT MATCHED THEN
    INSERT (UserGUID, Username, FirstName, LastName, AuthenticationMethod)
    VALUES (foo.Y, foo.Y, foo.Y, foo.Y, foo.Y);

Для вашего бонусного вопроса вы можете использовать предложение VALUES здесь как часть опции derived_table.

MERGE Users
USING (VALUES ('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}',
      'iboyd',
      'Ian',
      'Boyd',
      'Windows')) AS foo(UserGUID, Username, FirstName, LastName, AuthenticationMethod)
ON Users.UserName = foo.UserName
WHEN MATCHED THEN
  UPDATE SET Firstname = foo.FirstName,
             Lastname = foo.LastName
WHEN NOT MATCHED THEN
  INSERT (UserGUID,
          Username,
          FirstName,
          LastName,
          AuthenticationMethod)
  VALUES (UserGUID,
          Username,
          FirstName,
          LastName,
          AuthenticationMethod); 

Ответ 2

Таблица источников может быть любой, например:

MERGE 
   member_topic AS target
USING 
   (SELECT @Variable1, @Variable2, @Variable3) AS source(Col1, Col2, Col3)
ON 
   target.mt_member = source.Col1 
   AND source.Col1 = 0 
   AND source.Col2 = 110
WHEN MATCHED THEN 
   UPDATE SET mt_notes = 'test'
WHEN NOT MATCHED THEN 
   INSERT (mt_member, mt_topic, mt_notes) VALUES (0, 110, 'test');

Очевидно, что во вложенном исходном элементе вы можете делать гораздо больше. Выберите из представления, функции, переменной таблицы, даже CTE.

Что касается вопроса о бонусе, вы ответили на свой вопрос.

Иногда для очень больших таблиц я также использую подсказку ROWLOCK в целевой таблице, чтобы хотя бы попытаться не заблокировать всю таблицу в случае обновлений:

MERGE 
   member_topic WITH (ROWLOCK) AS target

Связанный с бонусом вопрос не работает, вот рабочий образец. Конечно, я переименовал некоторые объекты.

DECLARE @Variable1 AS INT;
SET @Variable1 = 1234;

MERGE dbo.Table1 WITH(ROWLOCK) target
USING(SELECT @Variable1) source(Key)
ON target.[Key] = source.[Key]
WHEN MATCHED THEN
    UPDATE SET
    Col1 = @SomeVar1,
    Col2 = @SomeVar2
WHEN NOT MATCHED THEN
INSERT 
        ([Key]
        ,[Col1]
        ,[Col2])
    VALUES
        (@Variable1
        ,@SomeVar1
        ,@SomeVar2);

Ответ 3

Следуя ответу Мартина Смита, вы можете сразу несколько строк значений сразу добавить несколько строк значений, просто повторяя скобки, разделяя их запятой, например

MERGE Users WITH (HOLDLOCK)
USING (VALUES ('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}',
      'iboyd',
      'Ian',
      'Boyd',
      'Windows'),
      ('{00000DC5-7A3E-4F1A-82C6-8EF452D2DE66}',
      'jsmith',
      'John',
      'Smith',
      'ActiveDirectory')) AS foo(UserGUID, Username, FirstName, LastName, AuthenticationMethod)
ON Users.UserName = foo.UserName
WHEN MATCHED THEN
  UPDATE SET Firstname = foo.FirstName,
             Lastname = foo.LastName
WHEN NOT MATCHED THEN
  INSERT (UserGUID,
          Username,
          FirstName,
          LastName,
          AuthenticationMethod)
  VALUES (UserGUID,
          Username,
          FirstName,
          LastName,
          AuthenticationMethod); 

Протестировано на SQL Server 2012. (Добавил бы это как комментарий, но слишком много символов.)

Я добавил HOLDLOCK, увидев this, потому что, если вы используете MERGE для UPSERT, безусловно, точка блокируется, синтаксис, безусловно, нет яснее. См. Также комментарий Марселя о ROWLOCK для больших таблиц.

Было другое сообщение Я нашел более ясным, чем средний, тоже.