【问题标题】:Problem with a dynamic function in SQL ServerSQL Server 中的动态函数问题
【发布时间】:2020-06-23 21:32:11
【问题描述】:

我有一张表dbo.t_products,我想知道最后更新的记录。为此,我有一个属性last_changed,它为每条记录存储上次更新的时间戳。

最后,我想将结果保存在一个名为 @y 的变量中。

DECLARE @y DATETIME
DECLARE @p_table VARCHAR(100)

SET @p_table = 'dbo.t_products'

EXECUTE sp_executesql N'SET @y = SELECT MAX(last_changed) FROM @p_table'
                        ,N'@p_table VARCHAR, @y DATETIME OUTPUT'
                        ,@p_table
                        ,@y OUTPUT
SELECT @y

系统返回如下信息:

消息 156,第 15 级,状态 1,第 25 行
关键字“SELECT”附近的语法不正确。

有什么想法吗?

【问题讨论】:

  • 调试动态SQL的第一步是打印你试图执行的SQL——然后错误的原因通常会很明显。
  • 我不确定我是否清楚地遵循了EXECUTE sp_executesql .... 的声明,但我看到的一件显而易见的事情是,@p_table 重复了。您能否仅提及简单的陈述(例如生成的动态陈述)
  • 这永远不会像这样工作。您不能参数化对象名称。
  • 用括号中的 SELECT 语句试试。让您跳过“关键字 'SELECT' 附近的语法不正确。”
  • 如果你发现@DaleK 提供的答案有帮助,你真的应该接受它meta.stackexchange.com/questions/5234/…

标签: sql sql-server dynamic-function


【解决方案1】:

在您的情况下(我假设)使用动态 SQL 的全部意义在于允许使用动态表名。在这种情况下,您必须将表名插入到动态 SQL 字符串中 - 您不能将其作为参数传递,这就是您首先要尝试的问题。

另外,您不需要SET 后跟SELECT,只需直接使用SELECT 来设置变量即可。

最后,您肯定希望使用QUOTENAME 函数来转义您的表名并避免 SQL 注入攻击 - 这需要您拆分表名和架构名称。

DECLARE @y DATETIME;
DECLARE @p_schema VARCHAR(100);
DECLARE @p_table VARCHAR(100);
DECLARE @SQL NVARCHAR(max);

SET @p_schema = 'dbo';
SET @p_table = 't_products';
-- Add the table name to the dynamic SQL 
SET @SQL = 'SELECT @y = MAX(last_changed) FROM ' + QUOTENAME(@p_schema) + '.' + QUOTENAME(@p_table);

EXECUTE sp_executesql @SQL, N'@y DATETIME OUTPUT', @y OUTPUT;

-- PRINT(@SQL); --- Debugging

SELECT @y;

【讨论】:

  • 如果需要,请here is a db fiddle
  • 我建议对这个很好的答案进行调整。 OP 应该使用两个参数。一个用于架构,另一个用于表名。这样你就可以用 QUOTENAME 包装它们以降低 sql 注入的风险。
  • Dale 我看到你添加了 QUOTENAME。问题是 OP 有 dbo.TableName 和 quotename 在那里不起作用。它会返回 [dbo.TableName]。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-08
  • 2019-06-03
  • 1970-01-01
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多