2008-09-17 26 views
6

Làm việc với SqlCommand trong C# Tôi đã tạo truy vấn có chứa phần IN (danh sách ...) trong mệnh đề where. Thay vì lặp qua danh sách chuỗi của tôi tạo danh sách tôi cần cho truy vấn (nguy hiểm nếu bạn nghĩ trong sqlInjection). Tôi nghĩ rằng tôi có thể tạo ra một tham số như:Danh sách chuỗi trong SqlCommand thông qua tham số trong C#

SELECT blahblahblah WHERE blahblahblah IN @LISTOFWORDS 

Sau đó, trong đoạn code tôi cố gắng thêm một tham số như thế này:

DataTable dt = new DataTable(); 
dt.Columns.Add("word", typeof(string)); 
foreach (String word in listOfWords) 
{ 
    dt.Rows.Add(word); 
} 
comm.Parameters.Add("LISTOFWORDS", System.Data.SqlDbType.Structured).Value = dt; 

Nhưng điều này không làm việc.

Câu hỏi:

  • Am Tôi cố gắng một cái gì đó không thể?
  • Tôi đã sử dụng phương pháp sai?
  • Tôi có sai sót trong cách tiếp cận này không?

Cảm ơn thời gian của bạn :)

Trả lời

3

Những gì bạn đang cố gắng làm là có thể nhưng không sử dụng cách tiếp cận hiện tại của bạn. Đây là một vấn đề rất phổ biến với tất cả các giải pháp có thể có trước khi SQL Server 2008 có các giao dịch liên quan đến hiệu suất, bảo mật và sử dụng bộ nhớ.

This link shows some approaches for SQL Server 2000/2005

SQL Server 2008 supports passing a table value parameter.

Tôi hy vọng điều này sẽ giúp.

+4

Các điểm liên kết đầu tiên giống với số thứ hai – Matt

+0

Các giải pháp tốt :) – graffic

3

Bạn muốn suy nghĩ về nơi danh sách đó đến từ đâu. Nói chung thông tin đó nằm trong cơ sở dữ liệu ở đâu đó. Ví dụ, thay vì điều này:

SELECT * FROM [Table] WHERE ID IN (1,2,3) 

Bạn có thể sử dụng một subquery như thế này:

SELECT * FROM [Table] WHERE ID IN (SELECT TableID FROM [OtherTable] WHERE OtherTableID= @OtherTableID) 
+0

Thật không may là thông tin không nằm trên một bảng khác. Là kết quả của một số thu thập dữ liệu. Nhưng là một cách tiếp cận tốt mà tôi sẽ viết ra để sử dụng trong tương lai. Cảm ơn – graffic

0

Tôi muốn giới thiệu cách thiết lập các thông số như là một chuỗi dấu phẩy phân cách các giá trị và sử dụng một hàm Split trong SQL để biến nó thành một bảng cột của các giá trị và sau đó bạn có thể sử dụng tính năng IN.

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648 - Split Chức năng

+0

