Forum Programmation.SQL Créer une clef avec une fonction

Posté par  .
Étiquettes : aucune
0
20
nov.
2007
Bonjour,
Pour une base de données, j'ai besoin d'identifier un dossier saisi dans une table à l'aide d'un champ qui doit être calculé.
Ce champ, qui sera la clef primaire de la table doit se présenter sous la forme : yyyymmdd-num-X. Avec :
- yyyymmdd la date du jour,
- num un numéro d'ordre de saisie et
- X une clef calculée sur un modulo 26 du total précédent.
Exemple : 20071119-01-F
Petit détail qui a son importance : cette base de données, comme toutes les autres, finalement, tourne sous postgresql version 8.2.5. Au point où j'en suis, voici comment j'ai procédé :
J'ai créé une table comme suit :

create table num_dos (
dat_cur varchar(8),
num_ord integer);


Et une fonction qui utilise cette table :

create or replace function num_dos() returns varchar as
$$
declare cur_rec record;
begin
select into cur_rec * from num_dos limit 1;
if (not found) then
insert into num_dos values (to_char(now(), 'yyyymmdd'), 1);
else
if (cur_rec.dat_cur != to_char(now(), 'yyyymmdd')) then
update num_dos set dat_cur = to_char(now(), 'yyyymmdd'), num_ord = 1;
else
update num_dos set num_ord = num_ord+1;
end if;
end if;
select into cur_rec * from num_dos limit 1;
return (cur_rec.dat_cur || '-' || trim(to_char(cur_rec.num_ord, '00')) || '-' || chr(65 + ( cur_rec.dat_cur || cur_rec.num_ord)::integer % 26));
end;
$$ language plpgsql;


Mon idée, partant de ça, est de créer une table dossier ainsi :

