2009-02-13 30 views
11

Ich habe eine App, die Aufgaben enthält und Sie können sie neu anordnen. Jetzt war ich verwirrt, wie man sie am besten speichert. Sollte ich einen colomn für die Bestellnummer haben und jedes Mal neu berechnen, wenn ich einen ändere? Bitte sagen Sie mir eine Version, bei der ich nicht alle Bestellnummern aktualisieren muss, da dies sehr zeitaufwendig ist (aus Sicht der Ausführung).Wie speichere ich Bestellungen?

Dies ist besonders schlimm, wenn ich eine, die ganz oben in der Reihenfolge ist, und ziehen Sie es dann auf den Boden.

  • Name (Bestellnummer)

-

  • 1Example (1)
  • 2Example (2)
  • 3Example (3)
  • 4Example (4)
  • 5Beispiel (5)

-

  • 2Example (1) *
  • 3Example (2) *
  • 4Example (3) *
  • 5Example (4) *
  • 1Example (5) *

* müssen in der Datenbank

geändert werden

auch einige Aufgaben können aufgrund von ihnen

+0

In diesem Beispiel müssten Sie nicht alle Positionen aktualisieren. Wenn Sie die Aufzeichnung 1 auf Position 6 setzen, sind Sie gut. Ein besseres Beispiel könnte sein, den unteren Rekord an die Spitze zu ziehen. –

Antwort

0

ich eine Bestellung Spalte in der Datenbank, die würde empfehlen, getan erhalten gelöscht. Wenn ein Objekt neu angeordnet wird, tauschen Sie den Bestellwert in der Datenbank zwischen dem neu angeordneten Objekt und den Objekten mit dem gleichen Bestellwert aus. Auf diese Weise müssen Sie nicht den gesamten Satz von Zeilen neu sortieren.

hoffe, dass das Sinn macht ... natürlich hängt das von Ihren Regeln für die Nachbestellung ab.

9

Normalerweise werde ich ein int oder smallint Spalt mit dem Namen etwas wie ‚Ordinal‘ oder ‚PositionOrdinal‘ hinzufügen, wie Sie vorschlagen, und mit dem genauen Vorbehalt erwähnen Sie — die Notwendigkeit, eine potenziell bedeutende Anzahl von Aufzeichnungen eines einzelnen jedes Mal zu aktualisieren Datensatz wird neu geordnet.

Der Vorteil ist, dass ein Schlüssel für eine bestimmte Aufgabe gegeben und eine neue Position für diese Aufgabe, der Code ein Element ist nur zwei Aussagen zu bewegen:

UPDATE `Tasks` SET Ordinal= Ordinal+1 WHERE Ordinal>[email protected] 
UPDATE `Tasks` SET Ordinal= @NewPosition WHERE TaskID= @TaskID 

Es gibt noch andere Vorschläge für eine doppelt verknüpfte Liste oder lexikalische Reihenfolge. Beide können schneller sein, aber auf Kosten von viel komplizierterem Code, und die Leistung spielt nur dann eine Rolle, wenn Sie eine Menge von Artikeln in derselben Gruppe haben.

Ob Leistung oder Code-Komplexität wichtiger ist, hängt von Ihrer Situation ab. Wenn Sie Millionen von Datensätzen haben, könnte sich die zusätzliche Komplexität lohnen.Normalerweise bevorzuge ich jedoch den einfacheren Code, da Benutzer normalerweise nur kleine Listen per Hand bestellen. Wenn es nicht so viele Elemente in der Liste gibt, spielen die zusätzlichen Aktualisierungen keine Rolle. Dies kann in der Regel Tausende von Datensätzen ohne spürbare Auswirkungen auf die Leistung behandeln.

Die einzige Sache, die Sie bei Ihrem aktualisierten Beispiel beachten sollten, ist, dass die Spalte nur zum Sortieren verwendet wird und ansonsten nicht direkt dem Benutzer angezeigt wird. Wenn Sie also ein Objekt von oben nach unten ziehen, müssen Sie nur diesen einen Datensatz ändern. Es spielt keine Rolle, dass Sie die erste Position leer lassen. Dies bedeutet, dass es ein geringes Potenzial gibt, Ihre Integer-Sortierung mit ausreichender Nachbestellung zu überfließen, aber lassen Sie mich noch einmal sagen: Benutzer bestellen normalerweise nur kleine Listen von Hand. Ich habe noch nie von diesem Risiko gehört, das tatsächlich ein Problem verursacht hat.

1

Wir machen es mit einer Sequenz-Spalte in der Datenbank.

Wir verwenden eine spärliche Nummerierung (z. B. 10, 20, 30, ...), sodass wir eine zwischen vorhandenen Werten "einfügen" können. Wenn die benachbarten Zeilen fortlaufende Nummern haben, nummerieren wir die Mindestzahl der Zeilen neu.

Sie wahrscheinlich Dezimalzahlen verwenden könnte - den Durchschnitt der Sequenznummern für die Zeilen benachbart, wo Sie einfügen, dann nur Sie die Zeile zu sein „bewegt“

14

Sie können Aufträge als Literale halten aktualisieren müssen, und verwenden lexikalische Art:

1. A 
2. Z 

hinzufügen Aufgabe:

1. A 
3. L 
2. Z 

hinzufügen mehr:

1. A 
4. B 
3. L 
2. Z 

Move 2 zwischen 1 und 4:

1. A 
2. AL 
4. B 
3. L 

usw.

Sie aktualisieren nur einen Datensatz zu einem Zeitpunkt: einen durchschnittlichen Brief zwischen den ersten, nehmen Sie nur, die sich unterscheiden: wenn Sie zwischen setzen A und C nehmen Sie B, wenn Sie zwischen ALGJ und ALILFG setzen, nehmen Sie ALH.

Buchstabe neben vorhandenen Zählern als vorhanden verkettet mit dem neben Z. I. e. Wenn Sie zwischen ABHDFG und ACSD F setzen müssen, zählen Sie zwischen ABH und AB(Z+), und schreiben Sie AB(letter 35/2), also ABP.

Wenn Sie keine Zeichenfolgenlänge mehr haben, können Sie immer eine vollständige Nachbestellung durchführen.

Update:

Sie können Ihre Daten als eine verknüpfte Liste halten.

Siehe den Artikel in meinem Blog darüber, wie es in MySQL zu tun:

Auf den Punkt gebracht:

/* This just returns all records in no particular order */ 

SELECT * 
FROM t_list 

id  parent 
------- -------- 
1  0 
2  3 
3  4 
4  1 

/* This returns all records in intended order */ 

SELECT @r AS _current, 
     @r := (
     SELECT id 
     FROM t_list 
     WHERE parent = _current 
     ) 
FROM (
     SELECT @r := 0 
     ) vars, 
     t_list 

_current id 
------- -------- 
0  1 
1  4 
4  3 
3  2 

Wenn die Elemente bewegen, werden Sie müssen höchstens 4 Zeilen aktualisieren.

Dies scheint der effizienteste Weg zu sein, eine geordnete Liste zu behalten, die häufig aktualisiert wird.

+1

Ich bin noch nie auf einen eleganten Algorithmus gestoßen (glücklich, erleuchtet zu werden!), Also habe ich bisher eine Gleitkommazahl und einen "Durchschnitt" der beiden benachbarten Werte bevorzugt. – Kristen

+0

String = [Char] = [Integer] – Henrik

+1

Dies ist so clever. Ich wünschte, ich hätte das schon gesehen, bevor ich MY implementiert habe :-( –

2

Aus Ihren Antworten kam ich mit einer Mischung auf, die wie folgt lautet:

Sagen wir:

  • 1Example (1)
  • 2Example (2)
  • 3Example (3)
  • 4Example (4)
  • 5Example (5)

Nun, wenn ich etwas zwischen 4 und 5 sortieren es würde wie folgt aussehen:

  • 2Example (2)
  • 3Example (3)
  • 4Example (4)
  • 1Example (4.5)
  • 5Example (5)

jetzt wieder etwas zwischen 1 und 5

  • 3Example (3)
  • 4Example (4)
  • 1Example (4,5)
  • 2Example (4,75)
  • 5Example (5)

es wird immer nehmen Sie die Hälfte der unterschied zwischen den zahlen

ich hoffe das funktioniert bitte korrigiert mich;)

