【问题标题】:How do I provide a string of Ids in a Select statement's IN clause even though the column is an integer即使列是整数,如何在 Select 语句的 IN 子句中提供 Id 字符串
【发布时间】:2010-10-19 00:18:52
【问题描述】:

我正在使用ObjectDataSource 分页数据,我有以下方法:

public int GetNumberOfArticles(string employeeIds)
{
    System.Data.DataTable dataTable;
    System.Data.SqlClient.SqlDataAdapter dataAdapter;
    System.Data.SqlClient.SqlCommand command;

    int numberOfArticles = 0;

    command = new System.Data.SqlClient.SqlCommand();
    command.Connection = Classes.Database.SQLServer.SqlConnection;

    command.CommandText = @"SELECT COUNT(*)
                            FROM 
                                  [Articles]
                            WHERE 
                                  [Articles].[EmployeeID] IN (@EmployeeIds)";

    command.Parameters.AddWithValue("@EmployeeIds", employeeIds);
    numberOfArticles = (int)command.ExecuteScalar();
    return numberOfArticles;
}

EmployeeID 是一个整数,因此,我放在employeeIds 中的任何内容都将转换为整数。但是,因为我使用的是 IN 关键字,很明显我想用逗号分隔的 id 列表替换 employeeIds

1, 2, 3

但是当我换行时:

command.Parameters.AddWithValue("@EmployeeIds", employeeIds);

类似:

command.Parameters.AddWithValue("@EmployeeIds", "1, 2, 3");

我收到一个异常,因为我提供了一个字符串,而 EmployeeIds 是一个整数。那么,我该怎么做呢?

谢谢。

编辑:

从回复中,我知道这必须手动完成,但是包含此方法的类将由ObjectDataSource 自动创建。那么如何在运行时提供employeeIds 的值呢?

【问题讨论】:

    标签: c# parameters sqlcommand sql


    【解决方案1】:

    这样做的唯一方法是在查询中手动解析字符串并将值插入内存表,然后在查询中加入内存表,而不是使用IN 子句。

    例如,this page on CodeProject 提供了这个功能:

    IF EXISTS(SELECT * FROM sysobjects WHERE ID = OBJECT_ID(’UF_CSVToTable’))
     DROP FUNCTION UF_CSVToTable
    GO
    
    CREATE FUNCTION UF_CSVToTable
    (
     @psCSString VARCHAR(8000)
    )
    RETURNS @otTemp TABLE(sID VARCHAR(20))
    AS
    BEGIN
     DECLARE @sTemp VARCHAR(10)
    
     WHILE LEN(@psCSString) > 0
     BEGIN
      SET @sTemp = LEFT(@psCSString, ISNULL(NULLIF(CHARINDEX(',', @psCSString) - 1, -1),
                        LEN(@psCSString)))
      SET @psCSString = SUBSTRING(@psCSString,ISNULL(NULLIF(CHARINDEX(',', @psCSString), 0),
                                   LEN(@psCSString)) + 1, LEN(@psCSString))
      INSERT INTO @otTemp VALUES (@sTemp)
     END
    
    RETURN
    END
    Go
    

    然后你可以像这样使用它:

    SELECT                          
        COUNT(*)
    FROM 
        [Articles]
    
    JOIN dbo.UF_CSVToTable(@EmployeeIds) ids on ids.sID = [Articles].[EmployeeID]
    

    不过,最终,这通常不是一个好习惯。但是如果有必要,那么这种方法应该以一种非常直接的方式提供给您。

    【讨论】:

    • +1,但你为什么说这不是很好的做法?如果您的数据库支持 UDF,这是一个很好的解决方案。对于更复杂的查询,此解决方案为您提供准备执行的好处:technet.microsoft.com/en-us/library/ms131667.aspx
    • 这是不好的做法,因为它不能(也不能)很好地扩展。如果您采用这种方法,您将受到数据类型的最大容量的限制。如果您走动态 SQL 路线,您将失去可重用执行计划的优势,并假设允许使用动态 SQL。
    【解决方案2】:

    您可以使用字符串连接创建这样的 SQL 语句:

    “选择...输入 (@id1,@id2,@id3)”

    然后:

    command.Parameters.AddWithValue("@id1", employeeIds[0]); command.Parameters.AddWithValue("@id2", employeeIds[1]); command.Parameters.AddWithValue("@id3", employeeIds[2]);

    (当然使用 for 循环)。

    这样你仍然可以使用参数插入值。

    【讨论】:

    • thnx,但我不知道会有多少个 ID。只有在运行时我才会知道。
    • 不知道ID个数也没关系,动态创建SQL。
    【解决方案3】:

    类似于this question,需要在运行时为每个值添加一个参数:

    public int GetNumberOfArticles(string employeeIds)
    {
        System.Data.DataTable dataTable;
        System.Data.SqlClient.SqlDataAdapter dataAdapter;
        System.Data.SqlClient.SqlCommand command;
    
        int numberOfArticles = 0;
    
        command = new System.Data.SqlClient.SqlCommand();
        command.Connection = Classes.Database.SQLServer.SqlConnection;
    
        string params = string.Join(",", employeeIds.Select((e, i)=> "@employeeId" + i.ToString()).ToArray());
        command.CommandText = @"SELECT                          
                                   COUNT(*)
                                FROM 
                                   [Articles]
                                WHERE 
                                   [Articles].[EmployeeID] IN (" + params + ")";
    
        for (int i = 0; i < employeeIds.Length; i++) {
           command.Parameters.AddWithValue("@employeeId" + i.ToString(), employeeIds[i]);
        }
    
        numberOfArticles = (int)command.ExecuteScalar();
    
        return numberOfArticles;
    }
    

    【讨论】:

      【解决方案4】:

      参数是一个不同的值,不能像您尝试那样用于动态创建 SQL 语句。您将需要使用字符串连接来创建 SQL 语句,这可能很简单:

      command.CommandText = @"SELECT COUNT(*) FROM [Articles] " +
          "WHERE [Articles].[EmployeeID] IN (" + employeeIds + ")";
      

      但是,如果它来自用户输入,则需要对 employeeIds 字符串进行清理,以避免 SQL 注入漏洞。您可以通过将字符串拆分为数组并解析每个元素以检查它是否为 int 来做到这一点。如果它通过了,那么你可以在连接之前将数组重新加入一个字符串。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-07
        • 1970-01-01
        • 2021-09-19
        • 2020-06-20
        • 1970-01-01
        相关资源
        最近更新 更多