Mam wymaganie biznesowe, aby każdy rekord w tabeli faktur miał identyfikator, który wygląda jak YYYYNNNNNN.
Część NNNNNN musi zostać uruchomiona ponownie na początku każdego roku. Tak więc pierwszy wiersz wprowadzony w 2016 roku będzie wyglądał jak 2016000001, a drugi jak 2016000002 itd. Powiedzmy, że ostatni rekord dla 2016 roku to 2016123456, Następny wiersz (z 2017 roku) powinien wyglądać jak 2017000001
Nie potrzebuję tego identyfikatora jako klucza podstawowego i przechowuję również datę utworzenia. Chodzi o to, że ten „identyfikator wyświetlania” jest unikalny (więc mogę za jego pomocą zapytać) i może być grupowany przez ludzi z roku na rok.
Jest mało prawdopodobne, aby jakiekolwiek zapisy zostały usunięte; Byłbym jednak skłonny kodować obronnie przed czymś takim.
Czy jest jakiś sposób, żebym mógł utworzyć ten identyfikator bez pytania o maksymalny identyfikator w tym roku za każdym razem, gdy wstawiam nowy wiersz?
Pomysły:
- A
CreateNewInvoiceSP
, która otrzymujeMAX
wartość za ten rok (szczęście) - Jakaś magiczna wbudowana funkcja do robienia dokładnie tego (mogę marzyć, dobrze)
- Będąc w stanie określić UDF lub coś w deklaracji
IDENTITY
lubDEFAULT
(??) - Widok, który używa
PARTITION OVER + ROW()
(usunięty byłby problematyczny) - Wyzwalacz włączony
INSERT
(nadal musiałby uruchomić jakieśMAX
zapytanie :() - Coroczne zadanie w tle, aktualizowałem tabelę z dodanym MAX dla każdego roku, który następnie ... Coś ?!
Z których wszystkie są nieco nie idealne. Wszelkie pomysły i odmiany są mile widziane!
źródło
Odpowiedzi:
W twoim polu znajdują się 2 elementy
Nie muszą być przechowywane jako jedno pole
Przykład:
YEAR(GETDATE())
Następnie utwórz kolumnę obliczeniową łączącą je (z odpowiednim formatowaniem). Sekwencję można zresetować po zmianie roku.
Przykładowy kod w SQLfiddle : * (SQLfiddle nie zawsze działa)
źródło
SEQUENCE
na początku każdego roku?NEXT VALUE FOR
wCASE
oświadczeniu (próbowałem)Czy rozważałeś utworzenie pola tożsamości o ziarnie = 2016000000?
To ziarno powinno być automatycznie zwiększane co roku, na przykład w nocy 2017/1/1 należy zaplanować
Ale już widzę problemy z projektem, na przykład: co jeśli masz milion płyt?
źródło
To, co zrobiłem w tym scenariuszu, to pomnożyć rok przez 10 ^ 6 i dodać do tego wartość sekwencji. Ma to tę zaletę, że nie wymaga obliczonego pola z jego (małym) bieżącym narzutem, a pole może być używane jako
PRIMARY KEY
.Istnieją dwa możliwe problemy:
upewnij się, że twój mnożnik jest wystarczająco duży, aby nigdy się nie wyczerpać, i
nie ma zagwarantowanej sekwencji bez przerw z powodu buforowania sekwencji.
Nie jestem ekspertem od SQL Server, ale prawdopodobnie możesz ustawić zdarzenie wyzwalające o godzinie 201x 00:00:00, aby zresetować sekwencję do zera. Tak też zrobiłem na Firebird (czy to był Interbase?).
źródło
Edycja: To rozwiązanie nie działa pod obciążeniem
Nie jestem fanem wyzwalaczy, ale wydaje mi się, że najlepiej to wypracować.
Plusy:
Edycja: Wady:
(Podziękowania dla @gbn, ponieważ czerpałem inspirację z ich odpowiedzi) (Wszelkie opinie zwrotne i wskazanie oczywistych błędów są mile widziane :)
Dodaj kilka nowych
COLUMN
iINDEX
Dodaj nowy
TRIGGER
źródło
NULL
wartości. Powrót do deski kreślarskiej ...ON Previous.Id = (I.Id -1)
powinien po prostu szukać), ale tak, nadal nie działa. Gdybym mógł zablokować tabelę (?) Podczas wstawiania i wyzwalania, myślę, że to zadziałałoby. Ale to też brzmi jak zapach kodu.