简体   繁体   中英

Update new foreign key column of existing table with ids from another table in SQL Server

I have an existing table to which I have added a new column which is supposed to hold the Id of a record in another (new) table.

Simplified structure is sort of like this:

Customer table

[CustomerId] [GroupId] [LicenceId]  <-- new column

Licence table <-- new table

[LicenceId] [GroupId]

The Licence table has a certain number of licences per group than can be assigned to customers in that same group. There are multiple groups, and each group has a variable number of customers and licences. So say there are 100 licences available for group 1 and there are 50 customers in group 1, so each can get a license. There are never more customers than there are licences.

Sample

Customer
[CustomerId] [GroupId] [LicenceId]
 1            1         NULL
 2            1         NULL
 3            1         NULL
 4            1         NULL
 5            2         NULL
 6            2         NULL
 7            2         NULL
 8            3         NULL
 9            3         NULL

Licence
[LicenceId] [GroupId]
 1            1
 2            1
 3            1
 4            1
 5            1
 6            1
 7            2
 8            2
 9            2
 10           2
 11           2
 12           3
 13           3
 14           3
 15           3
 16           3
 17           3

Desired outcome

Customer
[CustomerId] [GroupId] [LicenceId]
 1            1         1
 2            1         2
 3            1         3
 4            1         4
 5            2         7
 6            2         8
 7            2         9
 8            3         12
 9            3         13

So now I have to do this one time update to give every customer a licence and I have no idea how to go about it.

I'm not allowed to use a cursor. I can't seem to do a MERGE UPDATE, because joining the Customer to the Licence table by GroupId will result in multiple hits.

How do I assign each customer the next available LicenceId within their group in one query? Is this even possible?

You can use window functions:

with c as (
      select c.*, row_number() over (partition by groupid order by newid()) as seqnum
      from customers c
     ), 
     l as (
      select l.*, row_number() over (partition by groupid order by newid()) as seqnum
      from licenses c
     )
update c
    set c.licenceid = l.licenseid
    from c join
         l
         on c.seqnum = l.seqnum and c.groupid = l.groupid;

This assigns the licenses randomly . That is really just for fun. The most efficient method is to use:

row_number() over (partition by groupid order by (select null)) as seqnum

SQL Server often avoids an additional sort operation in this case.

But you might want to order them by something else -- for instance by the ordering of the customer ids, or by some date column, or something else.

Gordon has put it very well in his answer. Let me break it down into simpler steps for you.

Step 1. Use the ROW_NUMBER() function to assign a SeqNum to the Customers. Use PARTITION BY GroupId so that the number starts from 1 in every group. I would ORDER BY CustomerId

Step 2. Use the ROW_NUMBER() function to assign a SeqNum to the Licences. Use PARTITION BY GroupId so that the number starts from 1 in every group. ORDER BY LicenseId because your ask is to "assign each customer the next available LicenceId within their group".

Now use these 2 queries to update LicenseId in Customer table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM