简体   繁体   English

SQL Server无效的列名

[英]SQL Server invalid column name

If I try to execute the following code, I get the errors 如果我尝试执行以下代码,我会收到错误

Msg 207, Level 16, State 1, Line 3 Invalid column name 'Another'. 消息207,级别16,状态1,行3无效的列名称“另一个”。 Msg 207, Level 16, State 1, Line 4 Invalid column name 'Another'. 消息207,级别16,状态1,行4无效的列名称“另一个”。

even though the predicate for both IF statements always evaluates to false. 即使两个IF语句的谓词总是评估为false。

CREATE TABLE #Foo (Bar INT)
GO
IF (1=0)
BEGIN
    SELECT Another FROM #Foo
END
GO
IF (1=0)
BEGIN
    ALTER TABLE #Foo ADD Another INT
    SELECT Another FROM #Foo 
END
GO
DROP TABLE #Foo

This is probably over-simplified for the sake of the example; 为了这个例子,这可能过于简化了; in reality what I need to do is select the values from a column, but only if the column exists. 实际上我需要做的是从列中选择值,但仅在列存在时才选择。 If it doesn't exist, I don't care about it. 如果它不存在,我不关心它。 In the problem that drove me to ask this question, my predicate was along the lines of EXISTS (SELECT * FROM sys.columns WHERE object_id = @ID AND name = @Name) . 在驱使我提出这个问题的问题中,我的谓词是EXISTS (SELECT * FROM sys.columns WHERE object_id = @ID AND name = @Name) Is there a way to achieve this without resorting to my arch-enemy Dynamic SQL? 有没有办法实现这一点,而不诉诸我的敌人动态SQL? I understand that my SQL must always be well-formed (ie conform to grammar) - even within a block that's never executed - but I'm flabbergasted that I'm also being forced to make it semantically correct too! 我知道我的SQL必须始终是格式良好的(即符合语法) - 即使是在一个从未执行过的块中 - 但我也大惊小怪,我也被迫在语义上也正确!

EDIT: Though I'm not sure the code below adds much to the code above, it's a further example of the problem. 编辑:虽然我不确定下面的代码增加了上面的代码,但它是问题的另一个例子。 In this scenario, I only want to set the value of Definitely (which definitely exists as a column) with the value from Maybe (which maybe exists as a column) if Maybe exists. 在这种情况下,我只想设置绝对值(绝对存在作为列)的值,其值为Maybe(可能存在为列)如果Maybe存在。

IF EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('dbo.TableName', 'U') AND name = 'Maybe')
BEGIN
    UPDATE dbo.TableName SET Definitely = Maybe
END

SQL Server doesn't execute line by line. SQL Server不会逐行执行。 It isn't procedural like .net or Java code. 它不是像程序 .NET或Java代码。 So there is no "non-executed block" 所以没有“非执行块”

The batch is compiled in one go. 批处理一次编译。 At this point, the column doesn't exist but it knows the table will be. 此时,该列不存在,但它知道该表将是。 Table does not have a column called "Another". 表没有名为“Another”的列。 Fail. 失败。

Exactly as expected. 完全符合预期。

Now, what is the real problem you are trying to solve? 现在,你想要解决的真正问题是什么?

Some options: 一些选择:

  • 2 tables or one table with both columns 2个表或一个包含两列的表
  • use Stored procedures to decouple scope 使用存储过程来解除范围
  • not use temp tables (maybe not needed; it could be your procedural thinking...) 不使用临时表(可能不需要;它可能是你的程序性思考......)
  • dynamic SQL (from Mitch's deleted answer) 动态SQL(来自Mitch删除的答案)

Edit, after comment; 评论后编辑;

Why not hide schema changes behind a view, rather than changing all code to work with columns that may/may not be there? 为什么不隐藏视图后面的架构更改,而不是更改所有代码以使用可能/可能不存在的列?

You can use EXEC to handle it. 您可以使用EXEC来处理它。 It's not really dynamic SQL if the code never actually changes. 如果代码永远不会真正改变,那它就不是真正的动态SQL。

For example: 例如:

CREATE TABLE dbo.Test (definitely INT NOT NULL)
INSERT INTO dbo.Test (definitely) VALUES (1), (2), (3)

IF EXISTS (SELECT *
           FROM sys.columns
           WHERE object_id = OBJECT_ID('dbo.Test', 'U') AND
                 name = 'Maybe')
BEGIN
    EXEC('UPDATE dbo.Test SET definitely = maybe')
END

SELECT * FROM dbo.Test

ALTER TABLE dbo.Test ADD maybe INT NOT NULL DEFAULT 999

IF EXISTS (SELECT *
           FROM sys.columns
           WHERE object_id = OBJECT_ID('dbo.Test', 'U') AND
                 name = 'Maybe')
BEGIN
    EXEC('UPDATE dbo.Test SET definitely = maybe')
END

SELECT * FROM dbo.Test

DROP TABLE dbo.Test

您还可以使用不存在的表来尝试使用Martin Smith的 “替代方法”来获取列的“延迟名称解析”。

I had the same issue. 我遇到过同样的问题。 We are creating a script for all changes for years and this is the first time that we have this issue. 我们多年来为所有更改创建了一个脚本,这是我们第一次遇到此问题。 I've tried all your answers and didn't find the issue. 我已经尝试了你所有的答案,但没有找到问题。

In my case it was because of temporary table within the script that I'm using also within a stored procedure, although every sentence has go. 在我的情况下,这是因为脚本中的临时表我也在存储过程中使用,尽管每个句子都已经去了。 I've found that if I'm adding if exists with drop to the temporary table after the script is using the temporary table, it is working correctly. 我发现,如果我在脚本使用临时表后添加if存在并删除临时表,则表明它正常工作。

Best regards, Chen 最诚挚的问候,陈

Derived from the answer by @gbn. 源自@gbn的答案。 What i did to solve the issue was to use 'GO' between the ALTER query and the query that uses the column added by ALTER. 我解决这个问题的方法是在ALTER查询和使用ALTER添加的列的查询之间使用“GO”。 This will make the 2 queries to be run as separate batches thereby ensuring your 'Another' column is there before the SELECT query. 这将使2个查询作为单独的批处理运行,从而确保在SELECT查询之前存在“Another”列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM