Lista priorytetów zadań przechowywanych w bazie danych

9

Próbuję wymyślić najlepszy sposób na wykonanie następujących czynności:

Mam listę zadań zapisanych w bazie danych. Zadanie ma przypisany priorytet. Możesz zmienić priorytet zadania, aby zmienić kolejność wykonywania.

Mam na myśli coś bardzo podobnego do Pivotal Tracker.

Wyobraź sobie, że mieliśmy:

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

Uznajemy, że E jest teraz najważniejszym zadaniem

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

Muszę zaktualizować wszystkie 5 zadań, aby nadać im nowy priorytet.

Jeśli zadanie B stanie się wtedy ważniejsze niż AI, zrobiłbym to

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

Muszę zaktualizować tylko zadanie B i A.

Jakie byłyby sposoby ustrukturyzowania tego w bazie danych? Wyobrażam sobie, że w tej samej tabeli przechowywane byłyby różne projekty o takiej samej wadze.

Czy lepiej byłoby wskazać Zadanie, które ma miejsce po nim (trochę jak lista linków).

To naprawdę zrzut mózgu. Zastanawiałem się tylko, jak byś wdrożył coś takiego.

Pete
źródło

Odpowiedzi:

6
  1. Wygląda na to, że szukasz kolejki priorytetowej. Prawdopodobnie nie powinieneś ponownie obliczać liczb priorytetowych dla zadań, powinieneś po prostu obliczyć dla nich stałą wartość. Jeśli chcesz, aby zadanie E było ważniejsze, zmniejsz jego wartość.
  2. Mówisz w zasadzie o relacjach. B powinno być ważniejsze niż A. E powinno być najważniejszym zadaniem itp. Brzmi jak struktura drzewa i można przechowywać to w RDBMS z łączami nadrzędnymi.
Karoly Horvath
źródło
5

Jeśli użyjesz podwójnych liczb zmiennoprzecinkowych do wskazania priorytetu, nie musisz zmieniać kolejności:

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

Jeśli chcesz umieścić zadanie E między A i B, wówczas:

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

Więc teraz masz:

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

Jeśli chcesz wstawić D między E i B, po prostu ustaw jego priorytet na 1,75. Biorąc pod uwagę około 18 cyfr dziesiętnych w liczbie zmiennoprzecinkowej (1,75 to tak naprawdę 1,7500000000000000), powinieneś mieć najgorszy przypadek 53 kolejnych wstawek przed:

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

I zanim ktokolwiek narzeka na narzut związany z użyciem liczb podwójnych w porównaniu do liczb całkowitych, to tylko kilka instrukcji sprzętowych, w porównaniu z przetwarzaniem i narzutami we / wy ponownego uporządkowania listy w bazie danych, które byłyby o kilka rzędów wielkości większe.

James Anderson
źródło
1
Podoba mi się to podejście, ale powinno być: E.priority = A.priority + ((B.priority - A.priority) / 2) i A.priority + ((B.priority - A.priority) / 2) = B.priority
Marcel Panse
Dziękuję za wskazanie tej odpowiedzi - odpowiednio zmieniona odpowiedź
James Anderson
1

Zrobiliśmy to, o czym mówisz. Zrobiliśmy to za pomocą jednej procedury składowanej, która zmieniła kolejność listy elementów. Każda pozycja na liście miała unikalny identyfikator i numer porządkowy sortowania.

Na przykład:

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

Procedura składowana, która zmienia kolejność elementów, przyjmuje dwa parametry wejściowe:

@TaskId int,
@NewSortOrder int

Użyliśmy tabeli tymczasowej do przechowywania produktów w nowym zamówieniu:

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

Użyliśmy trzech instrukcji select, aby wprowadzić je do nowej kolejności:

-- 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

Następnie zaktualizowaliśmy tabelę podstawową (tblTasks) o nową kolejność sortowania, która w rzeczywistości jest kolumną tożsamości RowId tabeli tymczasowej:

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

To działa jak mistrz za każdym razem.

Michael Riley - AKA Gunny
źródło
0

Jeszcze się nad tym nie zastanawiałem ... Ale dlaczego po prostu nie zezwolić na ułamki dziesiętne, aby można było układać rzeczy między innymi bez aktualizacji wszystkiego?

Możesz wycisnąć coś między 1 a 2 o wartości 1,5.

