【问题标题】:Azure SQL Server Alternative to FOR..EACH loopAzure SQL Server FOR..EACH 循环的替代方案
【发布时间】:2021-09-08 17:41:24
【问题描述】:

我有一个 Azure SQL 数据库,其中包含一个用户表“tbl_User”和一个包含“AllocatedUserName”列的案例表“tbl_Case”。此列为空(未分配)或包含 tbl_User 中用户的用户名。

我希望能够遍历 tbl_User 并为每条记录更新 tbl_Case 中的前三个 unallocated 记录,并使用该用户名。

通常在 VBA 中执行此操作我会使用 For..Each 循环和更新语句。但是,从我读到的内容来看,这几乎肯定是在 T-SQL 中执行此操作的错误方式?

所以例如我的 tbl_User 会有:

UserID Username UserRole
1 John Reviewer
2 Paul Reviewer
3 Mark Reviewer

如果我的 tbl_Case 在手术前看起来像这样:

CaseID AllocatedUsername AllocatedDate
1 Paul 01 Sep 2021
2
3
4
5
6
7
8
9
10
11

之后它看起来像这样:

CaseID AllocatedUsername AllocatedDate
1 Paul 01 Sep 2021
2 John 08 Sep 2021
3 John 08 Sep 2021
4 John 08 Sep 2021
5 Paul 08 Sep 2021
6 Paul 08 Sep 2021
7 Paul 08 Sep 2021
8 Mark 08 Sep 2021
9 Mark 08 Sep 2021
10 Mark 08 Sep 2021
11

非常感谢任何指针! 吉姆

【问题讨论】:

  • 请发布表定义和示例数据。您可能不想在这里使用循环(这将是 SQL 中的 CURSOR 或 WHILE 循环)。
  • SQL 是一种基于集合的语言。没有理由在任何 SQL 方言、任何数据库产品中使用 FOR 循环。您可以编写一个UPDATE ... FROM .. WHERE 语句来选择您想要的行并修改它们。很多情况下可以使用FROM (SELECT TOP 10 ...)
  • 我认为您的问题存在一些措辞问题。您提到了“前三个”未分配记录的概念。这意味着某种排序(前三个是哪三个?)。那么,你点什么?这就是我认为您想要做的事情:“对于所有当前未分配的案例,最多将其中三个分配给每个用户”。这就引出了另一个问题:你想平均分配它们吗?例如,假设恰好有 3 个未分配案例。是三个用户每人得到一个案例,还是一个用户得到所有三个案例?如果您有 100 个用户,哪些用户会收到案例?
  • @allmhuran 这个想法是它会将前 3 个未分配的案例(按 CaseID 排序)简单地分配给 User1,接下来的 3 个给 User2,依此类推。在到达用户列表的末尾之前是否用完未分配的案例并不重要。在程序之前分配给用户的案例数量也无关紧要。因此,如果 User1 之前有 8 个案例,而 User 2 有 0 个案例,那么他们之后会有 11 个和 3 个案例。
  • @squillman 我在表格前后张贴了一些 - 我希望这有助于解释它?

标签: sql tsql for-loop


【解决方案1】:

这是一个解决方案,它对用户和案例进行编号,然后以数学方式将它们匹配在一起。对于非常大量的数据,性能可能会很差,在这种情况下,您可能希望将 CTE 实现为临时表,并将数学表达式(row_number* 3 位)评估为 numberedUsers 中的列和numberedCases 表,并建立索引,而不是在最终查询中加入表达式。

create table users(userid int primary key);
create table cases(caseid int primary key, userid int, allocatedDate date);

-- sample data. 
-- This solution does not assume that userids or caseids must be monotonically increasing. 
-- Gaps in id's are ok (likely to be the case if id's are generated by identity columns)

insert users
values (23), (24), (30), (40), (41);

insert cases
values (1, null), (2, 24), (5, null), (8, 40), (9, null), (10, null);

with numberedUsers (rn, userid) as 
(
select   row_number() over (order by userid), 
         userid
from     users
),
numberedCases (rn, caseid, userid) as
(
   select row_number() over (order by caseid),
          caseid,
          userid,
          allocatedDate
   from   cases
   where  userid is null
)
update   c
set      c.userId = u.userId,
         c.allocatedDate = getdate()
from     numberedCases c
join     numberedUsers u on c.rn > (u.rn - 1) * 3 and c.rn <= u.rn * 3;

【讨论】:

    猜你喜欢
    • 2015-08-28
    • 1970-01-01
    • 1970-01-01
    • 2017-08-06
    • 2012-09-20
    • 1970-01-01
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多