2011-01-06 52 views
5

Tôi đang phát triển một ứng dụng ASP.NET và chuyển một giá trị chuỗi như "1,2,3,4" vào một quy trình để chọn các giá trị đó là IN (1,2, 3,4) nhưng nói rằng "Chuyển đổi không thành công khi chuyển đổi giá trị varchar '1,2,3,4' thành kiểu dữ liệu int."SQL sử dụng giá trị được phân cách bằng dấu phẩy với mệnh đề IN

Đây là mã 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(); 
} 

Dưới đây là thủ tục của tôi:

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

Trả lời

8

Đây là một workaround tôi thấy để làm những gì bạn đang cố gắng để đạt được

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

này được danh sách phân dấu phẩy của bạn và so sánh nó với id (mà được biểu diễn như vậy ',1,', ',2,' vv) trong bảng sử dụng LIKE

+0

Fantasticoooooooooo :) :) Drahcir nó hoạt động như nét duyên dáng – user342944

+2

Tôi không nghĩ rằng giải pháp này sẽ hoạt động tốt trên các tập dữ liệu lớn, vì không có chỉ mục nào có thể được sử dụng trong trường hợp này. (Không thể sử dụng các chỉ mục khi bạn thêm tiền tố đối số tìm kiếm của một biểu thức tương tự với ký tự đại diện). –

1

Bạn cần phải sử dụng sp_executesql để đạt functionllity này

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 có nghĩa là xây dựng một chuỗi sql và thực hiện? – user342944

+0

@ user342944 - yes –

1

Mệnh đề IN có' t lấy một tham số ràng buộc như thế. Những gì nó đang được đưa ra khi truy vấn thực sự được tạo ra là SELECT * FROM CheckList_Groups Where id in ('1,2,3,4'). Về cơ bản mệnh đề IN đang được truyền một chuỗi duy nhất.

6

Chắc chắn nó không thể làm điều đó,

Truy vấn tạo sẽ sth như thế này

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

và chắc chắn nó không thể được thực thi.

bạn có thể xây dựng các truy vấn trong thủ tục lưu trữ của bạn sau đó thực hiện nó với exec

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

hoặc

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

nhưng trước tiên bạn phải thêm ',' để bắt đầu và kết thúc của tham số của bạn trong c của bạn # mã số

3

Không thể đặt các giá trị đó (chuỗi được phân tách bằng dấu phẩy) trong một giá trị tham số.

Những gì bạn sẽ phải làm, là tạo ra các câu lệnh SQL trong thủ tục lưu trữ của bạn tự động, bằng chuỗi nối. Bạn sẽ phải thực thi nó với quy trình được lưu trữ sp_executesql sau đó.

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 

Ngoài ra, không phải tôi đặt tên SP getUserRoles thay vì sp_getUserRoles. Lý do rất đơn giản: khi bạn thực hiện một thủ tục được lưu trữ có tên bắt đầu bằng sp_, thì SQL Server trước tiên sẽ truy vấn cơ sở dữ liệu master để tìm quy trình được lưu trữ, gây ra hiệu suất truy cập.

+0

Fredrik cảm ơn bạn vì đề xuất có giá trị này, tôi sẽ ghi nhớ điều này một cách chắc chắn :) – user342944

+0

tiêm gallore –

8

Nếu bạn không muốn sử dụng sql năng động, ive cách tốt nhất tìm thấy là để tạo ra một chức năng mà biến một chuỗi phân định vào một bảng, một cái gì đó như thế này làm việc cho một danh sách 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 

Sau đó sử dụng trong sp của bạn:

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

nhờ mẹo vặt – 0cool

+0

một chút chậm nhưng hoạt động. – johnny

+0

cũng thực sự không chậm. Truy vấn MY đã chậm. – johnny

3

Cách bạn đang cố gắng làm điều này là hơi sai. Bạn sẽ cần phải sử dụng EXECUTE để đạt được điều này.

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

Ardman Tôi nhận được 'Procedure expected parameter' @statement 'của loại' ntext/nchar/nvarchar 'lỗi khi tôi thử urs. bây giờ sẽ thử những người khác – user342944

+0

Đó có phải là sau khi tôi chỉnh sửa không? –

+0

Lỗi nói bạn nên sử dụng NVARCHAR. Vì vậy, làm như thế này: EXECUTE (N'SELECT ... 'và chỉ định rằng kiểu tham số pGroupdIDS cũng là một NVARCHAR. –

0

Chức năng tạo đầu tiên -

Chỉ cần chạy mã này

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 

Sau đó -

Sử dụng chức năng trong khung với chọn Statment -

DECLARE @LIST VARCHAR(200) 
SET @LIST = '1,3' 
SELECT Id, Descr FROM CSVDemo WHERE Id IN (SELECT * FROM dbo.CSVToTable(@LIST)) 
Các vấn đề liên quan