Đó là khá Sql Injection dễ bị: ( – graffic

1

Nếu tôi hiểu đúng, bạn đang cố gắng để vượt qua một danh sách như một tham số SQL.

Một số người đã cố gắng này trước khi thành công có giới hạn:

Passing Arrays to Stored Procedures

Arrays and Lists in SQL 2005

Passing Array of Values to SQL Server without String Manipulation

Using MS SQL 2005's XML capabilities to pass a list of values to a command

+0

Các liên kết đầu tiên nói về một biến bảng.Đây là những gì tôi đã tạo với DataTAble.Nhưng trong trường hợp này tôi không thể làm cho mssql nuốt nó. – graffic

0

Nếu bạn muốn vượt qua danh sách dưới dạng chuỗi trong một tham số, bạn chỉ có thể tạo truy vấn động .

DECLARE @query varchar (500) SET @query = 'SELECT blah blah Ở ĐÂU blahblah trong (' + @list + ')' EXECUTE (@query)

+1

Khá dễ dàng SQL Injection: (Nhưng cảm ơn :) – graffic

0

Tôi đã từng có cùng một vấn đề, Tôi nghĩ rằng bây giờ có cách để làm điều này trực tiếp trên API ADO.NET.

Bạn có thể xem xét chèn các từ vào một từ dễ cám dỗ (cộng với một queryid hoặc một cái gì đó) và sau đó đề cập đến điều đó dễ bị cám dỗ từ truy vấn. Hoặc tự động tạo chuỗi truy vấn và tránh chèn sql bằng các biện pháp khác (ví dụ: kiểm tra regex).

+0

Tôi sẽ đi với các tùy chọn đầu tiên + chèn sql số lượng lớn.Có lẽ điều này có thể giúp tôi tiết kiệm một số SQL I/O – graffic

1
  • Tôi có đang thử điều gì đó không thể?

Không, không phải là không thể.

  • Tôi đã tiếp cận sai?

cách tiếp cận của bạn không hoạt động (ít nhất là trong .net 2)

  • Tôi có sai lầm trong phương pháp này?

Tôi sẽ thử giải pháp "Joel Coehoorn" (câu trả lời thứ 2) nếu có thể. Nếu không, một tùy chọn khác là gửi thông số "chuỗi" với tất cả các giá trị được phân tách bằng dấu phân cách. Viết một truy vấn động (xây dựng nó dựa trên các giá trị từ chuỗi) và thực hiện nó bằng cách sử dụng "exec".

Một giải pháp khác sẽ là o tạo truy vấn trực tiếp từ mã. Somthing như thế này:

StringBuilder sb = new StringBuilder(); 
for (int i=0; i< listOfWords.Count; i++) 
{ 
    sb.AppendFormat("p{0},",i); 
    comm.Parameters.AddWithValue("p"+i.ToString(), listOfWords[i]); 
} 

comm.CommandText = string.Format(""SELECT blahblahblah WHERE blahblahblah IN ({0})", 
sb.ToString().TrimEnd(',')); 

Lệnh sẽ giống như thế:

SELECT blah WHERE blah IN (p0,p1,p2,p3...)...p0='aaa',p1='bbb' 

Trong MsSql2005, "IN" chỉ đang làm việc với 256 giá trị.

+0

Trên truy vấn dưới cùng, tôi gặp lỗi khi xuất hiện lần đầu tiên của p0. – micahhoover

0

Đây là một câu hỏi cũ nhưng tôi đã đưa ra một giải pháp thanh lịch cho điều này mà tôi thích sử dụng lại và tôi nghĩ rằng mọi người khác sẽ thấy nó hữu ích.

Trước hết, bạn cần phải tạo một FUNCTION trong SqlServer có đầu vào được phân tách và trả về một bảng có các mục được chia thành các bản ghi.

Dưới đây là đoạn mã sau cho việc này:

ALTER FUNCTION [dbo].[Split] 
(
    @RowData nvarchar(max), 
    @SplitOn nvarchar(5) = ',' 
) 
RETURNS @RtnValue table 
(
    Id int identity(1,1), 
    Data nvarchar(100) 
) 
AS 
BEGIN 
    Declare @Cnt int 
    Set @Cnt = 1 

    While (Charindex(@SplitOn,@RowData)>0) 
    Begin 
     Insert Into @RtnValue (data) 
     Select 
      Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1))) 

     Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData)) 
     Set @Cnt = @Cnt + 1 
    End 

    Insert Into @RtnValue (data) 
    Select Data = ltrim(rtrim(@RowData)) 

    Return 
END 

Bây giờ bạn có thể làm một cái gì đó như thế này:

Select Id, Data from dbo.Split('123,234,345,456',',') 

Và đừng sợ, đây không phải có thể dễ bị tấn công SQL injection.

Tiếp theo viết một stored procedure mà mất dữ liệu dấu phẩy của bạn được phân định và sau đó bạn có thể viết một câu lệnh SQL có sử dụng chia chức năng này:

CREATE PROCEDURE [dbo].[findDuplicates] 
    @ids nvarchar(max) 
as 
begin 
    select ID 
     from SomeTable with (nolock) 
    where ID in (select Data from dbo.Split(@ids,',')) 
end 

Bây giờ bạn có thể viết một C# wrapper xung quanh nó:

public void SomeFunction(List<int> ids) 
{ 
    var idsAsDelimitedString = string.Join(",", ids.Select(id => id.ToString()).ToArray()); 

    // ... or however you make your connection 
    var con = GetConnection(); 

    try 
    { 
     con.Open(); 

     var cmd = new SqlCommand("findDuplicates", con); 

     cmd.Parameters.Add(new SqlParameter("@ids", idsAsDelimitedString)); 

     var reader = cmd.ExecuteReader(); 

     // .... do something here. 

    } 
    catch (Exception) 
    { 
     // catch an exception? 
    } 
    finally 
    { 
     con.Close(); 
    } 
} 
Các vấn đề liên quan