Valider la structuration d'une Base de données (Tables, Champs et Relations entre Tables)

Bonsoir,
Je suis un amateur avec quelques notions très basiques en Base. J’ai réalisé une ébauche de structuration (Tables, Champs et Relations entre les Tables) d’une base de données qui doit accompagner des recherches historiques.
Puis-je la déposer ici pour le soumettre aux avis éclairés des membres de ce forum car j’aimerais que cette structuration soit validée (au moins dans son principe et ses grandes lignes) avant de commencer à l’utiliser ?
Merci beaucoup
Bonne soirée

Comment as-tu réalisé cette ébauche ? MCD, script SQL manuel, création de tables et relations au coup par coup ? Déjà une copie d’écran de l’affichage des relations (en disposant correctement les éléments du schéma : que l’on voit bien les relations et le contenu de chaque table) pourrait donner un bon aperçu.

Merci Primus pour cette réponse,
Mon niveau de connaissance de base est rudimentaire, je suis en train de le muscler en étudiant des tutos et mettant en application leurs exemples quand il y en a.
J’ai bricolé un descriptif de chaque table bdd projet base tables v6.odt (31.1 KB)
, un tableau des Relations bdd projet base relations v6 p1.odt (25.8 KB)
J’ai créé une première version dans Base que je peux mettre ici aussi
:face_with_peeking_eye: Voilà le résumé de mon projet de Bdd :
" 1. Au centre, il y a des Pièces d’archives qui doivent être dépouillées ; chaque Pièce a donc : sa Nature (par exemple, Rapport, Courrier, Article, Témoignage…), sa Cote (H 12 B 145…), son Traitement (à Faire, à Reprendre, Exploité…)
2. chaque Pièce peut être associée à un ou plusieurs Individus dont chacun a un Statut (Emetteur, Récepteur, Autres…) et peut avoir une Fonction (Journaliste, Préfet, Directeur…), fonction qui sera forcément liée à une Institution (Préfecture, Mairie, Cabinet d’avocats….)
3. Une Pièce également peut être directement associée à une ou plusieurs Institutions
4.Chaque Cote (H 12 B 145…) est aussi, et forcément, liée à un Fonds (Dossier judiciaire, Rapports mensuels, Collection Complète…) qui lui-même est forcément lié à une Structure (Archives nationales, Archives 85, Service Historique Défense…).
Mon planning : Etape en cours = validation de la structuration : répartition en Tables et relations entre les Tables et Etape suivante = construire les Formulaires (et Requêtes) de dépouillement et d’affichage des infos dépouillées
Merci de vos lumières

Difficile à dire quand on ne comprend pas exactement la structure. Je ne peux donc pas dire si le MCD est correct.

Par contre, ce qui saute aux yeux (du moins, aux miens) c’est la structuration des tables et la difficulté de lecture des noms d’attributs. Exemple, la table Individus. Personnellement je ferais les choses ainsi :

T_INDIVIDUS
IND_ID
IND_NOM
IND_PRENOM
IND_COM

Ce qui donnerait quelque chose de ce genre :

CREATE TABLE T_INDIVIDUS (
	IND_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL,
	IND_NOM VARCHAR(32) NOT NULL,
	IND_PRENOM VARCHAR(32) NOT NULL,
	IND_COM VARCHAR(1048)
	CONSTRAINT PK_IND_ID PRIMARY KEY (IND_ID)
);

Toutes les tables structurées pareillement donne une meilleure visibilité.

Sinon l’ébauche de base que tu as faite, elle donne quoi ?

Merci Primus pour cette réponse.
Effectivement, le nommage de mes champs pourrait être plus informatif :+1: c’est noté
La suite de ta réponse semble être du SQL dont je ne connais que quelques bribes, pour l’essentiel je passe par Base !
Dans mon ébauche (remplie avec des valeurs “fictives”) Base forum 22 02 v5.odb (54.5 KB), je bloque sur beaucoup de choses, mais c’est normal ! Je suis conscient que c’est très dur d’expliquer clairement ce qu’on veut faire avec sa bdd :thinking:
En 1er problème : arriver à ce qu’un Fonds, dans une Structure, ne puisse pas avoir la même cote qu’un autre Fonds associé à cette même Structure ; par exemple : “la cote «H 5 BZ 363 » associée au Fonds « Rapports préfectoraux » de la Structure « Archives 22 », ne peut être attribuée à aucun autre Fonds dans "Archives 22"” ; j’ai tenté une solution par FK dans une table d’association (voir schéma)
bdd projet base relations v5 p.1.odt (24.1 KB) mais ça ne fonctionne pas.
En 2ème : pouvoir afficher dans le formulaire “Saisie des pièces” non seulement la liste des Individus associés à cette pièce, mais aussi des infos complémentaires sur chaque individu données par des tables d’association (Statut, Fonction…)
Bonne soirée

