Wie kann eine automatische Erhöhung Revisionsnummer eindeutig einen Schlüssel in PGSQL erstellen?

StackOverflow https://stackoverflow.com/questions/912057

Frage

Unter der Annahme, ich habe die folgenden Tabellen.

PARENT: PARENT_ID serial, DESCRIPTION character varying(50)

CHILD: PARENT_ID integer, CHILD_ID integer, DESCRIPTION character varying(50)

Was würde Ich mag, um zu sehen ist jede Zeile in CHILD einen CHILD_ID, die durch 1, einzigartig pro PARENT_ID bei 1 und Schritten beginnt. Es würde zu einer Revisionsnummer ähnlich sein. Zum Beispiel ..

PARENT_ID 1, CHILD_ID 1
PARENT_ID 1, CHILD_ID 2
PARENT_ID 1, CHILD_ID 3
PARENT_ID 2, CHILD_ID 1
PARENT_ID 3, CHILD_ID 1
PARENT_ID 3, CHILD_ID 2

Gibt es eine Möglichkeit, den CHILD_ID Wert automatisch zugewiesen hat, wie zum Beispiel einer Sequenz oder Zwang, nur mit der Fähigkeit, ein CHILD_ID wieder zu verwenden, die gelöscht wurde? Die einzige Art, wie ich herausfinden kann, ist etwas zu den Auswirkungen dieser SQL.

INSERT INTO child SELECT parent_id, MAX(child_id)+1, 'description' FROM child WHERE parent_id = :PARENT_ID GROUP BY parent_id

Das ist ein bisschen wie ein Hack though. Ich stelle fest, dass Datenbanknormalisierung schlägt vor, Sie nicht einen Schlüssel zu einem anderen Zusammenhang haben sollte, aber ich habe diese Möglichkeit nicht aus anderen Gründen. Irgendwelche Ideen?

EDIT: Der Titel ist hässlich. Wenn einer von euch High-Scoring Leute von einem denken kann, die genauer sind, können Sie sich frei, es zu ändern.

War es hilfreich?

Lösung

Ich würde vorschlagen, mit:

CHILD: PARENT_ID integer, CHILD_ID serial, DESCRIPTION character varying(50)

Wenn Sie ein gewünschtes Ergebnis zu erhalten:

  • Sie Reihen auf Client-Seite zählen können.

  • Wenn Zeilen der Auswahl, wo PARENT_ID =? Sie können temporäre Sequenz verwendet werden.

  • In Kürze Postgresql 8.4 freigegeben werden Sie Windowing-Funktionen wie folgt verwenden können:

    $ create table child (parent_id integer, child_id serial);
    NOTICE:  CREATE TABLE will create implicit sequence "child_child_id_seq" for serial column "child.child_id"
    CREATE TABLE
    
    $ insert into child (parent_id) values (1), (1), (1), (2), (3), (3);
    
    $ select * from child;
     parent_id | child_id 
    -----------+----------
             1 |        1
             1 |        2
             1 |        3
             2 |        4
             3 |        5
             3 |        6
    (6 rows)
    
    $ select parent_id, row_number() over (partition by parent_id order by child_id) from child;
     parent_id | row_number 
    -----------+------
             1 |          1
             1 |          2
             1 |          3
             2 |          1
             3 |          1
             3 |          2
    (6 rows)
    

Es ist sehr schnell, einfach zu implementieren und wird sehr gut skalieren, wie es keine Parallelitätsprobleme sein kümmern.

Andere Tipps

Das Insert ist nicht die ganze Geschichte aber. Sie müssen auch Löschungen handhaben, die Lücke zu schließen, die erstellt wurde, wenn Sie wirklich die Zahlen wollen zusammenhängend sein.

Mein Vorschlag wäre, diesen Wert abzuleiten, wie Sie es brauchen. Was bestimmt die Reihenfolge der Zahl? Wenn es das Datum in das System eingegeben ist dann dieses Datum auf den Tisch hinzufügen und Ihre PK über die parent_id zu setzen und zu diesem Zeitpunkt, dann kann man ziemlich leicht kommen mit der Nummer entweder über SQL oder im Frontend wie Sie sie brauchen.

Sie könnten eine Inkrementierung Versionsnummer auf der übergeordneten Tabelle verwenden und das Kind ID auf diesen Wert gesetzt und es erhöhen. Sie werden wahrscheinlich die übergeordnete Zeile aktualisieren müssen und das Kind Zeile in einer einzigen Transaktion einfügen.

BEGIN
-- Get and hold onto parent_id and version values.
SELECT PARENT_ID, VERSION FROM PARENT WHERE PARENT_ID = :PARENT_ID;
-- Use the values to insert into the child table
INSERT INTO CHILD (PARENT_ID, CHILD_ID) VALUES (:PARENT_ID, :VERSION);
-- Update the version using an optimistic lock.
UPDATE PARENT SET VERSION = VERSION + 1 WHERE PARENT_ID = :PARENT_ID AND 
                                              VERSION = :VERSION_ID
-- If no rows are updated rollback the transaction and try again.
END

Dies wird das Kind ids gewährleisten streng aufsteigend sind, wird aber nicht id Werte nach dem Löschen wieder verwenden. Wenn Sie die Einschränkung der Wiederverwendung von altem ids vermeiden können, wird es Ihre Lösung vereinfachen (und die Lösung wird effizienter). Wenn Sie müssen Wiederverwendung ids dann haben Sie zwei Möglichkeiten, zum einen die Lösung, die Sie oben angegeben, aber beim Löschen alle Werte Umnummerierung, die nach dem von Ihnen gelöscht auftreten. Die andere Option ist eine Art von Funktion zu haben, dass das Kind-IDs, um durchsucht und vergleicht sie mit einer Reihe von aufeinanderfolgenden Zahlen und gibt den Wert, wenn die ersten nicht gefunden wird. Beide Lösungen sind komplexer und wird langsam sein, wie Sie benötigen, um eine Zeilen-Sperre herausnehmen zu verhindern gleichzeitige Aktualisierungen und entweder Einfügungen oder beide Einfügungen und Löschungen wird ein O entstehen (n) Strafe.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top