** 已编辑为在EXISTS测试中反转逻辑
我需要从可能不存在的表中选择一个字段。我还需要在子查询中执行此操作。
有一个来自工程的代码发行版,它将向我抓取的数据库中添加表以进行报告。如果该表存在,请选择该字段。如果没有,则给出一般故障。
**是的,有很多关于如何使用EXISTS的示例。这超出了它们的范围,因为它处理了可能不存在的问题。
新版本的代码将推广到多个站点,某些站点可能没有其他站点的表。我的东西必须为第0天做好准备-又名:提前推出(第-1天?)。
这是我要在SQL Server Management Studio(SQL 2016)(SSMS 17.4)中工作的代码(表和列重命名)
select 'Cern' as SiteName,
(
select
case when exists (select 1 from sys.tables where name like 'ProtonAcceleratorSecurity')
then
(select top 1 isnull(SecurityID,'Not on file') from [ProtonAcceleratorSecurity] with (nolock) )
else
(select 'No Security Table Found')
end
as SecurityID
它看起来像是人为的,但它与我要使用的确切查询非常接近(但与安全性无关)
目标是取回站点名称和第一个安全性ID(随机-无关紧要-不需要一致性)-但前提是该表确实存在。
问题是SSMS抛出一个错误,告诉我该表是我已经知道的无效对象。
@TabAlleman的最终答案,并作了小幅修改:
SET @sql = '
select ''Cern'' as SiteName, ' +
( select
case when exists (select 1 from sys.tables where name like 'ProtonAcceleratorSecurity')
then
'(select top 1 isnull(SecurityID,''Not on file'') from [ProtonAcceleratorSecurity] with (nolock) )'
else
'''No Security Table Found'''
end )
+ ' as SecurityID ';
EXEC (@sql); ```
答案 0 :(得分:2)
发生错误的原因是SQL Server将在执行之前分析并编译整个语句。因此,即使查询本身在引用对象之前进行检查以确保对象是有效的,您的查询也不能包含对无效对象的引用。解析器不够聪明,无法知道如果对象不存在则不会调用子查询,因此它将完全阻止您运行查询。
您可以欺骗解析器的一种方法是通过动态sql,它不会被预先解析:
DECLARE @sql varchar(max);
SET @sql = '
select ''Cern'' as SiteName, '
+
select
case when exists (select 1 from sys.tables where name like 'ProtonAcceleratorSecurity')
then
'(select top 1 isnull(SecurityID,''Not on file'') from [ProtonAcceleratorSecurity] with (nolock) )'
else
'''No Security Table Found'''
end
+
' as SecurityID
';
EXEC (@sql);
编辑是因为我不是在进行测试,而是为了阐明主意:
您需要检查外部查询中是否存在该表,但是仅构造一个使用该表的动态查询(如果存在)。要使其变得非常简单,忽略原始的CASE结构,您需要在逻辑上做到这一点:
IF EXISTS({SELECT query to test for MyTable})
@SQL = 'query that references MyTable';
ELSE
@SQL = 'query that doesn't reference MyTable';
EXECUTE (@SQL);
PS:我想我只是在第一个示例中修复了语法。
答案 1 :(得分:0)
我认为在单个查询中没有任何方法可以做到这一点。一种建议是将其隐藏在视图中:
IF OBJECT_ID('ProtonAcceleratorSecurity') IS NULL
BEGIN
CREATE VIEW ProtonAcceleratorSecurity
SELECT 'Not on file' as SecurityID
END;
然后您的查询可以简单地工作为:
select 'Cern' as SiteName,
(select top 1 coalesce(SecurityID, 'Not on file')
from ProtonAcceleratorSecurity
) as SecurityID
答案 2 :(得分:0)
您遇到了问题,因为执行语句时表必须存在。
如果将其分为两个语句,则没有问题。引用不存在的表的那个被标记为延迟编译,并且因为它永远不会执行,所以完全不需要编译并且没有错误。
DECLARE @table NVARCHAR(255)
DECLARE @column NVARCHAR(255)
DECLARE OUTER_CURSOR CURSOR
FOR SELECT DISTINCT [ID_TABLE_NAME] FROM dbo.VMO
OPEN OUTER_CURSOR
FETCH NEXT FROM OUTER_CURSOR INTO @table
WHILE (@@FETCH_STATUS <> -1)
BEGIN
DECLARE INNER_CURSOR CURSOR
FOR SELECT DISTINCT [USR_COL_NAME] FROM dbo.VMO
OPEN INNER_CURSOR
FETCH NEXT FROM INNER_CURSOR INTO @column
WHILE (@@FETCH_STATUS <> -1)
BEGIN
DECLARE @strQuery NVARCHAR(MAX)
SET @strQuery = 'UPDATE [' + @table + '] SET [' + @column + '] = ''101211'' WHERE [' + @column + '] = ''10120'';'
EXEC(@strQUERY)
FETCH NEXT FROM INNER_CURSOR INTO @column
END
CLOSE INNER_CURSOR
DEALLOCATE INNER_CURSOR
FETCH NEXT FROM OUTER_CURSOR INTO @table
END
CLOSE OUTER_CURSOR
DEALLOCATE OUTER_CURSOR