Unikałbym również wartości minimalnych i maksymalnych. Zezwalaj liczbom na przestawianie się na negatywy, jeśli ich priorytet jest wcześniejszy niż to, co obecnie wynosi 0.

Możesz rozważyć oddzielenie priorytetu „wyświetlania od ludzi” od wewnętrznych priorytetów „porządkowania”, aby uniknąć wyświetlania dziwnych miejsc po przecinku i wartości ujemnych.

jojo
źródło
Nie używaj miejsc po przecinku. Używaj ciągów, numerycznych lub alfabetycznych. Następnie zawsze możesz wstawić nową wartość między dwoma starymi, przynajmniej do momentu osiągnięcia limitu długości łańcucha.
kevin cline
0

Bardzo rozsądne jest wdrożenie Listy połączonej i jej operacji w RDBMS. Wystarczy zastąpić manipulacje tablicami i referencjami zapytaniami SQL. Nie jestem jednak pewien, czy jest to naprawdę najbardziej wydajny sposób, ponieważ niektóre proste operacje wymagają wielu zapytań SQL

Do tabeli zadań dodajesz kolumny „next_task” i „prev_task”, które są kluczami obcymi, do kolumny identyfikatora tej samej tabeli (zakładając, że „-1” jest równoważne NULL)

Zwróć zadanie za pomocą najwyższego priorytetu () : zapytanie SQL, które zwraca zadanie o wartości prev_task = -1

E jest najważniejszym zadaniem : zapytanie SQL, które zmienia następną_zadanie E na identyfikator zadania o najwyższym priorytecie. I zmienia poprzednią czynność E na -1 ...

Ta i inne operacje, takie jak umieszczenie E przed A lub wydrukowanie uporządkowanej listy zadań, będą wymagały o wiele więcej zapytań SQL, które powinny być całkowicie atomowe (chyba że jesteś w stanie zoptymalizować). Jest to dobre ćwiczenie, ale może nie najskuteczniejsze.

HH
źródło
0

Innym podejściem do problemu pierwszeństwa byłoby określenie, który przedmiot jest ważniejszy niż przedmiot. W aplikacji HR byłoby to jak powiedzenie, kto jest kierownikiem pracownika.

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

Następnie przeczytaj ten http://blog.sqlauthority.com/2012/04/24/sql-server-introduction-to-hierarchical-query-using-a-recursive-cte-a-primer/, aby utworzyć zapytanie, które daje pierwszeństwo poziomy.

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

Myślę, że jest to prostsze doświadczenie użytkownika w ustalaniu priorytetów, ale pozwala na wiele priorytetów na tym samym poziomie.

Steven Brown
źródło
-1

Jednym prostym sposobem byłoby zacząć od czegoś takiego:

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

Następnie, aby przenieść „Zadanie E” między Zadaniem A i Zadaniem B, powiedzmy, że po prostu ustawiłeś „Zadanie E” na coś w połowie drogi między Zadaniem A i Zadaniem B (tj. „150” w tym przypadku).

Oczywiście, jeśli ciągle zmieniasz priorytety, w końcu napotkasz problem polegający na tym, że dwa sąsiednie zadania nie mają „przerwy” na wstawianie nowych wpisów. Ale kiedy to się stanie, możesz po prostu „zresetować” wszystkie priorytety za jednym razem, powrócić do 100, 200, 300 itd.

Dean Harding
źródło
1
To jest właściwie to samo, co moja odpowiedź, zaczynając od większych liczb całkowitych zamiast ściśle zgrupowanych miejsc po przecinku. :)
jojo
-1

Nie jestem guru bazy danych, więc rozwiązałem ten najbardziej logiczny sposób w programie Access 2010. Mam pole „Priorytet”, które jest polem numerycznym. Potem mam wydarzenie dla tego pola.

Zdarzenie jest zdarzeniem po aktualizacji dla pola „Priorytet”, które wyzwala Zapytanie o aktualizację „qryPriority” w celu dodania 1 do numeru priorytetu wszystkich innych rekordów, które mają priorytet większy lub równy właśnie wprowadzonemu numerowi priorytetu.

Oto kod zdarzenia VB i aktualizacja zapytania SQL:

Kod VB zdarzenia „Priorytet”:

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

Aktualizacja zapytania „qryPriority” SQL:

UPDATE YOURTABLENAME SET YOURTABLENAME.Priority = [Priority]+1
WHERE (((YOURTABLENAME.Priority)>=[Forms]![YOURFORMNAME]![Priority]));
Keegan
źródło