PC SOFT

PROFESSIONAL NEWSGROUPS
WINDEVWEBDEV and WINDEV Mobile

Home → WINDEV 2024 → Insérer plusieurs données dans une rubrique
Insérer plusieurs données dans une rubrique
Started by Pierre, Oct., 31 2020 12:37 AM - 15 replies
Registered member
21 messages
Popularité : +1 (1 vote)
Posted on October, 31 2020 - 12:37 AM
Bonjour,
je cherche à intégrer plusieurs données dans une rubrique, par exemple avoir plusieurs créneaux dans la rubrique Creneaux d'une table client. Peut importe si je les stock en tant qu'ID ou texte.
J'ai créé donc une table Créneaux avec tous les créneaux possibles, lors de la création d'un client je lui affecte certains créneaux (les créneaux où tel client est dispo).
J'ai du passer par une table relais pour la relation client et créneaux à cause des cardinalités.
Du coup j'ai un IDcréneaux dans la table client mais je vois pas comment insérer plusieurs id créneaux dans cette rubrique qui est sensée être une clé unique.






Merci d'avance pour vos lumières.
Registered member
188 messages
Popularité : +12 (12 votes)
Posted on October, 31 2020 - 10:31 AM
Bonjour

A priori si comme je le comprends un client peut avoir plusieurs créneaux la manière classique de résoudre le point avec une base de données relationnelle est de faire comme vous l'avez fait via une table de relation. Dans ce cas il vous faut simplement retirer le champs IDCreneaux de la table client car il n'a pas d'utilité. C'est la voie recommandée par la norme SQL Qu'est-ce qui ne vous plait pas dans cette approche relationnelle ?

Certains SGBD offrent sinon des champs de type tableau qui permettent donc de faire du "multi value" donc de stocker plusieurs valeurs dans un tableau lié à l'enregistrement. De mon point de vue cela complique plutôt les choses et on s'éloigne de la norme SQL mais apparemment HFSQL le permet. Sans raison valable je vous déconseille plutôt cette solution.

Lorsque le volume de données devient énorme par contre la modélisation relationnelle peut montrer ses limites, les jointures SQL prenant trop de temps à s'exécuter. Le "multi value" devient alors nécessaire et c'est l'un des objectifs des bases dites "NoSQL" de proposer un stockage plus adapté souvent sous forme d'un empilement de "documents" pouvant contenir un chainage de données. Ici un "document" client pour contenir les informations détails des créneaux liés supprimant ainsi la nécessité de jointure SQL. Si vous n'êtes pas dans cette situation de très forte volumétrie le plus simple est de rester dans le monde relationnel qui a fait ses preuves offrant notamment des garanties en terme d'intégrité des données, ce que n'offre pas le monde NoSQL.

Pour résumer si votre situation exige du "multi value" alors il faut partir sur une base de données adaptée donc NoSQL (mongoDB etc...) sinon il vaut mieux rester sur du relationnel classique comme vous l'avez fait. Dans tous les cas évitez plutôt les champs de type tableau, une fausse bonne idée.

Dernier point, les moteurs SQL offre souvent une syntaxe pour "aplatir" les données liées dans une requête de sélection (souvent avec jointure). Imaginons que vous souhaitiez obtenir comme résultat de votre requête SQL IDClient,Nom,Liste des IDCreneaux (ou liste des libellés créneaux) du client en ligne. Avec HFSQL vous pouvez facilement obtenir ce résultat avec la fonction SQL STRING_AGG. Autrement dit vous pouvez obtenir un résultat "multi value" sans subir les désagréments d'un stockage "multi value". C'est l'approche à privilégier.

J'espère vous avoir éclairé plus qu'embrouillé n'hésitez pas si vous avez besoin de plus d'explications.

