如果表不存在,如何运行包含针对另一个 sql 实例上的表的查询的 If-Then-Else 语句?

Posted

技术标签:

【中文标题】如果表不存在,如何运行包含针对另一个 sql 实例上的表的查询的 If-Then-Else 语句?【英文标题】:How to run an If-Then-Else statement which includes a qry against a table on another sql instance, if table does not exists? 【发布时间】:2015-08-13 18:25:00 【问题描述】:

如果表存在于该数据库中,我正在尝试仅针对另一个实例上的数据库执行 sql 语句。当 qry 窗口连接到数据库存在的实例时,我在查询时反复执行此操作。但是,当 qry 窗口连接到另一个实例时,这种方法不起作用。注意:我连接到对象资源管理器中的两个实例。

以下代码是动态运行的 (EXEC @strSQL)。该表不存在,我预计打印响应“不存在”。

> IF EXISTS (
>                   SELECT 1
>                   FROM [SomeInstance].[SomeDatabase].sys.tables
>                   WHERE name = N'SomeTableThatDoesNotExist' 
>                       AND type = 'U'
>           )   
>   BEGIN       
>       PRINT 'EXISTS'      
>       SELECT *        
>       FROM [SomeInstance].[SomeDatabase].[dbo].[SomeTableThatDoesNotExist]    
>   END                         
>   ELSE
>       PRINT 'NOT EXISTS'

根据要求提供动态版本:

>   DECLARE @strSQL     VARCHAR(MAX)

>   SET @strSQL = '             
>       IF (OBJECT_ID(''[SomeInstance].[SomeDatabase].[dbo].[SomeTableThatDoesNotExist]'') IS NOT NULL)
>       BEGIN
>           PRINT ''IS NOT NULL''
>           SELECT *
>           FROM [SomeInstance].[SomeDatabase].[dbo].[SomeTableThatDoesNotExist];
>       END 
>       ELSE
>           PRINT ''IS NULL''
>       ';

>   BEGIN TRY
>       BEGIN TRANSACTION;
>           EXEC(@strSQL);
>       COMMIT TRANSACTION;
>   END TRY
>   BEGIN CATCH
>       EXECUTE up_tidydata_GetErrorInfo;
>   END CATCH

Dynamic Inside Dynamic 版本 1

>   
>   IF (OBJECT_ID('[SomeInstance].[SomeDatabase].[dbo].[SomeTableThatDoesNotExist') IS NOT NULL)
>       DECLARE @strSQLqry VARCHAR(MAX)
>       SET @strSQLqry = '
>           DECLARE @strSQLinside AS VARCHAR(MAX)
>           SET @strSQLinside = ''SELECT * FROM [SomeInstance].[SomeDatabase].[dbo].[SomeTableThatDoesNotExist];''
>           EXEC(@strSQLinside);
>           ';
>   EXEC(@strSQLqry)

Dynamic Inside Dynamic 版本 2

>   
>   DECLARE @strSQL     VARCHAR(MAX)
>   SET @strSQL = ' 
>       IF (OBJECT_ID(''[SomeInstance].[SomeDatabase].[dbo].[SomeTableThatDoesNotExist]'') IS NOT NULL)
>       DECLARE @strSQLqry VARCHAR(MAX)
>       SET @strSQLqry = ''
>           DECLARE @strSQLinside AS VARCHAR(MAX)
>           SET @strSQLinside = ''''SELECT * FROM [SomeInstance].[SomeDatabase].[dbo].[SomeTableThatDoesNotExist];''''
>           EXEC(@strSQLinside);
>           '';
>       EXEC(@strSQLqry)
>       ';
>   EXEC(@strSQL)

当它在数据库所在的实例上运行时,它按预期工作。含义跳过 Begin...End 并转到 ELSE 部分。

但是,当它在另一个实例上运行时,它会出错,说数据库中不存在该表(这就是使用条件 if-then-else 的原因)。当我查询另一个实例上的数据库中确实存在的表时,会收到预期的响应“EXISTS”。因此,似乎 THEN 语句和 ELSE 语句在另一个实例上运行时都必须有效。

