sql >> Databáze >  >> RDS >> Sqlserver

SQL Server Jedinečný složený klíč dvou polí s automatickým přírůstkem druhého pole

Od té doby, co někdo napsal podobnou otázku, přemýšlím o tom. První problém je, že DB neposkytují „rozdělitelné“ sekvence (které by se restartovaly/zapamatovaly na základě různých klíčů). Druhým je, že SEQUENCE objekty, které jsou poskytované jsou zaměřeny na rychlý přístup a nelze je vrátit zpět (tj. budete získat mezery). To v podstatě vylučuje použití vestavěného nástroje... což znamená, že musíme spustit vlastní.

První věc, kterou budeme potřebovat, je tabulka pro uložení našich sekvenčních čísel. To může být docela jednoduché:

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

Ve skutečnosti base Sloupec by měl být odkazem na cizí klíč na jakoukoli tabulku/id definující firmu (podniky)/subjekty, pro které vystavujete faktury. V této tabulce chcete, aby byly položky jedinečné pro vydanou entitu.

Dále chcete uložený proces, který bude mít klíč (base ) a vyplivněte další číslo v pořadí (invoiceNumber ). Potřebná sada klíčů se bude lišit (tj. některá čísla faktur musí obsahovat rok nebo celé datum vystavení), ale základní formulář pro tuto situaci je následující:

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 ;;

Všimněte si, že:

  1. Musíte spustit to v serializované transakci
  2. Transakce musí být stejný jako ten, který se vkládá do cílové tabulky (faktury).

Správně, při vystavování čísel faktur budete stále dostávat blokování pro jednotlivé firmy. Nemůžete vyvarujte se tomu, pokud čísla faktur musí být sekvenční, bez mezer – dokud nebude řádek skutečně potvrzen, může být vrácen zpět, což znamená, že číslo faktury by nebylo vystaveno.

Nyní, protože si nechcete pamatovat volání procedury pro záznam, zabalte to do spouštěče:

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

(samozřejmě máte více sloupců, včetně dalších, které by měly být vyplněny automaticky – budete je muset vyplnit)
...které pak můžete použít jednoduše:

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

Tak co jsme udělali? Většinou byla veškerá tato práce o zmenšení počtu řádků uzamčených transakcí. Do tohoto INSERT je potvrzeno, jsou uzamčeny pouze dva řádky:

  • Řádek v Invoice_Sequence zachování pořadového čísla
  • Řádek v Invoice pro novou fakturu.

Všechny ostatní řádky pro konkrétní base jsou zdarma – lze je libovolně aktualizovat nebo dotazovat (vymazání informací z tohoto druhu systému účetní obvykle znervózňuje). Pravděpodobně se budete muset rozhodnout, co se má stát, když dotazy normálně zahrnují nevyřízenou fakturu...



  1. Jak spojit tři stoly podle laravelova výmluvného modelu

  2. Pochopte skupinu podle klauzule v SQL Server - SQL Server / TSQL výukový program, část 130

  3. Jak získat krátký název měsíce z data v MySQL

  4. Jak funguje funkce OCT() v MySQL