--
Côme, Clairinfo
Registered member
188 messages
Popularité : +12 (12 votes)
Posted on October, 31 2020 - 10:58 AM
Et voici un exemple (non testé) plus concret d'une telle requête sur votre modèle de données
SELECT Client.IDClient,Client.Nom,STRING_AGG(Creneaux.Libelle,';') AS Libelle FROM Client JOIN Creneaux_Client ON (Client.IDClient=Creneaux_Client.IDClient) JOIN Creneaux ON(Creneaux.IDCreneaux=Creneaux_Client.IDCreneaux) GROUP BY Client.IDClient

Sauf coquille de ma part vous devriez obtenir en ligne IDClient,Nom, Liste des Libellés créneaux du client séparés par un point virgule.

--
Côme, Clairinfo
Registered member
188 messages
Popularité : +12 (12 votes)
Posted on October, 31 2020 - 11:02 AM
Aïe, il manque sans doute un espace après le second ON : ON (Creneaux.IDCreneaux ...

--
Côme, Clairinfo
Registered member
21 messages
Popularité : +1 (1 vote)
Posted on October, 31 2020 - 8:18 PM
Merci Côme c’est top comme réponse, ça m'a beaucoup aidé. Je vais en effet utiliser la fonction SQL String_AGG qui me parait convenir parfaitement à ce besoin.
J'ai cependant une question au sujet de l'insertion des données, lorsque j'insère un nouveau client je passe par du code wlangage classique tel que :
Client.Nom = SAI_Nom
Client.Prénom = SAI_Prénom
..etc..
HAjoute(Client)

il faut donc que j'insère ensuite les créneaux dans la table Creneaux_Client mais j'imagine que je dois utiliser une requete SQL pour profiter de la fonction agg ?

Merci.
Registered member
188 messages
Popularité : +12 (12 votes)
Posted on November, 01 2020 - 10:28 AM
Bonjour

Alors pour sauvegarder les champs SAI_xxx si ceux-ci sont reliés à une rubrique de la table vous pouvez éviter ces multiples assignations (Client.Nom = yyy Client.Prénom = zzz ...) par une instruction EcranVersFichier() qui fait ce travail pour tous les champs. A l'affichage en sens inverse vous pouvez utiliser FichierVersEcran().

Pour les créneaux le plus classique serait d'afficher sur votre fenêtre client une table présentant les différents créneaux du client. Dans ce cas pas besoin de la requête SQL En cas de doute sur ce point vous pouvez demander au RAD de vous créer une fiche maître détail pour avoir un exemple simple. Le plus classique étant d'ailleurs d'avoir cette table en consultation seule et de présenter 3 boutons <Ajouter> <Modifier> <Supprimer> qui permettent respectivement d'ajouter / modifier dans une petite fiche dédiée (présentant 1 ligne de créneau du client) et par ailleurs de supprimer un enregistrement. Maintenant selon votre maîtrise du code il y différentes possibilités plus élaborées.

Je vous ai présenté cette requête SQL car parfois en terme de présentation (ou de de traitement par code) on souhaite éviter la présentation du détail dans une table séparée, on souhaite récupérer en ligne les données détails et j'ai eu l'impression que c'était peut-être votre demande. Si c'est vraiment le cas oui vous pouvez vous passer de cette table détail, la requête SQL permettant d'afficher dans un simple champ les différents créneaux du client. Mais pour la gestion de ces créneaux (ajout / modification / suppression) vous ne couperez sans doute pas à une fiche avec une table pour pouvoir les sélectionner individuellement.

La présentation fiche + table (pour les détail) est un grand classique, elle est claire pour l'utilisateur, vouloir l'éviter n'est pas forcément un bon choix !

--
Côme, Clairinfo
Registered member
188 messages
Popularité : +12 (12 votes)
Posted on November, 01 2020 - 11:01 AM
En terme de présentation il serait aussi possible d'afficher sur la fiche client une table présentant tous les créneaux disponibles et d'avoir une case à cocher indiquant si le client a pris tel ou tel créneau. Dans ce cas le remplissage de la table serait fait par code en 2 étapes, ajouter tous les créneaux connus puis cocher ceux du client.

En conservant un stockage normalisé (le client dans sa table, ses créneaux dans une autre) vous pourrez très facilement trouver les client inscrits sur tel ou tel créneau par exemple, chose qui serait beaucoup moins simple en adoptant un stockage dénormalisé (mettre les créneaux dans un champ du client ou pire dans des champs Créneau1,Créneau2 ... Là c'est la catastrophe il faudra modifier le programme en cas d'ajout d'un créneau !

--
Côme, Clairinfo
Registered member
3,844 messages
Popularité : +227 (347 votes)
Posted on November, 01 2020 - 11:16 AM
Bonjour,
Je ne vois pas l'intérêt de String_Agg dans ce cas de figure.
Une fois le client et le créneau connus, tout se passe dans la table Créneau_Client.
Il suffit d'affecter les PK de client et de créneau à Créneau_Client.FK_Client, Créneau_Client.FK_Créneau. Windev se charge de calculer la clé composée

--
Il y a peut être plus simple, mais, ça tourne
Registered member
21 messages
Popularité : +1 (1 vote)
Posted on November, 01 2020 - 12:47 PM
Merci pour toutes ces explications et je suis tout à fait d'accord sur ce que vous dites, mais je vais être plus terre à terre, cad que là où je suis coincé c'est que je sais insérer les données clients dans sa table via un HAjoute ou avec les SAI_xxx mais je ne sais pas enregister dans deux tables différentes, dispatcher une partie dans Client et l'autre dans Créneaux_Client.

J'ai donc ajouté dans la fenêtre d'ajout client, une table à sélections multiples liée aux libellés de la table Créneaux.





C'est là que j'ai besoin d'une aide, ci-dessous mon code actuel mais comment j'insère les créneaux du client dans ma table Créneaux_Clients ?

Sur mon bouton OK, je code :

EcranVersFichier()
// S'il s'agit d'un nouvel enregistrement
SI Client..NouvelEnregistrement ALORS
ResAjoute est un booléen
ResAjoute = HAjoute(Client)

SI ResAjoute = Vrai ALORS
Info("Enregistrement client OK")
SINON
Avertissement("Enregistrement client NOK")
FIN

// Modifie le produit
HModifie(Client)
FIN

// Ferme la fenêtre
Ferme()



Encore merci pour votre aide précieuse :)
Registered member
188 messages
Popularité : +12 (12 votes)
Posted on November, 01 2020 - 1:06 PM
Bonjour
Oui, je me suis un peu emballé à la lecture de la demande j'ai cru que Pierre voulait dénormaliser le stockage de ses données créneaux.
Mon sang n'a fait qu'un tour et j'ai tout fait, un peu trop !, pour le ramener dans le droit chemin...
:D

--
Côme, Clairinfo
Registered member
188 messages
Popularité : +12 (12 votes)
Posted on November, 01 2020 - 5:51 PM
Alors voilà une démarche possible, je préfère ne pas vous livrer le code tout fait on apprend plus en faisant soi-même

a) Passer la liste en multi sélection (rubrique IHM dans les 7 onglets

b) Commencer dans votre code de validation par supprimer les créneaux actuellement rattachés au client via une requête SQL
"DELETE FROM Créneaux_Client WHERE IDClient = " + SAI_IDClient
(Voir l'instruction HExécuteRequêteSQL pour cela)

c) Parcourez la liste afin de trouver les éléments sélectionnés de la liste
Allez je vous aide un peu voici un exemple pour vous mettre sur la voie
nId est un entier
POUR TOUT LIGNELIGNE SELECTIONNEESELECTIONNEE DE LISTE_Test
nId = LISTE_Test..ValeurMémorisée
// d) Dans cette boucle une fois le nId trouvé, ajoutez le pour le client dans la table Créneaux_Client
// On le fait par code en jouant sur les fichiers et non les éléments de la fenêtre
SI PAS HRAZ(Créneaux_CLient) ALORS ... gérer l'erreur
Créneaux_Client.IDClient = SAI_IDCLient
Créneaux_Client.IDCréneaux = nId
SI PAS HAjoute(Créneaux_CLient) ALORS ... gérer l'erreur
FIN

