【问题标题】:Checking if column exists in temporary table always returns false in SQL Server检查临时表中是否存在列在 SQL Server 中总是返回 false
【发布时间】:2011-09-14 01:41:12
【问题描述】:

我有以下执行语句,它创建一个表(使用来自另一个过程的数据),将值插入一个临时表,添加一个图像列(因为它们不能包含在分组中),然后根据它更新它来自另一个临时表的标准(生成的表字段在 SSRS 报告中使用,因此我需要保留 IMAGE 数据类型):

EXEC ('SELECT ' + @COL_TO_GROUP_BY + @COL_ADDITONAL + @sColVals + ' INTO
#RESULTS_TABLE from (' + @SQL_STATEMENT + ') A ' + @WHERE_CLAUSE + ' GROUP BY ' +
@COL_TO_GROUP_BY +

' ALTER TABLE #RESULTS_TABLE
ADD IMAGE_DATA IMAGE

IF EXISTS(SELECT * FROM tempdb.INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 
''COLUMN_A'' and TABLE_NAME LIKE ''#RESULTS_TABLE%'')
BEGIN
    UPDATE #RESULTS_TABLE
    SET IMAGE_DATA = FILE_DATA
    FROM #RESULTS_TABLE A, #IMAGE_TABLE B 
    WHERE A.COLUMN_A = B.COLUMN_A
END

SELECT * FROM #RESULTS_TABLE')

问题是不管COLUMN_A 是否存在,IMAGE_DATA 的列总是NULL。有没有其他方法可以将数据放入 IMAGE_DATA 列?请帮忙!

注意:我将接受任何认为问题与其他表中的内容有关的答案,更具体地说,来自 WHERE 子句。我已经进行了多次验证,以确保条件既可以是真也可以是假(匹配行、不匹配行等)。所以这排除了条件语句。谢谢。

编辑:

我仍然不完全确定它的确切原因是什么,但我最终创建了一个全局临时表并运行了两个单独的过程,现在它似乎工作正常。我不得不接受与我自己的解决方案最匹配的答案。所有答案和 cmets 都非常可行。谢谢!

【问题讨论】:

  • 首先,我会尝试省略条件WHERE A.COLUMN_A = B.IMAGE_VALUE,这对我来说足以通过OBJ_ID找到正确的行
  • 感谢您指出这一点。在我的情况下,我需要同时具备这两个条件,因为有些行具有重复的 OBJ_ID。我简化了我的原始代码,也应该把它去掉,因为它看起来确实有误导性。我将编辑问题。
  • 不确定这是否有帮助,但我认为您可以像 cast(null as Image) as IMAGE_DATA 这样在您的选择语句中添加图像列,而无需将其添加到 group by 子句中,因为它是一个常量。顺便说一句,您为什么需要测试该列是否存在?
  • @Mikael Eriksson - 添加演员表只会让我删除 ALTER TABLE 语句。虽然效率更高,但并不能解决我的问题。不过感谢您的提示!我必须检查该列是否存在,因为我正在从另一个过程中提取动态列,并且 IMAGE_DATA 会根据该列是否存在来填充。我已经编辑了问题,使其更依赖于被检查的列。

标签: sql sql-server tsql exec temp-tables


【解决方案1】:

您的脚本中有几个问题:

  • TempDB 不是 tempdb 的正确名称。您的代码将在安装了区分大小写排序规则的服务器上中断。始终对所有数据库名称使用正确的大小写。如果在区分大小写的部署下运行,您的代码可能会在结果列名称(例如 COLUMN_A)上出现类似的中断。
  • 并发下逻辑不正确:会话 A 会看到会话 B 的 #temp 表并执行错误操作。
  • 一个简单的测试表明列可见的:

.

EXEC ('SELECT * INTO #RESULTS_TABLE from 
     (select *, newid() as COLUMN_A from master..spt_values) A;
ALTER TABLE #RESULTS_TABLE
ADD IMAGE_DATA varbinary(max);
IF EXISTS(SELECT * FROM TempDB.INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 
''COLUMN_A'' and TABLE_NAME LIKE ''#RESULTS_TABLE%'')
BEGIN
    update #RESULTS_TABLE 
       set IMAGE_DATA = 0xBAADF00D;
END
SELECT * FROM #RESULTS_TABLE')

此测试显示列更新,因此对 EXISTS 的检查成功。显而易见的结论是,在您的情况下,#RESULTS_TABLE 和 #IMAGE_TABLE 之间的 OBJ_ID 连接找不到任何匹配项,这完全取决于表的内容。

编辑

您可以将COLUMN_A设置为动态的,它在测试时仍然可以正常工作:

declare @cn sysname = case 
      when RAND() * 100 >= 50 then 'COLUMN_A' 
      else 'COLUMN_B' end;

EXEC (N'SELECT * INTO #RESULTS_TABLE from (
     select *, newid() as ' + @cn + N'  from master..spt_values) A;
...

【讨论】:

  • 感谢您的回答。请参阅问题的编辑。与我裸露,因为这是我使用这个论坛的第一个问题,所以我应该第一次更清楚地提出这个问题。我将尝试使用您用于测试的程序。
  • 无意冒犯,但每当我遇到“你的话与经过测试的行为”时,我都会选择“经过测试的行为”。球在你的球场上,你需要证明 IF 分支没有被拿走。
  • 我查看了您的脚本并意识到您执行它的方式与我的方式不同。我的脚本没有明确创建 COLUMN_A。 COLUMN_A 的显示取决于从另一个过程(另一个表)中提取的内容,因此是动态的。你是对的,如果我这样做,它工作正常(在这种情况下我可能根本不需要做检查)。我认为问题在于动态创建的列。
  • 如果 COLUMN_A 是动态生成的,测试仍然可以正常工作,请参阅我的更新。
  • 我最终创建了一个全局临时表和两个单独的过程。它现在似乎正在工作,所以我不会过多干预它。 :) 我不得不接受 gbn 的回答,因为他的推理与我的解决方案最匹配。不过,非常感谢您的努力。
【解决方案2】:

正确。

在编译时,该列不存在。也就是说,SQL Server 查看整个命令集并解析/编译它。代码中 ALTER TABLE 的效果不会对后面的命令可见。

您必须对 UPDATE 单独执行 ALTER TABLE

注意:对于 SQL Server 2005,您将拥有 varbinary(max),它更加灵活并消除了一些复杂性

【讨论】:

  • 感谢您的回复。我正在使用 SQL Server 2008。我尝试将图像列转换为 varbinary(max),甚至从二进制转换为 varbinary(根据其他建议),但它给了我乱码,所以这不是一个选项。你能澄清一下我应该如何与更新分开做一个 ALTER TABLE 吗?执行两个 EXEC 语句超出了临时表的范围。谢谢。
【解决方案3】:

您可以使用..检查临时表中是否存在列。

IF EXISTS (SELECT * FROM TempDB.INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'Column' AND TABLE_NAME LIKE '#TempTable%')
    PRINT 'Column exists'
ELSE
    PRINT 'Column doesn''t exists'

【讨论】:

  • 如果服务器上的 2 个数据库使用相同的 tmp 表名,这是不行的。该脚本将在其他数据库上看到 tmp 表,并认为它存在于当前数据库中。
【解决方案4】:

我知道这是一个很老的帖子,但想分享我的解决方案。

问题在于 INFORMATION_SCHEMA.COLUMNS 视图返回的 TABLE_NAME 是表名,因为它存储在 tempdb.sys.objects 表中,其中包括会话指示器。

您不能使用“TABLE_NAME like 'RESULTS_TABLE%'”,因为它不是会话安全的。

解决方案是直接使用表的对象 id 查询架构,而不是使用 INFORMATION_SCHEMA 视图,如下所示:

if exists (Select 1 
           from tempdb.sys.columns 
           where [object_id] = object_id('tempdb..#RESULTS_TABLE') 
             and name ='COLUMN_A')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 2019-10-06
    • 2010-09-13
    相关资源
    最近更新 更多