【问题标题】:How to combine multiple SQL Commands into one?如何将多个 SQL 命令合二为一?
【发布时间】:2018-10-24 11:16:41
【问题描述】:

是否可以通过将以下查询合并到单个 SQLCommand 中来优化它们?

SqlCommand cmd = new SqlCommand
{
    CommandType = CommandType.Text,
    CommandText = "DELETE FROM cbu_naslovi WHERE [ID]='" + CurrentID + "'",
    Connection = con
};
SqlCommand cmd1 = new SqlCommand
{
    CommandType = CommandType.Text,
    CommandText = "DELETE FROM cbu_deli WHERE [IDX]='" + CurrentID + "'",
    Connection = con
};
cmd.ExecuteNonQuery();
cmd1.ExecuteNonQuery();

编辑:工作解决方案,正如下面的社区回答所建议的那样

SqlCommand cmd = new SqlCommand
{
    CommandType = CommandType.Text,
    CommandText = "DELETE FROM cbu_naslovi WHERE [ID] = @CurrentID; DELETE FROM cbu_deli WHERE [IDX] = @CurrentID",
    Connection = con
};
cmd.Parameters.AddWithValue("@CurrentID", CurrentID);
cmd.ExecuteNonQuery();

【问题讨论】:

  • 您可以使用需要一次数据库调用的存储过程吗?
  • CurrentID = "'; 删除表 cbu_deli; --"
  • 从两个不同的表中删除是两种不同的逻辑操作。您不能仅通过将命令填充在一起来优化它们,因为解析它们不是瓶颈。发出两个命令完全没问题。 (但是,正如已经提到的,使用参数来防止 SQL 注入。像 Dapper 这样的微型 ORM 使这变得如此简单,没有理由不这样做。)
  • @JeroenMostert,微软的SqlParameter 类也很容易使用;)
  • @Adephx 在这种情况下注入是不可能的,但手动构建 sql 命令通常不是一个好习惯。您也没有说明 CurrentID 类型,但您将其值括在撇号中 - 这暗示了一些文本价值......如果我的评论难以理解,但您阅读并理解了 - 那么也许我的评论对您有一些价值毕竟:)

标签: c# sql wpf


【解决方案1】:

是的,您可以用分号分隔它们。例如,我有在单个调用中执行以下代码的代码

SET NOCOUNT ON;
DECLARE @decimalDate DECIMAL(12,0);
DECLARE @charDate CHAR(12);
DECLARE @utcDate DATETIMEOFFSET;
DECLARE date_cursor CURSOR FOR SELECT {1} FROM {0} WHERE ISNULL({1},0)!=0;
OPEN date_cursor;
FETCH NEXT FROM date_cursor INTO @decimalDate;
WHILE @@FETCH_STATUS=0
BEGIN
    BEGIN TRY SET @charDate=CONVERT(CHAR(12),@decimalDate);
        SET @utcDate=SwitchOffset(
                CONVERT(DATETIME,'20'
                    +SUBSTRING(@charDate,1,2)+'-'+SUBSTRING(@charDate,3,2)+'-'
                    +SUBSTRING(@charDate,5,2)+' '+SUBSTRING(@charDate,7,2)+':'
                    +SUBSTRING(@charDate,9,2)+':'+SUBSTRING(@charDate,11,2)
                ,121) AT TIME ZONE '{3}',0);
    END
    TRY BEGIN CATCH
        SET @utcDate=SysUtcDateTime();
    END CATCH;
    BEGIN
        TRY UPDATE {0} SET {2}=@utcDate WHERE CURRENT OF date_cursor;
    END TRY
    BEGIN CATCH END CATCH;
    FETCH NEXT FROM date_cursor INTO @decimalDate;
END;
CLOSE date_cursor;
DEALLOCATE date_cursor;

也有例外。例如,“创建过程”语句必须是块的第一条语句。但大多数 DML 都可以像这样进行批处理。

【讨论】:

  • 请注意,SQL Server 支持最近被称为“换行符”的创新,即使语句也用分号分隔,也可以熟练使用。即使它需要多两个字节。
  • 你肯定在这里为其他人编写代码,而不是为机器编写代码;)
【解决方案2】:

你可以这样写:

SqlCommand cmd = new SqlCommand
{
    CommandType = CommandType.Text,
    CommandText = $"DELETE FROM cbu_naslovi WHERE [ID]='{CurrentID}';DELETE FROM cbu_deli WHERE [IDX]='{CurrentID}'",
    Connection = con
};

【讨论】:

  • “$”代表什么?我假设 {string} 是 +string+? 的替代品
  • 是C#中的字符串插值,基本上比string.format()更易读。但仍然使用与此相反的参数。
  • @smolchanovsky 我可以肯定地认为这是正确的方法? CommandText = "DELETE FROM cbu_naslovi WHERE [ID] = @CurrentID; DELETE FROM cbu_deli WHERE [IDX] = @CurrentID",cmd.Parameters.AddWithValue("@CurrentID", CurrentID);
  • 这不应该仅仅因为可能存在 SQL 注入漏洞而被接受。
【解决方案3】:

如果你需要运行非查询操作,你可以尝试使用Server对象来执行一堆命令。 好处:您可以在 SQL 语句中使用GOCommand 不允许使用GO

server.ConnectionContext.ExecuteNonQuery("your SQL statement -- could be 100 statements with hundrends of GO commands", ExecutionTypes.Default)

服务器变量的类型为Server

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多