2010-10-25 37 views
8

tôi có một danh sách lớn của các tham số int cho một truy vấn SQL:Big danh sách tham số cho truy vấn SQL

update mytable set col='xyz' 
where id in (/* thousands of ints */) 

Vấn đề của tôi là trong SQL Server 2000 có một giới hạn cho các tham số. Tôi cũng có thể chạy truy vấn này trên SQL Server 2008.

Cách tốt hơn để thực hiện việc này là gì.

Edit:

Danh sách Id đến từ một chương trình C# . Không phải từ một bảng khác.

Trả lời

2

Các soulution làm việc tốt nhất cho tôi là SQL Server 2008: Table Valued Parameters

100000 Id cần 14-20s, 1000 Id cần ~ 140 mili giây.

sql = @" 
    update MyTable 
    set Col1 = 1 
    where ID in (select * from @ids) 
    "; 
sqlCmd = new SqlCommand {Connection = _sqlConn, CommandText = sql}; 

//Create a DataTable with one Column("id") and all ids as DataRows 
DataTable listOfLeadIDs = new DataTable(); 
listOfIDs.Columns.Add("id", typeof(int)); 
Ids.ToList<string>().ForEach(x => listOfIDs.Rows.Add(new object[] { int.Parse(x) })); 

//Bind this DataTable to the Command-object 
// Node: "IntTable" is an User-Defined-Table-Typ (new feature with SQL-2008) 
sqlCmd.Parameters.Add(
    new System.Data.SqlClient.SqlParameter("@ids", listOfIDs) { 
    TypeName = "IntTable" 
    }); 

//Execute the Query 
sqlCmd.ExecuteNonQuery(); 

Các User-Defined-Table-Typ:

CREATE TYPE [dbo].[IntTable] AS TABLE(
    [id] [int] NULL 
) 
GO 
2

Bạn có thể chèn các số nguyên vào một bảng tạm thời, và sau đó truy vấn như thế này:

update mytable m set col='xyz' 
where exists (select * from #MyTempTable where id = m.id) 
+0

Đây có phải là một ý tưởng tốt? thời gian thi công cho 5000x Chèn vào #MyTempTable có thể là cắt cổ. – Floyd

+0

'IN' là ** không ** một tùy chọn tốt nếu danh sách nhiều hơn một vài. 'EXISTS' là con đường để đi. – Brad

+0

@Brad: chính xác, được cập nhật. – RedFilter

1

Tại tất cả các chi phí, TRÁNHIN; đặc biệt là nếu bạn sau năm 2000. my backup


Thay vào đó, sử dụng EXISTS

UPDATE myTable 
SET col = 'newValue' 
FROM myTable 
WHERE EXISTS (
     SELECT * 
     FROM @myTempTable temp 
     WHERE myTable.ID = temp.ID) 
+0

giống như bài đăng RedFilters: thời gian truy tố 5000x Chèn vào #MyTempTable có thể là cắt cổ. – Floyd

+0

Tôi nên nghĩ rằng 5000 chèn của một đơn 'INT' sẽ không được như vậy xấu. Có cách nào khác bạn có thể lấy danh sách 'INT' qua truy vấn không? – Brad

+0

Không, tôi không thể. Đó là vấn đề của tôi. Danh sách các Id tạo bởi một chương trình. – Floyd

2

Một cách tiếp cận thay thế mà làm việc với SQL 2000 là sử dụng XML.

Có định dạng chương trình/ứng dụng ints như vậy:

'<root><TMP J="111"/><TMP J="222"/><TMP J="333"/></root>' 

.
Sau đó tạo thủ tục được lưu trữ sau đây:

CREATE PROCEDURE UpDateIntsFromXML (
    @sXML TEXT 
) 
AS 
    DECLARE @iDoc INT 
    EXEC sp_xml_preparedocument @iDoc OUTPUT, @sXML 

    UPDATE YourTable 
    SET  YourColumn = 'fixed value' 
    FROM OPENXML (@iDoc, '/root/TMP', 1) WITH (J INT) AS X 
    WHERE X.J = YourTable.IntColumn 

    EXEC sp_xml_removedocument @iDoc 
RETURN 

.
Sau đó, ứng dụng của bạn có thể gọi SP đó, chuyển một khối văn bản/XML có khả năng lớn.

Quan sát rằng root, TMPJ đều phân biệt chữ hoa chữ thường.

+0

Cách này có thể hoạt động, chúng tôi sẽ thử điều này. Chúng tôi cũng tìm thấy hai cách khác: * lúc đầu *: [Bảng tham số có giá trị] (http://lennilobel.wordpress.com/2009/07/29/sql-server-2008-table-valued-parameters-and- c-custom-iterators-a-match-made-in-heaven /) * hoặc * SqlBulkCopy .. chúng tôi cũng sẽ thử điều này. – Floyd

+0

+1, tôi thích điều này. Floyd, hãy cho chúng tôi biết nếu nó hoạt động. – Brad

+0

Hoạt động này nhưng Bảng-Giá trị-Tham số nhanh hơn. nhưng tính năng này không hoạt động với SQL-2000. – Floyd

0

Chia dữ liệu thành các nhóm nhỏ hơn và thực hiện nhiều truy vấn cập nhật.

Không có lý do gì để sử dụng bảng tạm thời, vì bạn truy xuất dữ liệu từ bên ngoài db, vì vậy không có cách nào để tránh việc chuyển dữ liệu của nó về phía db.

+0

Điều này làm việc với 'IN' hoặc' EXISTS' nhưng không phải với 'NOT IN' hoặc' NOT EXISTS' – Floyd

+0

Nhưng truy vấn không sử dụng 'IN', không phải là 'NOT IN'. Bạn thực hiện cùng một truy vấn nhưng nhiều lần, trên các tập dữ liệu nhỏ hơn ... – Andy

+0

Nhưng câu hỏi của tôi là "danh sách tham số bit cho truy vấn sql" không phải "danh sách tham số bit cho" trong "truy vấn" .. truy vấn chỉ là một exampel. – Floyd

0

Nếu ints theo bất kỳ cách nào tuần tự (nhiều hơn hai lần cùng một lúc), bạn có thể đặt chúng thành BETWEEN cặp.

Nhưng trong trường hợp này, chỉ cần tạo một chuỗi các int này và chuyển nó thành một tham số varchar(max).

-2

Tôi nghĩ bạn có thể muốn tạo bảng tạm thời dựa trên bộ nhớ bằng chỉ mục. Giả sử bảng bạn đang truy vấn là lớn, bạn sẽ không muốn thực hiện quét bảng so sánh từng hàng với mỗi 5000 kết quả phù hợp. Bạn muốn tham gia với sự giúp đỡ của hai chỉ mục.

CREATE TEMPORARY TABLE IF NOT EXISTS inputlist 
(i INT PRIMARY KEY) ENGINE = MEMORY; 

INSERT INTO inputlist (i) VALUES (1),(2),(3),(1000),(2000),(5000); 

SELECT * FROM your_table JOIN inputlist ON your_table.intvalues = inputlist.i; 

DROP TEMPORARY TABLE inputlist; 

SQL dựa trên MySQL, xem:
http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html
http://dev.mysql.com/doc/refman/5.1/en/insert.html
http://dev.mysql.com/doc/refman/5.1/en/create-table.html

+0

công việc doenst này với sql-2000 hoặc sql-2008. Nếu tôi cố gắng quá làm điều này với chèn singel (đa insets arnt hỗ trợ trong sql-2000) tôi nhận được một lỗi: 'Msg 8621, Level 17, State 88, Line 5 Bộ xử lý truy vấn nội bộ Lỗi: Bộ xử lý truy vấn chạy ra khỏi không gian ngăn xếp trong quá trình tối ưu hóa truy vấn.' Tôi sẽ gửi các đoạn chèn vào trong các khối nhưng điều này cần nhiều thời gian để vận chuyển và biên dịch câu lệnh. – Floyd

+0

Sai lầm của tôi, tôi không chú ý đến lưu ý MS Sql. Tôi không quen thuộc lắm, nhưng tôi đã lưu ý một trang gợi ý giải pháp cho vấn đề này, có thể đáng để thử nghiệm nhanh: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId = 897 & lngWId = 5 –

+0

Linh hồn này (từ nguồn của quicktest) hoạt động nhưng chỉ với một số rất ít id. không phải với hàng trăm và không phải với thousends. – Floyd

Các vấn đề liên quan