2009-05-17 9 views
1

J'ai une chaîne qui est une sortie d'une fonction, par exemple: "1,3,16, .., ..".Charindex dans SQL ne donne pas le résultat souhaité

J'ai utilisé la requête SQL suivante et l'ai exécutée dans le Générateur de requêtes dans Visual Studio, sans aucune erreur de syntaxe. J'ai donné 3,16 comme valeurs de paramètre @itemID, mais cela n'a pas donné les résultats désirés.

J'utilise la requête SQL suivante (sans charindex):

SELECT ItemID, Name, RelDate, Price, Status FROM item_k WHERE (ItemID = @itemIDs) 

je lui ai donné 3 que la valeur du paramètre @itemID, et je me suis un résultat pour elle. J'ai également donné 16 (à une occasion séparée) en tant que valeur du paramètre @itemID, et j'ai obtenu un résultat pour cela. Je conclus qu'il y a des valeurs pour ItemID 3 & 16.

Pourquoi une requête SQL avec charindex ne me donne aucun résultat? Je n'arrive pas à comprendre le problème ici, s'il vous plaît, aidez-moi.

Répondre

1

CHARINDEX retourne juste la position où le caractère est trouvé dans la chaîne.

Ainsi, lorsque @ItemIDs est réglé sur '3,16' alors votre clause WHERE ...

WHERE (ItemID = CAST(CHARINDEX(',', @ItemIDs) AS INT)) 

... équivaut à ...

WHERE ItemID = 2 

... parce que CHARINDEX retours 2 depuis la le caractère virgule est trouvé à la position 2 de la chaîne '3,16'.

Je devine que (a) vous n'avez pas une ligne dans votre table où ItemID est 2 et (b) vous ne voulez pas vraiment la position de la virgule pour dicter les lignes sont retournés.

+0

(a) je n'ai pas un dossier où ItemID est 2. (b) je veux la requête pour me faire les enregistrements. REMARQUE: @ItemIDs peut contenir différentes valeurs non "3,16" à chaque fois. Comment puis-je y parvenir? merci – pier

0

Essayez SELECT ItemID, Nom, RelDate, le prix, le statut DE item_k OU ItemID dans (@itemIDs)

+0

hmm. cela fonctionnerait si je donnais 1 valeur comme paramètre. Une incompatibilité de type est donnée lorsque j'entre "3,12" comme paramètre. – pier

1

Vous pouvez créer une requête dynamique qui utilise l'opérateur in:

declare @Sql varchar(1000) 
set @Sql = 'select ItemID, Name, RelDate, Price, Status from item_k where ItemID in (' + @itemIDs + ')' 
exec(@Sql) 

Attention avec ce que vous envoyez dans la procédure, cependant. Comme pour tout SQL dynamique, si les données proviennent d'une entrée utilisateur sans validation, la procédure est très ouverte pour l'injection SQL.

Edit:
C'est ce qui se passe dans la requête:

D'abord, nous déclarons une variable pour maintenir la requête dynamique. C'est juste une variable varchar qui est assez grande.

Dans la variable, nous avons placé la variable @itemIDs entre deux chaînes pour former la requête.Les valeurs séparées par des virgules est mise entre parenthèses de l'opérateur in pour former une expression similaire à: where ItemID in (1,3,16)

Enfin la commande exec exécute la requête dans la variable.

+0

Coudl vous pls. expliquer ce qui se passe exactement dans cette requête? – pier

+0

J'ai ajouté une explication ci-dessus. – Guffa

3

Voici encore une autre solution. Dans mon expérience, lorsque vous avez une liste de ItemIds comme une chaîne de valeurs séparées par des virgules, vous avez besoin d'une fonction split. C'est très utile d'avoir.

Avec une fonction split, vous pouvez simplement faire une INNER JOIN avec les résultats de l'appel de la fonction split et passer la liste des itemID et délimiteur associée comme suit:

DECLARE @ItemIDs varchar(100) 
SET @ItemIDs = '1,3,16,22,34,35' 

SELECT 
    ItemID, Name, RelDate, Price, Status 
FROM item_k 
    INNER JOIN dbo.UTILfn_Split(@ItemIDs,',') itemIds 
     ON itemIds.Value = item_k.ItemID 

Même si cela peut sembler compliqué au premier abord C'est la solution la plus élégante et la plus facile à entretenir. Voici le code pour créer la fonction dbo.UTILfn_Split. Vous devez exécuter cette première:

IF EXISTS (SELECT * FROM sysobjects WHERE id = 
object_id(N'[dbo].[UTILfn_Split]') AND xtype IN (N'FN', N'IF', N'TF')) 
DROP FUNCTION [dbo].[UTILfn_Split] 
GO 

CREATE FUNCTION dbo.UTILfn_Split 
(
    @String nvarchar (4000), 
    @Delimiter nvarchar (10) 
) 
RETURNS @ValueTable TABLE ([Value] nvarchar(4000)) 
BEGIN 
DECLARE @NextString nvarchar(4000) 
DECLARE @Pos int 
DECLARE @NextPos int 
DECLARE @CommaCheck nvarchar(1) 

--Initialize 
SET @NextString = '' 
SET @CommaCheck = RIGHT(@String,1) 
--Check for trailing Comma, if not exists, INSERT 
--if (@CommaCheck <> @Delimiter) 
SET @String = @String + @Delimiter 

--Get position of first Comma 
SET @Pos = CHARINDEX(@Delimiter,@String) 
SET @NextPos = 1 

--Loop while there is still a comma in the String of levels 
WHILE (@pos <> 0) 
BEGIN 
    SET @NextString = SUBSTRING(@String,1,@Pos - 1) 

    INSERT INTO @ValueTable ([Value]) Values (@NextString) 

    SET @String = SUBSTRING(@String,@pos +1,LEN(@String)) 

    SET @NextPos = @Pos 
    SET @pos = CHARINDEX(@Delimiter,@String) 
END 
RETURN 
END 
Questions connexes