Cela devrait le faire, si vous bloquez n'hésitez pas
Pour améliorer cela en terme d'intégrité vous pourriez intégrer tout cela dans une transaction afin d'être sûr que toutes ces instructions ont été exécutées ou bien aucune sur cette table Créneaux_Client. Bon c'est pour les bon élèves, pas d'obligation :D

--
Côme, Clairinfo
Registered member
21 messages
Popularité : +1 (1 vote)
Posted on November, 02 2020 - 8:27 PM
Bonjour et merci pour la réponse,
ça fonctionne bien !

Par contre pouvez-vous m'expliquer à quoi sert "SI PAS HRAZ(Créneaux_CLient) ALORS"... :o

Je suis intéressé pour voir la transaction,... un lien pour l'explication ?

Pour résumer :
J'ajoute donc le nom d'un nouveau client dans la table client, ensuite je récupère le dernier id inséré, puis via la boucle j'insère chaque éléments de créneaux avec l'idclient.

EcranVersFichier()//met en mémoire les info de saisie
SI PAS HAjoute(Client) ALORS //ajoute le nom du client dans la table client
Avertissement("Insertion Client NOK")
FIN
RecupIDClient est un numérique
RecupIDClient = Client.IDClient//recupere l'id qui vient d'être ajouté

nId est un entier
POUR TOUT LIGNELIGNE SELECTIONNEESELECTIONNEE DE LISTE_Creneaux //crée la boucle

