2011-01-06 13 views
5

Pracuję nad aplikacją ASP.NET i przekazuję wartość łańcuchową, taką jak "1,2,3,4", do procedury wyboru tych wartości, które są IN (1,2, 3,4), ale jego powiedzenie "Konwersja nie powiodła się podczas konwersji wartości varchar" 1,2,3,4 "do typu danych int."SQL korzysta z wartości rozdzielanych przecinkami z klauzulą ​​IN

Oto kod aspx:

private void fillRoles() 
{ 
    /*Read in User Profile Data from database */ 
    Database db = DatabaseFactory.CreateDatabase(); 

    DbCommand cmd = db.GetStoredProcCommand("sp_getUserRoles"); 

    db.AddInParameter(cmd, "@pGroupIDs", System.Data.DbType.String); 
    db.SetParameterValue(cmd, "@pGroupIDs", "1,2,3,4"); 

    IDataReader reader = db.ExecuteReader(cmd); 

    DropDownListRole.DataTextField = "Group"; 
    DropDownListRole.DataValueField = "ID"; 

    while (reader.Read()) 
    { 
     DropDownListRole.Items.Add((new ListItem(reader[1].ToString(), reader[0].ToString()))); 
    } 

    reader.Close(); 
} 

Oto moja procedura:

CREATE Procedure [dbo].[sp_getUserRoles](@pGroupIDs varchar(50)) 
AS BEGIN 
    SELECT * FROM CheckList_Groups Where id in (@pGroupIDs) 
END 

Odpowiedz

8

Oto workaround znalazłem zrobić to, co staramy się osiągnąć

CREATE Procedure [dbo].[sp_getUserRoles](
    @pGroupIDs varchar(50) 
    ) 
    As 
    BEGIN 
     SELECT * FROM CheckList_Groups Where (',' + @pGroupIDs +',' LIKE '%,' + CONVERT(VARCHAR, id) + ',%') 
    End 

ten dostaje rozdzielany przecinkami listę i porównuje go do identyfikatora (które są reprezentowane jak tak ',1,', ',2,' etc) w tabeli przy użyciu LIKE

+0

Fantastyczneoooooooooo :) :) Drahcir działało jak urok – user342944

+2

Nie sądzę, że to rozwiązanie zachowa się dobrze na dużych zestawach danych, ponieważ w tym przypadku nie można używać indeksów. (Indeksy nie mogą być używane, gdy przedrostek argumentu wyszukiwania podobnego wyrażenia jest wieloznaczny). –

1

Trzeba użyć sp_executesql Aby osiągnąć ten functionllity

CREATE Procedure [dbo].[sp_getUserRoles](
    @pGroupIDs varchar(50) 
    ) 
    As 
    BEGIN 

EXECUTE sp_executesql 
      N'SELECT * FROM CheckList_Groups Where id in (@pGroupIDs)', 
      N'@level varchar(50)', 
      @level = @pGroupIDs; 

End 
+0

u oznacza zbudować ciąg SQL i wykonać? – user342944

+0

@ user342944 - tak –

1

klauzula może” t przyjmuj taki powiązany parametr. To, co jest podawane podczas tworzenia zapytania, to SELECT * FROM CheckList_Groups Where id in ('1,2,3,4'). Zasadniczo klauzula IN jest przekazywana pojedynczym ciągiem znaków.

6

Pewnie, że nie może tego zrobić,

Wygenerowany zapytania byłoby czegoś jak ten

SELECT * FROM CheckList_Groups Where id in ('1,2,3,4') 

i upewnić się, że nie może być wykonana.

można zbudować kwerendę w procedurze przechowywanej następnie wykonać go z exec

'SELECT * FROM CheckList_Groups Where id in (' + @pGroupIDs + ')' 

lub

SELECT * FROM CheckList_Groups Where charindex(','+id+',' , @pGroupIDs)>0 

ale najpierw należy dodać ',' na początku i na końcu swojej parametru w C# kod

3

Nie można umieścić tych wartości (ciąg znaków oddzielonych przecinkami) w wartości parametru.

Co musisz zrobić, to utworzyć wyrażenie SQL w swojej procedurze przechowywanej dynamicznie, przez konkatenację ciągów. Będziesz musiał wykonać to z przechowywaną procedurą sp_executesql.

