Forum Programmation.SQL SELECT * FROM matable WHERE n'importeQuelChamp = 'maValeur'

Posté par  .
Étiquettes : aucune
3
26
août
2009
Bonjour,

comme l'indique le titre, je cherche à faire une requête de ce genre :

SELECT * FROM maTable WHERE n'importeQuelChamp = 'maValeur'

En pratique, faute de mieux, je fais comme ça :

SELECT * FROM maTable WHERE champ1 = 'maValeur' OR champ2 = 'maValeur' OR ... OR champN = 'maValeur'

Existe-t-il une méthode plus générique, qui évite de faire des OR en cascade ?

Merci d'avance.
  • # A essayer...

    Posté par  . Évalué à 3.

    Tu peux probablement "renverser la vapeur" en écrivant et testant une requête dans ce genre :
    select * from ma_table where 'maValeur' in (champ1, champ2, champ3, champ4);

    C'est du non testé, mais ça devrait rouler.
    • [^] # Re: A essayer...

      Posté par  . Évalué à 2.

      merci, effectivement ça marche, et c'est déjà plus propre.

      Mais s'il y a un moyen qui évite d'énumérer les champs, je suis preneur également.
    • [^] # Re: A essayer...

      Posté par  . Évalué à 2.

      Par contre, du coup, impossible d'utiliser LIKE, ce qui me pose un autre problème.
      • [^] # Re: A essayer...

        Posté par  . Évalué à 8.

        sur le principe, c'est quand même un peu malsain de pas savoir ce que tu es en train de chercher.

        Tu peux aussi avoir une table (valeur, type, id) triée sur valeur, ou type ferait référence au type de champ, et id pointerait sur l'id de la ligne contenant ta valeur. (c'est des noms moisis, c'est juste un exemple vite torché).

        Tu chercherais valeur dans cette table et le résultat de cette recherche te permettrait immédiatement d'identifier quel(s) champ(s) de quelle(s) ligne(s) contient ta valeur.
        • [^] # Re: A essayer...

          Posté par  . Évalué à 3.

          Je plussoie cette solution. Il y a vraiment un problème dans le modèle si on est obligé d'utiliser le genre de trick indiqué plus haut.
      • [^] # Re: A essayer...

        Posté par  . Évalué à 1.

        Tu peux panacher :

        SELECT * FROM table WHERE table.champ IN ('a', 'b', 'c') OR table.champ LIKE truc%
      • [^] # Re: A essayer...

        Posté par  . Évalué à 5.

        Bon, je vais d'abord préciser les choses : la requête qui suit devrait fonctionner en donnant le bon résultat, en énumérant les champs, et en utilisant la directive like. Je réponds juste pour dire qu'on peut combiner in et like dans une requête de ce genre, juste pour l'exercice de style quoi, mais en aucun cas pour indiquer une solution propre à ce problème.

        select * from maTable where
        true in (champ1 like 'maValeur%', champ2 like 'maValeur%', ...., champN like 'maValeurN');

        Voilà, ça fonctionne, j'ai testé sous postgres.

        C'était la minute de sql crade, juste pour le fun.
        Merci pour votre attention.
  • # Erreur de conception ?

    Posté par  . Évalué à 7.

    Je dirais qu'à priori, si tu as besoin de faire ce genre de manip', c'est que ta base doit être mal conçue. Ne serait-ce que parce qu'un enregistrement peut contenir des champs dont le type soit incompatible avec ce que tu cherches. Si tu en es à n champs, avec n ∈ ℕ, et pouvant représenter n'importe quelle valeur, alors c'est que ta requête n'est pas spécialement liée à la table que tu interroges.

    Peux-tu nous donner une vision plus globale de ton problème ?
    • [^] # Re: Erreur de conception ?

      Posté par  . Évalué à 2.

      Voilà mon application :

      côté base de données, j'ai une table ''utilisateurs'', avec des champs ''nom'', ''prenom'', ''email'', etc...

      côté page web, j'ai un tableau qui affiche la liste des utilisateurs, avec tous les champs.

      Mon tableau est en Ajax, il récupère la liste des utilisateurs sous forme d'un flux JSON ou XML.

      Au dessus de mon tableau, j'ajoute un formulaire avec un unique champ, ''recherche rapide''.
      Lors de la validation du champ, le tableau envoie le mot cherché en POST, récupère le flux contenant les résultats, et rafraîchit son contenu.

      L'idée, c'est que si on tape ''François'', on obtienne des résultats tels que :

      - François Nautré santos@gmail.com ...
      - Claude François foo@bar.com ...
      - Jean Dupont jean.dupont@francois.com ...

      Du coup, pour le moment, côté serveur, je fais (version simplifiée):

      SELECT * FROM table WHERE nom LIKE $_POST['recherche'] OR prenom LIKE $_POST['recherche'] OR email LIKE $_POST['recherche'] OR ...

      Ça marche, mais :

      1) j'ai plusieurs dizaines de champs
      2) je vais devoir faire ça pour plusieurs tableaux (qui affichent des tables différentes)

      Donc si le langage SQL prévoit une syntaxe pour rechercher une valeur dans n'importe quel champ d'une table, je suis preneur.

      C'est plus clair comme ça ? Est-ce ma base qui est mal conçue ?
      • [^] # Re: Erreur de conception ?

        Posté par  . Évalué à 4.

        cf mon commentaire précédent http://linuxfr.org/comments/1060861.html#1060861

        C'est possible d'élaborer en rajoutant le nom de la table dans le prototype de la table précédente.

        J'ai déjà vu une application résoudre ce genre de problème de cette façon, en rajoutant des tables dédiées à la recherche. Le hic, c'est qu'il faut du coup alimenter ces tables à la volée et que ça rajoute pas mal de complexité au code.
        L'avantage, c'est que ça scale mieux que devoir faire une recherche multi champs multi table dans une seule grosse requête SQL monstrueuse. Tu peux aussi découper plus finement ta recherche en indexant mot par mot dans ces tables dédiées, plutôt qu'en indexant la totalité du contenu des champs.
        • [^] # Re: Erreur de conception ?

          Posté par  . Évalué à 2.

          Je vois le principe, mais
          en rajoutant des tables dédiées à la recherche
          => j'aimerais éviter.
          • [^] # Re: Erreur de conception ?

            Posté par  . Évalué à 4.

            Je sais bien que les réponses à une question du genre "Change d'outil", c'est finalement assez exaspérant. Mais, tu sembles avoir la main sur la base de données, et probablement sur les outils utilisés, alors à mon tour de te poser une question :
            Pourquoi avoir choisi mysql ?
            Si tu peux effictivement changer, et t'orienter vers un autre SGBD, donne au moins une chance pour quelques essais à postgresql. Il sait faire le type de recherche que tu veux, il me semble, et ce nativement (j'ai rapidement parcouru la doc, et il me semble avoir vu quelque chose là dessus http://www.postgresql.org/docs/8.4/static/textsearch.html ).
            • [^] # Re: Erreur de conception ?

              Posté par  . Évalué à 3.

              j'ai effectivement la main sur la base et les outils.

              Cependant j'ai choisi MySQL parce que :

              - c'est ce que j'utilise quasi-systématiquement et que je m'en débrouille bien ;
              - je sais que je n'aurai pas de souci par la suite pour héberger pour application chez un prestataire tiers ;
              - pour l'application en question, MySQL est largement suffisant en termes de performances, fonctionnalités, capacité de stockage, montée en charge, etc...

              De plus, toujours dans le cas présent, mon souhait de légèrement simplifier quelques requêtes de recherche ne justifie pas d'envisager un changement de SGBD.

              Mais la question est tout-à-fait pertinente.
      • [^] # Re: Erreur de conception ?

        Posté par  . Évalué à 3.

        Bonjour,

        En concaténant les champs de recherche tu peux avoir un seul champ au final (à voir quel est l'opérateur de concaténation, là c'est pour Oracle...)
        SELECT * FROM table WHERE nom||prenom||email LIKE $_POST['recherche']
        • [^] # Re: Erreur de conception ?

          Posté par  (site web personnel) . Évalué à 1.

          Sauf que ici si la fille se prénomme Déborah et son nom de famille otmail, et que tu cherche hotmail, tu va la trouver ...alors que déborah à un copain geek qui lui héberge ces mails sur son nom de domaine perso :)
          • [^] # Re: Erreur de conception ?

            Posté par  (site web personnel) . Évalué à 2.

            Bof, dans ce cas il suffit de corriger un peu :

            SELECT * FROM table WHERE nom||'#'||prenom||'#'||email LIKE $_POST['recherche']

            Évidemment il ne faut pas chercher #, mais bon...

            On peut aussi prégénérer un champs recherche en concaténant à chaque création ou mise à jour des champs correspondant : ça évite de refaire les concaténations à chaque recherche. On perd un peu en place place, mais on gagne en performances.
        • [^] # Re: Erreur de conception ?

          Posté par  . Évalué à 2.

          Je confirme que ça marche avec MySQL.

          C'est vrai que c'est nettement plus propre que ce que je faisais au départ.
          • [^] # Re: Erreur de conception ?

            Posté par  . Évalué à 6.

            Ca va tant que tu n'as pas trop de données, parce que faire des concaténation et des like sur des chaînes de caractères en full scan, en terme de perfs, y a du potentiel de pas glop ...
      • [^] # Re: Erreur de conception ?

        Posté par  . Évalué à 4.

        En fait, ce que tu voudrais, c'est que SQL fasse de l'introspection sur les champs d'une table. Ça correspond à passer à de la "méta" programmation, et ça SQL de base ne sait pas faire (après, il y a peut-être des solutions cutom pour chaque BDD).
        • [^] # Re: Erreur de conception ?

          Posté par  . Évalué à 4.

          effectivement oui.

          En même temps, MySQL permet bien de consulter et éditer la structure d'une table (SHOW COLUMNS, ALTER TABLE, toussa...)
          • [^] # Re: Erreur de conception ?

            Posté par  . Évalué à 2.

            Oui, tu peux récupérer les résultats et les exploiter toi pour faire ce que tu veux dans ton appli. Mais tu ne pourras pas les exploiter en SQL pour faire ce que tu veux (genre : SELECT ... FROM ... WHERE (SHOW COLUMNS ...) LIKE ...)
            Pour faire une analogie avec les langages de programmation, si tu veux appeler toutes les méthodes d'un objet en Java (par exemple), tu ne pourra pas "de base". Il faudra utiliser les fonctions de méta-programmation.
      • [^] # Re: Erreur de conception ?

        Posté par  . Évalué à 2.

        SELECT * FROM table WHERE nom LIKE $_POST['recherche'] OR prenom LIKE $_POST['recherche'] OR email LIKE $_POST['recherche'] OR ...

        J'espère au moins que dans le vrai code les valeurs passées sont un minimum protégées parce que la porte ouverte à toutes les injections SQL...
        • [^] # Re: Erreur de conception ?

          Posté par  . Évalué à 2.

          Bien sûr !

          C'est un exemple ultra minimal et symbolique (une variable PHP au milieu d'une requête SQL...)
        • [^] # Re: Erreur de conception ?

          Posté par  . Évalué à 4.

          Non non, c'est fait exprès !

          Ça me permet d'ajouter un utilisateur ou de faire les sauvegardes directement à partir du champ de recherche ;-)
      • [^] # Re: Erreur de conception ?

        Posté par  (site web personnel) . Évalué à 0.


        Au dessus de mon tableau, j'ajoute un formulaire avec un unique champ, ''recherche rapide''.
        Lors de la validation du champ, le tableau envoie le mot cherché en POST, récupère le flux contenant les résultats, et rafraîchit son contenu.


        Je dis peut-être une bêtise, mais tu pourrais pas faire la recherche côté client, en javascript?
  • # recherche plein texte

    Posté par  (site web personnel) . Évalué à 9.

    Pourquoi (re-)développer des algorithmes de recherche plein texte ?
    http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
    (bon ça n'a l'air de fonctionner qu'en MyISAM :/ mais ça a peut-être évolué depuis).

    C'est au niveau de la table que tu spécifies FULLTEXT, ce qui indexera les champs significatifs.

    Tu peux aussi utiliser une vraie base de données relationnelle avec PostgreSQL pour le faire
    http://www.postgresql.org/docs/8.3/static/textsearch.html
    • [^] # Re: recherche plein texte

      Posté par  . Évalué à 2.

      Intéressant, je ne connaissais pas.

      Par contre :

      MATCH (col1,col2,...) AGAINST (expr [search_modifier])

      il faut tout de même préciser le nom des colonnes, donc ça ne résout pas mon problème initial.
      • [^] # Re: recherche plein texte

        Posté par  . Évalué à 2.

        et un show table T ne te liste pas les colonnes presentes dans la table T
      • [^] # Re: recherche plein texte

        Posté par  (site web personnel) . Évalué à 3.

        ça m'étonne cette affaire tout de même, peut-être faire une demande d'évolution pour gérer les champs à prendre en compte dans toute recherche au niveau de la table (plutôt que d'avoir à se palucher toutes les requêtes dans le code : forcément si ya un nouveau champ, tu peux avoir le cas où tu veux forcément qu'il soit pris automatiquement en compte, ou pas d'ailleurs).

        Peut-être demander à ce que ça soit fait au niveau d'une vue plutôt qu'au niveau table pour différencier les utilisations, 'fin j'élabore. L'idée c'est que ça puisse être géré au niveau du dictionnaire de données plutôt que dans chacune des requêtes, le besoin me paraît clair.

        Pour que cette demande d'évolution soit prise en compte, il risque de falloir demander à un développeur spécialiste de la recherche fulltext de la relire pour en profiter pour lui expliquer en direct ;-)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.