Je viens de jeter un oeil à ta base. Je ne comprends pas certaines choses propres au fonctionnement, ce qui est normal, mais j’ai relevé quelques erreurs. Par exemple, la table T_InstitutionsPieces, qui relie T_Pieces et T_Institutions. Le champ (et donc la clé primaire) ID_InstitutionsPieces est inutile. Il faut utiliser comme clé primaire les 2 clés ID_Institution et ID_Piece. En SQL ça donnerait ça:

CONSTRAINT PK_PIECES_INSTITUTIONS PRIMARY KEY (ID_Institution, ID_Piece)

PK_PIECES_INSTITUTIONS est le nom de la clé que j’ai choisi pour l’exemple (il faut toujours nommer les clés).

Et idem pour les tables similaires.

Il est évident qu’utiliser un script SQL pour créer tables et relations en un clic ne s’apprend pas du jour au lendemain. C’est pourquoi les étapes débutant par le MCD sont indispensables, avec au final, la génération dudit script qui créera la base.

Merci Primus,
J’ai bien travaillé un tuto en ligne qui expliquait cette démarche complète mais… là ça dépasse mon énergie ! J’ai choisi de bricoler - le plus sérieusement possible ! - avec Base.
Je n’ai pas compris cette utilisation, pour mes tables d’association, des FK (issus des tables associées) en double PK : car je l’ai testée et alors, je n’ai plus cette relation “plusieurs à plusieurs” (que j’ai essayé d’indiquer sur mon schéma)
bdd projet base relations v6.odt (24.1 KB)
: une même “Pièce” ne peut plus être associée à plusieurs “Institutions” et une même “Institution” ne peut plus être associée à plusieurs “Pièces”
Bonne soirée

Là j’ai plus de temps pour jeter un oeil à ta base. Mais faut dire quand même que pour un premier projet, tu n’as pas fait dans la facilité. D’autant plus que si tu as inséré des données, toute modification de la structure est souvent acrobatique.

Niveau tutoriel, je te conseille cette série d’articles (ils ont bien 20 ans, certains ont été mis à jour, mais le contenu est toujours d’actualité) :

https://perso.univ-lemans.fr/~cpiau/BD/SQL_PAGES/

Voici également le script d’une petite base toute simple qui t’aidera à mieux appréhender les principes:

CREATE TABLE T_CLIENTS (
	CLI_ID INTEGER GENERATED BY DEFAULT AS IDENTITY  (START WITH 1, INCREMENT BY 1) NOT NULL,
	CLI_NOM VARCHAR(32) NOT NULL,
	CLI_PRENOM VARCHAR(32) NOT NULL,
	CONSTRAINT PK_CLI_ID PRIMARY KEY (CLI_ID)
);

CREATE TABLE T_PRODUITS (
	PRO_ID INTEGER GENERATED BY DEFAULT AS IDENTITY  (START WITH 1, INCREMENT BY 1) NOT NULL,
	PRO_DES VARCHAR(32) NOT NULL,
	PRO_PUHT DECIMAL(10,2) NOT NULL,
	CONSTRAINT PK_PRO_ID PRIMARY KEY (PRO_ID),
	CONSTRAINT UK_PRO_DES UNIQUE (PRO_DES),
	CONSTRAINT CK_PRO_PUHT CHECK (PRO_PUHT > 0)
);

CREATE TABLE T_FACTURES (
	FAC_ID INTEGER GENERATED BY DEFAULT AS IDENTITY  (START WITH 1, INCREMENT BY 1) NOT NULL,
	CLI_ID INTEGER NOT NULL,
	FAC_DATE DATE NOT NULL,
	CONSTRAINT PK_FAC_ID PRIMARY KEY (FAC_ID),
	CONSTRAINT FK_ACHATS_CLIENTS FOREIGN KEY (CLI_ID) REFERENCES T_CLIENTS (CLI_ID)
);

CREATE TABLE T_FACTURES_LIGNES (
	FAC_ID INTEGER NOT NULL,
	PRO_ID INTEGER NOT NULL,
	FAC_PUHT DECIMAL(10,2) NOT NULL,
	FAC_QTE INTEGER NOT NULL,
	CONSTRAINT PK_FAC_ID_PRO_ID PRIMARY KEY (FAC_ID, PRO_ID),
	CONSTRAINT CK_FAC_PUHT CHECK (FAC_PUHT > 0),
	CONSTRAINT CK_FAC_QTE CHECK (FAC_QTE > 0),
	CONSTRAINT FK_FACTURES_LIGNES_FACTURES FOREIGN KEY (FAC_ID) REFERENCES T_FACTURES (FAC_ID) ON UPDATE CASCADE ON DELETE CASCADE,
	CONSTRAINT FK_FACTURES_LIGNES_PRODUITS FOREIGN KEY (PRO_ID) REFERENCES T_PRODUITS (PRO_ID)
);