+0

Das sollte funktionieren, aber die Präzision eines Doppel ist endlich. (So ​​ist die Größe eines Int, also sage ich nicht, dass es schlecht ist: nur etwas zu beachten). –

+0

Dies bedeutet auch, dass Sie nach mindestens drei Elementen suchen: nach dem zu reorganisierenden Element und nach den Elementen 1 größer und 1 kleiner als die neue Position des Hauptelements, sodass Sie deren Werte für den neuen Durchschnitt verwenden können. Abhängig davon, wie Sie Dinge tun, kann dies genauso teuer oder noch mehr als nur ein einfaches Update sein. –

+0

Nicht sicher, ich stimme zu: "Einfache Aktualisierung" von, sagen wir, 10 Elemente erfordert einige Mittel, ihnen eine neue Nummer zuzuordnen (was bedeuten könnte, sie zunächst in eine temporäre Tabelle zu bringen und ihnen eine Nummer basierend auf einer Sortierreihenfolge zuzuordnen VERBINDEN Sie es, dass zu der ursprünglichen Tabelle, um es mit einer neuen Nummer zu aktualisieren) – Kristen

1

Dies ist kein einfaches Problem. Wenn Sie eine geringe Anzahl an sortierbaren Elementen haben, würde ich sie alle auf ihre neue Reihenfolge zurücksetzen.

Sonst scheint es genauso viel Arbeit oder mehr zu "test-and-set" zu erfordern, nur die Datensätze zu ändern, die sich geändert haben.

Sie könnten diese Arbeit an die Client-Seite delegieren. Lassen Sie den Client die Sortierreihenfolge "Alt-Sortierreihenfolge" und "Neu-Sortierreihenfolge" verwalten und bestimmen Sie, welche Zeile [Sortierreihenfolge] aktualisiert werden soll. Übergeben Sie dann diese Tupel an die PHP-mySQL-Schnittstelle.

Sie diese Methode in der folgenden Art und Weise verbessern konnte (nicht Schwimmer erforderlich):

  1. Wenn alle sortierbare Elemente in einer Liste in eine Art Ordnung entsprechend ihrer Position in der initialisiert Listen Sie die Sortierreihenfolge für jedes Element so ein, dass sie wie folgt aussieht: row [Sortierreihenfolge] = Zeile [Sortierreihenfolge * K] Dabei ist K eine Zahl> durchschnittliche Anzahl der erwarteten Neuordnung der Liste. O (N), N = Anzahl der Elemente, erhöht jedoch die Einfügungskapazität um mindestens N · K mit mindestens K offenen Schlitzen zwischen jedem austretenden Paar von Elementen.

  2. Dann, wenn Sie ein Element zwischen zwei anderen einfügen möchten, ist es so einfach wie Ändern der Sortierreihenfolge zu einer, die> das untere Element ist und < der obere. Wenn zwischen den Elementen kein "Raum" vorhanden ist, können Sie einfach den "Spread" -Algorithmus (1), der im vorherigen Abschnitt vorgestellt wurde, erneut anwenden. Je größer K ist, desto seltener wird es angewendet.

Der K-Algorithmus, der von dem Client durchgeführt werden würde in dem PHP-Skript würde, während die Wahl der neuen Art Ordnung der (Javascript, vielleicht) selektiv angewandt.

+0

Ziemlich nah an der realen Sache.Dies ist in der Tat eine komplexe Sache, richtig zu handhaben, vor allem wenn Sie einige geordnete Listen verwalten müssen, die geändert werden können mehrere Benutzer gleichzeitig. –