Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Eindeutige Auto-Increment-Spalte von SQL Server im Kontext einer anderen Spalte

Nun, es gibt keine native Unterstützung für diesen Spaltentyp, aber Sie könnten ihn mit einem Trigger implementieren:

CREATE TRIGGER tr_MyTable_Number
ON MyTable
INSTEAD OF INSERT
AS

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN;

WITH MaxNumbers_CTE AS
(
    SELECT ParentEntityID, MAX(Number) AS Number
    FROM MyTable
    WHERE ParentEntityID IN (SELECT ParentEntityID FROM inserted)
)
INSERT MyTable (ParentEntityID, Number)
    SELECT
        i.ParentEntityID,
        ROW_NUMBER() OVER
        (
            PARTITION BY i.ParentEntityID
            ORDER BY (SELECT 1)
        ) + ISNULL(m.Number, 0) AS Number
    FROM inserted i
    LEFT JOIN MaxNumbers_CTE m
        ON m.ParentEntityID = i.ParentEntityID

COMMIT

Nicht getestet, aber ich bin mir ziemlich sicher, dass es funktionieren wird. Wenn Sie einen Primärschlüssel haben, können Sie diesen auch als AFTER implementieren trigger (ich mag es nicht, INSTEAD OF zu verwenden Trigger, sie sind schwerer zu verstehen, wenn Sie sie 6 Monate später ändern müssen).

Nur um zu erklären, was hier vor sich geht:

  • SERIALIZABLE ist der strengste Isolationsmodus; es garantiert, dass jeweils nur eine Datenbanktransaktion diese Anweisungen ausführen kann, die wir benötigen, um die Integrität dieser "Sequenz" zu gewährleisten. Beachten Sie, dass dies die gesamte Transaktion irreversibel fördert, sodass Sie dies nicht innerhalb einer Transaktion mit langer Laufzeit verwenden möchten.

  • Der CTE nimmt die höchste bereits verwendete Nummer für jede Eltern-ID auf;

  • ROW_NUMBER generiert eine eindeutige Sequenz für jede Eltern-ID (PARTITION BY ) beginnend mit der Nummer 1; Wir addieren dies zum vorherigen Maximum, falls es eines gibt, um die neue Sequenz zu erhalten.

Ich sollte wahrscheinlich auch erwähnen, dass Sie, wenn Sie immer nur eine neue untergeordnete Entität auf einmal einfügen müssen, diese Operationen besser durch eine gespeicherte Prozedur leiten, anstatt einen Trigger zu verwenden - Sie werden definitiv eine bessere Leistung erzielen . So wird es derzeit mit hierarchyid gemacht Spalten in SQL '08.