J'ai une exigence commerciale selon laquelle chaque enregistrement dans la table des factures a un identifiant qui ressemble à YYYYNNNNNN.
La partie NNNNNN doit redémarrer au début de chaque année. Ainsi, la première ligne entrée en 2016 ressemblerait à 2016000001 et la seconde à 2016000002 etc. Disons que le dernier record pour 2016 était 2016123456, la ligne suivante (de 2017) devrait ressembler à 2017000001
Je n'ai pas besoin que cet identifiant soit la clé primaire et je stocke également la date de création. L'idée est que cet «ID d'affichage» est unique (donc je peux l'interroger) et qu'il peut être groupé humain, par année.
Il est peu probable que des enregistrements soient supprimés; cependant, je serais enclin à coder défensivement contre quelque chose comme ça.
Existe-t-il un moyen de créer cet identifiant sans avoir à demander l'id max cette année à chaque fois que vous insérez une nouvelle ligne?
Idées:
- A
CreateNewInvoiceSP
, qui obtient laMAX
valeur de cette année (ouais) - Quelques fonctionnalités magiques intégrées pour faire exactement cela (je peux rêver correctement)
- Pouvoir spécifier un UDF ou quelque chose dans la déclaration
IDENTITY
orDEFAULT
(??) - Une vue qui utilise
PARTITION OVER + ROW()
(supprimée serait problématique) - Un déclencheur activé
INSERT
(aurait encore besoin d'exécuter uneMAX
requête :() - Un travail de fond annuel, mis à jour un tableau avec le MAX pour chaque année inséré que j'ai ensuite ... Quelque chose?!
Tout cela est un peu non idéal. Toutes les idées ou variations sont les bienvenues!
la source
Réponses:
Il y a 2 éléments dans votre domaine
Ils n'ont pas besoin d'être stockés dans un seul champ
Exemple:
YEAR(GETDATE())
Créez ensuite une colonne calculée les concaténant (avec un formatage approprié). La séquence peut être réinitialisée en cas de changement d'année.
Exemple de code dans SQLfiddle : * (SQLfiddle ne fonctionne pas toujours)
la source
SEQUENCE
au début de chaque année?NEXT VALUE FOR
dans uneCASE
déclaration (j'ai essayé)Avez-vous envisagé de créer un champ d'identité avec seed = 2016000000?
Cette graine doit être auto-incrémentée chaque année, par exemple la nuit du 2017/1/1, vous devez planifier
Mais je vois déjà des problèmes avec la conception, par exemple: que faire si vous avez des millions d'enregistrements?
la source
Ce que j'ai fait dans ce scénario était de multiplier l'année par 10 ^ 6 et d'y ajouter la valeur de séquence. Cela a l'avantage de ne pas nécessiter de champ calculé avec son (petit) surcoût continu et le champ peut être utilisé comme a
PRIMARY KEY
.Il y a deux pièges possibles:
assurez-vous que votre multiplicateur est suffisamment grand pour ne jamais être épuisé, et
vous n'êtes pas assuré d'une séquence sans lacunes en raison de la mise en cache de la séquence.
Je ne suis pas un expert de SQL Server, mais vous pouvez probablement définir un événement à déclencher à 201x 00:00:00 pour réinitialiser votre séquence à zéro. C'est aussi ce que j'ai fait sur Firebird (ou était-ce Interbase?).
la source
Edit: Cette solution ne fonctionne pas sous charge
Je ne suis pas un fan des déclencheurs, mais cela semble mieux que je puisse travailler.
Avantages:
Modifier: Inconvénients:
(Nous remercions @gbn car je me suis inspirée de leur réponse) (Tout commentaire et soulignant les erreurs évidentes sont les bienvenus :)
Ajoutez de nouveaux
COLUMN
s et unINDEX
Ajoutez le nouveau
TRIGGER
la source
NULL
valeurs entrées. Retour à la planche à dessin ...ON Previous.Id = (I.Id -1)
devrait simplement chercher), mais oui ne fonctionne toujours pas. Si je pouvais verrouiller la table (?) Pendant l'insertion et le déclenchement, je pense que cela fonctionnerait. Mais cela ressemble aussi à une odeur de code.