Ich habe eine Geschäftsanforderung, dass jeder Datensatz in der Rechnungstabelle eine ID hat, die wie JJJJNNNNNN aussieht.
Der NNNNNN-Teil muss zu Beginn eines jeden Jahres neu gestartet werden. Die erste Zeile, die 2016 eingegeben wurde, würde also wie 2016000001 und die zweite wie 2016000002 usw. aussehen. Nehmen wir an, der letzte Rekord für 2016 war 2016123456, die nächste Zeile (von 2017) sollte wie 2017000001 aussehen
Ich brauche diese ID nicht als Primärschlüssel und speichere auch das Erstellungsdatum. Die Idee ist, dass diese 'Anzeige-ID' nach Jahr eindeutig (damit ich sie abfragen kann) und gruppenfähig ist.
Es ist unwahrscheinlich, dass Datensätze gelöscht werden. Ich wäre jedoch geneigt, defensiv gegen so etwas zu programmieren.
Gibt es eine Möglichkeit, diese ID zu erstellen, ohne jedes Jahr bei jedem Einfügen einer neuen Zeile nach der maximalen ID fragen zu müssen?
Ideen:
- A
CreateNewInvoiceSP
, das denMAX
Wert für dieses Jahr erhält (yucky) - Einige magische integrierte Funktionen, um genau dies zu tun (ich kann richtig träumen)
- In der Lage sein, eine UDF oder etwas in der
IDENTITY
oderDEFAULT
Deklaration (??) anzugeben - Eine Ansicht, die verwendet
PARTITION OVER + ROW()
(gelöscht wäre problematisch) - Ein Trigger ein
INSERT
(müsste noch eineMAX
Abfrage ausführen :() - Ein jährlicher Hintergrundjob, aktualisiert eine Tabelle mit dem MAX für jedes eingefügte Jahr, die ich dann ... Etwas?!
All das ist ein bisschen nicht ideal. Irgendwelche Ideen oder Variationen sind jedoch willkommen!
quelle
Antworten:
Ihr Feld besteht aus 2 Elementen
Sie müssen nicht als ein Feld gespeichert werden
Beispiel:
YEAR(GETDATE())
Erstellen Sie dann eine berechnete Spalte, die sie verkettet (mit entsprechender Formatierung). Die Sequenz kann bei Jahreswechsel zurückgesetzt werden.
Beispielcode in SQLfiddle : * (SQLfiddle funktioniert nicht immer)
quelle
SEQUENCE
zu Beginn eines jeden Jahres neu zu starten ?NEXT VALUE FOR
in einerCASE
Aussage verwenden (ich habe es versucht)Haben Sie darüber nachgedacht, ein Identitätsfeld mit seed = 2016000000 zu erstellen?
Dieser Samen sollte jedes Jahr automatisch erhöht werden, zum Beispiel in der Nacht vom 1.1.2017, die Sie einplanen müssen
Aber ich sehe bereits Probleme mit dem Design, zum Beispiel: Was ist, wenn Sie Millionen Datensätze haben?
quelle
In diesem Szenario habe ich das Jahr mit 10 ^ 6 multipliziert und den Sequenzwert hinzugefügt. Dies hat den Vorteil, dass kein berechnetes Feld mit seinem (kleinen) laufenden Overhead erforderlich ist und das Feld als verwendet werden kann
PRIMARY KEY
.Es gibt zwei mögliche Fallstricke:
Stellen Sie sicher, dass Ihr Multiplikator groß genug ist, um niemals erschöpft zu sein
Durch das Zwischenspeichern der Sequenz wird Ihnen keine lückenlose Sequenz garantiert.
Ich bin kein Experte für SQL Server, aber Sie können wahrscheinlich ein Ereignis festlegen, das um 201x 00:00:00 ausgelöst wird, um Ihre Sequenz auf Null zurückzusetzen. Das habe ich auch auf Firebird gemacht (oder war es Interbase?).
quelle
Bearbeiten: Diese Lösung funktioniert nicht unter Last
Ich bin kein Fan von Triggern, aber das scheint das Beste zu sein, was ich herausfinden kann.
Vorteile:
Bearbeiten: Nachteile:
(Dank an @gbn, da ich mich von ihrer Antwort inspirieren ließ) (Feedback und Hinweis auf die offensichtlichen Fehler sind willkommen :)
Fügen Sie einige neue
COLUMN
s und einINDEX
Fügen Sie das neue hinzu
TRIGGER
quelle
NULL
Werten eingegeben werden. Zurück zum Zeichenbrett ...ON Previous.Id = (I.Id -1)
sollte nur suchen), aber ja, funktioniert immer noch nicht. Wenn ich die Tabelle (?) Während des Einfügens und Auslösens sperren könnte , würde es funktionieren. Aber das klingt auch nach einem Codegeruch.