Приоритетный список задач, хранящихся в базе данных


9

Я пытаюсь придумать лучший способ сделать следующее:

У меня есть список задач, хранящихся в базе данных. Задаче назначен приоритет. Вы можете изменить приоритет задачи, чтобы изменить порядок их выполнения.

Я думаю о чем-то очень похожем на Pivotal Tracker.

Итак, представьте, что у нас было следующее:

1 Task A
2 Task B
3 Task C
4 Task D
5 Task E

Мы решили, что E сейчас самая важная задача

1 Task E
2 Task A
3 Task B
4 Task C
5 Task D

Мне нужно обновить все 5 задач, чтобы дать им новый приоритет.

Если бы Задача B стала более важной, чем AI, я бы

1 Task E
2 Task B
3 Task A
4 Task C
5 Task D

Мне нужно обновить только задачи B и A.

Какими способами можно структурировать это в БД? Я предполагаю, что у вас будут разные проекты, хранящиеся в одной таблице, которые будут иметь собственный вес.

Было бы лучше указать задачу, которая происходит после нее (немного похоже на список ссылок).

Это просто мозговая свалка на самом деле. Просто было интересно, как вы будете реализовывать что-то подобное.

Ответы:


6
  1. Похоже, вы ищете приоритетную очередь. Вы, вероятно, не должны пересчитывать числа приоритетов для задач, вы просто должны вычислить фиксированное значение для них. Если вы хотите, чтобы задача Е была более важной, уменьшите ее значение.
  2. Вы по сути говорите об отношениях. B должен быть более важным, чем A. E должен быть самой важной задачей и т. Д. Это звучит как древовидная структура, и вы можете сохранить ее в RDBMS с родительскими ссылками.

5

Если вы используете двойные числа с плавающей запятой для указания приоритета, вам не нужно переупорядочивать:

1.00 Task A
2.00 Task B
3.00 Task C
4.00 Task D
5.00 Task E

Если вы хотите поместить задачу E между A и B, то:

  E.priority = A.priority + ((B.priority - A.priority) / 2)

Итак, теперь у вас есть:

1.00 Task A
1.50 Task E
2.00 Task B
3.00 Task C
4.00 Task D

Если вы хотите вставить D между E и B, просто установите приоритет 1.75. Учитывая приблизительно 18 десятичных цифр в числе с плавающей запятой (1.75 на самом деле 1.7500000000000000), вы должны иметь наихудший случай 53 последовательных вставок до:

 A.priority + ((B.priority - A.priority) / 2) = B.priority

И прежде чем кто-либо будет жаловаться на издержки использования двойных и целых чисел, это всего лишь несколько аппаратных инструкций по сравнению с накладными расходами на обработку и ввод / вывод для переупорядочения списка в базе данных, что будет на несколько порядков больше.


1
Мне нравится этот подход, но он должен быть следующим: E.priority = A.priority + ((B.priority - A.priority) / 2) и A.priority + ((B.priority - A.priority) / 2) = B.priority
Марсель Пансе

Спасибо за указание на это - ответ изменен соответствующим образом
Джеймс Андерсон

1

Мы сделали именно то, о чем вы говорите. Мы сделали это с помощью одной хранимой процедуры, которая переупорядочила список элементов. Каждый элемент в списке имел уникальный идентификатор и номер порядка сортировки.

Например:

TaskId int identity(1,1),
Task varchar(50),
SortOrder int

Хранимая процедура, которая переупорядочивает элементы, принимает два входных параметра:

@TaskId int,
@NewSortOrder int

Мы использовали временную таблицу для хранения элементов в новом порядке:

CREATE TABLE #Tasks
(
RowId int identity(1,1),
TaskId int
)

Мы использовали три оператора select, чтобы привести их в новый порядок:

-- Step 1
INSERT INTO #Tasks
SELECT TaskId FROM tblTasks
WHERE SortOrder < @NewSortOrder
ORDER BY SortOrder

--Step 2
INSERT INTO #Tasks
VALUES(@TaskId)

--Step 3
INSERT INTO #Tasks
SELECT TaskId FROM tblTasks
WHERE SortOrder >= @NewSortOrder
ORDER BY SortOrder

Затем мы обновили базовую таблицу (tblTasks) новым порядком сортировки, который фактически является столбцом идентификатора RowId временной таблицы:

-- Update Base Table
UPDATE tblTasks
SET SortOrder = t2.RowId
FROM tblTasks t1
INNER JOIN #Tasks t2
ON t1.TaskId = t2.TaskId

