Упорядочивание записей SQL по «весу»

#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