IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement SQL Server Discussion :

Recherche d'une chaine dans plusieurs colonnes


Sujet :

Développement SQL Server

  1. #1
    Candidat au Club
    Homme Profil pro
    Programmeur analyste
    Inscrit en
    Août 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Programmeur analyste
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 5
    Points : 2
    Points
    2
    Par défaut Recherche d'une chaine dans plusieurs colonnes
    Ma recherche ne me retourne jamais de résultat quelqu'un peut m'aider?
    J'utilise sql server !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    set ANSI_NULLS ON
    set QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[sp_RechercheClient]  @critere varchar(50)
    AS 
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
    WHERE upper(CNOM)+upper(CRESP)+upper(CADR)+upper(CVIL) LIKE upper('%@critere%')
    Merci d'avance

  2. #2
    Invité
    Invité(e)
    Par défaut
    Votre façon de faire est dégueulasse et ne doit pas être très performante.
    Vous feriez mieux de faire une clause différente par champs.
    En plus, si un des champs est null, la concaténation retournera un null...
    Sinon, c'est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WHERE upper(CNOM)+upper(CRESP)+upper(CADR)+upper(CVIL) LIKE upper('%'+@critere+'%')

  3. #3
    Membre émérite

    Homme Profil pro
    Chargé de Développement et d'Analyse de données
    Inscrit en
    Mars 2010
    Messages
    1 278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chargé de Développement et d'Analyse de données
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 278
    Points : 2 856
    Points
    2 856
    Par défaut
    Essaye ceci pour voir

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SET ANSI_NULLS ON
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[sp_RechercheClient]  @critere varchar(50)
    AS 
    DECLARE @varUpper VARCHAR (1024)
    SET @varUpper = upper (@critere)
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
    WHERE upper(CNOM)+upper(CRESP)+upper(CADR)+upper(CVIL) LIKE '%' + @varUpper + '%'
    Etienne ZINZINDOHOUE
    Billets-Articles

  4. #4
    Candidat au Club
    Homme Profil pro
    Programmeur analyste
    Inscrit en
    Août 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Programmeur analyste
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Citation Envoyé par 7gyY9w1ZY6ySRgPeaefZ Voir le message
    Votre façon de faire est dégueulasse et ne doit pas être très performante.
    Vous feriez mieux de faire une clause différente par champs.
    En plus, si un des champs est null, la concaténation retournera un null...
    Sinon, c'est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WHERE upper(CNOM)+upper(CRESP)+upper(CADR)+upper(CVIL) LIKE upper('%'+@critere+'%')
    Merci pour l'encouragement Je suis débutant en sql server alors je suis ouvert au suggestion

    zinzineti : Merci sa fonctionne !

  5. #5
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par darkgamin Voir le message
    Merci pour l'encouragement Je suis débutant en sql server alors je suis ouvert au suggestion
    Désolé de vous ouvrir les yeux, mais les pistes sont dans la suite du message :
    Vous feriez mieux de faire une clause différente par champs.
    En plus, si un des champs est null, la concaténation retournera un null...
    Si vous voulez plus de détails, je reste à votre disposition.

  6. #6
    Candidat au Club
    Homme Profil pro
    Programmeur analyste
    Inscrit en
    Août 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Programmeur analyste
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Citation Envoyé par 7gyY9w1ZY6ySRgPeaefZ Voir le message
    Désolé de vous ouvrir les yeux, mais les pistes sont dans la suite du message :
    Si vous voulez plus de détails, je reste à votre disposition.
    En effet j'aimerais bien améliorer ma procédure. Cependant je ne comprend pas très bien ce que vous voulez dire par "faire une clause différente par champ" Merci!

  7. #7
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par darkgamin Voir le message
    En effet j'aimerais bien améliorer ma procédure. Cependant je ne comprend pas très bien ce que vous voulez dire par "faire une clause différente par champ" Merci!
    Faites comme ceci, comme ça si vous avez un champ à null, ça pourra tout de même vous ramener la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    WHERE CNOM LIKE '%'+@critere+'%'
    	or CRESP LIKE '%'+@critere+'%'
    	or CADR LIKE '%'+@critere+'%'
    	or CVIL LIKE '%'+@critere+'%'
    De plus, MS Sql server n'est pas case sensitive par défaut - (sauf si la collation a été modifié pour que la bd le soit), alors les upper ne sont pas vraisemblablement pas nécessaire dans votre requête.

  8. #8
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Bonjour,

    Effectivement 7gyY9w1ZY6ySRgPeaefZ a raison d'enlever les UPPER si la collation des colonnes n'est pas sensible à la casse.
    C'est d'ailleurs fort probablement le cas si vous avez fait une installation de SQL Server par défaut ...
    Dans ce cas, la collation utilisée est celle de la base de données.
    Et si vous ne l'avez pas spécifié lors de la création de la base de données, c'est celle de l'instance SQL Server

    Pour le savoir, et en supposant que vous êtes sous SQL Server 2005 ou 2008 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT		S.name + '.' + T.name AS table_name
    		, C.name AS column_name
    		, C.collation_name
    		, FHC.description
    FROM		sys.columns AS C
    INNER JOIN	sys.tables AS T
    			ON T.object_id = C.object_id
    INNER JOIN	sys.schemas AS S
    			ON S.schema_id = T.schema_id
    INNER JOIN	sys.fn_helpcollations() AS FHC
    			ON C.collation_name = FHC.name
    WHERE		S.name = 'dbo'
    AND		T.name = 'CLIENTS_AVANTAGE'
    AND		C.name IN ('CNOM', 'CRESP', 'CADR', 'CVIL')
    Pour connaître la collation utilisée par votre base de données :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT		D.name AS database_name
    		, D.collation_name AS database_collation_name
    		, FHC.description AS collation_description
    FROM		sys.databases AS D
    INNER JOIN	sys.fn_helpcollations() AS FHC
    			ON D.collation_name = FHC.name
    --WHERE		D.name = 'leNomDeVotreBaseDeDonnees'
    Et pour l'instance SQL Server :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT		SC.server_collation_name
    		, FHC.description AS server_collation_name
    FROM		(SELECT	SERVERPROPERTY('Collation') AS server_collation_name) AS SC
    INNER JOIN	sys.fn_helpcollations() AS FHC
    			ON SC.server_collation_name = FHC.name
    Vous pouvez retrouver ces requêtes dans le billet que je viens de publier (merci de m'en avoir donné l'idée )

    Dans la description de la collation, vous pouvez savoir si la collation est sensible ou non à la casse.
    Si elle ne l'est pas, alors l'utilisation de la fonction UPPER() est inutile et surtout contre-performante pour deux raisons :

    - d'abord il faut que SQL Server mette en majuscules le mot
    - comme il se base sur les statistiques de distribution des données dans les colonnes, l'utilisation d'une fonction sur une des colonnes participant à un prédicat (JOIN ou WHERE) devient non-cherchable.
    C'est la raison pour laquelle 7gyY9w1ZY6ySRgPeaefZ a qualifié votre façon de faire de dégueulasse : comme SQL Server ne peut pas prédire combien de lignes dans votre table vont vérifier le prédicat, il est obligé de lire toute la table, ce qui est très contre-performant.

    En changeant le prédicat de recherche par une suite de OR, c'est un peu mieux.
    Cela aurait été encore mieux si votre prédicat de LIKE peut être @critere + '%', parce que dans ce cas un index sur au moins l'une des colonnes du WHERE/OR aurait accéléré la requête.
    SQL Server aurait alors cherché toutes les lignes qui vérifient le prédicat sur cette colonne à travers l'index, puis aurait extrait le reste des données en lisant les pages de données référencées par les lignes trouvées dans l'index.

    Pour accélérer la recherche floue, il faut penser à un index de texte intégral.
    Vous pouvez l'article de SQLPro à ce sujet ici

    @++

  9. #9
    Membre expert Avatar de iberserk
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    Novembre 2004
    Messages
    1 795
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 795
    Points : 3 173
    Points
    3 173
    Par défaut
    Attention au FULLTEXT qui ne reproduit pas complètement le LIKE....

    En combinant les deux?
    Prendre conscience, c'est transformer le voile qui recouvre la lumière en miroir.
    MCTS Database Development
    MCTS Database Administration

  10. #10
    Candidat au Club
    Homme Profil pro
    Programmeur analyste
    Inscrit en
    Août 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Programmeur analyste
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Merci beaucoup sa fonctionne très bien !
    Cependant, la recherche me semble être devenu plus lente.
    Est-ce que cette nouvelle requête parcours 4 fois la base de donnée pour la recherche?
    Est-ce que l'ancienne requête parcourais seulement 1 fois la base de donnée en additionant les champs?

    Merci encore a vous pour votre aide !

  11. #11
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Il faudrait pour cela que vous nous donniez :

    - la structure complète de la table (colonnes et index)
    - la requête ...
    - ... et son plan d'exécution réel (que l'on obtient dans une onglet distinct de la console en pressant CTRL + M avant d'exécuter la requête)

    @++

  12. #12
    Invité
    Invité(e)
    Par défaut
    Si vous aviez beaucoup de champs à Null, ça peut être une explication mais bon, là je fais Madame Soleil...
    Il faudrait les informations demandées par elsuket pour être plus concret.

  13. #13
    Candidat au Club
    Homme Profil pro
    Programmeur analyste
    Inscrit en
    Août 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Programmeur analyste
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Voici la première requête (qui me semble plus rapide)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    set ANSI_NULLS ON
    set QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[sp_RechercheClient]  @critere varchar(50)
    AS 
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
    WHERE (CNOM)+ ' ' + (CRESP)+ ' ' + (CADR)+ ' ' + (CVIL)+ ' ' +(CTELB)+ ' ' +(CPROV)+ ' ' +(CPAYS) LIKE('%' + @critere + '%')
    voici la deuxième requête (qui me semble plus lente)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    set ANSI_NULLS ON
    set QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[sp_RechercheClient]  @critere varchar(50)
    AS 
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
     WHERE CNOM LIKE '%'+@critere+'%'
    	OR CRESP LIKE '%'+@critere+'%'
    	OR CADR LIKE '%'+@critere+'%'
    	OR CVIL LIKE '%'+@critere+'%' 
    	OR CPROV LIKE '%'+@critere+'%' 
    	OR CPAYS LIKE '%'+@critere+'%' 
    	OR CTELB LIKE '%'+@critere+'%'
    Pour la table, elle contient une trentaine de champs.
    la clé primaire est CNUM et contient des valeur du genre :
    0000ACR100
    0000ACR105
    0000AGR100
    0000AGR105
    ...
    etc.

    pour le plan d'exécution réel je n'arrive pas a le trouver. J'utilise sql server 2005.

    Je me demandais aussi si c'étais possible d'ajouter un deuxième critère de recherche avec un opérateur comme (ou, et , sans)

    Merci encore pour l'aide ! C'est très appréciée !

  14. #14
    Membre expert Avatar de iberserk
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    Novembre 2004
    Messages
    1 795
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 795
    Points : 3 173
    Points
    3 173
    Par défaut
    Que donne cette requête:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    SET ANSI_NULLS ON
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[sp_RechercheClient]  @critere varchar(50)
    AS 
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
     WHERE CNOM LIKE '%'+@critere+'%'
    UNION 
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
     WHERE CRESP LIKE '%'+@critere+'%'
    UNION
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
     WHERE CADR LIKE '%'+@critere+'%'
    UNION
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
     WHERE CVIL LIKE '%'+@critere+'%'
    UNION
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
    WHERE CPROV LIKE '%'+@critere+'%'
    UNION
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
    WHERE CPAYS LIKE '%'+@critere+'%'
    UNION
    SELECT *
    FROM dbo.CLIENTS_AVANTAGE
    WHERE CTELB LIKE '%'+@critere+'%'

    Pour le plan d’exécution, sous management studio à droite du bouton 'executer' vous devez avoir un bouton à cocher avant de lancer la requête...
    Cochez le puis lancez la requête, un deuxième onglet devrait apparaître a côté du résultat de requête avec le plan d’exécution...
    Prendre conscience, c'est transformer le voile qui recouvre la lumière en miroir.
    MCTS Database Development
    MCTS Database Administration

  15. #15
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Le problème est le LIKE de toute façon.
    Donc la seule façon que je vois pour optimiser cela est de dé-normaliser en stockant les mots qui composent les critères de recherche dans une seule colonne ...

    @++

Discussions similaires

  1. Réponses: 3
    Dernier message: 09/05/2011, 14h10
  2. Recherche d'une valeur dans plusieurs colonnes
    Par Arnaud F. dans le forum Langage SQL
    Réponses: 2
    Dernier message: 01/03/2009, 11h44
  3. Recherche d'une chaine dans un champ
    Par Cyberbob002 dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 06/01/2006, 15h21
  4. Comment rechercher une chaine dans plusieurs tables ?
    Par tsing dans le forum Requêtes
    Réponses: 2
    Dernier message: 26/11/2005, 18h04
  5. [Tableaux] Recherche d'une chaine dans un tableau
    Par tom06440 dans le forum Langage
    Réponses: 5
    Dernier message: 20/10/2005, 23h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo