开发者

Why is test for existing column failing in SQL?

I have this SQL change script that runs as part of my nant orchestrated DB creation or update:

SET XACT_ABORT ON
BEGIN TRANSACTION

PRINT 'Change MyColumn column to MyNewColumn column in MyTable table'
IF EXISTS (SELECT *
           FROM sys.columns
           WHERE Name = 'MyColumn' AND Object_id = OBJECT_ID('[dbo].[MyTable]'))
BEGIN
    PRINT '-> Exists, change it'
    /* NOTE THE NEXT LINE */
    SET @Value = (SELECT MyColumn FROM [dbo].[MyTable])

    ALTER TABLE [dbo].[MyTable]
    DROP CONSTRAINT DF_MyTable_MyColumn

    ALTER TABLE [dbo].[MyTable]
    DROP COLUMN MyColumn

    ALTER TABLE [dbo].[MyTable]
    ADD MyNewColumn nvarchar(20) NULL

    ALTER TABLE [dbo].[MyTable]
    ADD CONSTRAINT DF_MyTable_MyNewColumn DEFAULT ('') FOR MyNewColumn

    PRINT '-> Add values back into table'
    SET @Dynamic_Sql = 'UPDATE [dbo].[MyTable] SET MyNewColumn = ''' + @Value + ''''
    EXEC(@Dynamic_Sql)

    PRINT '-&g开发者_如何学运维t; Alter to NOT NULL'
    ALTER TABLE [dbo].[MyTable]
    ALTER COLUMN MyNewColumn nvarchar(20) NOT NULL
END
ELSE
BEGIN
PRINT '-> Does not exist, skip it'
END

I have already ran this update script before and made the changes to the DB (so MyColumn no longer exists). But now I have a new script that comes after this one, but my "build" fails on this line of this script with:

Msg 207, Level 16, State 1, Line 15 Invalid column name 'MyColumn'

where Line 15 is the FROM sys.columns line. But this is actually complaining about the line I have within the IF statement, where I have put in the NOTE comment. Why would this be the behaviour? Of course the column name will be invalid if it no longer exists.


Do you include the GO batch separator after you create all of your columns? If not, the columns won't be created by the time your first query runs, because the query parser parses it all at the same time -- at parse time, the column really doesn't exist.

By adding the GO batch separator, you force it to parse the portions of the query which use your newly created columns after the columns are actually created.


The problem (as Dave Markle alludes to, so feel free to accept his answer) is that SQL Server parses the entire section of the script. It sees that you're referring to MyColumn and that column doesn't exist, so it gives you the error. It doesn't matter that it's within an IF statement.

You can test it easily with this script:

CREATE TABLE dbo.Test (my_id int)
GO
IF (1=0)
    SELECT blah FROM Test

If I can find a way to defer the parsing, I'll update this answer, but other than using dynamic SQL I don't think that you can.

EDIT: Here's one possible solution. I didn't go through Martin's link yet, but that may be another.

CREATE FUNCTION dbo.Get_my_id ()
RETURNS INT
AS
BEGIN
    DECLARE @my_id INT
    SELECT @my_id = blah FROM dbo.Test
    RETURN @my_id
END
GO
CREATE TABLE dbo.Test (my_id INT)
GO
DECLARE @my_id INT

IF (1=0)
    SELECT @my_id = dbo.Get_my_id()
GO

BTW, if your table has more than one row in it, you realize that the value of your variable cannot be predicted, correct?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