2010-07-15 4 views
0

Désolé pour le long courrier, mais la majeure partie est un code épelant mon scénario:dynamique de requêtes SQL (entrées variables, et les entrées variables par colonne)

Je suis en train d'exécuter une requête dynamique (je l'espère par une procédure stockée) pour extraire les résultats en fonction d'un nombre variable d'entrées.

Si j'avais une table:

(dbo).(People) 
ID Name Age 
1 Joe 28 
2 Bob 32 
3 Alan 26 
4 Joe 27 

Je veux permettre à l'utilisateur de rechercher par l'une des trois colonnes, pas de problème:

DECLARE @ID int, @Name nvarchar(25), @Age int 
SET @ID = 1 
SET @Name = 'Joe' 
SET @Age = null 

SELECT * 
FROM dbo.People 
WHERE 
(ID = @ID or @ID is null) AND 
(Name like @Name or @Name is null) AND 
(Age = @Age or @Age is null) 

Et je récupère le résultat que je veux .

Maintenant, si je veux rechercher plusieurs champs dans une colonne, je peux le faire sans problème:

DECLARE @text nvarchar(100) 
SET @text = '1, 3' 

DECLARE @ids AS TABLE (n int NOT NULL PRIMARY KEY) 

--//parse the string into a table 
DECLARE @TempString nvarchar(300), @Pos int 
SET @text = LTRIM(RTRIM(@text))+ ',' 
SET @Pos = CHARINDEX(',', @text, 1) 
IF REPLACE(@text, ',', '') <> '' 
BEGIN 
    WHILE @Pos > 0 
    BEGIN 
     SET @TempString = LTRIM(RTRIM(LEFT(@text, @Pos - 1))) 
     IF @TempString <> '' --just: IF @TempString != '' 
     BEGIN 
      INSERT INTO @ids VALUES (@TempString) 
     END 
     SET @text = RIGHT(@text, LEN(@text) - @Pos) 
     SET @Pos = CHARINDEX(',', @text, 1) 
    END 
END 


SELECT * 
FROM dbo.People 
WHERE 
ID IN (SELECT n FROM @ids) 

Maintenant, mon problème est que je ne peux pas sembler comprendre comment combiner les deux puisque je ne peux pas mettre:

WHERE 
(Name like @Name or @Name is null) AND 
(Id IN (SELECT n FROM @ids) or @ids is null) 

Parce que @ids ne sera jamais nulle (car il est une table)

Toute aide serait grandement appréciée!

Merci à l'avance ... et laissez-moi savoir si je peux préciser quoi que ce soit

Répondre

0

Essayez:

(Id IN (SELECT n FROM @ids) OR NOT EXISTS (SELECT * FROM @ids)) 
+0

IIRC, pas [sargable] (http://en.wikipedia.org/wiki/Sargable) –

+0

Merci pour l'aide, c'est la solution dont j'avais besoin. mais actuellement, ma table est assez petite et avec le temps ça va grandir, et assez rapidement, donc je me demande à quel point cela va affecter la performance ...? – Brett

+1

@Brett - Je suis avec OMG Ponies sur l'approche globale. C'est simplement la réponse la plus courte et la plus simple en accord avec votre approche. J'ai décidé de ne pas faire de refactoring, mais généralement le plan d'exécution pour la recherche "unifiée" n'est pas bon, et il vaut mieux dérouler les conditions "manuellement" afin d'obtenir les meilleurs plans d'exécution pour chaque option. Quand il y a des combinaisons complexes, générer du code dynamiquement pour que ce soit exactement ce qui est nécessaire est finalement le plus efficace. C'est un peu plus un défi dans votre cas à cause des listes au lieu de paramètres uniques. –

0

Vous pouvez essayer:

NOT EXISTS (SELECT 1 FROM @ids) 
OR EXISTS (SELECT 1 FROM @ids where n = Id) 

Mais ceux-ci mieux être petites tables - cette requête ne sera probablement pas très bien jouer avec des index sur vos tables.

+0

Pourriez-vous jeter un oeil à ma question ici> http://stackoverflow.com/questions/4832511/oracle-database-connection-with-vb-net-using-oraoledb-oracle – StealthRT

1

Vous pouvez utiliser une instruction IF:

IF LEN(@ids) > 0 
BEGIN 

    SELECT * 
    FROM dbo.People 
    WHERE ID IN (SELECT n FROM @ids) 

END 
ELSE 
BEGIN 

    SELECT * 
    FROM dbo.People 

END 

Sinon, consider making the query real dynamic SQL (minding pitfalls of course).

+0

Et si tous les trois de mes variables, ID, Nom et Age peuvent chacun avoir une liste (potentiellement). Cela signifie que je devrais avoir 9 conditions différentes ... – Brett

+2

@Brett: Tout ce qui dépasse une condition m'amène à utiliser le SQL dynamique. Vous pouvez le faire en une seule requête, mais ce sera non-sargable (ne pas effectuer idéalement - voir le lien dans mon commentaire à Cade Roux). –

+0

Merci pour votre aide, et je prévois de lire plus de ce document demain, je n'ai pas fini de le terminer aujourd'hui .... encore une fois, appréciez toute votre aide! – Brett

0

Une solution rapide:

(`%,' + Id + ',%' like ',' + @ids + ',' or @ids is null) 
and (`%,' + Name + ',%' like ',' + @names + ',' or @names is null) 

Donc, si l'utilisateur passe @ids = 1,2, la première ligne donne:

`%,1,%' like ',1,2,' 

Il est une bonne idée de filtrer espaces avant et après les virgules. :)

Questions connexes