[Résolu] Intégrité référentielle avec requête INSERT

Discussions sur le module de base de données Base et plus particulièrement sur le langage SQL ou sur les connexions aux SGBD tiers.
Les questions sur les macros doivent être postées dans la section dédiée en dessous.

Modérateur : Vilains modOOs

Règles du forum
Cette section est dédiée au module Base et plus particulièrement sur le langage SQL ou sur les connexions aux SGBD tiers. Vous ne devez pas poster ici de questions sur les macros mais utiliser la section éponyme.
Pour accélérer les réponses, vous pouvez mettre en ligne votre base en joignant un fichier ODB : comment faire.
Xylo
Membre hOOnoraire
Membre hOOnoraire
Messages : 116
Inscription : 08 nov. 2013 14:50

[Résolu] Intégrité référentielle avec requête INSERT

Message par Xylo »


La modération vous a écrit: Le titre du sujet a été débarrassé de Problème d', le terme étant inutile car il n'est pas explicite

Bonjour.

Ce sujet fait suite à celui-ci : https://forum.openoffice.org/fr/forum/v ... =8&t=63266

Mais comme il s'agit d'un problème purement lié au SQL, je le poste dans cette section.

La macro, qui techniquement fonctionne parfaitement, exécute 3 requêtes via un bouton. La première requête est OK :

Code : Tout sélectionner