Elle comporte 4 tables : T_CLIENTS, T_PRODUITS, T_FACTURES et T_FACTURES_LIGNES. La table des clients et des produits sont dotées chacune d’une clé primaire (automatiquement unique) à incrémentation automatique : GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1). La table des factures également. L’ID correspond au numéro de facture.

Comme une facture ne comprend que rarement un seul produit, une table des lignes de factures est située entre les factures et les produits. Cette table n’a pas besoin de clé primaire propre (à numéro auto) ; on peut imaginer la doter d’un tel champ et d’une clé qui va avec mais ça ne sert strictement à rien de numéroter (au niveau base de données) une telle table. C’est pourquoi les 2 clés étrangères (FK_) qui sont déclarées (FAC_ID et PRO_ID) font référence aux clés primaires de T_FACTURES et de T_PRODUITS. Et cela est défini par la contrainte CONSTRAINT PK_FAC_ID_PRO_ID PRIMARY KEY (FAC_ID, PRO_ID). De la même manière, dans T_FACTURES, la clé étrangère déclarée (CLI_ID) fait référence à la clé primaire de T_CLIENTS. Une fois que tu auras parfaitement assimilé ce principe, tout sera plus facile.

Dans cette base exemple, j’ai également placé quelques contraintes de validation (CK_). On s’assure que le PUHT et la quantité sont supérieurs à 0. On trouve également une contrainte d’unicité (UK_) dans T_PRODUITS ; ceci garanti que 2 produits (PRO_DES : la désignation du produit) ne porteront pas le même nom.

Pour tester cette base, tu en crées une nouvelle. Tu vas dans les tables et dans le menu Outils/SQL et tu copies-colles ce script avant de l’exécuter. Ensuite tu vas dans Affichage/Actualiser les tables. Tu peux alors afficher les relations et voir comment tout ça fonctionne.

SUITE DU MESSAGE PRÉCÉDENT

J’ai restructuré ta base (après avoir extrait le script). Les clés primaires inutiles ont été supprimées. Le script s’exécute correctement, même si je ne comprends toujours pas bien le fonctionnement de ton organisation.

Certaines tables sont inutiles. Par exemple, T_IndividusStatuts. La clé étrangère ID_Statut devrait figurer directement dans T_Individus et être reliée dans T_Statuts. Idem pour T_IndividusPieces. Mais je n’ai pas touché à ça afin de ne pas trop perturber ton infrastructure.

J’ai par contre relevé quelques “malfaçons” dans la table T_Institutions.

  • Le numéro et le nom de la rue ne doivent pas être séparés.
  • Pour le code postal (ainsi que le numéro de rue), tu utilises des champs numériques. On n’utilise de tels types de données que pour les valeurs calculées. Un code postal est donc un CHAR(5).
  • Localités et codes postaux doivent figurer dans une table séparée (dans l’absolu, les adresses aussi mais passons) sinon la table, si elle est conséquente, va comporter de nombreux doublons. C’est pourquoi j’ai ajouté une table T_Localites et une clé étrangère dans T_Institutions. Il faudra donc modifier ces deux tables en conséquence.
CREATE TABLE T_Localites (
	ID_Localite INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL,
	CodePostal CHAR (5) NOT NULL,
	Localite VARCHAR(32) NOT NULL,
	CONSTRAINT PK_ID_Localite PRIMARY KEY (ID_Localite),
	CONSTRAINT CK_CodePostal CHECK (CodePostal BETWEEN '01000' AND '97680'),
	CONSTRAINT UK_CodePostalLocalite UNIQUE (CodePostal, Localite)
);

CREATE TABLE T_Fonctions (
	ID_Fonction INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	Fonction VARCHAR(100)
);

CREATE TABLE T_Structures (
	ID_Structure INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	Structure VARCHAR(50)
);

CREATE TABLE T_Traitements (
	ID_Traitement INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	Traitement VARCHAR(100)
);

CREATE TABLE T_Fonds (
	ID_Fonds INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	FondsNom VARCHAR(50),
	FondsCommentaire LONGVARCHAR,
	FondsDateDebut DATE,
	FondsDateFin DATE
);

CREATE TABLE T_Statuts (
	ID_Statut INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	Statut VARCHAR(10)
);

CREATE TABLE T_Institutions (
	ID_Institution INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	InstitutionNom1 VARCHAR(50),
	InstitutionNom2 VARCHAR(50),
	InstitutionAbreviation VARCHAR(10),
	InstitutionDateDebut DATE,
	InstitutionDateFin DATE,
	ID_Localite INTEGER,
	CONSTRAINT FK_T_Institutions_T_Localites FOREIGN KEY (ID_Localite) REFERENCES T_Localites (ID_Localite)
);

