SQL Server 2014 - 编译期间奇怪的 SP 行为

0 sql-server stored-procedures sql-server-2014

今天我注意到在 SQL Server 2014 中创建存储过程的过程中出现了一个奇怪的行为。下面是我的测试过程。请解释为什么 SQL Server 不允许用第一个SELECT编译而允许用第二个编译。

CREATE PROCEDURE [dbo].[test]
AS
BEGIN

    SET NOCOUNT ON;

    IF 1=0  -- this will never occur
    BEGIN
        select x from Table -- TABLE EXIST BUT COLUMN NOT - STORED PROCEDURE IS NOT CREATED
        --Msg 207, Level 16, State 1, Procedure test, Line 25
        --Invalid column name 'x'.

        -- But if i change 
        select x from TableWhichNotExistInDatabase  -- This table not exist in database, but stored procedure has been created without any problems and I can exec it without errors (    because of 1=0 in if )

    END
    ELSE 
    SELECT ''
END
Run Code Online (Sandbox Code Playgroud)

在我的实际过程中,我正在创建具有各种模式的临时表(从作为参数传递的 XML)。接下来我尝试验证存储过程中的一些数据。验证块由 IF 语句控制。

临时表的创建和存储过程调用由动态创建的过程执行。

我认为问题出在执行计划或类似的创建过程中的某个地方。如果数据库中不存在该表,则 SQL Server 允许在表不存在时创建存储过程。但是,当表存在时,存储过程的创建失败,因为架构无效 - 没有列。

我正在寻找一种禁用模式检查但没有任何成功的解决方案。

关于如何绕过此限制有什么想法吗?

Sco*_*red 6

您遇到的现象称为Deferred Name Resolution

创建存储过程时,会解析过程中的语句以确保语法准确性。如果在过程定义中遇到语法错误,则会返回错误并且不会创建存储过程。如果语句在语法上正确,则存储过程的文本存储在 sys.sql_modules 目录视图中。

当第一次执行存储过程时,查询处理器从 sys.sql_modules 目录视图中读取存储过程的文本,并检查该过程使用的对象的名称是否存在。这个过程称为延迟名称解析,因为存储过程引用的表对象在创建存储过程时不需要存在,而只在执行时才存在。

> 延迟名称解析只能在您引用不存在的表对象时使用。所有其他对象在创建存储过程时必须存在。例如,当您在存储过程中引用现有表时,您不能列出该表不存在的列。

我知道解决这个问题的唯一方法是使用动态 SQL。