【问题标题】:Can you use a SQLParameter in the SQL FROM statement?可以在 SQL FROM 语句中使用 SQLParameter 吗?
【发布时间】:2011-02-03 21:37:26
【问题描述】:

我正在尝试在 C# 中针对 SQL 服务器数据库创建参数化查询。

代码:

        query = new StringBuilder( "SELECT @fields FROM @tables");

        using(SqlConnection connection = new SqlConnection(connection))
        {
            SqlCommand command = new SqlCommand(query.ToString(), connection);
            command.Parameters.AddWithValue("@fields", fields.ToString());
            command.Parameters.AddWithValue("@tables", tables.ToString());

            try
            {
                connection.Open();
                Int32 rowsAffected = command.ExecuteNonQuery();
                Console.WriteLine("RowsAffected: {0}", rowsAffected);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

奇怪的是这会失败并显示消息“必须声明表变量\”@tables\”。但是正如您所看到的,它已明确定义。

所以我的问题是:

  1. 能否传递一个参数来定义 FROM 中的表格列表 陈述?
  2. 如果可以,为什么不可以 这行得通吗?

【问题讨论】:

  • 作为这些关于动态 SQL 的答案的旁注。在构建动态 SQL 时,始终、始终、始终要非常小心,以避免 SQL 注入。当您动态构建 SQL 时,您会敞开心扉,因此请确保您正在检查它,无论是在您的应用程序中,还是在 SQL 脚本本身中。
  • @Joe 正是我试图尽可能多地参数化的原因。 Where 子句也将完全由参数驱动 - 再加上用户界面没有文本字段,只有复选框和多选列表这一事实,我应该得到很好的覆盖。
  • 您不一定信任选择框输入。恶意用户很容易在表单上运行 javascript 来更改那里的值,或者简单地手动发布表单并使用他们想要的值,而不是表单应该限制您的内容。 (这是假设这是一个 Web 应用程序,但同样的概念也适用于 Windows 应用程序,只是略有不同)。因此,请确保您的服务器代码中还有另一层保护。
  • @Joe Right...这也是我想要参数化 SELECT 和 FOR 语句的原因。 Fooey。

标签: c# sql parameters


【解决方案1】:

SQL 不支持将 FROM 子句参数化。因此,您必须使用动态 SQL,或在将查询字符串提交到数据库之前创建/连接查询字符串。

【讨论】:

  • 如果你走这条路,请注意 SQL 注入。
  • @Abe Miessler:这正是 FROM 子句不支持替换的原因。
  • 真的吗?为什么它适用于参数而不适用于表名?相关:stackoverflow.com/questions/4892166/…
  • 连接 SQL 时始终保持安全的一种简单方法是使用此构造 `string.format("'{0}'", arg.replace("'", "''")) ` 并在与连接相同的语句中的每个参数上使用它。永远不要相信一个变量,除非它是一个数字。到目前为止,只要您在任何地方都保持警惕(即使是您刚刚从自己的数据库中读取的数据,您也永远不知道其他代码放在那里),我到目前为止还没有发现任何可以通过此的注入)
【解决方案2】:

不,很遗憾,您不能在 FROM 子句中使用参数。

【讨论】:

    【解决方案3】:

    我认为这不是 SQL 命令及其参数应有的样子。它应该看起来像

    SELECT fieldName1, fieldName2
    FROM   TableName
    WHERE  fieldName = @paramName
    

    您不能将参数用作要选择的字段或目标表的定义。如果您需要定义要选择的字段,只需在调用之前在 StringBuilder 中编写命令字符串 - 根据您的需要。参数用于过滤目的。在您的情况下,您不需要任何参数,只需构建您的命令并执行。

    【讨论】:

    【解决方案4】:

    如果您确信您的表名和列名没有问题,那么您可以在构建动态 SQL 之前对数据库进行一些安全检查。

    这只是为了说明 - 对于现实生活,显然你需要让它更清洁:

    declare @TABLE_NAME nvarchar(128)
    set @TABLE_NAME = 'Robert'');DROP TABLE Students;--' -- This line will raise an error
    set @TABLE_NAME = 'BOOK' -- This line will go through properly
    
    declare @sql varchar(max)
    set @sql = 'SELECT * FROM '
    
    if exists (select 1 from sys.objects where type = 'U' and name = @TABLE_NAME)
        begin
            set @sql = @sql + @TABLE_NAME
            exec (@sql)
        end
    else
        begin
            raiserror ('ERROR ERROR ERROR', 0, 0)
            return
        end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-19
      • 2012-09-19
      • 2011-02-25
      • 1970-01-01
      • 1970-01-01
      • 2011-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多