2011-01-06 18 views
5

Sto sviluppando un'applicazione ASP.NET e passando un valore di stringa come "1,2,3,4" in una procedura per selezionare quei valori che sono IN (1,2, 3,4) ma dicendo "Conversione fallita durante la conversione del valore varchar '1,2,3,4' nel tipo di dati int".SQL utilizza valori separati da virgola con la clausola IN

ecco il codice 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(); 
} 

Ecco la mia procedura:

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

risposta

8

Ecco un workaround ho trovato per fare ciò che si sta cercando di ottenere

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

Questo diventa il tuo virgole elenco delimitato e lo confronta con le id (che sono rappresentati in questo modo ',1,', ',2,' ecc) nella tabella utilizzando LIKE

+0

Fantasticoooooooooo :) :) Drahcir ha funzionato come un fascino – user342944

+2

Non penso che questa soluzione si comportano bene su dataset di grandi dimensioni, poiché in questo caso non è possibile utilizzare indici. (Gli indici non possono essere utilizzati quando si prefigura l'argomento di ricerca di un'espressione di tipo con un carattere jolly). –

1

è necessario utilizzare sp_executesql per raggiungere questo 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 significa costruire una stringa SQL ed eseguire? – user342944

+0

@ user342944 - sì –

1

la clausola può' t prendere un parametro associato in questo modo. Quello che viene dato quando la query viene effettivamente creata è SELECT * FROM CheckList_Groups Where id in ('1,2,3,4'). Essenzialmente la clausola IN viene passata una singola stringa.

6

Certo non può farlo,

La query generato sarebbe qc come questo

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

e sicuro che non può essere eseguito.

si può costruire la query in stored procedure poi eseguirlo con exec

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

o

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

ma è necessario innanzitutto aggiungere il ',' per iniziare e alla fine del parametro in C# codice

3

Non è possibile inserire questi valori (la stringa separata da virgole) in un valore di parametro.

Quello che dovrete fare è creare l'istruzione SQL nella stored procedure in modo dinamico, mediante concatenazione di stringhe. Dovrai eseguirlo con la procedura memorizzata sp_executesql quindi.

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 

Inoltre, non è che ho chiamato la SP getUserRoles invece di sp_getUserRoles. Il motivo è molto semplice: quando si esegue una stored procedure il cui nome inizia con sp_, SQL Server innanzitutto interrogherà il database master per trovare quella stored procedure, che causa un offcourse di prestazioni.

+0

Fredrik grazie per questo prezioso suggerimento Vorrei tenerlo presente di sicuro :) – user342944

+0

iniezione gallore –

8

Se non volete utilizzare SQL dinamico, i migliori che abbia modo trovato è quello di creare una funzione che trasforma una stringa delimitata in una tabella, qualcosa come questo funziona per una lista 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 

Quindi utilizzare che nella tua 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

grazie per il trucco – 0cool

+0

un po 'lento ma funziona. – johnny

+0

beh, in realtà non è lento. La mia query era già lenta. – johnny

3

Il modo in cui si sta tentando di farlo è leggermente sbagliato. È necessario utilizzare EXECUTE per raggiungere questo obiettivo.

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

Ardman I am getting 'La procedura prevede il parametro' @statement 'di tipo' ntext/nchar/nvarchar 'quando ho provato urs. ora proveremo gli altri – user342944

+0

È dopo la mia modifica? –

+0

L'errore dice che dovresti usare NVARCHAR. Quindi, fallo in questo modo: EXECUTE (N'SELECT ... 'e specifica che il tipo del parametro pGroupdIDS è anche un NVARCHAR. –

0

First creare funzione -

Basta eseguire questo codice

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 

Poi -

funzione Use in staffa con select statment -

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