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

MS SQL Server Discussion :

Variable varchar contenant des id (3,4,5) avec un IN


Sujet :

MS SQL Server

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    176
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 176
    Points : 91
    Points
    91
    Par défaut Variable varchar contenant des id (3,4,5) avec un IN
    Bonjour,

    Dans une procédure stockée, je reçois une variable varchar qui contient une suite d’ID sous cette forme 3,4,5,6

    Je voudrais trouver toutes les enregistrements avec ces ID.

    J’ai fait comme ça : (il y a pas une méthode plus correcte ?)

    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
    ALTER PROCEDURE [dbo].[GestionRetourMaterielEtat]
    	-- Add the parameters for the stored procedure here
    	@PIDDossierTab varchar(300)
     
    AS
    BEGIN
    	-- SET NOCOUNT ON added to prevent extra result sets from
    	-- interfering with SELECT statements.
    	SET NOCOUNT ON;
     
        -- Insert statements for procedure here
        DECLARE @sql AS VARCHAR(255)
     
        SET @sql = 'SELECT  
        Saturna.dbo.dossier.NumDossier
        FROM Saturna.dbo.dossier 
        LEFT JOIN Saturna.dbo.Client_Dossier ON Saturna.dbo.Client_Dossier.IDdossier  = Saturna.dbo.dossier.IDdossier 
        LEFT JOIN Saturna.dbo.Adresse_Dossier ON Saturna.dbo.Adresse_Dossier.IDdossier = Saturna.dbo.dossier.IDdossier 
        WHERE Saturna.dbo.dossier.IDdossier IN (' + @PIDDossierTab + ')'
     
    	EXECUTE (@sql);
    Quand j’exécute, j’obtiens une erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Msg 4145, Level 15, State 1, Line 5
    An expression of non-boolean type specified in a context where a condition is expected, near 'Adres'.
     
    (1 row(s) affected)
    Je me suis basé sur ce post pour le requête : http://forums.whirlpool.net.au/archive/928435



    Maintenant, si je retire un des deux LEFT JOIN, j’obtiens bien mes résultats.
    Une idée ?

    D’avance, merci.

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    176
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 176
    Points : 91
    Points
    91
    Par défaut
    Bon, je retourne dormir...

    DECLARE @sql AS VARCHAR(255)

    C'était simplement trop petit pour la taille de la query...

    N'empêche, il n'y a pas une meilleur méthode ?

  3. #3
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Ce n'est pas faux mais elle a de gros défauts, dont le SQL Injection et la multiplication des plans d'exécutions.

    Si vous lisez l'anglais, j'ai trouvé ce lien qui recense de nombreuses méthodes (lien que j'ai simplement survolé) :
    http://www.sommarskog.se/arrays-in-sql-2005.html

  4. #4
    Expert éminent
    Avatar de Lyche
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2007
    Messages
    2 523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 523
    Points : 6 775
    Points
    6 775
    Billets dans le blog
    4
    Par défaut
    Tu peux faire un split des valeurs sur ton séparateur ","

    ensuite insérer dans une table temporaire ou dans une table fixe puis faire un select exists des éléments de ta table.
    Rejoignez la communauté du chat et partagez vos connaissances ou vos questions avec nous

    Mon Tutoriel pour apprendre les Agregations
    Consultez mon Blog SQL destiné aux débutants

    Pensez à FAQ SQL Server Ainsi qu'aux Cours et Tuto SQL Server

  5. #5
    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,

    Pour le dépouillement de la chaîne, vous pouvez voir le billet que j'ai publié à ce sujet.

    Privilégiez l'utilisation de sp_executesql, qui permet de paramétrer les requêtes et donc de réutiliser les plans de requêtes, donc :

    - de diminuer le temps de requête en évitant la compilation
    - de ne pas pourrir le cache de plans avec des plans qui ont une forte probabilité de ne jamais être réutilisés ...

    J'ai donné des exemples d'utilisation de sp_executesql ici

    @++

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    176
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 176
    Points : 91
    Points
    91
    Par défaut
    Merci pour votre retour.

    Je vais travailler avec sp_executesql.

    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
    ALTER PROCEDURE [dbo].[GestionRetourMaterielEtat]
    	-- Add the parameters for the stored procedure here
    	@PIDDossierTab varchar(300)
     
    AS
    BEGIN
    	-- SET NOCOUNT ON added to prevent extra result sets from
    	-- interfering with SELECT statements.
    	SET NOCOUNT ON;
     
    	DECLARE @SQLString NVARCHAR(500)
    	DECLARE @ParmDefinition NVARCHAR(500)
     
    	DECLARE @IntVariable INT
    	DECLARE @Lastlname varchar(50)
     
    	SET @SQLString = N'SELECT @LastlnameOUT = saturna.dbo.dossier.Responsable
                       FROM saturna.dbo.dossier
                       WHERE saturna.dbo.dossier.IDdossier IN ('+@PIDDossierTab+')'
     
    	SET @ParmDefinition = N'@LastlnameOUT varchar(50) OUTPUT'
     
    	EXECUTE sp_executesql
    		@SQLString,
    		@ParmDefinition,
    		@LastlnameOUT=@Lastlname OUTPUT
     
    	SELECT @Lastlname
     
    END
    Par contre, je vais devoir stocker les résultats dans une table temporaire avant de faire un SELECT sur cette table.

    Bon, je sais que ce n'est pas top...

    http://blog.developpez.com/elsuket/p...e-performance/

    Mais je ne vois pas comment faire autrement surtout avec mes connaissances.

    J'ai lu le billet sur le dépouillement mais ça ne fait pas tilt.

  7. #7
    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 y a un problème avec la procédure stockée que vous avez écrite : vous passez un certain nombre d'identifiants, et très probablement plus d'un : jusque là pas de problème.

    Mais vous ne vous pouvez pas l'affecter à une variable, sinon SQL Server n'y stockera que l'un d'entre-eux, le premier ou le dernier suivant la requête et les index qui la supportent.
    N'étant pas ensembliste, votre requête est donc fausse.
    On voit également souvent cette erreur dans les triggers.

    Rappelez vous qu'une fonction de table, qu'elle soit en ligne ou à plusieurs instructions, retourne ... une table : donc rien ne vous empêche d'effectuer une jointure directement sur la fonction, comme on le ferait avec une variable de type table.

    Souvenez-vous aussi que l'appel à sp_executesql est fait dans le contexte de la base de données courante (à moins que vous qualifiez le nom des objets par la base de données à laquelle ils appartiennent, ou que utilisiez USE).

    En conséquence, après avoir créé la table et la fonction de mon billet pour le dépouillement d'une chaîne de valeurs séparées par des virgules, on peut donc écrire :

    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
    ALTER PROCEDURE [dbo].[GestionRetourMaterielEtat]
    	@PIDDossierTab varchar(300) 
    AS
    BEGIN
    	SET NOCOUNT ON
     
    	DECLARE @sql nvarchar(500)
    		, @Lastlname varchar(50)
    		, @cr nchar(2) = NCHAR(13) + NCHAR(10)
     
    	SET @sql =
    	N'SELECT	D.Responsable' + @cr
    	+ 'FROM		saturna.dbo.dossier AS D' + @cr
    	+ 'INNER JOIN	dbo.SplitStringToInt(@_PIDDossierTab, '','') AS T' + @cr
    	+ '			ON D.IDdossier = T.element' + @cr
     
    	EXEC	sp_executesql
    			@sql
    			, N'@_PIDDossierTab varchar(300)'
    			, @_PIDDossierTab = @PIDDossierTab
    END
    J'ai créé cela dans une base de données nommée ELSUKET sur mon PC.
    Ensuite j'ai exécuté :

    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
    CREATE DATABASE saturna
    GO
     
    USE saturna
    GO
     
    CREATE TABLE dbo.dossier
    (
    	IDdossier int NOT NULL
    	, Responsable varchar(50) NOT NULL
    )
    GO
     
    INSERT	INTO dbo.dossier VALUES (1, 'toto'), (2, 'titi'), (3, 'tutu')
    GO
    Puis :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    USE ELSUKET
    GO
     
    EXEC dbo.GestionRetourMaterielEtat '1,2,3'
    Et voici le résultat :



    Ensuite s'il s'agit d'une requête qui est exécutée un paquet de fois par seconde, vous pouvez avoir recours à une table partitionnée.
    Il suffit pour cela d'avoir une colonne de type uniqueidentifier, et une colonne calculée persistante indexée qui est le ABS(BINARY(CHECKSUM(GUID))) % x de cette colonne, puis de partitionner par cette dernière.
    X est le nombre de partitions dont vous avez besoin pour limiter les accès concurrents aux même pages.

    @++

  8. #8
    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
    Question Bête mais avez vous la main sur le code appelant? quelle est votre version de SQL SERVER?


    En effet on peut avantageusement passer par des Table Valued Parameters pour ce genre de besoins depuis la version 2008... (ADO.NET le gère très facilement par exemple).

    http://msdn.microsoft.com/en-us/library/bb675163.aspx
    Prendre conscience, c'est transformer le voile qui recouvre la lumière en miroir.
    MCTS Database Development
    MCTS Database Administration

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Batch] Variable texte contenant des mots réservés
    Par canorra dans le forum Scripts/Batch
    Réponses: 5
    Dernier message: 10/09/2012, 16h02
  2. Réponses: 1
    Dernier message: 28/12/2011, 18h34
  3. Réponses: 7
    Dernier message: 06/01/2010, 08h32
  4. [MySQL] Classé un champ varchar, contenant des dates
    Par gastoncs dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 13/09/2009, 01h04
  5. Tri varchar contenant des nombres et des lettres
    Par ben106 dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 15/08/2007, 21h58

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