Comparaison de deux tables via champ lookup

Étiquetté : , ,

  • Comparaison de deux tables via champ lookup

    Posté par Laurent CARRIERE sur 7 mars 2022 à 20h34

    Bonsoir la communauté.

    voilà mon souci.

    j’ai une table RESERVOIR avec IDRESERVOIR

    J’ai une table NETTOYAGE avec comme champ recherche IDRESERVOIR

    comme je peux avoir mes réservoirs nettoyés, je voudrais avoir mes réservoirs non nettoyés !

    pour cela j’ai crée des collections et mis ceci dans items de la 3eme galerie : Filter(reservoircollection;!(IDRESERVOIR in nettoyagecollection.IDRESERVOIR) mais cela ne marche pas …

    j’ai essayé en remplaçant les collections par les galeries.allitems sans succès.

    merci de votre aide

    PostID=8LH1lVbKjN748zo

    Laurent CARRIERE a répondu Il y a 2 mois, 4 semaines 1 Membre · 10 Réponses
  • 10 Réponses
  • Ludovic Perrichon

    Membre
    8 mars 2022 à 16h41

    Peut etre quelque chose comme Filter(RESERVOIR;CountIf(NETTOYAGE; IDRESERVOIR = ID) > 0)

    Juste a voir, mais le ID, faudra peut etre lui dire qu’il vient de ta table réservoir via le fameux “disambiguation”, c’est à dire Filter(RESERVOIR;CountIf(NETTOYAGE; IDRESERVOIR = RESERVOIR[@ID]) > 0)

    CommentID=X0nbQb0HKzNL4xz, PostID=8LH1lVbKjN748zo

  • R3dKap

    Membre
    8 mars 2022 à 17h20

    @Laurent CARRIERE il faut que tu fasses comme ceci :

    Filter(n    reservoircollection;n    Not(n        ID in ShowColumns(n            AddColumns(n                nettoyagecollection;n                "IdNettoyageReservoir";n                IDRESERVOIR.Idn            );n            "IdNettoyageReservoir"n        )n    )n)

    En effet, le IN doit avoir sur sa droite une table à une seule colonne. On construit donc cette table en récupérant l’Id de IDRESERVOIR dans nettoyagecollection dans une colonne dédiée (AddColumns()) et en ne conservant au final que cette colonne-là (ShowColumns()). A partir de là, on peut faire la négation sur le IN.

    Si tu n’y arrives pas, poste une capture de ton erreur ici… 😉

    CommentID=SRVq8HoF0DnfT5x, PostID=8LH1lVbKjN748zo

  • R3dKap

    Membre
    8 mars 2022 à 17h27

    Au passage, la technique de Ludovic devrait marcher aussi… Y’a juste une p’tite erreur : c’est IDRESERVOIR.Id et pas juste IDRESERVOIR et c’est = 0 et pas > 0.

    Je sais pas trop laquelle est la plus performante… Celle de Ludo est plus élégante je trouve… 😉

    CommentID=uT09UrSV40wTQaJ, PostID=8LH1lVbKjN748zo

  • Laurent CARRIERE

    Membre
    8 mars 2022 à 20h48

    Merci pour l’intérêt.

    alors, Emmanuel voici le message d’erreur : “Impossible de convertir ce type de données, Powerapps ne peut pas convertir ce number en table”.

    c’est le même genre de message qu’avec mes premiers essais…

    je tente l’autre methode d’ici demain

    CommentID=3WfXyWC18zw1ie6, PostID=8LH1lVbKjN748zo

  • Laurent CARRIERE

    Membre
    8 mars 2022 à 21h50

    pour ce qui est de la deuxième méthode – l’erreur vient du fait qu’il ne peut pas comparer une table (OUVRAGEcollection.IDdb) avec un texte (ID_ouvrages.Value).

    CommentID=S3jBGnItVINyaMV, PostID=8LH1lVbKjN748zo

    • Ludovic Perrichon

      Membre
      9 mars 2022 à 7h58

      à la palce de OUVRAGECollection.IDdb, si on met IDdb seulement ?

      SubCommentID=h5GmgQ9XeZbVN4j, CommentID=S3jBGnItVINyaMV, PostID=8LH1lVbKjN748zo

  • Laurent CARRIERE

    Membre
    9 mars 2022 à 8h29

    Filter(OUVRAGEcollection; CountIf(interventionnettoyagecollection;IDdb = Value(ID_OUVRAGES.Value))=0)

    Effectivement dans ce cas là plus d’erreur, par contre, il ne filtre pas. En tout cas la réponse a ce filtre est la totalité de la table OUVRAGEcollection.

    si je met < ou > ou <> 0 réponse 0 au filtre

    CommentID=XdvH5XujqtICRjg, PostID=8LH1lVbKjN748zo

  • Laurent CARRIERE

    Membre
    9 mars 2022 à 9h18

    en remplacant le = par in, j’ai des résultats.

    je les vérifie car j’ai des différences qu’il faut que j’explique :(((( par exemple :

    ma formule c’est donc : Filter(ouvragepartypecollection;CountIf(interventionnettoyageparannee;IDdb in ID_OUVRAGES.Value)=0)

    pour : ouvragepartypecollection (j’ai 62 éléments dans la galerie)

    intervention nettoyé par année : 1 en 2022

    le résultat de ma 3eme galerie est bien 61 restant a nettoyer.

    par contre :(((((( pour 2021 : 34 interventions et la la 3eme galerie me donne 27 enregistrements (il m’en manque donc 1).

    en tout cela a l’air d’etre une bonne piste

    CommentID=D063IsAFbYvIgAN, PostID=8LH1lVbKjN748zo

  • R3dKap

    Membre
    9 mars 2022 à 9h30

    @Laurent CARRIERE et @Ludovic je vais essayer de vous amener à comprendre pourquoi vous n’y arrivez pas afin de vous donner l’autonomie de le faire par vous-même par la suite…

    En fait, il y a confusion dans les données que vous manipulez. Mais avant toute chose, il faudrait idéalement améliorer la nomenclature des objets et des variables parce-que là, même moi je m’y perds…
    Ce que je recommande c’est d’utiliser en tout temps la nomenclature suivante (j’aimerais tellement que TOUS les développeurs Power Apps du monde entier suivent la même nomenclature… ce serait tellement plus simple pour se parler et lire le code des p’tits copains… 😀) :

    • collection locale : colNomDeLaCollection (à définir avec les fonctions ClearCollect(), Collect(), Filter(), …)

    • variable globale : gloNomDeLaVariableGlobale (à définir avec la fonction Set())

    • variable locale : locNomDeLaVariableLocale (à définir avec la fonction UpdateContext())

    • colonne d’une liste SharePoint (nom interne) : scNomDeLaColonne (colonne à créer en 2 temps comme expliqué ici au paragraphe Création des colonnes)

    Vous noterez au passage le jeu de majusucules/minuscules A RESPECTER pour plus de lisibilité… 😉

    Pour en revenir à la formule qui ne fonctionne pas…

    Si j’ai bien compris la manière dont sont organisées les données :

    • une liste RESERVOIR avec une colonne IDRESERVOIR de type texte (en gros c’est le catalogue des réservoirs)

    • une liste NETTOYAGE avec une colonne IDRESERVOIR de type recherche qui pointe vers la liste RESERVOIR (sur le champ IDRESERVOIR je suppose)

    Là encore, déjà, aussi un petit souci de nomenclature :

    • la liste contenant TOUS les réservoirs devrait s’appeler RESERVOIRS au pluriel (c’est tout bête mais ça représente mieux la réalité et dans le code par la suite le fait de voir le pluriel me fait potentiellement comprendre plus facilement que c’est une liste) ; à la rigueur CatalogueReservoirs aurait même mieux… bref…

    • idem pour le nom de la liste NETTOYAGE qui serait mieux lotie avec un ‘S’

    • dans la liste NETTOYAGE, la colonne IDRESERVOIR est mal nommé car on ne nettoie pas un IDRESERVOIR mais un RESERVOIR -> donc autant l’appeler RESERVOIR tout simplement : en gros, le modèle de données, dans sa nomenclature, doit refléter la réalité (je nettoie quoi ? un réservoir -> j’appelle ma colonne RESERVOIR)

    Et là on en arrive au plus important : la structure de cette colonne de recherche IDRESERVOIR de la liste NETTOYAGE. Comme vous le savez sa structure est la suivante :

    {n    Id: ...;n    Value: ...n}

    La première colonne Id va contenir la valeur de la colonne ID (remarquez ici les majuscules) de l’élément dans la liste liée RESERVOIR. Et la colonne Value va contenir la valeur de la colonne liée (ici IDRESERVOIR) de l’élément dans la liste RESERVOIR.

    Voilà… Il faut bien avoir ça en tête au moment où on manipule les données.

    Maintenant, supposons que l’on veuille mettre en place le filtrage proposé par @Ludovic. Pour rappel, l’idée c’est de filtrer la liste RESERVOIR pour ne conserver que les réservoirs qui ne sont jamais utilisés dans la liste NETTOYAGE (colonne de recherche IDRESERVOIR).

    Donc, pour faire ça, on va donc écrire quelque chose qui ressemble à ça :

    Filter(RESERVOIR; <condition de filtrage>)

    La condition de filtrage va consister à regarder, pour le RESERVOIR en cours (en effet, n’oubliez pas que la fonction Filter() fonctionne comme une boucle où chaque élément de la collection en premier paramètre va être confronté à la condition spécifiée dans le 2è paramètre), s’il existe des lignes dans NETTOYAGE dont la colonne IDRESERVOIR pointe sur ce réservoir. S’il n’en existe aucune alors on “conserve” le réservoir en question et on sait qu’il n’a pas été nettoyé. On va utiliser la fonction CountIf() pour vérifier l’existence de ces lignes.

    La formule se complète donc ainsi :

    Filter(n    RESERVOIR; n    CountIf(NETTOYAGE; <condition de comptage>)=0n)

    Que veux-t-on faire dans la condition de comptage ? On veut rechercher des éléments de NETTOYAGE IDRESERVOIR pointe sur le réservoir en cours du Filter() (de la boucle). Or souvenez-vous, IDRESERVOIR dans NETTOYAGE c’est {Id: <ID dans RESERVOIR>; Value: <IDRESERVOIR dans RESERVOIR>}.

    Donc, ma condition va être la suivante :

    IDRESERVOIR.Id = ID (celui de RESERVOIR)

    Mais y’a un souci : il existe aussi une colonne ID dans NETTOYAGE. Comment Power Apps va savoir si ID c’est celui de RESERVOIR ou de NETTOYAGE dans notre formule ? Il y a ambiguïté… Pour résoudre ce problème, on a 2 solutions :

    • soit on utilise l’opérateur de désambiguïté : IDRESERVOIR.Id = RESERVOIR[@ID] (on précise que la colonne ID est celle de la liste RESERVOIR)

    • soit on nomme temporairement la liste RESERVOIR dans la fonction Filter() pour pouvoir y faire référence ailleurs dans la formule : Filter(RESERVOIR As ItemReservoir; ...) et la condition du CountIf() serait alors IDRESERVOIR.Id = ItemReservoir.ID

    Je préfère la 2è solution. Et notre formule finale est donc la suivante :

    Filter(n    RESERVOIR As ItemReservoir; n    CountIf(NETTOYAGE; IDRESERVOIR.Id = ItemReservoir.ID)=0n)

    Au passage, lorsque je tape mon code je procède par étapes : j’écris les fonctions en partant du niveau le plus haut et je rentre en profondeur au fur et à mesure. Ca m’évite des erreurs de parenthèses et des oublis de paramètres. Et donc, j’écris les choses ainsi :

    Filter(RESERVOIR As ItemReservoir; )

    Puis :

    Filter(RESERVOIR As ItemReservoir; CountIf()=0)

    Puis :

    Filter(RESERVOIR As ItemReservoir; CountIf(NETTOYAGE; IDRESERVOIR.Id = ItemReservoir.ID)=0)

    Voilou… En espérant que vous avez bien suivi la logique et vous saurez l’appliquer à d’autres cas de figure… 😉

    CommentID=sU0c4GHCY5Bgb5X, PostID=8LH1lVbKjN748zo

  • Laurent CARRIERE

    Membre
    9 mars 2022 à 9h39

    Respect et merci.

    effectivement j’avais tout cela en tête (un peu partout en vrac) notamment quand tu veux un defaultselectedItems dans uneliste de choix basé sur un champ recherche – la aussi il faut se servir de l’Id du champ recherche….

    merci encore a vous deux

    CommentID=CGdDY3V53qDqQhA, PostID=8LH1lVbKjN748zo

Connectez-vous pour répondre.