2008-09-18 18 views
10

Wszyscy wiemy, że przygotowane oświadczenia są jednym z najlepszych sposobów obrony przed atakami typu SQL injection. Jaki jest najlepszy sposób tworzenia przygotowanego oświadczenia z klauzulą ​​"IN". Czy istnieje prosty sposób na zrobienie tego z nieokreśloną liczbą wartości? Weźmy na przykład następujące zapytanie.Obsługa danych w klauzuli IN z parametrami SQL?

SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (1,2,3) 

Obecnie używam pętli nad moimi możliwymi wartościami, aby zbudować ciąg znaków taki jak.

SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (@IDVAL_1,@IDVAL_2,@IDVAL_3) 

Czy można użyć tylko przekazać tablicę jako wartość parametru zapytania i użyć kwerendy w następujący sposób?

SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (@IDArray) 

W przypadku ważne Pracuję z SQL Server 2000, w Vb.NET

+0

dodać znacznik SQLServer – MotoWilliams

+0

może być również odpowiedni znacznik t-sql. –

Odpowiedz

1

Jeśli chcesz przekazać tablicę, trzeba będzie funkcję w SQL, które można włączyć do tej tablicy podselekcja.

Funkcje te są bardzo powszechne i większość systemów domowych korzysta z nich.

Większość komercyjnych, a raczej profesjonalnych ORM'ów robi ins przez zrobienie garści zmiennych, więc jeśli masz to działa, myślę, że to standardowa metoda.

-1

W SQL Server 2008 w końcu udało się rozwiązać ten klasyczny problem, dodając nowy typ danych "table". Najwyraźniej pozwala to przekazać tablicę wartości, które mogą być użyte w podsekcji, aby osiągnąć to samo, co instrukcja IN.

Jeśli używasz programu SQL Server 2008, możesz to sprawdzić.

+0

"Jeśli jest to ważne, pracuję z programem SQL Server 2000" – digiguru

5

Proszę bardzo - najpierw utworzyć następującą funkcję ...

Create Function [dbo].[SeparateValues] 
(
    @data VARCHAR(MAX), 
    @delimiter VARCHAR(10) 
) 
    RETURNS @tbldata TABLE(col VARCHAR(10)) 
As 
Begin 
    DECLARE @pos INT 
    DECLARE @prevpos INT 

    SET @pos = 1 
    SET @prevpos = 0 

    WHILE @pos > 0 
     BEGIN 

     SET @pos = CHARINDEX(@delimiter, @data, @prevpos+1) 

     if @pos > 0 
     INSERT INTO @tbldata(col) VALUES(LTRIM(RTRIM(SUBSTRING(@data, @prevpos+1, @[email protected])))) 

     else 

     INSERT INTO @tbldata(col) VALUES(LTRIM(RTRIM(SUBSTRING(@data, @prevpos+1, len(@data)[email protected])))) 

     SET @prevpos = @pos 
    End 

    RETURN 

END 

następnie użyć następujących ...

Declare @CommaSeparated varchar(50) 
Set @CommaSeparated = '112,112,122' 
SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (select col FROM [SeparateValues](@CommaSeparated, ',')) 

myślę SQL Server 2008 pozwoli funkcje tabeli.

UPDATE

Będziesz wycisnąć dodatkową wydajność, używając następującej składni ...

SELECT ID,Column1,Column2 FROM MyTable 
Cross Apply [SeparateValues](@CommaSeparated, ',') s 
Where MyTable.id = s.col 

Ponieważ poprzednia składnia powoduje SQL Server, aby uruchomić dodatkowy „sort” polecenia przy użyciu " IN "klauzula. Plus - moim zdaniem wygląda ładniej: D!

+0

Rozwiązuje to rozwiązanie, ponieważ zapewnia ładną funkcję do tworzenia tabel z list o dowolnej wartości oddzielonej przez użytkownika - dlaczego głosowanie jest wyłączone? – digiguru

+0

Głosowałem za tobą. To jest rozwiązanie, którego również używamy. Działa z SQL 2000 i koncepcyjnie jest łatwa do zrozumienia dla młodszych członków zespołu. Gdybym mógł, zagłosowałbym na 5 punktów. Widziałem tę technikę opisaną w postach i artykułach. To rozwiązanie działa również dobrze z usługami SQL Report. –

+0

Awesome, Thanks! – Jaxedin

-2

Oto jedna technika używam

ALTER Procedure GetProductsBySearchString 
@SearchString varchar(1000), 
as 
set nocount on 
declare @sqlstring varchar(6000) 
select @sqlstring = 'set nocount on 
select a.productid, count(a.productid) as SumOf, sum(a.relevence) as CountOf 
from productkeywords a 
where rtrim(ltrim(a.term)) in (''' + Replace(@SearchString,' ', ''',''') + ''') 
group by a.productid order by SumOf desc, CountOf desc' 

exec(@sqlstring) 
+0

Wykonywanie ciągów sql jest bardzo niebezpiecznym sposobem robienia rzeczy w środowisku produkcyjnym. – digiguru

0

Można utworzyć tabelę tymczasową Temptable z pojedynczą wartość kolumny i włóż wszystkie identyfikatory. Następnie można to zrobić za pomocą podselekcji:

SELECT ID,Column1,Column2 FROM MyTable WHERE ID IN (SELECT VALUE FROM TempTable) 
0

Idź z rozwiązaniem opublikowanym przez digiguru. To świetne rozwiązanie wielokrotnego użytku i stosujemy tę samą technikę. Nowi członkowie zespołu to uwielbiają, ponieważ oszczędzają czas i utrzymują spójne procedury przechowywania.Rozwiązanie działa również dobrze z raportami SQL, ponieważ parametry przekazywane do procedur składowanych w celu utworzenia zestawów rekordów przechodzą w varchar (8000). Po prostu to podłącz i idź.