11

I am using the MERGE statement within a database project to populate reference data from a static value set, such as the following below:

    MERGE INTO dbo.[User] AS TARGET
USING (VALUES
    ('me@somewhere.com', '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);

The problem comes in when I want to populate the secondary table based of content in other tables. For example, my UserPermission table contains user ID and role ID and I'd like my static value set to be something like ('me@somewhere.com', 'Admin') and be able to join to User and Permission to get the ID values for INSERTing. Not sure where do to that...

Edit:

User Table(ID, Username) 1, John Smith 2, Mark Wahlerg

Role Table(ID, RoleName) 1, Administrator 2, User 3, Guest

User-Role Table (User ID, Role ID)

I want the SQL for the MERGE statement to adjust the User-Role table such that I can do specify something like:

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

and it will join to determine the IDs, insert the combinations that dont exists (and maybe delete the ones that do, but aren't in the MERGE.

Solution:

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)
Scotty.NET
  • 12,533
  • 4
  • 42
  • 51
Rich
  • 2,076
  • 1
  • 15
  • 16
  • Just curious, why are you using MERGE here instead of a much simpler `INSERT ... SELECT`? I'm not saying you can't do this with `MERGE` but it seems overkill for such a trivial operation. – Aaron Bertrand May 09 '12 at 19:34
  • @AaronBertrand, this is a simplistic example, normally I have multiple rows and use the UPDATE and DELETE capabiltities of MERGE. I was trying to isolate the problem. – Rich May 09 '12 at 19:39
  • The problem is in your `USING` clause. You just have hard-coded values there; you need it to actually be using a `SELECT` if you need to draw those values from a table. Also there are some pretty smart people who can help solve your problems, but they're much more interested in solving your actual problem - dumbing it down just leads to unnecessary questions like the one I asked. – Aaron Bertrand May 09 '12 at 19:41
  • Those values are meant to be hard coded, but the problem is I don't want to insert those specific values, but instead IDs from other tables based upon the hard coded values. The example is one that works now. The problem is taking the next step, which is the problem described afterwards. – Rich May 09 '12 at 19:45
  • You need to better specify which are the hard coded values you want to use, and which are the hard coded values you don't want to use. Can you show some actual sample data before and after and how you want the merge to actually affect the data? Are you trying to do this for all values in the usernames table, or specific ones? If specific, how are you specifying? Details, details, details. – Aaron Bertrand May 09 '12 at 19:47
  • Can a user belong to more than one role? – Aaron Bertrand May 09 '12 at 20:05
  • I can't see a reason for not changing the insert by removing the 'values (...)' line to a 'select' which includes your static fields and also joins to other tables to look up the relevant id's. – Chris Moutray May 09 '12 at 19:44
  • The ID fields must be known before the INSERT, for the ON clause to match up the MERGE source and target to determine whether the MERGE is supposed to update, insert, or delete. – Rich May 09 '12 at 19:46

1 Answers1

10

Merge supports CTEs so perhaps you can use this as your source, combining your static data and performing any joins within the cte.

Chris Moutray
  • 18,029
  • 7
  • 45
  • 66
  • 1
    That was the trick. My experience with CTEs and table value constructors was a little weak, hence my not knowing where they can be used (and used together). – Rich May 09 '12 at 20:15