2010-04-06 4 views
5

Tworzę procedurę składowaną, do której chcę przekazać jako zmienną listę identyfikatorów rozdzielanych przecinkami. Chcę używać identyfikatorów na select, coś jak:SQL - procedura składowana z Select Statement przy użyciu IN (@Variable_CommaDelimitedListOfIDS)

Create Procedure up_TEST 
@Ids VARCHAR(MAX) 
AS 
SELECT * FROM ATable a 
WHERE a.Id IN(@Ids) 

Oczywiście pojawia się błąd, że @Ids jest varchar a nie INT ale w jaki sposób mogę przekonwertować lista rozdzielany przecinkami?

używam 2008

Dzięki

Odpowiedz

2

Dla tych przypadków używam SQL Server funkcja ta tabela, które można dostosować do własnych potrzeb:

CREATE FUNCTION dbo.f_params_to_list (@par VARCHAR(500)) 
returns @result TABLE (value VARCHAR(30)) 
AS 
begin 
    DECLARE @TempList table 
      (
      value VARCHAR(30) 
     ) 

    DECLARE @Value varchar(30), @Pos int 

    SET @par = LTRIM(RTRIM(@par))+ ',' 
    SET @Pos = CHARINDEX(',', @par, 1) 

    IF REPLACE(@par, ',', '') <> '' 
    BEGIN 
      WHILE @Pos > 0 
      BEGIN 
       SET @Value = LTRIM(RTRIM(LEFT(@par, @Pos - 1))) 
       IF @Value <> '' 
       BEGIN 
        INSERT INTO @TempList (value) VALUES (@Value) --Use Appropriate conversion 
       END 
       SET @par = RIGHT(@par, LEN(@par) - @Pos) 
       SET @Pos = CHARINDEX(',', @par, 1) 

      END 
    END  
    INSERT @result 
    SELECT value 
     FROM @TempList 
    RETURN 
END  

W swojej procedurze przechowywanej będzie go używać tak:

Create Procedure up_TEST 
@Ids VARCHAR(MAX) 
AS 
SELECT * FROM ATable a 
WHERE a.Id IN(SELECT value FROM dbo.f_params_to_list(@Ids)) 
0

Jednym ze sposobów może być podzielona i włożyć identyfikatory w tempory stole niż używać SQL w klauzuli ...

4

Ponieważ używasz programu SQL Server 2008, spójrz na numer table-valued parameters.

+0

@ TGnat, fajny człowieku, dzięki za cynk! +1 –

+0

+1 - jeśli chcesz zobaczyć porównanie wydajności różnych technik, jakie możesz zastosować (CSV vs TABLE wartościowane parametry vs XML), o tym niedawno napisałem na blogu: http://www.adathedev.co.uk /2010/02/sql-server-2008-table-valued-parameters.html – AdaTheDev

+1

@AdaTheDev, na podstawie twojego linku, po co utworzyć nowy typ parametru tabeli dla IDklienta, np. 'CREATE TYPE CustomerIDTableType AS TABLE (ID INTEGER PRIMARY KEY) ; 'może to być bardziej wielokrotnego użytku, aby po prostu to zrobić:' CREATE TYPE IntTableType AS TABLE (INTEGER IDENTYCZNY KLUCZ) * i używać go do przekazywania dowolnej listy liczb całkowitych –

2

Użyj parametru wartości tabeli (nowy w SQl Server 2008). Ustawić go tworząc rzeczywisty typ parametru tabeli:

CREATE TYPE IntTableType AS TABLE (ID INTEGER PRIMARY KEY) 

Twoja procedura byłaby wtedy:

Create Procedure up_TEST 
    @Ids IntTableType READONLY 
AS 

SELECT * 
    FROM ATable a 
    WHERE a.Id IN (SELECT ID FROM @Ids) 

RETURN 0 
GO 

jeśli nie można użyć wartości parametrów tabeli, patrz: "Arrays and Lists in SQL Server 2008 Using Table-Valued Parameters" by Erland Sommarskog, to istnieje wiele sposobów podzielić łańcuch w SQL Server. W tym artykule omówiono zalety i wady prawie każdej metody:

"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog

Trzeba utworzyć funkcję Split. W ten sposób funkcja podziału może być stosowany:

SELECT 
    * 
    FROM YourTable        y 
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value 

I prefer the number table approach to split a string in TSQL ale istnieje wiele sposobów, aby podzielić ciągi w SQL Server, patrz poprzedni odnośnik, który opisuje wady i zalety każdego z nich.

Dla metody Numery tablicy do pracy, trzeba zrobić to ustawienie tabeli jednorazową, która stworzy tabelę Numbers który zawiera wiersze od 1 do 10000:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number 
    INTO Numbers 
    FROM sys.objects s1 
    CROSS JOIN sys.objects s2 
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number) 

Gdy tabela liczb jest skonfigurowana utworzyć tę funkcję dzielone: ​​

CREATE FUNCTION [dbo].[FN_ListToTable] 
(
    @SplitOn char(1)  --REQUIRED, the character to split the @List string on 
    ,@List  varchar(8000)--REQUIRED, the list to split apart 
) 
RETURNS TABLE 
AS 
RETURN 
(

    ---------------- 
    --SINGLE QUERY-- --this will not return empty rows 
    ---------------- 
    SELECT 
     ListValue 
     FROM (SELECT 
        LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue 
        FROM (
          SELECT @SplitOn + @List + @SplitOn AS List2 
         ) AS dt 
         INNER JOIN Numbers n ON n.Number < LEN(dt.List2) 
        WHERE SUBSTRING(List2, number, 1) = @SplitOn 
      ) dt2 
     WHERE ListValue IS NOT NULL AND ListValue!='' 

); 
GO 

teraz można łatwo podzielić ciąg CSV do tabeli i dołącz do niego:

Create Procedure up_TEST 
@Ids VARCHAR(MAX) 
AS 
SELECT * FROM ATable a 
WHERE a.Id IN (SELECT ListValue FROM dbo.FN_ListToTable(',',@Ids)) 
1

Wydaje się, że wszyscy dzisiaj robią coś takiego!

Spójrz na http://www.sqlteam.com/article/parsing-csv-values-into-multiple-rows - jest to sposób przetwarzania rozdzielanej zmiennej wejściowej w celu uzyskania zestawu wyników zawierającego podzielone elementy poprzez połączenie z tabelą liczb/tabel (co dobrze jest mieć w bazie danych mimo to jeszcze nie). To daje ci prosty zestaw wyników, do którego możesz dołączyć zgodnie z normalnym.

1
CREATE PROCEDURE PROCEDURENAME 
@Id Numeric(18,0) 
AS 
BEGIN 
    SELECT * FROM tableName 
    WHERE tableName.Id IN (@Id) 
END 
+0

Witamy w stackoverflow. Myślę, że źle odczytałeś pytanie. Powyższe nie zadziałałoby z listą * wielu * identyfikatorów (to także stare pytanie, na które już udzielono odpowiedzi :). – Leigh