2016-12-07 47 views
0

我目前正试图尝试从我的简单的C#应用​​程序捕获插入SQL查询,但是当我试图插入数据到数据库与用户ID将其添加到userIDList参数中,则出现错误提示哪里在条款错误服务器上最多只支持2100参数

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

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

任何其他解决办法可以解决这个? 谢谢

+0

可能的复制。该服务器最多支持2100个参数](http://stackoverflow.com/questions/23045912/the-incoming-request-has-too-many-parameters-the-server-supports-a-maximum-of-2) –

+0

这有点奇怪,因为你*没有使用参数*(你可能应该是,btw);你也没有使用LINQ,所以你可能不需要这个标签。但是,问题:你使用的是什么版本的sql-server?最简单的“修复”可能是'string_split',但那只是2016年;否则,自定义拆分UDF或表值参数可能是很好的替代品。但是:你确定示例代码是错误的代码吗?因为*不会创建大量参数*(只有2) –

+0

@MarcGravell我正在使用SQL Server 2014,您是什么意思自定义拆分UDF? –

回答

1

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

除了将ID列表作为单独参数发送外,您还可以将单个@IDList参数作为单个逗号分隔的字符串发送,并在服务器端将其解析为ID。下面是我使用的这个(贷款以及从杰夫MODEN的代码修改)功能:

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

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#中很清晰,每种​​方法都是分开的。

编辑:使用罗斯文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 
} 
+0

这是一个存储过程吗? –

+0

不,这是一个TVF(表值函数 - 类似于SP但不是SP)。 –

+0

但我使用C#,在哪里可以找到TVF? –

1

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

我不再能够访问项目,我已经实施了这个项目,但blog post中的所有内容都可用。下面的代码没有经过测试,但我希望它能让你朝正确的方向发展。

1。在你的数据库创建一个新的类型:

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

2.把它作为参数:

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; 
} 

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) 

创建参数方法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