【问题标题】:Using ISNULL(MAX(@Variable) returns Variable, not numeric value as expected使用 ISNULL(MAX(@Variable) 返回变量,而不是预期的数值
【发布时间】:2020-04-04 03:38:56
【问题描述】:

我有一个正在运行的存储过程,它正在变量表 (v) 中查找 ID 名称作为其他数据库表(a、b、c 等)的摘要。由于并非所有表都有名为 ID 的 ID,因此我将它们存储在此变量表中。

这将用于从相应的表中获取最大 ID。

运行以下命令时一切正常,我得到了对应表的最大 ID:

DECLARE @TableMaxID INT

SELECT @TableMaxID  = ISNULL(MAX(TableID_a),0) 
FROM DB.SCHEMA.Table_a

PRINT @TableMaxID 

运行这个查询我正确地得到了最大 ID 表格表 a - '59'

由于我想在此命令中使用变量,我尝试了以下操作

DECLARE @TableMaxID INT
    ,@TableIdName NVARCHAR (50)
SET @TableIdName = 'TableID_a'

SELECT TableMaxID  = ISNULL(MAX(@TableIdName),0) 
FROM DB.SCHEMA.Table_a

运行它会导致错误

将 nvarchar 值“TableID_a”转换为数据类型 int 时转换失败。

只有在使用SELECT 命令时,我才明白发生了什么——因为我得到了@TableIdName 变量的名称而不是数值“59”

DECLARE @TableMaxID INT
        ,@TableIdName NVARCHAR (50)
SET @TableIdName = 'TableID_a'

SELECT ISNULL(MAX(@TableIdName),0) 
FROM DB.SCHEMA.Table_a

PRINT @TableMaxID

返回变量名'TableID_a'

我有点困惑。我在这里做错了什么。有没有办法像我尝试那样使用该变量,或者我完全错了。

【问题讨论】:

  • 简短的回答是不能在查询中使用变量值作为列名,因为 T-SQL 不会像宏一样扩展它。有必要在代码中构建和执行动态 SQL 语句字符串。也就是说,将列和表作为参数传递表明存在设计缺陷,恕我直言。见this recent question

标签: sql-server tsql isnull


【解决方案1】:

如果将字符串作为参数传递给MAX 函数,则会返回字符串(而不是同名列的最大值):

SELECT MAX('TableID_a') -- output TableID_a

所以你必须使用动态 SQL 语句来创建 SQL 语句并执行。您可以使用这样的存储过程来获取特定表的最大列:

-- procedure to get the maximum value of a column of a specific table.
CREATE PROCEDURE GetMaxValue @tableName VARCHAR(100), @columnName VARCHAR(100)
AS
DECLARE @sql NVARCHAR(100)
SET @sql = 'SELECT MAX(' + @columnName + ') FROM ' + @tableName;

EXEC sp_executesql @sql

你可以像这样调用创建的存储过程GetMaxValue

EXEC GetMaxValue '<name-of-table>', '<name-of-column>'

但请记住,此调用等效于以下SELECT 语句:

SELECT MAX(<name-of-column>) FROM <name-of-table>

【讨论】:

    【解决方案2】:

    如果你在表达式中使用变量,它的值将在表达式中使用,而不是标识符等于变量值的对象的值。

    您似乎想要动态 SQL,即在变量中创建查询文本,然后执行此查询。

    DECLARE @maxid integer;
    DECLARE @idcolumnname sysname = 'di';
    DECLARE @query nvarchar(max) = N'
    SELECT @maxid = isnull(max(' + quotename(@idcolumnname) + N'), 0)
           FROM elbat;';
    
    EXECUTE sp_executesql @query, N'@maxid integer output', @maxid = @maxid output;
    
    SELECT @maxid;
    

    db<>fiddle

    注意事项:

    • 您应该使用sysname 而不是一些[n][var]char 作为对象名称。 sysname 一种显式用于对象名称的特殊数据类型。
    • 在将对象名称连接到查询之前,您应该在对象名称上使用quotename(),以确保它们在查询中被正确引用。否则可能会发生错误,甚至可能发生 SQL 注入。

    【讨论】:

    • 感谢sticky bit,想了解更多关于您的sysname 评论的信息。这是否意味着在将 dbnames、模式、表、列等项目作为变量处理时,我将始终使用 sys 名称变量而不是“nvarchar”? (不太明白“对象名称”是什么意思)
    • 是的,就是这样。对象名称是对象的名称。比如表格等等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-27
    • 2012-06-10
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多