Base de données générique. Trucs et astuces. - SQL/NoSQL - Programmation
Marsh Posté le 08-08-2004 à 19:36:03
Pour info, avant de poster ce topic, j'avais fait le même modèle afin de stocker des étudiants inscrits à l'université suivant des cours et ayant des éxamens, etc.
Voici la requête permettant de retrouver la moyenne générale pondérée de chaque étudiant inscrit en 3° année.
Je pense que ça donne un bon ordre d'idée de ce que j'entends pas "généricité"
PS: ici j'ai utiliser EVE et EVP afin d'introduite une notion évènements (relation à une date précise, sous-relation à une date précise)
|
Marsh Posté le 08-08-2004 à 19:44:56
PS² : Merci de ne pas venir troller "ton système c'est de la merde patati patata". C'est un système utilisé, dont je suis aucunement l'inventeur, et qui fait ses preuves depuis des années sur de gros systèmes. C'est ainsi que dans la boîte chez qui je suis prestataire on a pu implmenter des choses absolument inédites pour l'ERP, sans devoir modifier ni la base si les exe.
Le système tel que je le décris est évidement extrêment simplifié, et la notion de paramètrage (faire en sorte que le programme crée lui-même les requêtes en fonction des informations demandées) est totalement mis de côté. Je ne vous parlerai d'ailleurs pas de ce dernier point, car non seulement je ne le maîtrise pas suffisament pour l'expliquer, mais surtout il fait très certainement l'objet d'un brevet ou toute autre protection légale, et je n'ai pas envie de me mettre en parte-à-faux avec la société qui me donne du pain à manger.
Marsh Posté le 08-08-2004 à 21:18:20
Ca a l'air un peu prise de tête pour la construction de requêtes, vu que tous les noms sont génériques
Perso, j'ai toujours bossé sur des systèmes classiques, ou le modèle de données calque les infos stoquées ... mais le modèle générique peut être sympa aussi, pour peu qu'un ensemble d'API soit développé pour y accéder, ce qui le rend plus spécifique
edit: je comprends mieux maintenant pourquoi dans tes posts précédents j'avais du mal à comprendre les noms de tables et champs de tes requêtes
et en fait, la plupart des problèmes que tu avais devaient venir de ce modèle générique (tes jointures monstrueuses et unions ... ).
Marsh Posté le 08-08-2004 à 21:37:46
Bah vu qu'on peut aliaser les tables dans les requêtes, l'utilisation de noms génériques n'est pas trop contraignante.
les champs, ça peut des fois en effet être lourd, mais c'est une question d'habitude.
Par contre, le gros avantage, c'est que vu que tu n'as pas 36 tables, tu connais le nom de tous les champs par coeur au bout d'une heure, ce qui permet d'aller bien plus vite, même quand tu manipules des données que tu n'as pas l'habitude de manipuler.
Sinon, si tu écris proprement tes API, tu peux au contraire les rendre elles-même génériques.
Mattons que tu aies un écran : Affectation des dépots aux clents.
Tu sais que tu dois récupérer les CLI et les DEP utilisant une relation qui/quoi sur CLI et DEP.
Tu utilises alors une table de définition des qui/quoi :
TQUIQUOI
TYPREL
QUI
QUOI
Dedans, tu mets par exemple :
1 / CLI / DEP -- Association client/depot
2 / PRO / DEP -- Association produit/depot
...
Et une table TQUIQOIQUE
TYPSREL
TYPREL
QUE
Avec dedans :
1 / 2 / FOU -- Association produit/depot/fournisseur
etc.
Tu fais alors deux API :
getQuiQuoi(typrel)
et
getQuiQuoiQue(typsrel)
La getQuiQuoi(typrel) va faire cette requête :
SELECT t1.nom, t2.nom
FROM relation, tie t2, tie t1, tquiquoi
WHERE tquiquoi.typrel = $typrel
AND t1.typtie = tquiquoi.qui
AND t2.typtie = tquiquoi.quoi
=> Ca te ressors les données liées, suivant la relation choisie.
Idem pour l'autre API. En les complexifiant un peu, tu peux ajouter un certain nombre de règles et de filtres paramètrables soit depuis une table spécifique, soit des paramètres supplémentaires.
Bref, au contraire, si tu fais bien ton code, non seulement le modèle est générique, mais ton code l'est aussi
Marsh Posté le 08-08-2004 à 21:39:46
Tu peux même faire une table d premier niveau qui permet depuis une API d'une couche plus haute de choisir quelle API utiliser.
Ainsi, le jour où une relation qui/quoi se transforme en qui/quoi/que, t'as rien à changer nul part, mais seulement l'entrée dans cette table de premier niveau.
Marsh Posté le 08-08-2004 à 21:40:43
Ouaip, je vois l'esprit, mais je demande à voir dans un projet assez conséquent (genre 200 infos différentes à stoquer)
Marsh Posté le 08-08-2004 à 21:46:28
200 ça commece à faire beucoup
Mais dans l'ERP que j'utilise (donc ça commence quand même à faire une base assez volumineuse avec une grande complexité des traîtements) ça marche bien, donc voilà quoi
Le plus gros intérêt en fait, ce qu'en ajoutant des lignes dans ces tables de paramètrage dont je parle, tu peux complètement changer le fonctionnement de ton appli, et gérer de nouveaux types d'infos sans toucher une ligne de code, ce qui est loin d'être négigeable.
Marsh Posté le 08-08-2004 à 21:53:09
Ca doit être ce type de modèle générique qui est utilisé pour la gestion de produits, genre la BDD de rue-montgallet.com ou de monsieurprix ... enfin quelquechose d'approchant
Marsh Posté le 08-08-2004 à 23:21:01
Hmmm. Il serait intéressant de savoir qu'elle est la différence au niveau de la charge pour le serveur entre cette méthode et une méthode plus "traditionnel" où le nombre de tables est plus grand et les tables plus petites. Le fait de regrouper un maximum d'info n'influence-t-il pas trop néfastement sur les performances?
Autre point qui me dérange, c'est que j'ai un peu du mal à voir comment tu peux intégrer facilement des contraintes de relation avec ce système.
Enfin, ce système pourrait-il s'adapter à une ontologie?
Marsh Posté le 08-08-2004 à 23:32:56
Ca doit être en effet le pb : à trop vouloir faire un modèle générique, on ne doit pas pouvoir accéder aux informations aussi rapidement ...
Marsh Posté le 08-08-2004 à 23:34:08
Niveau bench, je n'en ai jamais fait. Celà dit, je pense qu'avec des index correctement paramétrés, on doit pouvoir minimiser l'impact de grosses tables. Deplus, mine de rien, autant les index sont plus gros, autant on en a moins à charger en mémoire lors des requêtes. Ca mérite bench donc. A mon avis la différence de perfs doit aller légèrement à l'avantage d'un modèle conventionnel, à condition qu'on ne tape pas dans toutes les tables à la fois en permanence (là je pense que "mon" système pourrait prendre l'avantage)
Pour ce qui est des relations, j'ai décris ceci dans mon post précédent. Attention toutefois. La généricité est là pour éviter les modifications de code lors de l'évolution des relations entre les données. Pour cette raison, la reconstruction à la volée des requêtes d'interrogation suivant les relations prendra de facto bien plus de temps que des requête pré-écrites utilisant un modèle traditionnel. Mais sur un gros système, le prix et l'importance de développement spéficiques est amplement suppérieur à l'achat d'un serveur plus puissant qui permettra d'utiliser un système générique qui pourra se passer de développement spéficiques (en tout cas, les minimiser)
Je suis en train de faire un petit site PHP qui va mettre en évidence l'utilisation de ce système, avec génération à la volée des requêtes nécessaires pour retrouver les relations. Il n'y aura rien à propos des contraintes par contre (contraintes du type "si A est rempli, alors B ou C doivent m'être aussi" ou "si A > B alors C = 0" ce genre de choses. L'ERP sur lequel je travaille prends ça en charge, mais est on ne peut plus complexe, donc pour le moment je n'ai aucune idée de comment il fait (j'ai regardé les tables dans lequelles il stocke ces infos, et c'est un joyeux bordel )
Sinon, je ne sais pas ce que veux dire "ontologie", donc je ne peux pas répondre à la dernière question
Marsh Posté le 11-08-2004 à 08:59:39
Salut
intéressant, mais ce système pose aussi des problèmes ; à mon avis, il va y avoir de soucis avec cette table de "tiers" :
1. Obligation d'avoir une clé composite, répercutée partout. Sans détailler maintenant, je proscris les clés composites justement à cause des problèmes de maintenance et d'évolutivité, voire de volume.
2. Obligation de typer les requêtes sur les tiers pour des besoins fonctionnels différents (une personne s'intéresse aux clients, l'autre aux fournisseurs, une autre s'intéresse aux adresses des clients et à leurs codes postaux, pour étudier les volumes de ventes par code postal par exemple)
3. Il y a moins de généricité qu'il n'y paraît, parce que ta base d'exemple est simplificatrice. Tu évacues notamment les problèmes de codification (les clients sont connus et référencés depuis x années par des codes auxquels on se réfère et qu'on désire conserver, par exemple 4 lettres 2 chiffres 8 lettres, clé unique, les dépôts sont connus par des numéros : D1 à D 54). Dans la table générique, il faut un identificateur mais tu dois ajouter autant de colonnes qu'il y a de types de tiers pour stocker les clés "réelle" connues par les utilisateurs ; toutes ces colonnes doivent être facultatives puisqu'elles concernent juste une partie des lignes, et il faut aussi gérer les contraintes d'unicité sur ces codes
Pour pallier ce problème, tu codes à mort pour gérer l'intégrité ou tu réintroduis des tables client, dépot, fournisseur pour stocker les données spécifiques (comme dans un modèle objet, en fait)...
D'une certaine manière, tu réinventes le sgbd là...
J'ai des "portions généricisées" dans mes bases (pour les adresses notamment), mais la gestion des adresses est complexe, riche, et la généricité introduit aussi des lourdeurs au niveau du développement client, pour la cohérence des saisies...
bref, faut voir...
Marsh Posté le 11-08-2004 à 16:13:47
CREATE TABLE TIE (
TYPTIE VARCHAR2 (3),
SIGTIE VARCHAR2 (12),
NOMTIE VARCHAR2 (18),
...
CODZN1 VARCHAR2 (12),
CODZN2 VARCHAR2 (12),
CODZN3 VARCHAR2 (12),
CODZN4 VARCHAR2 (12),
CODZN5 VARCHAR2 (12),
CODZN6 VARCHAR2 (12),
CODZN7 VARCHAR2 (12),
CODZN8 VARCHAR2 (12),
CODZN9 VARCHAR2 (12),
CODZN10 VARCHAR2 (12),
CODZN11 VARCHAR2 (12),
CODZN12 VARCHAR2 (12),
CODZN13 VARCHAR2 (12),
CODZN14 VARCHAR2 (12),
CODZN15 VARCHAR2 (12),
CODZN16 VARCHAR2 (12),
...);
CREATE UNIQUE INDEX TIE_IDX1 ON
TIE(CODSOC, TYPTIE, SIGTIE)
TABLESPACE IX_M_SIZE PCTFREE 10
STORAGE(INITIAL 1380K NEXT 132K PCTINCREASE 0 ) ;
(CODSOC est un champ supplémentaire, car cette base tourne en mmode "multi-société" : plusieurs instances de l'ERP se partagent la même base sans mélanger leurs données)
On voit ici que :
- Le "SIGTIE" peut très bien ne pas être numérique. A ce moment, tu peux très bien stocker des dépots "D1" tout comme l'utilisateur "JAN2004-0123"
- Pour les infos très spécifiques, ou futures évolutions non prévues, rien ne t'empêche de créer des "colonnes poubelles", qui, via un simple paramètrage dans ton appli ou même une table de la base, permet d'associée à ces champs, pour un TYPTIE donné, (ou un autre CODZN donné) une série de règles de gestions. Par exemple, ici, la CODZN4 suis une règle spéciale : si le CODPAY (pays) du tiers de type 'CLI' est 'IT' (Italie) alors il doit être égal à 'PUB' ou 'PRIV', tandis que pour les autres pays il doit rester vide.
Pourtant, pour le typtie = 'ETS' (groupement de pays) le CODZN4 contient l'identifiant du dépot de retour SAV correspondant.
Bref, si derrière tu assures un minimum au niveau algo, tu peux faire au contraire, avec une table extrêment simple, quelquechose qu'il serait extrêment complexe à modéliser de façon "standard".
Après, il faut en effet bien réfléchir pour faire les modules de contraintes dynamiques par contre. Mais pour la majorité des besoins, ça reste assez simple à faire, et pas forcément de coder de spécifique (ici, on ne code rien sur l'ERP, on n'est pas du tout maître des sources. Par contre, via un écran, on peut à peu près faire tout ce qu'on veut avec n'importe quoi au niveau de la création de règles de gestions spécifiques au données)
Marsh Posté le 12-08-2004 à 15:16:09
Arjuna a écrit : - Pour les infos très spécifiques, ou futures évolutions non prévues, rien ne t'empêche de créer des "colonnes poubelles", qui, via un simple paramètrage dans ton appli ou même une table de la base, permet d'associée à ces champs, pour un TYPTIE donné, (ou un autre CODZN donné) une série de règles de gestions. Par exemple, ici, la CODZN4 suis une règle spéciale : si le CODPAY (pays) du tiers de type 'CLI' est 'IT' (Italie) alors il doit être égal à 'PUB' ou 'PRIV', tandis que pour les autres pays il doit rester vide. |
Personellement, j'éviterai de créer des colonnes poubelles. Au début ça peut paraitre une bonne idée, mais on arrive très vite aux limites de ce genre de solution. Par exemple, si tu veux stocker une description de ton produit, tu dépassera facilement les 12 caractères d'un champs CODZ. A mon avis, mieux vaut stocker les informations spécifiques dans un seul champs de grande taille (type blob ou text) et les organiser à ta guise (CSV, XML, etc ...).
Le problème de cette méthode c'est que tu ne peux plus utiliser les infos stockées dans ce champs dans la clause where d'une requête.
Marsh Posté le 12-08-2004 à 15:57:25
Les CODZN ici servent à stocker des CODE (comme le nom l'indique : CODE ZONE )
Pour les libellés, il y a une table TXT, avec une clé générique qui permet de reprendre les clés composées de la plupart des autres tables, avec deux champs clé supplémentaire afin d'identifier quel type de texte c'est et la langue. A ça, tu rajoutes un compteur, et tu peux faire autants de textes de tous types pour chaque élément de ta base.
De la même façon, il y a une table de CODZN, qui reprends ce système. Ainsi, si tu es limité par le nombre de CODZN, tu peux toujours en créer un nombre infini dans cette table.
Cependant, ce systèmen n'est utilisé qu'en dernier recours, car les contrôles à effectuer sur ces tables sont bien plus lourds, donc nécessitent plus de temps, et un paramètrage plus complexe.
En fait, en y regardant bien, tu peux stocker n'importe quelle base dans 5 tables :
- TRUC <= La table où il y a tous les machins à stocker.
- TXT <= La table où il y a tous les textes associés aux machins
- ATTR <= La table où il y a tous les attributs de tous les machins
- REL <= La table qui stocke les relations entre les machins ou des relations
- REL_ATTR <= La table qui stocke les attributs des relations
En étant bien tordu, on peut même fisionner REL et TRUC, ainsi que REL_ATTR et ATTR.
Marsh Posté le 12-08-2004 à 15:59:56
ok
Marsh Posté le 12-08-2004 à 17:34:42
Et Arjuna inventa l'usine à gaz
Perso je pense que ce genre de système est sympa pour de petites appli, mais dés que ca prend de l'ampleur ca devient ingérable. Et en plus t'est obligé de faire une tonne de doc, parce que sinon, il n'y a que toi qui pourra t'y retrouver, et encore, aprés 6 mois sans y toucher, ca doit faire mal au crane
Par contre pour une série de petites apllis, la c'est du bonheur
Marsh Posté le 12-08-2004 à 18:30:42
Je dirais le contraire
Preuve en est, c'est sur un gros système que j'ai découvert cette astuce (bon, c'est pas réduit à 5 tables hein )
Niveau code AU CONTRAIRE. Je vous posterai le code de mon site quand je l'aurai terminé, vous verrez que c'est on ne peut plus simple. Il n'y a PAS UN SEULE ligne de code dans mes pages.
Le but est de faire une série de fonctions, plus ou moins complexes, qui sont capable de gérer tous les cas. Celles-là, tu les documentes. Mais elles sont en faible nombre, et mine de rien, elles ne sont pas très complexes.
Ensuite, t'as plus qu'à appeler ces fonctions, les seuls paramètres sont des paramètres récupérés dans des tables de paramètres, qui vont décrire "pour le type de relation X, je dois lier ça avec ça en utilisant tel truc".
L'appel à ta fonction se limite donc à :
getInfos(numéroRelation, numéroElementPère)
=> Et tu récupère tout ce qui correspond à la relation de ton élément avec les critères définis par numéroRelation.
La table de paramètrage reste relativement simple :
"NUMREL, TYPQUI, TYPQUOI, CRITERE, DESCRIPTION"
Et peut aisément être administrée par un écran unique.
Non, vraiment, c'est au contraire particulièrement adapté aux très ros systèmes, là où toucher le code représente se palucher 25 exe de 80 Mo chacun, et refaire le plan de test qui qui représente 3 classeurs gros format posés sur une étagère.
Dans ce cas, t'es content de n'avoir qu'à changer un paramètre pour gérer de nouvelles données et des relations.
Alors évidement, ici c'est bien plus complexe comme système, et les gars y passent des mois à mettre en place un truc, mais modifier un exe, faut attendre un délais d'un minimum de 6 mois, et se repalucher une batterie de tests automatisés qui plombent un octo-processeur pendant 14 jours non-stop.
Le choix est donc vite fait
Par contre, pour un petit projet, c'est idiot de créer un progiciel (parceque c'est ni plus ni moins qu'un procgiciel) afin de gérer 4 lignes réparties dans deux tables.
Marsh Posté le 12-08-2004 à 20:07:09
Je dirais que ce genre de modèle est surtout utile dans les logiciels qui doivent s'adapter à un grand nombre de situations différentes (typiquement les ERP).
Par contre pour un logiciel qui a une fonction bien définie, c'est inutile.
Marsh Posté le 12-08-2004 à 20:59:15
J'ajouterais aussi la notion d'évolution : "l'application doit-être pouvoir évoluer simplement et considérablement sans coût ?" doit être la première question qui se pose lors du choix de ce type de modèle. C'est pour moi le cas de la plupart des sites webs notamment. Le meilleur exemple, c'est mon site actuel. La base est nickel chrome 100% merise et tout.
Résultat, je doit refaire intégralement la base pour pouvoir intréger les éléments que je veux ajouter. J'en profite donc pour passer à un modèle générique.
Marsh Posté le 13-08-2004 à 00:45:51
Arjuna a écrit : J'ajouterais aussi la notion d'évolution : "l'application doit-être pouvoir évoluer simplement et considérablement sans coût ?" doit être la première question qui se pose lors du choix de ce type de modèle. C'est pour moi le cas de la plupart des sites webs notamment. Le meilleur exemple, c'est mon site actuel. La base est nickel chrome 100% merise et tout. |
Il faut quand même prendre en compte la charge de developpement suplémentaire que représente un modèle générique. une modification du modèle de données n'enraine pas forcement un charge de developpement astronomique et peut être moins lourde que d'adopter un modèle générique.
Marsh Posté le 08-08-2004 à 19:27:39
Bonjour, ce topic a pour but de présenter certaines astuces qui permettent de créer des modèles de données génériques.
Qu'est-ce que j'entends par généricité ?
Selon moi, un modèle des données générique permet, sans modifier le modèle (ajout de tables/colonnes) de modifier l'intégralité des informations stockées dans une base de données, ainsi que leurs relations.
C'est de la dénormalisation de Merise/UML ?
Oui et non. C'est de la dénormalisation dans le sens ou les tables vont stocker diverses informations, qui après une analyse classique Merise ou UML auraient dûes être stockées dans des tables différentes. Cependant, en poussant plus loin l'analyse, on peut isoler des similitudes entre ces données, et les regrouper sous une appelation générique. Il en résulte que la modélisation effectuée reste conforme à Merise notamment. Dans ce topic je me base sur l'architecture de la base de données d'un petit ERP sur lequel je travaille, dont la base est certifiée Merise niveau 3.
Un exemple d'utilité
Si on vous demande de gérer dans une base des clients, des produits des dépots et des groupements de clients, vous pouvez créer une table pour chaque type d'information :
- Table "client"
- Table "client_adresse"
- Table "groupement_de_clients"
- Table "groupement_de_clients_adresse"
- Table "depot"
- Table "depot_adresse"
- Table "produit"
Avec dans chacune de ces tables des informations FK qui permettent de lier nu produit à un dépot, un client à une famille de clients, etc.
Mise en place de la généricité ; pourquoi
Si demin on vous demande en plus d'associer un client à des dépôts afin qu'il n'accède qu'à certains produits, vous allez devoir créer une table de correspondance, et des FK en plus. Idem si on vous demande d'intégrer une notion de fournisseurs par produit et par dépot.
Ainsi, l'intégralité de votre code qui exploite la base de données risque d'être impacté par cette modification.
Je vous propose, pour cet exemple simple, de créer seulement quatre tables : tiers / adresses / relation (qui/quoi) / sous-relation (qui/quoi/que)
La table tiers va stocker :
- Les clients
- Les familles
- Les dépots
- Les produits
- Les fournisseurs
Pourquoi ce regroupement ? Tous ces éléments sont identifiés grâce à un ID, et on un NOM, plus quelques informations qui peuvent être identiques (pays d'origine, actif, etc.)
La table des adresses va stocker :
- Les adresses des clients
- Les adresses des groupements de clients
- Les adresses des dépôts
- Les adresses des fournisseurs
Je pense que je n'ai pas besoin d'expliquer ce que ces informations ont en commun
La table des relations va stocker les relations entre deux tiers :
- Client / Groupement de clients
- Client / dépôt
- Produit / dépot
La table des sous-relations va stocker les relations entre trois tiers :
- Dépôt / Produit / Fournisseur
Evidement, ces tables risquent de faire poubelle si on ne peux pas différencier un produit d'un client par exemple. Ainsi, dans la table des tiers, on va utiliser une clé primaire composée : un ID et un type de tiers. Cette clé sera présente dans chaqueune des autres tables, afin de différencier les adresses et les relations.
Structure de la table TIERS :
- SIGTIE (Sigle Tiers : ID)
- TYPTIE (Type de Tier : CLI : Client / GRC : Groupement de clients / PRO : Produit / DEP : Dépôt / FOU : Fournisseur
- NOMTIE : Nom du tiers
- ACTIF : Indique si le tiers est actif ou non (Y/N)
Structure de la table ADRESSE :
En plus de la double clé héritée de la table des tiers, j'ajoute une seconde double clé TYPADR/NUMADR qui permet de stocker plusieurs adresses de types différents pour un même tiers. Par exemple, plusieurs adresses de livraison possible pour un même client, plusieurs adresses commerciales pour un fournisseurs implémenté proche de puisieurs déots.
- TYPTIE
- SIGTIE
- TYPADR (type d'adresse : COM : Commerciale / FAC : Facturation / LIV : Livraison)
- NUMADR (numéro de l'adresse, auto incrément)
- CONTACT
- NUMRUE
- NOMRUE
- CP
- VILLE
- TEL
- FAX
- EMAIL
La table des relations :
En plus de la double clé (TYPQUI/SIGQUI/TYPQUOI/SIGQUOI) j'ajoute un numéro de relation, qui est un auto-incrément. Ce sera utile pour la table des sous-relations.
- NUMREL (numéro unique)
- TYPQUI (Type du tiers origine)
- SIGQUI (Sigle du tiers origine)
- TYPQUOI (Type du tiers cible)
- SIGQUOI (Sigle du tiers cible)
Pour associer un produit "1" aux dépots "5" et "8", on fera par exemple :
INSERT INTO RELATION VALUES ('PRO', 1, 'DEP', 5); -- ID AUTO = 1
INSERT INTO RELATION VALUES ('PRO', 1, 'DEP', 8); -- ID AUTO = 2
La table des sous-relations.
Afin d'optimiser l'espace, au lien de reprendre la première relation qui/quoi, on va la créer dans la table des relations, et réutiliser son NUMREL. On n'a donc plus qu'à le lier au QUE. Voici la structure :
- NUMREL (Relation d'origine)
- TYPQUE (Type du tiers cible)
- SIGQUE (Sigle du tiers cible)
Pour associer par exemple le produit 1 du dépot 5 au fournisseur "2", et le produit 1 du dépôt 8 au fournisseur "7", on fera :
INSERT INTO SRELATION VALUES (1, 'FOU', 2);
INSERT INTO SRELATION VALUES (2, 'FOU', 7);
Note; Si au lieu d'associer un produit d'un dépot à un fournisseur, on veut associer un poduit directement à un fournisseur, il suffit de ne pas créer cette sous-relation, et créer la relation suivante :
INSERT INTO RELATION VALUES ('PRO', 2, 'FOU', 12);
=> Ainsi, le produit 2 est lié au fournisseur 12 quelquesoit le dépôt. On peut aussi lier un fournisseur à un dépôt de la même manière, toujours sans modifier le modèle des données.
On peut optimiser les deux tables de relation en utilisant une table "relationtype", qui permet d'indiquer pour un TYPREL quel typqui est lié avec quel typquoi et quel typque Seulement, cela rends la lecture des tables moins claire. Par contre, cela permet d'augmenter la généricité du code qui est derrière, en permettant la construction de requête dynamiques, simplement en lisant au préalable dans cette table comment retrouver la bonne relation. Perso, je préfère utiliser d'autres systèmes pour rendre le code génériques (écriture de "toutes les requêtes possible" et lecture dans une table de paramètre laquelle utiliser. Dans tous les cas, vous pouvez toujours utiliser des requêtes en dur.
Exploitation
Maintenant qu'on a construit cette usine à gaz, un exemple pratique.
Le client 1 a commandé le produit 5. Comme on ne l'a plus en stock, on recherche l'adresse du fournisseur à contacter pour passer une commande de réaprovisionnement.
Je pars du principe "le plus complexe" : un client est associé à un dépôt, et les produits de chaque dépôt est associé à un fournisseur différent.
Dans un premier temps, on recherche les dépôts auxquel est associé le client :
select dep.id, dep.nom
from tiers dep, tiers cli, relation clidep
where cli.typtie = 'CLI'
and cli.sigtie = 1
and clidep.typqui = cli.typtie
and clidep.sigqui = cli.sigtie
and clidep.typquoi = 'DEP'
and dep.typtie = clidep.typquoi
and dep.sigtie = clidep.sigquoi
Maintenant qu'on a cette liste, il faut la filtrer avec la liste des dépots qui permettent de stocker le produit 5.
select dep.id, dep.nom
from relation prodep, tiers dep, tiers cli, relation clidep
where cli.typtie = 'CLI'
and cli.sigtie = 1
and clidep.typqui = cli.typtie
and clidep.sigqui = cli.sigtie
and clidep.typquoi = 'DEP'
and dep.typtie = clidep.typquoi
and dep.sigtie = clidep.sigquoi
and pro.typtie = 'PRO'
and pro.sigtie = 5
and prodep.typqui = pro.typtie
and prodep.sigqui = pro.sigtie
and prodep.typquoi = dep.typtie
and prodep.sigquoi = dep.sigtie
Enfin, on recherche la liste des fournisseurs qui approfisiennent les dépots trouvé avec le produit 5.
select fou.id, fou.nom
from srelation prodepfou, tiers fou, tiers pro, rel prodep, tiers dep, tiers cli, relation clidep
where cli.typtie = 'CLI'
and cli.sigtie = 1
and clidep.typqui = cli.typtie
and clidep.sigqui = cli.sigtie
and clidep.typquoi = 'DEP'
and dep.typtie = clidep.typquoi
and dep.sigtie = clidep.sigquoi
and pro.typtie = 'PRO'
and pro.sigtie = 5
and prodep.typqui = pro.typtie
and prodep.sigqui = pro.sigtie
and prodep.typquoi = dep.typtie
and prodep.sigquoi = dep.sigtie
and fou.typtie = 'FOU'
and prodepfou.numrel = prodep.numrel
and prodepfou.typque = fou.typtie
Et enfin, on cherche les adresses commerciales 'COM' de chacun de ces fournisseurs.
select fou.nomtie, adr.contact, adr.numrue, adr.cp, adr.ville, adr.fax, adr.email
from adresse adr, srelation prodepfou, tiers fou, tiers pro, rel prodep, tiers dep, tiers cli, relation clidep
where cli.typtie = 'CLI'
and cli.sigtie = 1
and clidep.typqui = cli.typtie
and clidep.sigqui = cli.sigtie
and clidep.typquoi = 'DEP'
and dep.typtie = clidep.typquoi
and dep.sigtie = clidep.sigquoi
and pro.typtie = 'PRO'
and pro.sigtie = 5
and prodep.typqui = pro.typtie
and prodep.sigqui = pro.sigtie
and prodep.typquoi = dep.typtie
and prodep.sigquoi = dep.sigtie
and fou.typtie = 'FOU'
and prodepfou.numrel = prodep.numrel
and prodepfou.typque = fou.typtie
and adr.typtie = fou.typtie
and adr.sigtie = fou.sigtie
and adr.typadr = 'COM'
Hop, on a la liste des différentes adresses de tous les fournisseurs qui vont permettre de nous réapprovisionner en fonction de notre besoin. On peut ajouter à cette requête l'adresse des dépôts que chaque fournisseur peut livrer, etc.
Le principal avantage de ce système, c'est que si demain le mode d'attachement des fournisseurs aux produits/dépot change, vous n'avez rien à à changer dans structure de la base, mais simplement les données à re-remplir correctement (ça peut même se faire de façon automatique avec des requêtes en parant des données existantes), et la requête ci-dessus à modifier pour par exemple lier directement le fournisseur au produits.
Ce système permet aussi de gérer du 1,1 avec la même représentation que du n,n, ainsi, ce genre de variances dans les règles de gestion n'impacte en rien ni le modèle ni les requêtes.
De la même façon, ce modèle est déjà près à stocker des KIT (produits composés), des familles de produit, etc.
En rajoutant un champ "RELVAL" dans les tables relation / sous-relation, on pourra stocker aussi des LOT de produits, des délais de réaprovisionnement, etc.
Bref, cette représentation doit très certainement avoir des limites, mais pour le moment, je n'en ai rencontré aucune.
Par contre, il nécessire mûre réflexion, notamment pour ce qui est de la définition des clés qui/quoi(/que)
Ce "mini-cours" est basé sur mon expérience personnelle. Je ne me vente pas d'être un grand gourou en la matière, et il existe peut-être (certainement) des façon encore plus puissantes de gérer ce type d'information (notamment pour ce qui est des relations, ce qui est actuellement le point le plus faible de ce système (en effet, si on veut gérer un qui/quoi/que/où, on est bloqué, à moins d'utiliser des bidouilles plus ou moins propres (tiers fictifs basés sur le relnum d'une relation qui/quoi afin de rajouter un niveau par exemple)
Tout commentaire est le bienvenu. Posez vos questions et problèmes d'implémentation, et je m'efforcerai de vous répondre du mieu que je peux.
Message édité par Arjuna le 08-08-2004 à 19:32:34