#sql #sql-server #sql-server-2019
#sql #sql-сервер #sql-server-2019
Вопрос:
В SQL Server 2019 у меня есть таблица неназначенных задач и другая таблица рабочих, которые доступны для работы над этими задачами. Мое требование состоит в том, чтобы распределить работников равномерно по доступным задачам, обновив WorkerID
столбец в Tasks
таблице с ID
помощью работника, который будет выполнять задачу.
- Как количество рабочих, так и количество задач могут отличаться при каждом запуске SQL.
- В любой таблице может быть больше записей, чем в другой.
- Назначение задач начинается с первого рабочего в таблице Workers и заканчивается, когда все задачи назначены. (В целях справедливости рандомизация рабочих не выполняется от запуска к запуску.)
- В любой таблице может быть ноль записей.
Учитывая таблицы со следующими структурами, я хотел бы знать, как выполнять эти назначения без использования цикла. Я подозреваю, что это можно сделать с помощью номеров строк, ранга или какой-либо другой подобной магии SQL Server, но я не смог в этом разобраться. Спасибо!
Таблица задач:
JobID JobName WorkerID
------------------------------------
23 Carry Groceries NULL
1234 Drive NULL
6543 Dig NULL
234567 Walk NULL
78 Clean Room NULL
54 Cook Dinner NULL
2 Move Logs NULL
34 Cut Grass NULL
99 Milk Chickens NULL
Таблица рабочих:
WorkerID WorkerName
---------------------
67 Larry
42 Sue
10 Peter
45 Steve
Ожидаемые результаты для Tasks
таблицы:
JobID JobName WorkerID
--------------------------------------
23 Carry Groceries 67
1234 Drive 42
6543 Dig 10
234567 Walk 45
78 Clean Room 67
54 Cook Dinner 42
2 Move Logs 10
34 Cut Grass 45
99 Milk Chickens 67
Ответ №1:
Вы можете назначить номер с помощью оконных функций, а затем join
. Метод «циклического перебора»:
with toupdate as (
select t.*, row_number() over (order by (select null)) as seqnum
from tasks t
)
update toupdate
from toupdate join
(select w.*,
row_number() over (order by (select null)) as seqnum,
count(*) over () as cnt
from workers w
) w
on w.seqnum = ( (toupdate.seqnum - 1) % w.cnt) 1;
Комментарии:
1. Спасибо, Гордон Линофф! Это отлично работает, хотя я обнаружил, что первым назначенным работником был второй работник, выбранный из рабочих. Поскольку они все равно просто выполняют цикл, это все равно соответствует спецификации, но для понимания будущего сопровождающего я вычел 1 из toupdate.seqnum перед тем, как применить его к модулю, и, похоже, он скорректировал его так, чтобы первый назначенный рабочий был первым выбранным рабочим: на w.seqnum= ((toupdate.seqnum — 1) % w.cnt) 1;
2. @user1876354 . . . Это кажется разумным, и ваше предложение — прекрасный способ его решения.