Это работает как чемпион каждый раз.


0

Я еще не обдумал это ... Но почему бы просто не разрешить десятичные дроби, чтобы вы могли вставлять вещи между другими без обновления всего?

Вы можете сжать что-то между 1 и 2 со значением 1,5.

Я также избегал бы минимальных и максимальных значений. Разрешить числам переходить в негативы, если их приоритет идет раньше того, что сейчас равно 0.

Вы можете подумать о том, чтобы иметь приоритет «человеческого отображения» отдельно от внутренних приоритетов «упорядочивания», чтобы избежать показа странных десятичных и отрицательных значений.


Не используйте десятичные дроби. Используйте строки, числовые или буквенные. Затем вы всегда можете вставить новое значение между двумя старыми, по крайней мере, пока не достигнете предела длины строки.
Кевин Клайн

0

Весьма разумно реализовать связанный список и его операции в СУБД. Просто замените манипуляции с массивами и ссылками на SQL-запросы. Однако я не уверен, что это действительно самый эффективный способ, так как некоторые простые операции потребуют много SQL-запросов.

Для таблицы задач вы добавляете столбцы «next_task» и «prev_task», которые являются внешними ключами, к столбцу id той же таблицы (при условии, что «-1» эквивалентно NULL)

Возврат задачи с наивысшим запросом () : SQL, который возвращает задачу с prev_task = -1

E является наиболее важной задачей : SQL-запрос, который заменяет следующую задачу E на идентификатор задачи с наивысшим приоритетом. И изменяет предыдущую задачу Е на -1 ...

Эта и другие операции, такие как размещение E перед A или печать упорядоченного списка задач, потребуют еще много SQL-запросов, которые должны быть полностью атомарными (если вы не можете оптимизировать). Это хорошее упражнение, но, возможно, не самый эффективный способ его выполнения.


0

Другой подход к проблеме приоритета состоит в том, чтобы указать, какой предмет важнее предмета. В HR-приложении это все равно, что сказать, кто менеджер сотрудника.

ID  Name           ParentPriority
1   TopPriority    NULL
2   Medium         1
3   Low            2
4   AnotherMedium  1
5   Less than 2    2

Затем прочитайте этот http://blog.sqlauthority.com/2012/04/24/sql-server-introduction-to-hierarchical-query-using-a-recursive-cte-a-primer/ чтобы сделать запрос, который дает приоритет уровни.

ID  Name           ParentPriority  PriorityLevel
1   TopPriority    NULL            1
2   Medium         1               2
3   Low            2               3
4   AnotherMedium  1               2
5   Less than 2    2               3

Я думаю, что это более простой пользовательский опыт в установлении приоритетов, но он допускает несколько приоритетов одного уровня.


-1

Одним простым способом было бы начать с чего-то вроде этого:

100 Task A
200 Task B
300 Task C
400 Task D
500 Task E

Затем, чтобы переместить «Задачу E» между Задачей A и Задачей B, скажем, вам просто нужно установить приоритет «Задачи E» на что-то среднее между Задачей A и Задачей B (то есть «150» в данном случае).

Конечно, если вы постоянно меняете приоритеты, вы в конечном итоге столкнетесь с проблемой, когда у двух смежных задач нет «пробела» для вставки новых записей. Но когда это происходит, вы можете просто «сбросить» все приоритеты за один раз, вернувшись к 100, 200, 300 и т. Д.


1
На самом деле это то же самое, что и мой ответ, только начиная с больших целых чисел вместо близко сгруппированных десятичных дробей. :)
Jojo

-1

Я не гуру базы данных, поэтому я решил это самым логичным способом, каким мог бы быть в Access 2010. У меня есть поле «Приоритет», которое является числовым полем. Тогда у меня есть событие для этого поля.

Это событие после обновления для поля «Приоритет», которое инициирует запрос на обновление «qryPriority» для добавления 1 к номеру приоритета всех других записей, у которых приоритет выше или равен только что введенному номеру приоритета.

Вот код VB события и SQL-запрос на обновление:

Событие VB Код «Приоритет»:

Private Sub Priority_AfterUpdate()
Me.Refresh
If Priority > 0 Then
DoCmd.OpenQuery ("qryPriority")
End If
Me.Refresh
Priority = Priority - 1
End Sub

«qryPriority» Обновление запроса SQL:

UPDATE YOURTABLENAME SET YOURTABLENAME.Priority = [Priority]+1
WHERE (((YOURTABLENAME.Priority)>=[Forms]![YOURFORMNAME]![Priority]));
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.