使用 SQL 服务器中另一个 table 的 ID 更新现有 table 的新外键列

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

我有一个现有的 table,我在其中添加了一个新列,该列应该在另一个(新)table.

中保存记录的 ID

简化后的结构是这样的:

客户table

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

许可 table <-- 新 table

[LicenceId] [GroupId]

许可证 table 每个组的许可证数量超过了可以分配给同一组客户的许可证数量。有多个组,每个组都有可变数量的客户和许可证。 假设第 1 组有 100 个可用许可证,第 1 组有 50 个客户,所以每个人都可以获得一个许可证。客户永远不会超过许可证。

样本

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

所以现在我必须进行一次更新才能为每个客户提供一个许可证,但我不知道该怎么做。

不允许我使用光标。我似乎无法进行 MERGE UPDATE,因为通过 GroupId 将客户加入许可证 table 会导致多次点击。

如何在一次查询中为每个客户分配其组内的下一个可用 LicenceId? 这可能吗?

您可以使用 window 函数:

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;

这会随机分配许可证。那真的只是为了好玩。最有效的方法是使用:

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

SQL 服务器通常会在这种情况下避免额外的排序操作。

但您可能希望通过其他方式对它们进行排序,例如通过客户 ID 的排序、日期列或其他方式。

戈登在他的回答中说得很好。 让我为您分解为更简单的步骤。

第 1 步。使用 ROW_NUMBER() 函数为客户分配一个 SeqNum。使用 PARTITION BY GroupId,以便每个组中的数字从 1 开始。我会按 CustomerId

订购

第 2 步。使用 ROW_NUMBER() 函数为许可证分配一个 SeqNum。使用 PARTITION BY GroupId,以便每个组中的数字从 1 开始。 ORDER BY LicenseId 因为您的要求是“为每个客户分配其组中的下一个可用 LicenceId”。

现在使用这 2 个查询更新客户 table 中的 LicenseId。