CREATE TABLE T_Individus (
	ID_Individu INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	IndividuNom VARCHAR(100),
	IndividuPrenom VARCHAR(100),
	IndividuCommentaire LONGVARCHAR
);

CREATE TABLE T_Cotes (
	ID_Cote INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	Cote VARCHAR(30)
);

CREATE TABLE T_Natures (
	ID_Nature INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	Nature VARCHAR(100)
);

CREATE TABLE T_Pieces (
	ID_Piece INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
	ID_Nature INTEGER NOT NULL,
	PieceCommentaire LONGVARCHAR,
	PieceDatePrincipale DATE,
	PieceDateAutre1 DATE,
	ID_Cote INTEGER NOT NULL,
	CONSTRAINT SYS_FK_77 FOREIGN KEY(ID_Nature) REFERENCES T_Natures(ID_Nature),
	CONSTRAINT SYS_FK_212 FOREIGN KEY(ID_Cote) REFERENCES T_Cotes(ID_Cote)
);

CREATE TABLE T_IndividusPieces (
	ID_Piece INTEGER NOT NULL,
	ID_Individu INTEGER NOT NULL,
	CONSTRAINT PK_INDIVIDUS_PIECES PRIMARY KEY (ID_Piece, ID_Individu),
	CONSTRAINT SYS_FK_562 FOREIGN KEY(ID_Piece) REFERENCES T_Pieces(ID_Piece),
	CONSTRAINT SYS_FK_88 FOREIGN KEY(ID_Individu) REFERENCES T_Individus(ID_Individu)
);

CREATE TABLE T_InstitutionsPieces (
	ID_Institution INTEGER NOT NULL,
	ID_Piece INTEGER NOT NULL,
	CONSTRAINT SYS_FK_138 FOREIGN KEY(ID_Institution) REFERENCES T_Institutions(ID_Institution),
	CONSTRAINT SYS_FK_167 FOREIGN KEY(ID_Piece) REFERENCES T_Pieces(ID_Piece)
);

CREATE TABLE T_InstitutionsIndividus (
	ID_Institution INTEGER NOT NULL,
	ID_Individu INTEGER NOT NULL,
	DebutInstitutionIndividu DATE,
	FinInstitutionIndividu DATE,
	CONSTRAINT PK_INSTITUTIONS_INDIVIDUS PRIMARY KEY (ID_Institution, ID_Individu),
	CONSTRAINT SYS_FK_155 FOREIGN KEY(ID_Institution) REFERENCES T_Institutions(ID_Institution),
	CONSTRAINT SYS_FK_164 FOREIGN KEY(ID_Individu) REFERENCES T_Individus(ID_Individu)
);

CREATE TABLE T_IndividusStatuts (
	ID_Individu INTEGER NOT NULL,
	ID_Statut INTEGER NOT NULL,
	CONSTRAINT PK_INDIVIDUS_STATUTS PRIMARY KEY (ID_Individu, ID_Statut),
	CONSTRAINT SYS_FK_461 FOREIGN KEY(ID_Statut) REFERENCES T_Statuts(ID_Statut),
	CONSTRAINT SYS_FK_528 FOREIGN KEY(ID_Individu) REFERENCES T_Individus(ID_Individu)
);

CREATE TABLE T_PiecesTraitements (
	ID_Piece INTEGER NOT NULL,
	ID_Traitement INTEGER NOT NULL,
	DateTraitement DATE,
	CONSTRAINT PK_PIECES_TRAITEMENTS PRIMARY KEY (ID_Piece, ID_Traitement),
	CONSTRAINT SYS_FK_497 FOREIGN KEY(ID_Piece) REFERENCES T_Pieces(ID_Piece),
	CONSTRAINT SYS_FK_500 FOREIGN KEY(ID_Traitement) REFERENCES T_Traitements(ID_Traitement)
);

CREATE TABLE T_IndividusFonctions (
	ID_Individu INTEGER NOT NULL,
	ID_Fonction INTEGER NOT NULL,
	DebutFonctionIndividu DATE,
	FinFonctionIndividu DATE,
	CONSTRAINT PK_INDIVIDUS_FONCTIONS PRIMARY KEY (ID_Individu, ID_Fonction),
	CONSTRAINT SYS_FK_732 FOREIGN KEY(ID_Individu) REFERENCES T_Individus(ID_Individu),
	CONSTRAINT SYS_FK_735 FOREIGN KEY(ID_Fonction) REFERENCES T_Fonctions(ID_Fonction)
);

