其中In Clause错误服务器仅支持最多2100个参数

时间:2016-12-07 08:29:11

标签: c# sql

我正在尝试从我的简单C#应用程序中尝试捕获插入SQL查询,但是当我尝试将数据插入到具有添加到userIDList参数中的用户ID的数据库时,出现错误说< / p>

  

传入的请求包含太多参数。服务器支持   最多2100个参数。

userIDList有时会包含60个以上的数组,然后会弹出错误。

我的SQL CommandText将包含

"SELECT * FROM TIME_ATTENDANCE_REPORT WHERE TRXDATETIME = @Date AND USERID IN (001,002,003,004,....)

所以我认为如果超过某个数字,那么错误弹出

以下是我的示例代码:

List<string> userIDList = new List<string>();
using (SqlCommand sqlDBComm = new SqlCommand())
                    {
                        openConnection();
                        SqlDataReader sqlDBReader;
                        sqlDBReader = null;
                        sqlDBComm.CommandText = "SELECT * FROM TIME_ATTENDANCE_REPORT WHERE TRXDATETIME = @Date AND USERID IN (" + string.Join(",", userIDList) + ") ORDER BY USERID ASC ";
                        sqlDBComm.Parameters.Add("@Date", SqlDbType.DateTime);
                        sqlDBComm.Parameters["@Date"].Value = GetDateFrom;
                        sqlDBComm.Connection = sqlDB;
                        sqlDBComm.CommandType = CommandType.Text;
                        try
                        {
                            sqlDBReader = sqlDBComm.ExecuteReader();
                            t.Load(sqlDBReader);
                            sqlDBReader.Close();

                            if (t.Rows.Count > 0)
                            {
                                status = "Update";
                            }
                            else
                            {
                                status = "Insert";
                            }
                        }
                        catch (Exception errMsg)
                        {
                            MessageBox.Show("Error Code: " + errMsg.ToString());
                        }
                        finally
                        {
                            sqlDBReader.Close();
                            closeConnection();
                        }
                    }

任何其他解决方案都可以解决此问题? 感谢

2 个答案:

答案 0 :(得分:1)

有很多方法可以解决这个问题。

您可以将单个@IDList参数作为单个逗号分隔的字符串发送,而不是将ID列表作为单独的参数发送,并将其解析为服务器端的ID。这是我用于此的一个函数(从Jeff Moden的代码中借用和修改):

CREATE FUNCTION [dbo].[iSplitter] (@Parameter VARCHAR(MAX))
RETURNS @splitResult TABLE (number INT, [value] INT)
AS
BEGIN
SET @Parameter = ','+@Parameter +',';

WITH cteTally AS
    (
        SELECT TOP (LEN(@Parameter))
            ROW_NUMBER() OVER (ORDER BY t1.Object_ID) AS N
            FROM Master.sys.All_Columns t1
            CROSS JOIN Master.sys.All_Columns t2
    )
INSERT @splitResult
    SELECT ROW_NUMBER() OVER (ORDER BY N) AS Number,
    SUBSTRING(@Parameter,N+1,CHARINDEX(',',@Parameter,N+1)-N-1) AS [Value]
    FROM cteTally
        WHERE N < LEN(@Parameter) AND SUBSTRING(@Parameter,N,1) = ','
RETURN
END

创建此功能一次后,我会这样做:

sqlDBComm.CommandText = @"SELECT * FROM TIME_ATTENDANCE_REPORT tar
    inner Join dbo.iSplitter(@UserIdList) ul on tar.USERID = ul.[value]
    WHERE TRXDATETIME = @Date
    ORDER BY USERID ASC ";
sqlDBComm.Parameters.AddWithValue("@UserIdList",string.Join(",", userIDList));

这适用于5-6K整数ID,但如果与20-30K或更多ID一起使用则超时。然后我创建了另一个替代方案作为CLR过程,并且在不到一秒的时间内解析列表服务器端。但我认为这个足以满足您的需求。

另一种方法是将ID作为XML参数发送并再次解析服务器端。

另一种方法是发送表参数。

PS:这是link that shows sample code for other ways。该网站使用土耳其语,但C#中的代码非常清晰,按照方法分开。

编辑:使用Northwind Orders表的XML示例:

void Main()
{
    int[] IDList = { 10265,10266,10267,10268,10269,10270,10271,10272,10273,10274,10275, 10320, 10400 };
    var idsAsXML = new XElement("IDS",
        from i in IDList
        select new XElement("Row", new XAttribute("Id", i)));

    string sql = @"
  DECLARE @hDoc int;
  DECLARE @tbl TABLE (Id int);
  exec sp_xml_preparedocument @hDoc OUTPUT, @XML;
  INSERT @tbl 
    SELECT * 
    FROM OPENXML(@hDoc, @Nodename, 1) WITH (Id int);
  EXEC sp_xml_removedocument @hDoc;

  select * from Orders o
  where exists (select * from @tbl t where t.Id = o.OrderId) ";

    DataTable tbl = new DataTable();
    using (SqlConnection con = new SqlConnection(@"server=.\SQLExpress;Trusted_Connection=yes;Database=Northwind"))
    {
        SqlCommand cmd = new SqlCommand(sql, con);
        cmd.Parameters.AddWithValue("@XML", idsAsXML.ToString());
        cmd.Parameters.AddWithValue("@NodeName", "/IDS/Row");
        con.Open();
        tbl.Load(cmd.ExecuteReader());
        con.Close();
    }

    //tbl.Dump(); // linqPad luxury
}

答案 1 :(得分:1)

您可以创建Table-Valued-Parameter并将其作为参数传递。它要求您在数据库中创建一个新类型,并使您能够将数组传递给查询,并让数据库将其视为表。如果这是你做了很多的事情,它可以派上用场。

我无法再访问我实施此项目的项目,但blog post中提供了所有内容。下面的代码没有经过测试,但我希望它可以帮助您找到正确的方向。

1。在数据库中创建新类型:

CREATE TYPE integer_list_tbltype AS TABLE (n int NOT NULL PRIMARY KEY)

2. 将其作为参数传递:

sqlDBComm.Parameters.Add("@userIds", SqlDbType.Structured)
sqlDBComm.Parameters["@userIds"].Direction = ParameterDirection.Input
sqlDBComm.Parameters["@userIds"].TypeName = "integer_list_tbltype"
sqlDBComm.Parameters["@userIds"].Value = CreateDataTable(userIDList)

3. 创建参数的方法:

private static DataTable CreateDataTable(IEnumerable<int> ids) {
    DataTable table = new DataTable();
    table.Columns.Add("n", typeof(int));
    foreach (int id in ids) {
        table.Rows.Add(id);
    }
    return table;
}

4. 在SQL中使用它:

... AND USERID IN (SELECT n FROM @userIds)
从这里

CreateDataTable

How to pass table value parameters to stored procedure from .net code

从这里休息:

http://www.sommarskog.se/arrays-in-sql-2008.html#introduction