#sql #tsql #sql-server-2008
#sql #tsql #sql-server-2008
Вопрос:
У нас есть система, которая обрабатывает записи по номеру «приоритета» в таблице. Мы определяем приоритет по содержимому таблицы, например
UPDATE table
SET priority=3
WHERE processed IS NULL
UPDATE table
SET priority=2
WHERE balance>50
UPDATE table
SET priority=1
WHERE value='blah'
(пожалуйста, игнорируйте тот факт, что между приоритетами могут быть «совпадения» :))
Это работает нормально — таблица обрабатывается в порядке приоритета, поэтому сначала обрабатываются все строки, в которых столбец «значение» равен «бла».
Мне было поручено добавить опцию упорядочивания записей по определяемому «весу». Например, мы хотели бы, чтобы 50% обработки имели приоритет 1, 25%-й приоритет 2 и 25%-й приоритет 3. Следовательно, из приведенных выше, в каждых 100 записях 50 из них будут теми, где «значение» равно «бла», 25 из них будут там, где «баланс» больше 50 и т.д.
Я пытаюсь понять, как это сделать: какое-то взвешенное увеличивающееся значение для «приоритета», по-видимому, было бы лучшим способом, но я не могу понять, как это закодировать. Кто-нибудь может помочь, пожалуйста?
РЕДАКТИРОВАТЬ: Извинения, следовало бы сказать: это работает на MSSQL 2008
Комментарии:
1. Какую версию SQL вы используете?
2. Я не уверен, что понимаю. Вам нужно извлекать записи в порядке, который вы описываете, или обновлять их в таблице?
3. Как вы определяете, что приоритет 2 (баланс> 50) может быть изменен на 1?
4. У меня все еще возникают проблемы с определением крайних случаев. Что, если в вашей таблице будет только 4 записи с приоритетом 3? Какой из них должен быть равен 2, а какой — 1?
5. меняется ли количество записей регулярно (т. Е. Во время выполнения обработки)? Что выполняет обработку — хранимый процесс или какой-то внешний процесс?
Ответ №1:
Общая идея состоит в том, чтобы собирать задачи в сегменты, разделенные по границе целых чисел:
select
task_id
from (
select
task_id,
((task_priority_order - 1) / task_priority_density) as task_processing_order
from (
select
t.task_id as task_id,
t.priority as task_priority,
row_number()
over (partition by t.priority order by t.priority) as task_priority_order,
case
when t.priority = 3 then 50
when t.priority = 2 then 25
when t.priority = 1 then 25
end as task_priority_density
from
table t
)
)
order by task_processing_order
В диапазоне от 0.0 до 0. (9) мы получили 100 записей, построенных из первых 50 записей с приоритетом 3, первых 25 записей с приоритетом 2 и первых 25 записей с приоритетом 1.
Следующий диапазон от 1.0 до 1.(9) представляет следующую корзину записей.
Если больше нет задач с некоторым значением приоритета, то оставшиеся задачи будут размещены в корзинах в том же соотношении. Например. если недостаточно задач с приоритетом 3, то оставшиеся задачи будут расположены в соотношении 50/50.
task_id — некоторый суррогатный ключ для идентификации задачи.
PS Извините, я не могу протестировать этот запрос сейчас, поэтому любая коррекция синтаксиса очень ценится.
Обновление: синтаксис запроса исправлен в соответствии с комментариями.
Комментарии:
1. Я изменил
priority_density
task_priority_density
вCASE
инструкции, и я изменил row_number наrow_number() over ( partition by t.priority ORDER BY t.priority) -1 as task_priority_order
— не уверен, правильно ли это, но он жаловался, если я этого не сделал. Теперь, похоже, он прекрасно работает с тестовой таблицей; Мне нужно будет изменить его для работы с производственной системой, но это дает мне 90% пути. Большое вам спасибо !
Ответ №2:
Данный тестовый скрипт предоставляет следующий результат. Если вы изложите некоторые правила о том, каким должен быть конечный результат, я готов еще раз взглянуть на это.
Результаты
Priority Processed Balance Value
3 NULL NULL NULL
NULL 0 49 NULL
NULL 1 49 NULL
NULL 0 50 NULL
NULL 1 50 NULL
2 0 51 NULL
2 1 51 NULL
2 0 51 Notblah
1 1 51 blah
Тестовый скрипт
DECLARE @Table TABLE (Priority INTEGER, Processed BIT, Balance INTEGER, Value VARCHAR(32))
INSERT INTO @Table VALUES
(NULL, NULL, NULL, NULL)
, (NULL, 0, 49, NULL)
, (NULL, 1, 49, NULL)
, (NULL, 0, 50, NULL)
, (NULL, 1, 50, NULL)
, (NULL, 0, 51, NULL)
, (NULL, 1, 51, NULL)
, (NULL, 0, 51, 'Notblah')
, (NULL, 1, 51, 'blah')
UPDATE @table SET priority=3 WHERE processed IS NULL
UPDATE @table SET priority=2 WHERE balance > 50
UPDATE @table SET priority=1 WHERE value = 'blah'
SELECT *
FROM @table