CREATE TABLE T_StructuresFonds (
	ID_Structure INTEGER NOT NULL,
	ID_Fonds INTEGER NOT NULL,
	ID_Cote INTEGER NOT NULL,
	CONSTRAINT PK_STRUCTURES_FONDS_COTES PRIMARY KEY (ID_Structure, ID_Fonds, ID_Cote),
	CONSTRAINT SYS_FK_813 FOREIGN KEY(ID_Structure) REFERENCES T_Structures(ID_Structure),
	CONSTRAINT SYS_FK_816 FOREIGN KEY(ID_Fonds) REFERENCES T_Fonds(ID_Fonds),
	CONSTRAINT SYS_FK_819 FOREIGN KEY(ID_Cote) REFERENCES T_Cotes(ID_Cote)
);

Merci mille fois Primus pour ce temps passé à mon… projet !
Je vais regarder tout ça : le tuto sur les bdd en Sql, ton exemple et même ton script de structuration de ma base :clap: :clap: (je viens de comprendre que dans Base, il suffit d’entrer ces instructions Sql dans la fenêtre Outil/Sql !).

  • Pour l’instant les données rentrées sont fictives (mon idée étant d’attendre que le proto de ma bdd soit au point pour l’utiliser en vrai, après y avoir importé !! des données stockées actuellement dans des tables Calc :stuck_out_tongue_winking_eye:)
  • J’ai essayé d’expliquer dans mon 2ème message ce que je veux faire : en résumé il s’agit de l’exploitation de pièces d’archives : pour chacune je veux pouvoir lui associer des infos, par exemple concernant des Institutions sachant qu’une même Pièce peut être associée à +sieurs Institutions et une même Institution associé à +sieurs Pièces : d’où ma création de Tables d’associations pour gérer ces relations +sieurs à +sieurs. Et ce que j’ai cru comprendre de ta préconisation : “par exemple, la table T_InstitutionsPieces, qui relie T_Pieces et T_Institutions. Le champ (et donc la clé primaire) ID_InstitutionsPieces est inutile. Il faut utiliser comme clé primaire les 2 clés ID_Institution et ID_Piece
    c’est qu’avec ces 2 clés primaires : il ne pourra y avoir une même Institution associée à 2,3 ou plus Pièces différentes ni une même Pièce associée à 2,3 ou plus Institutions ? Mais c’est bien possible que je me trompe :crazy_face:
    Bien noté les remarques pour “Adresse”, éclatement en plusieurs tables : par paresse, j’avais fait l’impasse dessus :face_with_open_eyes_and_hand_over_mouth: et utilisation de CHAR et pas de NUMERIC : très utile à savoir
    Je regarde tout ça et reviens ici dans quelques jours.
    Bonne semaine

Sur le fond je peux peut-être comprendre un peu mais pas sur la forme, puisque c’est un domaine que je ne connais pas. Néanmoins, pour répondre à ton questionnement, toutes les relations sont de 1 à plusieurs (1:N) ; tu pourras donc faire les associations que tu veux.

Il y a quand même des choses qui attirent mon attention. Par exemple, à quoi servent les dates dans la table T_InstitutionsIndividus ?

Bref, après ça faudra créer les requêtes et les formulaires pour la saisie et ça n’est pas non plus de tout repos quand on débute.

Dernière version, écrite à ma manière et épurée (autant que ce peu selon ce que je peux essayer de comprendre au fonctionnement). Les tables de liaison sont préfixées TJ au lieu de T. Les noms de colonnes sont standardisées afin de s’y retrouver très facilement. J’ai également ajouté des NOT NULL là où il le fallait.

Bon courage. :slightly_smiling_face:

CREATE TABLE T_LOCALITES (
	LOC_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL,
	LOC_CP CHAR (5) NOT NULL,
	LOC_LABEL VARCHAR (32) NOT NULL,
	CONSTRAINT PK_LOC_ID PRIMARY KEY (LOC_ID),
	CONSTRAINT CK_LOC_CP CHECK (LOC_CP BETWEEN '01000' AND '97680'),
	CONSTRAINT UK_LOC_LABEL UNIQUE (LOC_CP, LOC_LABEL)
);

CREATE TABLE T_FONCTIONS (
	FON_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	FON_LABEL VARCHAR (100) NOT NULL
);

CREATE TABLE T_STRUCTURES (
	STR_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	STR_LABEL VARCHAR (50) NOT NULL
);

CREATE TABLE T_TRAITEMENTS (
	TRA_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	TRA_LABEL VARCHAR (100) NOT NULL
);

CREATE TABLE T_FONDS (
	FON_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	FON_NOM VARCHAR (50) NOT NULL,
	FON_COM LONGVARCHAR,
	FON_DATE_DEB DATE,
	FON_DATE_FIN DATE
);

CREATE TABLE T_STATUTS (
	STA_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	TRA_LABEL VARCHAR (10) NOT NULL
);

