Clé primaire avec numéro séquentiel préfixé...

Clé primaire avec numéro séquentiel préfixé... - SQL/NoSQL - Programmation

Marsh Posté le 14-03-2006 à 15:46:23    

Hello :hello:,
 
Je reprends un projet en cours de développement et j'ai un point qui ne me semble pas très clair.
 
Le but est de créer une clef primaire composée des deux derniers chiffres de l'année en cours + les chiffres du mois en cours + numéro séquentiel.
Exemple : 06-03-0114
 
Le "numéro séquentiel" doit s'initialiser à chaque changement de mois, ainsi le premier enregistrement du mois prochain devrait-être le "06-03-0001" :heink:
 
Je doute fort qu'une base de données (je travaille ici sous Informix) puisse gérer "automatiquement" et toute seule ces données et les gérer par code me semble assez risquer pour une application extranet.  :??:
 
Avez-vous un retour d'expérience ou une réponse efficace au sujet de ce genre de chose?
 
Merci beaucoup.
 
Michel

Reply

Marsh Posté le 14-03-2006 à 15:46:23   

Reply

Marsh Posté le 14-03-2006 à 17:46:50    

Je suis loin d'être calé mais dans ton cas :
- je me dirais que c'est assez tordu de choisir une clé primaire comme celle-ci.
- je bidouillerai mes insertions de la manière qui va suivre.
 
Je décline toute responsabilité quand à la "goret attitude" qui pourrait découler de mon message.
J'utilise la syntaxe MySQL mais l'équivalent devrait exister de ton côté.
 
Insert into matable (`cle_primaire`) values ([select ci-joint])
 
c'est là que c'est moche et largement optimisable je pense.
 
Je décompose.
On va faire une concaténation de deux choses :
- le couple année-mois.
- l'id_max de la période en cours + 1.
 
Ca va nous donner année-mois-(id_max+1)
 
Sous MySQL la fonction now() permet de récupérer la date et l'heure courante.
Associé à DATE_FORMAT et un masque de saisie, on a déjà la moitié du boulot de fait :  

SELECT DATE_FORMAT( now( ) , '%y-%m' )


 
Pour la suite c'est un peu plus lourd.
On commence par lister les id pour le mois et l'année en cours.
La fonction LEFT permet de conserver les 5 caractères en partant de gauche (année-mois) pour effectuer notre tri.
On sélectionne la partie id avec RIGHT:

Select RIGHT(`cle_primaire`,4)  
from matable  
where LEFT( `cle_primaire` , 5 ) = DATE_FORMAT( now( ) , '%y-%m' )


 
Ce qui nous interesse c'est l'id_max donc on repasse une couche, le casting vers binary est peut être pas le meilleur choix.

SELECT MAX( CAST( RIGHT( `cle_primaire` , 4 ) AS BINARY ) )
FROM matable
WHERE LEFT( `cle_primaire` , 5 ) = DATE_FORMAT( now( ) , '%y-%m' )


 
Le soucis c'est que si pour année-mois en cours il n'y a pas d'enregistrement, tu te retrouve avec NULL. ca se corrige avec la fonction coalesce(découverte sous peu, jsuis fan :D), je lui file 1 en paramètre.  
En fait coalesce analyse chaque paramètre et renvoie le premier qui est non nul donc 1 dans notre cas.
 
Dernier détail, il faut ajouter 1 à noter id_max sinon on se retrouve avec un doublon:


SELECT MAX( 1 + coalesce( CAST( RIGHT( `cle_primaire` , 4 ) AS BINARY ) ,1) )
FROM matable
WHERE LEFT( `cle_primaire` , 5 ) = DATE_FORMAT( now( ) , '%y-%m' )


 
Au final :

select DATE_FORMAT(now(),'%y-%m'),
MAX(1+coalesce(CAST(RIGHT(`cle_primaire`,4) as BINARY),1))  
from matable  
where LEFT(`cle_primaire`,5)=DATE_FORMAT(now(),'%y-%m')


 
 
 
Tu remarqueras que cette requête n'est pas prête à être inserée dans  
Insert into matable (`cle_primaire`) values ([select ci-joint]).
 
Je n'ai pas réussi à faire ma concaténation (problème de casting je pense). De plus, il faut "générer" les '0' manquants car ce select va sortir :
06-03    1
au lieu de
06-03    0001
 
Voilà un début de piste mais bon encore une fois, c'est bête de devoir réinventer la roue quand l'autoincrement fait ca très bien ...


Message édité par jeoff le 14-03-2006 à 17:52:57
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed