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:
- Musíte spustit to v serializované transakci
- 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...