nId = LISTE_Creneaux..ValeurMémorisée

Creneaux_Client.IDClient = RecupIDClient
Creneaux_Client.IDCreneaux = nId
SI PAS HAjoute(Creneaux_Client) ALORS // ajoute idclient et les idcreneaux dans la table IDCreneaux
Avertissement("Insertion Creneaux NOK")
FIN

FIN
Ferme()




Registered member
188 messages
Popularité : +12 (12 votes)
Posted on November, 03 2020 - 11:15 AM
Bonjour

HRAZ permet de s'assurer que l'on part pour la création d'un nouvel enregistrement sans valeur provenant d'un autre enregistrement parcouru (il n'y a qu'un buffer par champ de fichier GLOBAL à l'application, un "truc" très particulier propre à HFSQL !) et que l'on part avec les éventuelles valeurs par défaut associées aux champs. C'est important avant la création d'un nouvel enregistrement.
https://doc.pcsoft.fr/fr-FR/?3044118&verdisp=170

Pour la partie transaction, je suppose que vous êtes en HFSQL Classic non client-serveur et dans ce cas la création d'une transaction est un peu particulière, elle passe par la création d'un fichier externe contenant les anciennes données qui sera supprimé à la validation de la transaction
https://doc.pcsoft.fr/?1000023384&name=htransaction_fonction.

--
Côme, Clairinfo
Registered member
21 messages
Popularité : +1 (1 vote)
Posted on November, 03 2020 - 12:56 PM
Ha ok, c’était pas aussi clair dans la doc au sujet du Hraz !
J'ai vraiment bien avancé, encore merci !
Registered member
21 messages
Popularité : +1 (1 vote)
Posted on November, 03 2020 - 12:58 PM
Vous donneriez pas, par hasard, des cours sur windev ? Je cherche un formateur sur ce logiciel.
Registered member
188 messages
Popularité : +12 (12 votes)
Posted on November, 03 2020 - 3:41 PM
Super si j'ai pu vous aider, merci pour votre retour.
Si vous souhaitez aller plus loin (formation par exemple) le mieux est de me contacter en direct :
https://www.clairinfo.fr/v2/scripts/form_contact.php
(La réponse à question anti robot est : Igny)

--
Côme, Clairinfo