为什么Microsoft SQL Server检查存储过程中的列而不检查表?

为什么Microsoft SQL Server检查存储过程中的列而不检查表?,sql,sql-server,tsql,Sql,Sql Server,Tsql,在定义存储过程时,Microsoft SQL Server似乎检查列名有效性,但不检查表名有效性。如果它检测到引用的表名当前存在,它将根据该表中的列验证语句中的列名。例如,这将运行OK: CREATE PROCEDURE [dbo].[MyProcedure] AS BEGIN SELECT Col1, Col2, Col3 FROM NonExistentTable END GO 。。。这将: CREATE PROCEDURE [dbo].[M

在定义存储过程时,Microsoft SQL Server似乎检查列名有效性,但不检查表名有效性。如果它检测到引用的表名当前存在,它将根据该表中的列验证语句中的列名。例如,这将运行OK:

CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
    SELECT
        Col1, Col2, Col3
    FROM
        NonExistentTable
END
GO
。。。这将:

CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
    SELECT
        ExistentCol1, ExistentCol2, ExistentCol3
    FROM
        ExistentTable
END
GO
。。。但此操作失败,列名称无效:

CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
    SELECT
        NonExistentCol1, NonExistentCol2, NonExistentCol3
    FROM
        ExistentTable
END
GO

为什么SQL Server检查列而不是表的存在性?这肯定是不一致的;它应该两者都做,或者两者都不做。我们可以定义SP,这些SP可能引用架构中尚不存在的表和/或列,这对我们很有用,因此有没有办法关闭SQL Server对当前存在的表中是否存在列的检查?

这称为延迟名称解析

没有办法把它关掉。您可以使用动态SQL或(令人讨厌的黑客!)添加对不存在的表的引用,以便延迟该语句的编译

CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN

CREATE TABLE #Dummy (c int)

    SELECT
        NonExistantCol1, NonExistantCol2, NonExistantCol3
    FROM
        ExistantTable 
    WHERE NOT EXISTS(SELECT * FROM #Dummy)    


DROP TABLE #Dummy

END
GO
这篇文章应该能回答你的问题

从文章中:

第一次执行存储过程时,查询 处理器从中读取存储过程的文本 sys.sql_模块目录视图并检查对象的名称 所使用的程序都存在。这个过程称为延迟 名称解析,因为存储的 创建存储过程时,过程不需要存在,但 只有当它被执行时


即,;表的不检查,还是列的检查?表的不检查。如果一个语句中使用的所有表都存在,那么它就不会延迟;你为什么要放下桌子?笨蛋?临时表不是在存储过程完成后自动删除的吗?@Jez-是的。只是习惯!那么,为什么要创建虚拟表呢?好的,这回答了“如何”而不是“为什么”。。。如中所述,MS这样做的理由是什么?如果他们也对列名进行延迟名称解析(或者该选项是可用的),这将更加有用?如果该表存在,请检查其列。否则,如果表还不存在,就无法检查它的列。不。。。SQL Server可能会说“错误”。表不存在。它根本不必允许延迟名称解析。另一方面,它可能会意识到一个列还不存在,但会推迟对它的解析,因为您以后可能会继续更改模式。推迟表名解析而不是列名解析似乎不一致。@Jez-您可以通过使用
和SCHEMABINDING来获得一致的行为,这使它在更严格的方向上保持一致。在审阅队列中遇到了这一点,并在中编辑了相关信息。