CREATE TABLE T_INDIVIDUS (
	IND_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	STA_ID INTEGER NOT NULL,
	IND_NOM VARCHAR (100) NOT NULL,
	IND_PRENOM VARCHAR (100) NOT NULL,
	IND_COM LONGVARCHAR,
	CONSTRAINT FK_101 FOREIGN KEY (STA_ID) REFERENCES T_STATUTS (STA_ID)
);

CREATE TABLE T_INSTITUTIONS (
	INS_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	LOC_ID INTEGER NOT NULL,
	INS_NOM_1 VARCHAR (50) NOT NULL,
	INS_NOM_2 VARCHAR (50),
	INS_ABR VARCHAR (10),
	INS_DATE_DEB DATE,
	INS_DATE_FIN DATE,
	CONSTRAINT FK_102 FOREIGN KEY (LOC_ID) REFERENCES T_LOCALITES (LOC_ID)
);

CREATE TABLE T_COTES (
	COT_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	COT_LABEL VARCHAR (30) NOT NULL
);

CREATE TABLE T_NATURES (
	NAT_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	NAT_LABEL VARCHAR (100) NOT NULL
);

CREATE TABLE T_PIECES (
	PIE_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL PRIMARY KEY,
	NAT_ID INTEGER NOT NULL,
	COT_ID INTEGER NOT NULL,
	PIE_COM LONGVARCHAR,
	PIE_DATE_1 DATE,
	PIE_DATE_2 DATE,
	CONSTRAINT FK_103 FOREIGN KEY (NAT_ID) REFERENCES T_NATURES (NAT_ID),
	CONSTRAINT FK_104 FOREIGN KEY (COT_ID) REFERENCES T_COTES (COT_ID)
);

CREATE TABLE TJ_INDIVIDUS_PIECES (
	IND_ID INTEGER NOT NULL,
	PIE_ID INTEGER NOT NULL,
	CONSTRAINT PK_INDIVIDUS_PIECES PRIMARY KEY (IND_ID, PIE_ID),
	CONSTRAINT FK_105 FOREIGN KEY (IND_ID) REFERENCES T_INDIVIDUS (IND_ID),
	CONSTRAINT FK_106 FOREIGN KEY (PIE_ID) REFERENCES T_PIECES (PIE_ID)
);

CREATE TABLE TJ_INSTITUTIONS_PIECES (
	INS_ID INTEGER NOT NULL,
	PIE_ID INTEGER NOT NULL,
CONSTRAINT PK_INSTITUTIONS_PIECES PRIMARY KEY (INS_ID, PIE_ID),
	CONSTRAINT FK_107 FOREIGN KEY (INS_ID) REFERENCES T_INSTITUTIONS (INS_ID),
	CONSTRAINT FK_108 FOREIGN KEY (PIE_ID) REFERENCES T_PIECES (PIE_ID)
);

CREATE TABLE TJ_INSTITUTIONS_INDIVIDUS (
	INS_ID INTEGER NOT NULL,
	IND_ID INTEGER NOT NULL,
	IND_DATE_DEB DATE,
	IND_DATE_FIN DATE,
	CONSTRAINT PK_INSTITUTIONS_INDIVIDUS PRIMARY KEY (INS_ID, IND_ID),
	CONSTRAINT FK_109 FOREIGN KEY (INS_ID) REFERENCES T_INSTITUTIONS (INS_ID),
	CONSTRAINT FK_110 FOREIGN KEY (IND_ID) REFERENCES T_INDIVIDUS (IND_ID)
);

CREATE TABLE TJ_PIECES_TRAITEMENTS (
	PIE_ID INTEGER NOT NULL,
	TRA_ID INTEGER NOT NULL,
	TRA_DATE DATE,
	CONSTRAINT PK_PIECES_TRAITEMENTS PRIMARY KEY (PIE_ID, TRA_ID),
	CONSTRAINT FK_111 FOREIGN KEY (PIE_ID) REFERENCES T_PIECES (PIE_ID),
	CONSTRAINT FK_112 FOREIGN KEY (TRA_ID) REFERENCES T_TRAITEMENTS (TRA_ID)
);

CREATE TABLE TJ_INDIVIDUS_FONCTIONS (
	IND_ID INTEGER NOT NULL,
	FON_ID INTEGER NOT NULL,
	FON_DATE_DEB DATE,
	FON_DATE_FIN DATE,
	CONSTRAINT PK_INDIVIDUS_FONCTION PRIMARY KEY (IND_ID, FON_ID),
	CONSTRAINT FK_113 FOREIGN KEY (IND_ID) REFERENCES T_INDIVIDUS (IND_ID),
	CONSTRAINT FK_114 FOREIGN KEY (FON_ID) REFERENCES T_FONCTIONS (FON_ID)
);