我想通过注释掉 FROM 行来确认这一点。当我在数据库存在的实例上运行它时,响应是预期的“不存在”(这意味着它忽略了 BEGIN...END)。

但是,当我在连接到另一个实例时运行它时,会产生错误“必须指定要从中选择的表”。

注意,我尝试过检查表的变体(如果存在,如果 OBJECT_ID...IS NOT NULL)

【问题讨论】:

我的建议是动态 sql,但你说这就是你正在使用的。您能否扩展您的代码以包含创建动态 sql 字符串并执行它的部分? 动态版本,也显示了 OBJECT_ID 方法,正在包含在原始消息中 动态内动态尝试的问题:您需要在 IF 语句中使用 BEGIN END 块。否则,只有 IF 之后的第一个语句取决于 IF 是否为真。其余的都将被执行。 【参考方案1】:

我敢打赌,问题在于您是在一个动态上下文中运行整个示例查询。

我想如果你这样尝试,它会起作用的:

IF EXISTS (
                  SELECT 1
                  FROM [SomeInstance].[SomeDatabase].sys.tables
                  WHERE name = N'SomeTableThatDoesNotExist' 
                      AND type = 'U'
          )  
      BEGIN       
      PRINT 'EXISTS';
      DECLARE @sql varchar(max) = '
        SELECT *        
        FROM [SomeInstance].[SomeDatabase].[dbo].[SomeTableThatDoesNotExist]
      ';
      EXEC(@sql);
      END                            
      ELSE
           PRINT 'NOT EXISTS'

如果您出于其他原因必须使整个事情动态化,那么我认为您仍然可以通过动态内部动态方法取得成功。但是对不存在的表的查询需要在它自己的上下文中,这样优化器就不会在它不存在时尝试验证它的存在。

编辑: 问题是,如果您的“IF EXISTS()”检查与“SELECT FROM NoSuchTable”查询在同一上下文中,那么优化器将不允许整个语句批处理运行,因为它将检查并查看表不存在。没关系,您无法从逻辑上达到尝试从不存在的表中进行选择的地步。优化器在开始运行第一条语句之前验证当前上下文中引用的每个对象是否存在。

但是,当您执行 IF EXISTS() THEN Run-some-dynamic-statement 时,优化器不会评估动态语句的内容,直到它遇到 EXECUTE(@sql) 命令。除非 IF EXISTS() 为真,否则它永远不会执行该命令,因此除非表存在,否则它根本不会被评估。

【讨论】:

是的,但所有这些都在一个 case 语句循环中,我在其中针对一系列表运行查询(一些可能存在,一些可能不存在)。因此,这就是动态 sql 中包含 IF Exists 的原因。所以,我会在动态中尝试你建议的动态。 动态中的动态,如果允许的话,应该可以工作。用更详细的解释编辑我的答案。 我在动态中尝试了两个版本的动态,更新的原始帖子带有示例。两者都导致相同的错误,即该表不存在。当我在一个确实存在的表上运行这些版本时,它们工作了。出现,对象正在所有场景中被评估。 您的回答促使我将注意力转向案例循环。在case语句之后发生了检查表是否存在的想法:并将全局变量设置为“是”或“否”(使用全局变量用户存储过程)。接下来,检查全局变量状态,如果是,运行动态查询,如果不是,则进入下一个循环。基本上,从动态 qry 中提取 IF Exists 并使用全局变量。 对此我能提供的唯一回应是,这取决于“案例循环”的设置方式。如果它是基于集合的,则不会为集合中的每一行单独评估全局变量。如果它在一个while循环中,每次只有一种可能的情况,那么它可能会起作用。

以上是关于如果表不存在,如何运行包含针对另一个 sql 实例上的表的查询的 If-Then-Else 语句?的主要内容,如果未能解决你的问题,请参考以下文章

如果表不存在,我需要使用 sqlplus [重复] 运行脚本

如果表不存在,如何使用 Derby Db 创建表

sql查询一个表不包含另一个表的数据,两种方法。

如何将一个表的查询结果插入到另一个表中?

使用 sqitch 中的 mysql 查询验证表不存在

sql学习