INSERT INTO T_SAISIE (SAI_ANNEE, SAI_MOIS) SELECT SAI_VD_ANNEE, SAI_VD_MOIS FROM T_SAISIE_VD
Les données de la table T_SAISIE_VD (qui ne comprendra toujours qu'une seule ligne) sont copiées dans la table T_SAISIE. C'est au niveau des 2 autres que quelque chose ne fonctionne pas.

Chacune de ces 2 requêtes est identique : copier les enregistrements (et là il y a plusieurs lignes) de la table T_PARTS_A_VD dans la table T_PARTS_A. Et idem pour T_PARTS_B.

Code : Tout sélectionner

INSERT INTO T_PARTS_A (PAR_A_LIB, PAR_A_TAUX) SELECT PAR_A_VD_LIB, PAR_A_VD_TAUX FROM T_PARTS_A_VD
À l'exécution j'ai ce message d'erreur qui s'affiche :
copie.png
Je sais ce qu'il veut dire mais je ne sais pas le résoudre. Dans la table T_PARTS_A (et T_PARTS_B), il faut également que soit inséré SAI_ID de la table T_SAISIE pour respecter comme il se doit l'intégrité référentielle.

Merci.
Vous ne pouvez pas consulter les pièces jointes insérées à ce message.
Dernière modification par Xylo le 12 déc. 2020 08:44, modifié 1 fois.
Libre Office 7.1.8.1 - Linux Mint 20.3 Una
Avatar de l’utilisateur
jeanmimi
Grand Maître de l'OOffice
Grand Maître de l'OOffice
Messages : 16960
Inscription : 03 mars 2006 16:02
Localisation : Venise verte

Re: intégrité référentielle avec requête INSERT

Message par jeanmimi »

Bonjour,
Après avoir modifié les champs de la Table T_SAISIE en Entrée requise : Non
j'ai testé l'instruction SQL de la première requête en SQL direct :
Instruction SQL INSERT.jpg
Même chose avec la deuxième instruction SQL, en modifiant le champ SAI_D de la Table T_PARTS_A : Valeur automatique : Non, Entrée requise : Non
Instruction SQL INSERT 2.jpg
Vous ne pouvez pas consulter les pièces jointes insérées à ce message.
Dernière modification par jeanmimi le 10 déc. 2020 13:04, modifié 1 fois.
LibreOffice : Version : 24.2 (x64)(12 avril 2024)
Adoptium JRE ou Oracle JRE (x64), Windows 10, Thunderbird, Firefox
Xylo
Membre hOOnoraire
Membre hOOnoraire
Messages : 116
Inscription : 08 nov. 2013 14:50

Re: intégrité référentielle avec requête INSERT

Message par Xylo »

Oui mais cette requête-là fonctionne, c'est avec les deux autres qu'il y a un problème d'intégrité référentielle.
Libre Office 7.1.8.1 - Linux Mint 20.3 Una
Avatar de l’utilisateur
jeanmimi
Grand Maître de l'OOffice
Grand Maître de l'OOffice
Messages : 16960
Inscription : 03 mars 2006 16:02
Localisation : Venise verte

Re: intégrité référentielle avec requête INSERT

Message par jeanmimi »

Xylo a écrit :c'est avec les deux autres
Quelles deux autres ?
LibreOffice : Version : 24.2 (x64)(12 avril 2024)
Adoptium JRE ou Oracle JRE (x64), Windows 10, Thunderbird, Firefox
Xylo
Membre hOOnoraire
Membre hOOnoraire
Messages : 116
Inscription : 08 nov. 2013 14:50

Re: intégrité référentielle avec requête INSERT

Message par Xylo »

En tout il y a 3 requêtes : la première remplit les champs de T_SAISIE avec les données de T_SAISIE_V et est OK. La seconde et la troisième doivent remplir les champs de T_PARTS_A et T_PARTS_B avec les données de T_PARTS_A_VD et T_PARTS_B_VD. Si on exécute ces requêtes individuellement, ça fonctionne mais ça n'a pas de sens puisque c'est depuis le formulaires F_SAISIE que les 3 exécutions doivent se faire ; et la colonne SAI_ID de T_PARTS_A et T_PARTS_B (clé étrangère) doit obligatoirement contenir le même ID que SAI_ID de T_SAISIE, la clé primaire (comme les 2 premiers enregistrements que j'ai remplis manuellement).

Code : Tout sélectionner

Sub InsertSaisie

   Dim Context As Object
   Dim Database As Object
   Dim Connection As Object
   Dim Statement As Object
   Dim strSQL As String
   Dim oForm As Object
   Dim ODate As Object
   
   Context = CreateUnoService("com.sun.star.sdb.DatabaseContext")
   Database = Context.GetByName("mdlSaisie")
   Connection = Database.GetConnection("","")
   Statement = Connection.CreateStatement()
   
' FONCTIONNE
   strSQL = "INSERT INTO T_SAISIE (SAI_ANNEE, SAI_MOIS) SELECT SAI_VD_ANNEE, SAI_VD_MOIS FROM T_SAISIE_VD"
   
' PROBLÈME D'INTÉGRITÉ RÉFÉRENTIELLE
   strSQL = "INSERT INTO T_PARTS_A (PAR_A_LIB, PAR_A_TAUX) SELECT PAR_A_VD_LIB, PAR_A_VD_TAUX FROM T_PARTS_A_VD"

' PROBLÈME D'INTÉGRITÉ RÉFÉRENTIELLE
   strSQL = "INSERT INTO T_PARTS_B (PAR_B_LIB, PAR_B_TAUX) SELECT PAR_B_VD_LIB, PAR_B_VD_TAUX FROM T_PARTS_B_VD"
   
   Statement.ExecuteUpdate(strSQL)
   
   Connection.Close()
   
   oForm = ThisComponent.DrawPage.Forms.GetByName("frmSaisie")
   oForm.Reload()
   oForm.Last()
   
   oDate =  oForm.GetByName("datSaiDate")
   oDate.Date = CDateToUnoDate(Date())
   oDate.Commit
   
End Sub
Libre Office 7.1.8.1 - Linux Mint 20.3 Una
Avatar de l’utilisateur
jeanmi2403
SuppOOrter
SuppOOrter
Messages : 1398
Inscription : 18 janv. 2008 09:02
Localisation : Val de Marne

Re: intégrité référentielle avec requête INSERT

Message par jeanmi2403 »

Bonjour,
Ça ne peut pas se faire tout seul !! La requête ne peut pas savoir quoi y mettre, d'où le problème d'intégrité (Attempt to insert Null)
Il faut que tu récupère la clé primaire de l'enregistrement que tu viens d'insérer dans la table principale pour l'injecter dans la clé étrangère de la seconde table.
ça se fait automatiquement avec la relation quand c'est à travers le formulaire.
Jeanmimi a écrit :Après avoir modifié les champs de la Table T_SAISIE en Entrée requise : Non
j'ai testé l'instruction SQL de la première requête en SQL direct :
Effectivement, les enregistrements sont bien ajoutés, mais sans la clé....Logique.

Ceci dit, je ne compreds pas pourquoi recopier tous les enregistrements de la table pour chaque enregistrement de la table saisie.
Bonne journée,
Dernière modification par jeanmi2403 le 10 déc. 2020 15:29, modifié 2 fois.
Jean-Michel
LibO 7.5.9 et AoO 4.1.15 sur Windows 11 & Ubuntu 22.04
LibO 7.6 sur OpenSuse & Linux MX
Xylo
Membre hOOnoraire
Membre hOOnoraire
Messages : 116
Inscription : 08 nov. 2013 14:50

Re: intégrité référentielle avec requête INSERT

Message par Xylo »

jeanmi2403 a écrit :Ça ne peut pas se faire tout seul
Mais ça j'en suis conscient mais je ne sais pas comment faire, d'où ce sujet.

Édit 18 heures

J'ai ressorti une base Access. La requête exécutée dans la procédure est celle-ci :

Code : Tout sélectionner

INSERT INTO T_PARTS_A (PAR_A_LIB, PAR_A_TAUX)
SELECT T_SAISIE.SAI_ID, T_PARTS_A_VD.PAR_A_VD_LIB, T_PARTS_A_VD.PAR_A_VD_TAUX
FROM T_SAISIE, T_PARTS_A_VD
WHERE (((T_SAISIE.SAI_ID) In (SELECT Max(SAI_ID) FROM T_SAISIE)));
Mais LO n'en veut pas, il me renvoit ce message d'erreur que je ne comprends pas :
copie2.png
jeanmi2403 a écrit :Ceci dit, je ne compreds pas pourquoi recopier tous les enregistrements de la table pour chaque enregistrement de la table saisie.
Cas pratique : un bulletin de paie. Les tables T_PARTS_A et T_PARTS_B pourraient contenir les cotisations salariales et patronales. À chaque génération d'une fiche, ces cotisations, dont les valeurs sont stockées dans T_PARTS_A_VD et T_PARTS_B_VD, sont incorporées dans ces deux tables (les intitulés ne le sont pas en dur) avec leur taux, leur montant, etc.

Édit 19 heures 10

J'avais oublié une colonne dans le script :

Code : Tout sélectionner

INSERT INTO T_PARTS_A (SAI_ID, PAR_A_LIB, PAR_A_TAUX)
SELECT T_SAISIE.SAI_ID, T_PARTS_A_VD.PAR_A_VD_LIB, T_PARTS_A_VD.PAR_A_VD_TAUX
FROM T_SAISIE, T_PARTS_A_VD
WHERE (((T_SAISIE.SAI_ID) In (SELECT Max(SAI_ID) FROM T_SAISIE)));
Là, oups ! Les données sont copiées dans le dernier enregistrement !

Dernier édit

J'avais oublié de reporter la ligne Execute. Là je pense que c'est bon :

Code : Tout sélectionner

Sub InsertSaisie

   Dim Context As Object
   Dim Database As Object
   Dim Connection As Object
   Dim Statement As Object
   Dim strSQL As String
   Dim oForm As Object
   Dim ODate As Object
   
   Context = CreateUnoService("com.sun.star.sdb.DatabaseContext")
   Database = Context.GetByName("mdlSaisie")
   Connection = Database.GetConnection("","")
   Statement = Connection.CreateStatement()
  
   strSQL = "INSERT INTO T_SAISIE (SAI_ANNEE, SAI_MOIS) SELECT SAI_VD_ANNEE, SAI_VD_MOIS FROM T_SAISIE_VD"
   Statement.ExecuteUpdate(strSQL)
   strSQL = "INSERT INTO T_PARTS_A (SAI_ID, PAR_A_LIB, PAR_A_TAUX) SELECT T_SAISIE.SAI_ID, T_PARTS_A_VD.PAR_A_VD_LIB, T_PARTS_A_VD.PAR_A_VD_TAUX FROM T_SAISIE, T_PARTS_A_VD WHERE (((T_SAISIE.SAI_ID) In (SELECT Max(SAI_ID) FROM T_SAISIE)));"
   Statement.ExecuteUpdate(strSQL)
   strSQL = "INSERT INTO T_PARTS_B (SAI_ID, PAR_B_LIB, PAR_B_TAUX) SELECT T_SAISIE.SAI_ID, T_PARTS_B_VD.PAR_B_VD_LIB, T_PARTS_B_VD.PAR_B_VD_TAUX FROM T_SAISIE, T_PARTS_B_VD WHERE (((T_SAISIE.SAI_ID) In (SELECT Max(SAI_ID) FROM T_SAISIE)));"
   Statement.ExecuteUpdate(strSQL)
   
   Connection.Close()
   
   oForm = ThisComponent.DrawPage.Forms.GetByName("frmSaisie")
   oForm.Reload()
   oForm.Last()
   
   oDate =  oForm.GetByName("datSaiDate")
   oDate.Date = CDateToUnoDate(Date())
   oDate.Commit
   
End Sub
J'attends un peu pour clôturer, après quelques tests...
Vous ne pouvez pas consulter les pièces jointes insérées à ce message.
Libre Office 7.1.8.1 - Linux Mint 20.3 Una
Avatar de l’utilisateur
jeanmi2403
SuppOOrter
SuppOOrter
Messages : 1398
Inscription : 18 janv. 2008 09:02
Localisation : Val de Marne

Re: intégrité référentielle avec requête INSERT

Message par jeanmi2403 »

Bonsoir,
Xylo a écrit :J'avais oublié une colonne dans le script :
Le message d'erreur était explicite ! :bravo:
Pour réinitialiser les Autochamp après tous les essais:

Code : Tout sélectionner

ALTER TABLE "table" ALTER COLUMN column RESTART WITH value 
Bonne soirée,
Dernière modification par jeanmi2403 le 10 déc. 2020 20:44, modifié 1 fois.
Jean-Michel
LibO 7.5.9 et AoO 4.1.15 sur Windows 11 & Ubuntu 22.04
LibO 7.6 sur OpenSuse & Linux MX
Avatar de l’utilisateur
jeanmi2403
SuppOOrter
SuppOOrter
Messages : 1398
Inscription : 18 janv. 2008 09:02
Localisation : Val de Marne

Re: intégrité référentielle avec requête INSERT

Message par jeanmi2403 »

Re-Bonsoir,
SI je peux me permettre, un petit conseil pour l'organisation.
Pour me faciliter les choses, la clé primaire de toutes mes tables est nommée ID, et les clés étrangères ID_Nom, où Nom est le nom de la table où elles sont liées.
Il est ainsi plus aisé d'écrire les requêtes, par exemple WHERE "Table1.ID"="Table2.ID_Table1"
Mais ce n'est que mon point de vue.
Bonne soirée,
Jean-Michel
LibO 7.5.9 et AoO 4.1.15 sur Windows 11 & Ubuntu 22.04
LibO 7.6 sur OpenSuse & Linux MX
Xylo
Membre hOOnoraire
Membre hOOnoraire
Messages : 116
Inscription : 08 nov. 2013 14:50

Re: intégrité référentielle avec requête INSERT

Message par Xylo »

Oui, le message d'erreur était explicite mais comme je n'avais pas vu qu'il manquait une colonne, je le trouvais incompréhensible.

Pour la réinitialisation de l'incrémentation, c'est ok aussi. Au niveau des ID, je vais voir tout ça.

Tout fonctionne très bien, même en exécutant la macro à partir d'un enregistrement déjà rempli, il en crée un nouveau et se positionne dessus. Par contre, il reste un détail. À la base, j'avais défini comme NOT NULL les champs date, mois, année, référence et code. Pour les trois premiers, pas de problème, la requête les remplit. Mais en l'état, je ne peux pas définir référence et code comme non nuls puisque la contrainte serait violée juste après oForm.Reload() étant donné que ces champs ne sont pas encore remplis, d'où un message d'erreur qui l'indique. C'est un tout petit détail mais quand même...
Libre Office 7.1.8.1 - Linux Mint 20.3 Una
Avatar de l’utilisateur
Dolev
InconditiOOnnel
InconditiOOnnel
Messages : 951
Inscription : 19 août 2018 05:20

Re: intégrité référentielle avec requête INSERT

Message par Dolev »

Bonjour,

Souvent quand les requêtes ne fonctionnent pas (ou mal) c'est que le modèle relationnel est incorrect.
relations.JPG
Pourrais-tu expliquer ce que représente chaque table?
On dirait qu'il y a de la redondance.
Vous ne pouvez pas consulter les pièces jointes insérées à ce message.
Open Office 4.1.15 sous Windows 11
Xylo
Membre hOOnoraire
Membre hOOnoraire
Messages : 116
Inscription : 08 nov. 2013 14:50

Re: intégrité référentielle avec requête INSERT

Message par Xylo »

Dolev a écrit :Pourrais-tu expliquer ce que représente chaque table? On dirait qu'il y a de la redondance.
Les 3 tables avec suffixe VD représentent les valeurs par défaut dont les enregistrements sont insérés dans les 3 tables T_SAISIE, T_PARTS_A et T_PARTS_B. Ces 3 tables VD comprennent un nombre d'enregistrements fixes (sauf évidemment pour T_SAISIE qui ne contient qu'une ligne) qui peuvent éventuellement être modifiés en fonction de différentes choses (tel un taux qui change d'un mois à l'autre).

Pour ce qui est de la table T_SAISIE, dans Access j'utilisais une fonction de domaine pour arriver à mes fins. Cas pratique : une facturation. Chaque mois, on doit insérer le mois en cours et l'année. Grâce à la macro et à la requête, ça évite de la saisir à la main pour chaque facture créée.

Pour les tables PARTS, comme je l'ai déjà dit, les requêtes permettent l'insertion de plusieurs lignes dans un sous-formulaire en un seul clic, ce qui serait extrêmement fastidieux à faire à la main (sans compter les risques d'oubli et donc d'erreurs). Là il s'agit d'une base de test. Dans la réalité, aucune valeur en dur de type CHAR ou VARCHAR n'est insérée. Par exemple, dans la colonne PAR_A_LIB (qui contient les lignes Valeur 1A, Valeur 1B, etc...), avec une base réelle, ce champ serait une clé étrangère de type INTEGER qui irait chercher les valeurs dans une table spécifique. Ainsi, il n'y a pas de redondance.

Autre cas pratique : la saisie d'opérations comptables. Admettons une écriture d'achats de marchandises au comptant. Une telle écriture va comporter à la base 6 enregistrements dans le sous-formulaire. Tout saisir manuellement, c'est long et chiant, sans compter les risques d'erreur. Avec différents presets paramétrés dans des tables spécifiques, il n'y a qu'à insérer et saisir les montants dans les bonnes colonnes (indiquées par une valeur 0.00).
Libre Office 7.1.8.1 - Linux Mint 20.3 Una