create table dos
(
num_dos varchar(13) default num_dos() primary key,
...


Mes questions à propos de cette façon de faire :
- Comment gérer les cas où l'ajout dans la table dos échoue ? Parce que dans ce cas, la fonction num_dos() aura été appelée pour rien, et le numéro d'ordre sera incrémenté pour rien. Du coup, je risque d'avoir des trous dans mes numéros d'ordre, ce que j'aimerai éviter autant que possible. A moins que le fait d'encadrer ça dans une transaction suffise à éviter la mise à jour de la table num_dos en cas de rollback ?
Y a-t-il une autre façon de faire la même chose qui soit plus efficace ? J'ai bien pensé à créer une fonction similaire qui, au lieu de se baser sur une table annexe, se base sur la table dos, en parcourant tous les champs num_dos commençant par la date du jour, et à ajouter 1 au dernier numéro trouvé, mais ça me parraissait lourd, d'autant que cette table risque de contenir beaucoup d'enregistrements.
Qu'en pensez-vous ? Avez-vous d'autres idées pour gérer ça ? Passer par une "rule" sur la table num_dos ? Passer par une nouveau type ?
Merci pour vos idées par avance, je poursuis mes essais avec cette structure en attendant d'éventuels avis sur la question.
  • # .

    Posté par  . Évalué à 4.

    Je sais pas si ça peut te servir, mais depuis que mes clés primaires n'ont plus aucun sens, je m'en porte beaucoup mieux : en clé primaire, tu utilises un identifiant unique qui ne veut rien dire pour l'utilisateur. D'ailleurs tu ne l'affiches pas ( jamais jamais ! ). Comme ça, quelque soient les evolutions qu'on te demande, tu n'aura pas à changer tes jointures etc. Donc pour cet identifiant, tu utilises le mécanisme propre à ton sgbd ( genre séquence, colonne identity etc ). En plus tu auras des beaux index efficaces et tout et tout.
    Ensuite tu règles ton second problème : celui des compteurs. c'est un problème connu en base de données. Une solution est d'utiliser une table de compteurs. En encapsulant le tout dans une transaction, tu évitera les trous de numérotations sans problème.
    • [^] # Re: .

      Posté par  . Évalué à 2.

      Bon, ben déjà, merci d'avoir confirmé le point 2. J'ai effectué quelques tests unitaires avec les tables définies ci-dessus, et ça correspond bien à mes besoins, et réagit comme prévu, notament lorsqu'un échec d'ajout est constaté, que ce soit dans une transaction ou non.
      Pour ton point 1, par contre, j'avoue avoir réfléchi un peu à la question que tu soulèves, et j'avoue ne pas vraiment comprendre ou saisir tous les tenants et aboutissants de cette manière de procéder.
      Postgres (mais il ne doit pas être le seul) me permet sans difficulté d'indexer mon champ primaire tel que défini ci-dessus, et permet aussi de faire ces petites choses tellement pratiques que sont les "on update cascade" et consorts.
      Du coup, si la structure de ce champ doit changer, ça ne me complique pas plus la vie que ça. Bref, il doit y avoir quelque chose qui m'échappe.
      Quant-au fait de cacher la clef primaire aux utilisateurs, là encore, je ne comprends pas bien le pourquoi du comment, car c'est un identifiant unique qui permet à coup sûr d'identifier un enregistrement particulier d'une table. Lorsque l'utilisateur fait une recherche sur cet identifiant, il est certain de n'avoir qu'un seul résultat, et donc les erreurs de traitement possible sont moindres. Si tu masques ce champ "automatique" pour en afficher d'autre(s) qui font le même travail, ta base de données comporte tout un tas de champs qui sont redondants, et j'avoue ne pas en comprendre l'intérêt.
      M'enfin, je cherche juste à comprendre, pas à démolir ta façon de travailler.
      Merci de m'avoir confirmé le point 2, car je vais maintenant pouvoir avancer.
      • [^] # Re: .

        Posté par  . Évalué à 3.

        Pour le coup, je suis d'accord avec SNT

        J'ai eu a refaire un systeme de base de donnée et je m'etais d'abord orienté vers ID_unique = numero de dossier

        Seulement les utilisateurs créent des dossiers, en suppriment, et fon un roulement en numerotant les dossiers en fonctions des classeurs de rangement.

        Du coup je fais bien un id_unique interne à la base de données (et utilisé uniquement par moi et la base de données) mais j'affiche un champ "n° de dossier" qui est un champ calculé sur le modele departement-commercial-dossier
        • [^] # Re: .

          Posté par  . Évalué à 2.

          Pardonne moi d'insister, mais dans l'exemple que tu donnes, et même si je comprends le sens de ta démarche, je n'en voit toujours pas l'intérêt. Quelle importance que les utilisateurs changent la clef primaire ?
          Parce que si je comprends bien ton propos, ce qui t'a gêné lors de la création de ta base, c'est que tes utilisateurs créent des dossiers, en suppriment, et changent les numéros des dossiers au grès du rangement de la paperasse qui découle de l'application se reposant sur la base de données. Soit, mais je ne vois vraiment pas en quoi cela pose un problème.
          Alors, juste pour l'anecdote (faisont une petite analogie), je suis en train de (re)lire le cycle des fondations d'I.Asimov, et j'en suis au dernier volet "Terre et fondation". Et justement, hier soir, dans le chapitre que je lisais, Golan Trevize s'interrogeait sur le Plan Seldon à peu près en ces termes : "Le Plan repose sur deux axiomes qui sont : la population sur laquelle il s'applique doit être importante, et elle doit ignorer les prédictions faites par la psychohistoire". Mais il doit y avoir un axiome tellement évident, que personne n'a mis le doigt dessus, que tout le monde voit sans le regarder et qui invalide tout le reste.
          Hé ben là, je pense être dans la même situation. J'ai l'impression que cette histoire de clef visible ou non, telle que vous l'évoquez tous les deux apporte quelque chose, mais je ne vois pas quoi.
          Il est fort probable également que l'environnement dans lequel nous travaillons les uns les autres, ainsi que les besoins et contraintes ne soient pas les mêmes, et que nous ayons tous raison. Mais là, vraiment, ça m'échappe.
          • [^] # Re: .

            Posté par  . Évalué à 3.

            Je bosse sur plein de sgbd différents et sur des versions pas forcément tres recentes, alors je n'ai pas forcément le "on update cascade" à ma disposition. Dans le cas où la fonction existe, c'est déjà moins problématique. Et encore. Imagine un changement de format de ton numéro de dossier : c'est plus du string(10), mais du string(20), il faut faire une mise à jour du format de colonne dans toutes les tables qui référencent ta clé primaire. Déjà c'est moins drole.
            Pour les perfs, j'ai pas fait de benchs, mais j'ai pas de mal à imaginer que faire des jointures sur des numbers soit plus efficace que de faire des jointures sur des string(). Surtout si la taille du champ vient à grossir au fil des années.
            • [^] # Re: .

              Posté par  . Évalué à 1.

              Ok, merci pour ces explications.
              C'est bien ce que je pensais, il s'agit bien de cas que je ne suis pas prêt de rencontrer, vu le domaine d'application des bases que je créé et administre.
              Mais l'information est toujours bonne à prendre, au cas où...

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.