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


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

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是有用的,所以有没有办法关闭SQL Server对列存在的检查 在目前存在的表中


2358
2017-11-30 16:14


起源



答案:


这称为延迟名称解析。

无法将其关闭。您可以使用动态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

17
2017-11-30 16:16



这是;不检查表格或检查列? - Jez
不检查表格。如果语句中使用的所有表都存在,则不会延迟。 - Martin Smith
感谢您的解释;为什么你需要DROP TABLE #Dummy?存储过程完成后,临时表是否自动删除? - Jez
@Jez - 是的,他们是。只是习惯! - Martin Smith
就此而言,为什么要创建Dummy表呢? - Jez


答案:


这称为延迟名称解析。

无法将其关闭。您可以使用动态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

17
2017-11-30 16:16



这是;不检查表格或检查列? - Jez
不检查表格。如果语句中使用的所有表都存在,则不会延迟。 - Martin Smith
感谢您的解释;为什么你需要DROP TABLE #Dummy?存储过程完成后,临时表是否自动删除? - Jez
@Jez - 是的,他们是。只是习惯! - Martin Smith
就此而言,为什么要创建Dummy表呢? - Jez


这篇文章在 MSDN 应该回答你的问题。

来自文章:

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


-2
2017-11-30 16:23



好吧,这回答了“怎么样”而不是'为什么'......因为,MS的理由是什么?如果他们也对列名称进行了延迟名称解析(或者该选项可用),那将会更有用。 - Jez
那么SQL Server正在尽可能地进行验证,对吧?如果表存在,请检查其列。否则,如果表尚不存在,则无法检查其列。 - bitxwise
不...... SQL Server可以说'错误。表不存在。'它根本不必允许延迟名称解析。另一方面,它可以意识到列尚不存在但是推迟了它的解析,因为您可能会在以后继续更改模式。推迟表名解析而不是列名解析似乎令人恼火地不一致。 - Jez
@Jez - 您可以通过使用获得一致的行为 WITH SCHEMABINDING 这使得它在更严格的方向上保持一致。 - Martin Smith
在审核队列中遇到此问题并编辑了相关信息。 - AHiggins