Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Unikalny złożony klucz składający się z dwóch pól w programie SQL Server z automatycznym przyrostem drugiego pola

Odkąd ktoś zadał podobne pytanie, zastanawiałem się nad tym. Pierwszym problemem jest to, że DB nie dostarczają „partycjonowanych” sekwencji (które mogłyby się zrestartować/zapamiętać w oparciu o różne klucze). Po drugie, SEQUENCE obiekty, które są nastawione na szybki dostęp i nie można ich cofnąć (tzn. będziesz uzyskać luki). To zasadniczo wyklucza korzystanie z wbudowanego narzędzia... co oznacza, że ​​musimy rozwijać własne.

Pierwszą rzeczą, której będziemy potrzebować, jest tabela do przechowywania naszych numerów sekwencyjnych. To może być dość proste:

CREATE TABLE Invoice_Sequence (base CHAR(1) PRIMARY KEY CLUSTERED,
                               invoiceNumber INTEGER);

W rzeczywistości base kolumna powinna być odniesieniem do klucza obcego do dowolnej tabeli/identyfikatora definiującej firmę/podmioty, dla których wystawiasz faktury. W tej tabeli chcesz, aby wpisy były unikalne dla wystawionej jednostki.

Następnie potrzebujesz zapisanego proc, które zajmie klucz (base ) i wypluj następną liczbę w sekwencji (invoiceNumber ). Zestaw niezbędnych kluczy będzie się różnić (tj. niektóre numery faktur muszą zawierać rok lub pełną datę wystawienia), ale podstawowy formularz dla tej sytuacji jest następujący:

CREATE PROCEDURE Next_Invoice_Number @baseKey CHAR(1), 
                                     @invoiceNumber INTEGER OUTPUT 
AS MERGE INTO Invoice_Sequence Stored
              USING (VALUES (@baseKey)) Incoming(base)
                 ON Incoming.base = Stored.base
   WHEN MATCHED THEN UPDATE SET Stored.invoiceNumber = Stored.invoiceNumber + 1
   WHEN NOT MATCHED BY TARGET THEN INSERT (base) VALUES(@baseKey)
   OUTPUT INSERTED.invoiceNumber ;;

Pamiętaj, że:

  1. Trze musisz uruchom to w serializowanej transakcji
  2. Transakcja musi być tym samym, który jest wstawiany do tabeli docelowej (faktury).

Zgadza się, nadal będziesz blokować poszczególne firmy podczas wystawiania numerów faktur. Nie możesz unikaj tego, jeśli numery faktur muszą być sekwencyjne, bez przerw - dopóki wiersz nie zostanie faktycznie zatwierdzony, może zostać wycofany, co oznacza, że ​​numer faktury nie zostałby wystawiony.

Teraz, ponieważ nie chcesz pamiętać o wywołaniu procedury dla wpisu, zapakuj go w wyzwalacz:

CREATE TRIGGER Populate_Invoice_Number ON Invoice INSTEAD OF INSERT
AS 
  DECLARE @invoiceNumber INTEGER
  BEGIN
    EXEC Next_Invoice_Number Inserted.base, @invoiceNumber OUTPUT
    INSERT INTO Invoice (base, invoiceNumber) 
                VALUES (Inserted.base, @invoiceNumber)
  END

(oczywiście masz więcej kolumn, w tym inne, które powinny być wypełniane automatycznie - musisz je wypełnić)
...których możesz użyć, mówiąc po prostu:

INSERT INTO Invoice (base) VALUES('A');

Więc co zrobiliśmy? Cała ta praca polegała głównie na zmniejszeniu liczby wierszy zablokowanych przez transakcję. Do tego INSERT jest zatwierdzone, zablokowane są tylko dwa wiersze:

  • Wiersz w Invoice_Sequence utrzymywanie numeru sekwencyjnego
  • Wiersz w Invoice dla nowej faktury.

Wszystkie inne wiersze dla określonej base są bezpłatne - można je dowolnie aktualizować lub odpytywać (usuwanie informacji z tego rodzaju systemu często denerwuje księgowych). Prawdopodobnie musisz zdecydować, co powinno się stać, gdy zapytania zwykle zawierają oczekującą fakturę...



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. nvarchar konkatenacja / index / nvarchar(max) niewytłumaczalne zachowanie

  2. Konwertuj „datetime” na „datetime2” w SQL Server (przykłady T-SQL)

  3. Przecinki w danych CSV

  4. Jak @@MAX_CONNECTIONS działa w SQL Server

  5. WYBIERZ WYRÓŻNIENIE w jednej kolumnie