SQL Server – Colonne d'identifiant de préfixe et de remplissage de zéro

Pour être rapide, voici mon problème, j'ai essayé de searchr StackOverflow pour la réponse mais je ne peux pas find une réponse satisfaisante.

J'ai une table InvoiceHeader avec des colonnes (simplifié):

InvoiceID : Int - PK Identity(1,1) InvoiceDate : date CustomerID : Int - FK to Customer table 

Etc…

Je vais fréquemment afficher des informations sur la facture aux users. Lorsque j'affiche le numéro de facture pour les users, j'ai besoin d' append un préfixe et un remplissage de zéro à l'InvoiceID.

Par exemple :

 InvoiceID : 1 Invoice Number : INV0000001 

Ma question est, devrais-je faire une colonne BRAND NEW PERSISTED COMPUTED dans la table InvoiceHeader pour save le numéro de facture formaté comme ceci:

 InvoiceNumber AS 'INV' + RIGHT('000000'+cast(InvoiceID as varchar(7)),7) 

ou devrais-je sélectionner le InvoiceID et le traiter dans INV0000001 à l'exécution de mon application?

Mon dilemme :

  • Si j'ajoute une nouvelle colonne COMPUTED COMPUTED (ie InvoiceNumber) alors je peux créer un index non clusterisé à InvoiceNumber qui aidera quand il y aura une requête avec InvoiceNumber dans la clause WHERE. Mais cela aura toujours besoin de couvrir l'index ou d'inclure l'index pour get la valeur d'une autre colonne. Un autre avantage est que je n'ai pas besoin de le "formater" pour devenir INV0000001 chaque fois que je dois l'afficher.
  • Si je formate InvoiceID pour devenir INV0000001 à SELECT QUERY à partir de mon application, ce sera trop "corvée", chaque fois que je veux afficher InvoiceNumber, je dois le formater. Mais je n'aurai pas besoin d'une autre colonne qui a essentiellement la même valeur avec InvoiceID avec un préfixe et un remplissage de zéro.
  • Le numéro de facture sera utilisé par les users pour la search, par exemple: trouvez-moi une facture avec un numéro comme '1234' + '%'. Si cela est fait à InvoiceID (colonne entière) il fera une conversion IMPLICIT, cela rendra la requête plus lente? L'index PK sera-t-il toujours utilisé par le plan de requête?

EDIT : En pensant à beaucoup d'endroits où je devrai formater manuellement le numéro de facture chaque fois que j'en ai besoin (si je n'utilise pas la colonne calculée), je suis maintenant presque obligé d'aller avec la solution d' Esperento57 :

Faire 2 nouvelle colonne:

 InvoiceID : int identity (PK) Prefix : char(3) --> INV, etc InvoiceNumber : Prefix + RIGHT('000000'+cast(InvoiceID as varchar(7)),7) 

Mais je ne ferai pas PK inclure Prefix parce que InvoiceID est l' identity sorte qu'il est unique par lui-même.

Je considère aussi toujours le sharepoint vue de Matt sur la séparation des préoccupations aussi, parce que cela fait du sens.

Ma proposition pour vos colonnes:

  • InvoiceID: entier non nul avec autoincrement (la séquence n'est pas nécessaire, SQL Server fait le travail)

  • Préfixe: varchar (10) non null FK sur PREFIXTABLE

  • InvoiceID et Prefix sont la key primaire

  • InvoiceNumber: colonne calculée et persistante = Préfixe + RIGHT ('0000000' + InvoiceID, 7)

  • Ajouter un index sur InvoiceNumber

Avec ma proposition, vous pouvez:

  1. Changer le préfixe si nécessaire
  2. Vous avez l'intégrité sur le préfixe
  3. Vous avez de l'intégrité sur votre key complète et gardez la key vraiment primaire
  4. Vous n'avez pas à recalculer la key complète
  5. En cas de récupération de données, vous pouvez faire des sauts de séquences à vos keys ou simplement choisir un autre préfixe
  6. Vous pouvez append une description dans votre table PREFIX pour expliquer votre préfixe (pour futur développeur par exemple)

Vous devriez le garder comme une valeur numérique dans la database et le formater, cela vous empêchera de stocker inutilement des données sans valeur et améliorera les performances des requêtes. Vous pouvez appliquer le format à un niveau bas dans votre application si cela réduit le nombre de places à formater, mais en fonction de la complexité de votre application, il est peu probable que vous ayez besoin d'écrire cette logique de formatting plus d'une fois.

modifier

Il y a quelques points valables dans les autres réponses, par exemple le point sur les numéros manquants peut ou ne peut pas être important pour vous – vous seul savez si cela est pertinent.

La question de changer le préfixe dans le futur, je serais méfiant à less que vous sachiez que c'est une exigence concrète maintenant. Il existe plusieurs manières de modifier une modification de votre préfixe, que vous la stockiez dans la database, la génériez dans une vue ou dans la couche d'interface user / métier. C'est une de ces choses que je suggérerais à KISS et YAGNI !

NB Martin Fowler fait un très bon point dans l'article ci-dessus sur la distinction entre la construction de fonctionnalités présomptives et la construction de logiciels extensibles. Il s'agit de la mesure importante à utiliser systématiquement lors de l'examen des designs relatives à ces types de problèmes: faites le minimum pour vous assurer d'avoir des points d'extension, mais ne mettez en œuvre que les fonctionnalités dont vous avez besoin.

Je pense que vous devriez vraiment séparer l' ID interne, qui est une key primaire et est utilisé pour identifier un logging, à partir d'une string que l'user voit.

L'user final ne devrait jamais voir les ID générés par IDENTITY , car il peut facilement y avoir des lacunes.

Donc, j'ai deux colonnes normales: int InvoiceID et char(10) InvoiceNumber . Oui, il y aura une méthode distincte pour générer un numéro de facture suivant. Dans SQL Server 2014, j'utiliserais l'object SEQUENCE avec l'option NO CACHE pour cela.

Lorsque vous séparez les ID internes des numéros de facture visibles par l'user, vous pouvez facilement modifier le format de ces numéros dans le futur. Par exemple, dans deux ans, le département des finances peut décider d'introduire un autre préfixe ABC000001 . Évidemment, toutes les factures historiques existantes doivent conserver leurs numéros. Avec une colonne séparée pour le numéro de facture, il n'y a pas de problème. Avec une colonne calculée, vous aurez un problème.

Si c'est la formule pour calculer le numéro de facture,

 InvoiceNumber : Prefix + RIGHT('000000'+cast(InvoiceID as varchar(7)),7) 

Ici, l'écart entre le nombre de factures n'a pas d'importance.

Ensuite, je garderais onlyInvoiceID. Alors que l'affichage, je vais formater le numéro de facture de cette manière soit en bas niveau ou proc lui-même. Lorsque l'user va chercher le numéro de la facture, j'enlève le préfixe et le jette dans la variable int.

Ensuite, je vais effectuer une search sur la colonne invoiceID.

Mais si Prefix peut changer et qu'il ne devrait pas y avoir de GAP entre les numéros de facture alors,

i) Garder le préfixe dans la même table est une mauvaise idée.

ii) Le calcul du numéro de facture changera aussi parce que vous devez maintenir la continuité.

Mais je ne ferai pas PK inclure Prefix parce que InvoiceID est l'identité de sorte qu'il est unique par lui-même.

Cela dépend. Bien sûr, selon moi aussi Prefix est hors de question. Mais InvoiceID peut être PK + CI ou seulement PK ou seulement identité ou seulement CI.

vous hv pour examiner chaque option.