CREATE TABLE TJ_STRUCTURES_FONDS (
	STR_ID INTEGER NOT NULL,
	FON_ID INTEGER NOT NULL,
	COT_ID INTEGER NOT NULL,
	CONSTRAINT PK_STRUCTURES_FONDS_COTES PRIMARY KEY (STR_ID, FON_ID, COT_ID),
	CONSTRAINT FK_115 FOREIGN KEY (STR_ID) REFERENCES T_STRUCTURES (STR_ID),
	CONSTRAINT FK_116 FOREIGN KEY (FON_ID) REFERENCES T_FONDS (FON_ID),
	CONSTRAINT FK_117 FOREIGN KEY (COT_ID) REFERENCES T_COTES (COT_ID)
);

Magnifique Primus : j’ai du travail pour toute la semaine :wink:
. Je pensais qu’il y avait une différence entre “un à +sieurs” : “un même Institution peut être associée à +sieurs Individus mais un même Individu ne peut être associé qu’à une Institution”" et “+sieurs à +sieurs” : “un même Institution peut être associé à +sieurs Individus et un même Individu peut être associé à +sieurs Institutions” ; je vais voir approfondir en utilisant ta bdd
. “les dates dans la table T_InstitutionsIndividus ?” : en fait quand je rencontre un Individu (dans une pièce), je peux l’associer à une Institution et éventuellement avec la période pendant laquelle il a été présent dans cette Institution (de la même manière, je peux associer un Individu à une Fonction et éventuellement avec la période pendant laquelle il a occupé cette Fonction)
. “faudra créer les requêtes et les formulaires pour la saisie” : tout à fait exact, j’ai un tout petit peu commencé, mon idée est de partir de formulaires basiques mais opérationnels dont j’améliorerai petit à petit la praticité et convivialité.
Pour l’instant, je cherche à valider la structuration (répartition en tables et relations entre elles) - ce que je vais faire en pratiquant la base que tu as créée - avant de me jeter à l’eau :stuck_out_tongue_winking_eye:
Bonne semaine

J’ai conservé les relations telles qu’elles étaient dans la première base que tu as jointe : des relations 1:N. Après ça, possible que tu t’aperçoives à l’usage que certaines ne sont pas bonnes pour ta structure ; il n’y a que toi qui peux le savoir.

Une relation 1:N (un à plusieurs) signifie qu’une entité (par exemple un client, le côté 1) peut avoir une ou plusieurs factures mais qu’une facture ne peut appartenir qu’à un seul client. En termes de base de données, il faut quand même développer cette définition. Dans le commerce dit traditionnel, c’est-à-dire le commerce physique, une personne qui entre dans un magasin n’est considérée comme client que si elle achète. Mais dans le commerce en ligne, on doit s’inscrire comme client avant (ou au moment) d’acheter. Ce qui veut dire que dans ce cas, une personne peut très bien devenir client en s’inscrivant sans pour autant passer la moindre commande (du moins pas tout de suite). Donc, dans une base de données, dans les fait, un client peut avoir 0, 1 ou plusieurs factures.

Avec une relation similaire, un produit (côté 1) peut figurer dans 0, 1 ou plusieurs factures. Mais, de l’autre côté, un produit ne peut pas figurer plus d’une fois dans la même facture (il ne doit pas figurer dans 2 lignes de la même facture ; si le client désire plus d’une unité, la quantité est là pour combler sa demande). C’est pour cette raison que, comme je te l’avais indiqué dans base, créer une colonne (et une clé primaire) spécifique dans une table de lignes de factures est inutile. L’intégrité est assurée par le couple de clés ID facture et ID produit qui s’assure donc qu’un même produit ne figurera jamais dans 2 lignes d’une même facture.

Pour ton questionnement, prenons le cas d’un médecin traitant. Un médecin traitant peut avoir 0 (quoi qu’à zéro, si il n’en reste pas moins médecin, on ne peut plus vraiment dire qu’il soit médecin traitant), 1 ou plusieurs patients ; mais un assuré social (donc un patient) ne peut avoir d’enregistré à la Sécurité Sociale que un et un seul médecin traitant au maximum. Sur la copie d’écran suivante, une relation 1:N est définie côté médecins, mais de 1:1 côté patients. Et tant qu’à faire, le script correspondant (avec une table de jonction TJ là encore sans clé primaire propre à elle).

Noter quand même qu’une clé primaire dans une table de jonction peut être utile, si par exemple, cette dite table est à l’origine d’un formulaire qui va établir des contrats de travail. Dans ce cas, la clé primaire peut servir comme numéro de contrat.

Copie d’écran des relations

CREATE TABLE T_INDIVIDUS_CA (
	IND_CA_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL,
	IND_CA_LIB VARCHAR(16) NOT NULL,
	CONSTRAINT PK_IND_CA_ID PRIMARY KEY (IND_CA_ID)
);

