【问题标题】:Invalid column name error when using QUOTENAME使用 QUOTENAME 时出现无效的列名错误
【发布时间】:2026-01-17 09:50:01
【问题描述】:

我有几个具有相同结构的表。这些表按年份命名,即 2001、2002 等等。我需要在每个表中的列中搜索一个值并获取每个表的计数。

我在下面创建了一个存储过程,但我一直收到错误

无效的列'lol'

这是使用的存储过程:

CREATE PROCEDURE [dbo].[CountSP]
    @TableName NVARCHAR(128),
    @SearchParam NVARCHAR(50),
    @SearchInput NVARCHAR(200)
AS 
BEGIN 
    SET NOCOUNT ON;
    DECLARE @Sql NVARCHAR(MAX);

    SET @Sql = N'SELECT COUNT('+QUOTENAME(@SearchParam)+') FROM ' + QUOTENAME(@TableName) +'WHERE'+QUOTENAME(@SearchParam)+'LIKE '+QUOTENAME(@SearchInput)+

          + N' SELECT * FROM '+QUOTENAME(@TableName)

    EXECUTE sp_executesql @Sql
END

执行它:

DECLARE @return_value INT

EXEC    @return_value = [dbo].[CountSP]
        @TableName = N'1999',
        @SearchParam = N'USERDESC',
        @SearchInput = N'lol'

SELECT  'Return Value' = @return_value

【问题讨论】:

  • 注意:直接使用SysNameQUOTENAME(@TableName) +'WHERE' 将是 [TableNameYouPassed]WHERE ... + N' SELECT * FROM '+QUOTENAME(@TableName) 在那里做什么?
  • “我有几个具有相同结构的表。这些表按年份命名,即 2001,2002 等等” 你的问题就在那里。 您应该有一个带有年份列的表来存储所有这些信息。修复数据库结构是解决问题的方法。任何其他答案都不是解决方案,而是解决方法。话虽如此,我很清楚这样一个事实,很多时候,修复数据库结构不是一种选择 - 所以需要解决方法。
  • @ZoharPeled 正确但在这里不可行。这些表实际上是由我迁移到这里的外部资源提供的数据库

标签: sql sql-server tsql


【解决方案1】:

我不知道你为什么在那里使用LIKE 运算符而不使用通配符,也直接使用SysName 数据类型作为对象名称。

Create PROCEDURE [dbo].[CountSP]
(
  @TableName SysName,
  @SearchInput NVARCHAR(50),
  @SearchParam SysName
)
AS 
  SET NOCOUNT ON;

  DECLARE @SQL NVARCHAR(MAX) = N'SELECT COUNT(' +
                               QUOTENAME(@SearchParam) +
                               N') FROM ' +
                               QUOTENAME(@TableName) +
                               N' WHERE ' +
                               QUOTENAME(@SearchParam) +
                               N' = ' + --You can change it to LIKE if needed
                               QUOTENAME(@SearchInput, '''') +
                               N';';
  -- There is no benifits of using LIKE operator there
  EXEC sp_executesql @SQL;

那么你可以称它为

EXEC [dbo].[CountSP] N'YourTableNameHere', N'SearchInput', N'ColumnName';

【讨论】:

  • “我不知道你为什么在那里使用 LIKE 运算符而不使用通配符”:猜测,因为@SearchInput 可能 有一个通配符。
  • @Larnu 是的,根据我在那里看到的@SearchInput = N'lol'
  • @Sami 有没有一种方法可以不使用表名的变量,而是传入数据库中找到的所有表名?我目前正在使用 .net 应用程序来调用上述代码,而不是为每个表多次调用它,我想在 sql 本身的一个查询中执行
  • @keshav 这是另一个相关的问题,你可以随时点击 按钮,我知道你会得到很多很好的答案,而不仅仅是我 :)
【解决方案2】:

这是因为它目前被翻译成:

SELECT COUNT([USERDESC]) FROM [1999] WHERE [USERDESC] LIKE [lol]

这意味着它将“USERDESC”列与“lol”列进行比较,但据我了解,lol 不是列而是值?这意味着您应该丢失该变量的 QUOTENAME。 请参阅此处的文档:https://docs.microsoft.com/en-us/sql/t-sql/functions/quotename-transact-sql?view=sql-server-2017

【讨论】:

    【解决方案3】:

    你需要将你的参数@SearchInput作为参数传递给sp_execute

    CREATE PROCEDURE [dbo].[CountSP] @TableName sysname, --This is effectively the same datatype (as sysname is a synonym for nvarchar(128))
                                     @SearchParam sysname, --Have changed this one though
                                     @SearchInput nvarchar(200)
    AS
    BEGIN
        SET NOCOUNT ON;
        DECLARE @Sql nvarchar(MAX);
    
        SET @Sql = N'SELECT COUNT(' + QUOTENAME(@SearchParam) + N') FROM ' + QUOTENAME(@TableName) + N'WHERE' + QUOTENAME(@SearchParam) + N' LIKE @SearchInput;' + NCHAR(13) + NCHAR(10) +
        N'SELECT * FROM ' + QUOTENAME(@TableName);
    
    
        EXECUTE sp_executesql @SQL, N'@SearchInput nvarchar(200)', @SearchInput;
    
    END;
    

    QUOTENAME,默认情况下,将引用括号中的值 ([])。它确实接受第二个参数,该参数可用于定义不同的字符(例如,QUOTENAME(@Value,'()') 会将值括在括号中)。但是,对于您想要的,您希望参数化该值,而不是注入(引用的)值。

    【讨论】:

    • 再次吹毛求疵:sysnamenvarchar(128) 在两个方面有所不同:最重要的是 sysname 在不同的系统中可能意味着不同的长度 - 所以用 sysname 编写的代码是更便携,不太重要的是sysname 不可为空。
    最近更新 更多