你能在SQL FROM语句中使用SQLParameter吗?

3

我正在尝试使用C#对SQL Server数据库创建参数化查询。

代码:

        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. 如果可以,为什么这个方法不起作用?

1
关于动态SQL的答案,有一点需要注意。在构建动态SQL时,一定要非常小心,以避免SQL注入攻击。当您动态构建SQL语句时,可能会面临风险,因此请确保对其进行检查,无论是在应用程序中还是在SQL脚本本身中。 - Joe Enos
@Joe 正是因为这个原因,我正在尽可能地将参数化。Where 子句也将完全由参数驱动 - 再加上用户界面没有文本字段,只有复选框和多选列表,我应该会很好地完成任务。 - morganpdx
1
您不能完全信任选择框输入。恶意用户很容易在表单上运行JavaScript来更改值,或者仅手动提交表单以使用他们想要的值,而不是您的表单所限制的值。(假设这是一个Web应用程序,但相同的概念也适用于Windows应用程序,只是有些不同)。因此,请确保您的服务器代码还有另一层保护。 - Joe Enos
@Joe 对啊...这就是我想要对SELECT和FOR语句进行参数化的原因。唉。 - morganpdx
4个回答

7

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


如果你选择这条路,请注意 SQL 注入。 - Abe Miessler
@Abe Miessler:这正是为什么FROM子句不支持替换的原因。 - OMG Ponies
真的吗?为什么它适用于参数但不适用于表名?相关链接:https://dev59.com/PG445IYBdhLWcg3wXZS9 - Abe Miessler
1
一个在连接 SQL 时始终保持安全的简单方法是使用这个结构 string.format("'{0}'", arg.replace("'", "''")) 并将其用于与连接相同语句中的每个参数。除非变量是数字,否则不要相信它。到目前为止,只要你在实现它时保持警惕(即使是在从自己的数据库中读取的数据上),我从未发现任何可以通过此方式绕过的注入攻击。 - David Mårtensson

2
抱歉,您不能在FROM子句中使用参数。

1

我认为这不是SQL命令及其参数应该呈现的方式。它应该像这样:

SELECT fieldName1, fieldName2
FROM   TableName
WHERE  fieldName = @paramName

你不能使用参数作为要选择的字段或目标表的定义。如果你需要定义要选择的字段,只需在调用它之前使用 StringBuilder 组成命令字符串 - 正如你所需要的那样。参数是用于筛选目的。在你的情况下,你不需要任何参数,只需构建并执行你的命令。


1
+1:你的假设是正确的,但别忘了小博比·泰布尔斯 - OMG Ponies

0

如果您确信您的表格和列名字是正确的,那么在构建动态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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接