CREATE TABLE T_INDIVIDUS (
	IND_ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL,
	IND_CA_ID INTEGER NOT NULL,
	IND_NOM VARCHAR(32) NOT NULL,
	IND_PRENOM VARCHAR(32) NOT NULL,
	CONSTRAINT PK_IND_ID PRIMARY KEY (IND_ID),
	CONSTRAINT FK_INDIVIDUS_INDIVIDUS_CA FOREIGN KEY (IND_CA_ID) REFERENCES T_INDIVIDUS_CA (IND_CA_ID)
);

CREATE TABLE T_PATIENTS (
	PAT_ID INTEGER NOT NULL,
	PAT_DATE_NAI DATE NOT NULL,
	PAT_NUM_SS CHAR(15),
	CONSTRAINT PK_PAT_ID PRIMARY KEY (PAT_ID),
	CONSTRAINT FK_PATIENTS_INDIVIDUS FOREIGN KEY (PAT_ID) REFERENCES T_INDIVIDUS (IND_ID)
);

CREATE TABLE T_MEDECINS (
	MED_ID INTEGER NOT NULL,
	MED_NUM_ADELI CHAR(9),
	CONSTRAINT PK_MED_ID PRIMARY KEY (MED_ID),
	CONSTRAINT FK_MEDECINS_INDIVIDUS FOREIGN KEY (MED_ID) REFERENCES T_INDIVIDUS (IND_ID)
);

CREATE TABLE TJ_PATIENTS_MEDECINS (
	PAT_ID INTEGER NOT NULL,
	MED_ID INTEGER NOT NULL,
	CONSTRAINT PK_PAT_MED_ID PRIMARY KEY (PAT_ID),
	CONSTRAINT FK_PATIENTS_MEDECINS FOREIGN KEY (PAT_ID) REFERENCES T_PATIENTS (PAT_ID),
	CONSTRAINT FK_MEDECINS_PATIENTS FOREIGN KEY (MED_ID) REFERENCES T_MEDECINS (MED_ID)
);

Merci Primus pour toutes ces informations :+1:
Je dois clarifier cette histoire de Relation “n à n” : dans mon schéma de relations
bdd projet base relations v6.odt (24.1 KB)
je pensais avoir défini sept relations “n à n” ((les flèches bleues), deux “1 à n” et une “1 à 1”
Pour l’instant, je vais étudier et digérer tout ce que tu as posté et reviens en fin de semaine
Bonne soirée

Question de vocabulaire il me semble. Toutes tes relations sont de même nature, 1:N.

https://www.zupimages.net/up/22/10/laod.png

Une relation est “plusieurs à plusieurs” lorsqu’une table intermédiaire est située entre deux tables avec comme clé primaire les clés des deux dites tables. Exemple caractéristique avec une table de lignes de factures placée entre celle des factures et celle des produits.

Encore merci Primus :grinning: J’ai travaillé sur la base que tu as écrite pour moi. Globalement j’en ai compris la logique (où je retrouve finalement ma démarche initiale, à part ma gestion des Tables Jointes et de leurs PKs !) et j’en retiens les exigences de rigueur dans la construction, dans l’appellation des tables, des champs… :+1: Je mets une version avec deux créations de TJ ! :

  1. Une TJ pour “Individus et Statuts” : car un même individu peut avoir +sieurs statuts différents et un même statut va être associé à +sieurs individus.
  2. Une TJ pour “Individu_Institution_Fonction” [mais je ne suis pas sûr du tout qu’elle soit adaptée ??] : en effet, je réorganise la structuration dans ce sens :
  • un Individu peut ne pas être associé à une Institution et dans cas, il n’aura pas de Fonction
  • si un Individu est associé à une Institution, il peut être associé à une ou plusieurs Fonction(s) (donc associée(s) à cette Institution), sur des périodes éventuellement précisées… Je vais travailler aussi sur tes 2 autres tables : les Médecins et leurs patients et les Factures pour finir de bien comprendre ces relations “n à n”
    ask.libreoffice.org 22 03 11 v2.odb (5.0 KB)
    !
    Bon vikend

C’est toujours le même problème. Structurellement, une base peut être parfaite, mais seul celui qui a les mains dedans sait comment elle doit être gérée et si des choses sont à modifier. Je me souviens d’une amie, comptable, qui m’avait demandé la mise en forme sur tableur d’une formule de comptabilité dont je n’entendais absolument rien. :woozy_face: Ça n’avait pas été facile…

Édit : je viens de regarder les relations dans la dernière base que tu as fournie et je me demande l’utilité de la table TJ_INDIVIDUS_STATUTS. Et en plus, attention aux confusions, dans T_STATUTS tu as nommé la colonne TRA_LABEL au lieu de STA_LABEL.