Bonsoir JBdev,
Envoyé par
JBdev
la table proposition aura (niveau MPD) comme clé primaire {IdProp, IdCli,IdEnt}, IdProp nécessiterait l'extra AUTO_INCREMENT mais Mysql le refuse du fait de sa participation dans la composition de la clé primaire de la table.
Les différents SGBD permettent l’utilisation d’un auto-incrément, mais on n’est pas obligé de s’en servir : il y a quand même d’autres façons de générer des valeurs uniques pour les clés. Quoi qu’il en soit, avant le milieu des années quatre-vingt-dix, chacun devait se débrouiller tout seul, comme un grand...
Prenons l’exemple MySQL suivant, dans lequel il s’agit d’identifier les entreprises, tout en se passant de l’auto-incrémentation offerte par ce SGBD. Le principe est de dire que la nouvelle clé primaire {EntrepriseId} est incrémentée d’une unité par rapport à la dernière clé créée, ce qui passe par l’utilisation de la fonction d’agrégation MAX (où n représente le pas de l’incrément) :
MAX(EntrepriseId) + n
Quand il s’agit de créer la 1re clé, pour empêcher au bonhomme Null de se manifester, on utilise la fonction COALESCE (où m représente la valeur initiale de la clé :
COALESCE(MAX(EntrepriseId) + n, m)
Un script :
CREATE TABLE ENTREPRISE
(
EntrepriseId INT NOT NULL
, EntrepriseSiren CHAR(9) NOT NULL
, EntrepriseNom VARCHAR(64) NOT NULL
, CONSTRAINT ENTREPRISE_PK PRIMARY KEY (EntrepriseId)
, CONSTRAINT ENTREPRISE_AK UNIQUE (EntrepriseSiren)
) ;
INSERT INTO ENTREPRISE (EntrepriseId, EntrepriseSiren, EntrepriseNom)
SELECT COALESCE(MAX(EntrepriseId) + 1, 1), '123456789', 'Dugoineau'
FROM ENTREPRISE ;
INSERT INTO ENTREPRISE (EntrepriseId, EntrepriseSiren, EntrepriseNom)
SELECT COALESCE(MAX(EntrepriseId) + 1, 1), '234567890', 'Naudin et Cie'
FROM ENTREPRISE ;
Au résultat :
EntrepriseId EntrepriseSiren EntrepriseNom
1 123456789 Dugoineau
2 234567890 Naudin et Cie
Plutôt qu’alourdir les INSERT avec les fonctions MAX et COALESCE, on peut préférer mettre en œuvre un trigger interceptant les INSERT et chargé de l’incrémentation (pour varier les plaisirs, allons-y pour une incrémentation de 5 en 5, débutant à 100) :
DELIMITER GO
CREATE TRIGGER IncrementonsEntreprise BEFORE INSERT ON ENTREPRISE
FOR EACH ROW
BEGIN
SET NEW.EntrepriseId = (SELECT COALESCE(MAX(EntrepriseId) + 5, 100)
FROM ENTREPRISE) ;
END
GO
DELIMITER ;
INSERT INTO ENTREPRISE (EntrepriseId, EntrepriseSiren, EntrepriseNom)
VALUES (0, '123456789', 'Dugoineau') ;
INSERT INTO ENTREPRISE (EntrepriseId, EntrepriseSiren, EntrepriseNom)
VALUES (0, '234567890', 'Naudin et Cie') ;
Au résultat :
EntrepriseId EntrepriseSiren EntrepriseNom
100 123456789 Dugoineau
105 234567890 Naudin et Cie
Variation sur le thème
Supposons qu’aux entreprises sont accrochés des établissements et qu’on utilise l’identification relative :
[ ENTREPRISE ]----1,N--------(Composer)--------1,1 (R)----[ ETABLISSEMENT ]
Table des établissements :
CREATE TABLE ETABLISSEMENT
(
EntrepriseId INT NOT NULL
, EtablissementId INT NOT NULL
, EtablissementSiret CHAR(14) NOT NULL
, EtablisssementNom VARCHAR(64) NOT NULL
, CONSTRAINT ETABLISSEMENT_PK PRIMARY KEY (EntrepriseId, EtablissementId)
, CONSTRAINT ETABLISSEMENT_AK UNIQUE (EtablissementSiret)
, CONSTRAINT ETABLISSEMENT_ENTREPRISE_FK FOREIGN KEY (EntrepriseId)
REFERENCES ENTREPRISE (EntrepriseId)
) ;
Un trigger pour gérer l’« auto-incrémentation relative » (et pallier ainsi la carence du SGBD ^^) :
CREATE TRIGGER IncrementonsEtablissement BEFORE INSERT ON ETABLISSEMENT
FOR EACH ROW
BEGIN
SET NEW.EtablissementId = (SELECT COALESCE(MAX(EtablissementId) + 1, 1)
FROM ETABLISSEMENT
WHERE EntrepriseId = NEW.EntrepriseId) ;
END
GO
Quelques insertions d'établissements :
INSERT INTO ETABLISSEMENT (EntrepriseId, EtablissementId, EtablissementSiret, EtablisssementNom)
SELECT EntrepriseId
, 0
, '12345678912345', 'Clinique Dugoineau'
FROM ENTREPRISE
WHERE EntrepriseSiren = '123456789' ;
INSERT INTO ETABLISSEMENT (EntrepriseId, EtablissementId, EtablissementSiret, EtablisssementNom)
SELECT EntrepriseId
, 0
, '23456789012345', 'La péniche'
FROM ENTREPRISE
WHERE EntrepriseSiren = '234567890' ;
INSERT INTO ETABLISSEMENT (EntrepriseId, EtablissementId, EtablissementSiret, EtablisssementNom)
SELECT EntrepriseId
, 0
, '23456789012346', 'Le clapier'
FROM ENTREPRISE
WHERE EntrepriseSiren = '234567890' ;
INSERT INTO ETABLISSEMENT (EntrepriseId, EtablissementId, EtablissementSiret, EtablisssementNom)
SELECT EntrepriseId
, 0
, '23456789012347', 'Chez Mme Mado'
FROM ENTREPRISE
WHERE EntrepriseSiren = '234567890' ;
Au résultat :
EntrepriseId EtablissementId EtablissementSiret EtablisssementNom
100 1 12345678912345 Clinique Dugoineau
105 1 23456789012345 La péniche
105 2 23456789012346 Le clapier
105 3 23456789012347 Chez Mme Mado
Envoyé par
JBdev
M'amenant pour le coup à la question de mon topic l'identification relative apporte-elle autant que cela? Ou est ce que ce sont les SGBD qui ne sont pas à la hauteur de cette notion?
L’identification relative sert notamment à résoudre de façon simple les contraintes de chemin, c'est-à-dire en évitant les triggers (fouillez dans les forums, j’en parle assez souvent). Dans la soute, la propagation de l’identifiant EntrepriseId chez les descendants des entreprises permet de faire de la « clusterisation » (veuillez me pardonner ce barbarisme, mais il est vraiment tentant...) et offre ainsi des possibilités de gains en performances fort intéressants.
Peu importe que le SGBD ne soit pas à la hauteur, on vient de voir que ça n’est pas un problème.
Envoyé par
JBdev
Chaque entreprise affilie un nombre n de client, chaque client est propre à l'entreprise ( agrégat selon WinDesign sur le MCD ci-dessous )
D’accord, je vois ce que vous entendez par agrégat, ça correspond au concept proposé en 1977 par John et Diane Smith dans Database abstractions: Aggregation and Generalization. L’agrégation a été évoquée dans quelques discussions, par exemple ici.
Votre modélisation de l’agrégation correspond à celle qui est proposée dans la FAQ Merise. Mais l’exemple proposé (en 2004) n’est pas fameux et je ne reconnais pas la patte de Dominique Nanci (élégance du style, pertinence en ont pris un coup), quelqu’un a dû passer derrière lui pour bricoler le MCD, injecter des contre-vérités (un agrégat n’est pas nécessairement vide). Je dis surtout que l’exemple n’est pas fameux (et devrait être remplacé !) parce que la cardinalité portée par la patte connectant l’entité-type Elève et l’association EstInscrit est 1,1 : en conséquence, l’entité-type Classe_Elève n’est qu’une restriction-projection de l’entité-type Elève, ce que l’on perçoit mieux en passant au stade logique :
Classe {ClasseId, ClasseNom}
PRIMARY KEY {ClasseId} ;
Elève {EleveId, ClasseId, EleveNom, ElevePrenom}
PRIMARY KEY {EleveId}
FOREIGN KEY {ClasseId} REFERENCES Classe ;
ClasseEleve {EleveId, ClasseId}
PRIMARY KEY {EleveId}
FOREIGN KEY {EleveId} REFERENCES Elève ;
FOREIGN KEY {ClasseId} REFERENCES Classe ;
Si l’on transpose cette représentation dans votre système, je ne saisis pas l’intérêt de ce pseudo agrégat : autant brancher sur CLIENT les associations qui le sont actuellement sur CLIENT_ENTREPRISE...
Avez vous des règles de gestion des données non dites ici, justifiant un agrégat ? (Un vrai...)
A suivre...
Partager