CREATE PROCEDURE [dbo].[getUserRoles](@groupIds NVARCHAR(50)) 
AS BEGIN 
    DECLARE @statement NVARCHAR(255) 

    SELECT @statement = N'SELECT * FROM CheckList_Groups Where id in (' + @pGroupIDs + N')'  

    execute sp_executesql @statement 
END 

także, że nie nazwałem SP getUserRoles zamiast sp_getUserRoles. Powód jest bardzo prosty: po uruchomieniu procedury składowanej, której nazwa zaczyna się od sp_, SQL Server najpierw wyśle ​​zapytanie do bazy danych master, aby znaleźć procedurę przechowywaną, która powoduje, że wydajność jest wykrywana.

+0

Fredrik dziękuję za tę cenną sugestię, na pewno będę o tym pamiętać na pewno :) – user342944

+0

Zastrzyk gallore –

8

Jeśli nie chcesz korzystać z dynamicznego SQL, najlepszym sposobem Znalazlem jest stworzenie funkcji, która okazuje się ograniczony ciąg na stole, coś jak to działa na liście Integer:

CREATE FUNCTION [dbo].[StringToIntList] 
(@str VARCHAR (MAX), @delimeter CHAR (1)) 
RETURNS 
    @result TABLE (
     [ID] INT NULL) 
AS 
BEGIN 

    DECLARE @x XML 
    SET @x = '<t>' + REPLACE(@str, @delimeter, '</t><t>') + '</t>' 

    INSERT INTO @result 
    SELECT DISTINCT x.i.value('.', 'int') AS token 
    FROM @x.nodes('//t') x(i) 
    ORDER BY 1 

RETURN 
END 

Następnie użyj to w twoim sp:

CREATE Procedure [dbo].[sp_getUserRoles](
    @pGroupIDs varchar(50) 
    ) 
    As 
    BEGIN 
     SELECT * FROM CheckList_Groups Where id in (
      SELECT ID FROM dbo.StringToIntList(@pGroupIds,',') 
     ) 
    End 
+0

dzięki za podstęp – 0cool

+0

nieco powolny, ale działa. – johnny

+0

dobrze w rzeczywistości nie jest powolny. MOJE zapytanie było już wolne. – johnny

3

Sposób, w jaki próbujesz to zrobić, jest nieco błędny. Aby to osiągnąć, musisz użyć EXECUTE.

CREATE PROCEDURE [dbo].[sp_getUserRoles](@pGroupIDs nvarchar(50)) 
As 
BEGIN   
    EXECUTE (N'SELECT * FROM CheckList_Groups Where id in (' + @pGroupIDs + ')'; 
END 
+0

Ardman Otrzymuję komunikat "Procedura oczekuje parametru" wyrażenie "typu" ntext/nchar/nvarchar "podczas próby urs. teraz wypróbujesz innych – user342944

+0

Czy to po mojej edycji? –

+0

Błąd mówi, że powinieneś używać NVARCHAR. Zrób to tak: WYKONAJ (N'SELECT ... 'i określ, że typ parametru pGroupdIDS jest również NVARCHAR.) –

0

pierwsza funkcja Create -

Wystarczy uruchomić ten kod

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE FUNCTION [dbo].[CSVToTable] (@InStr VARCHAR(MAX)) 
RETURNS @TempTab TABLE 
    (id int not null) 
AS 
BEGIN 
    ;-- Ensure input ends with comma 
    SET @InStr = REPLACE(@InStr + ',', ',,', ',') 
    DECLARE @SP INT 
DECLARE @VALUE VARCHAR(1000) 
WHILE PATINDEX('%,%', @INSTR) <> 0 
BEGIN 
    SELECT @SP = PATINDEX('%,%',@INSTR) 
    SELECT @VALUE = LEFT(@INSTR , @SP - 1) 
    SELECT @INSTR = STUFF(@INSTR, 1, @SP, '') 
    INSERT INTO @TempTab(id) VALUES (@VALUE) 
END 
    RETURN 
END 
GO 

Następnie -

Używaj funkcji w wsporniku z wybranymi statment -

DECLARE @LIST VARCHAR(200) 
SET @LIST = '1,3' 
SELECT Id, Descr FROM CSVDemo WHERE Id IN (SELECT * FROM dbo.CSVToTable(@LIST)) 
Powiązane problemy