Unexpected error running Liquibase: Invalid column name 'rmCopy' [duplicate] - sql

This question already has answers here:
How to check if a column exists in a SQL Server table
(31 answers)
Closed 4 days ago.
I am running a migration script:
--liquibase formatted sql
--changeset endDelimiter:GO
--liquibase formatted sql
--changeset endDelimiter:GO
IF COL_LENGTH('dbo.Account_Details', 'rmCopy') IS NULL
BEGIN
ALTER TABLE [dbo].[Account_Details]
ADD [rmCopy] [nvarchar](255),
[Copy] [varchar](255)
END
IF COL_LENGTH('dbo.Account_Details', 'rmCopy') IS NOT NULL
BEGIN
UPDATE Account_Details SET rmCopy = 'Target 1 (25)', [Copy] = 'Target 1 (25)' WHERE id = 1;
UPDATE Account_Details SET rmCopy = 'Target 2 (50)', [Copy] = 'Target 2 (50)' WHERE id = 2;
UPDATE Account_Details SET rmCopy = 'Target 3 (75)', [Copy] = 'Target 3 (75)' WHERE id = 3;
UPDATE Account_Details SET rmCopy = 'Target 4 (100)', [Copy] = 'Target 4 (100)' WHERE id = 4;
END
I am getting error like this:
Unexpected error running Liquibase: Invalid column name 'rmCopy'. [Failed SQL: IF COL_LENGTH('dbo.Account_Details', 'rmCopy') IS NULL

IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'[dbo].[Account_Details]' ) AND name = 'rmCopy')
BEGIN
ALTER TABLE ADD -- etc...
END

Related

Simplify SQL by nesting

Currently I have to copy and the following code into SQL developer and then copay & paste the results. How can I nest the following SQL to make life easier?
Select * from ir.application where application_number = 'xxxxxxxxxx';
Transpose xxxxxxxxxx with actual application number
Run this statement. Copy below SQL
--application ID = aaaaaaa
--aaaaaaa
Transpose --aaaaaaa with ID number by highlighting and hitting CTRL + C
Copy and paste the following SQL into SQL Developer
select * from document where app_id = aaaaaaa;
Copy the ID result into the SQL code transposing "aaaaaaa" with the result from above
Hit Run
Copy and paste the following SQL into SQL Developer
--document ID = ddddddd
--ddddddd
Transpose --ddddddd with ID number by highlighting and hitting CTRL + C
Copy and paste the following into SQL Developer
--aaaaaaa = application ID from 1st query
--ddddddd = document ID from 2nd query
update ir.application set application_number = null where id = aaaaaaa;
update ir.application set ttl_id = null where id = aaaaaaa;
update document set app_id = null where id = ddddddd;
update document set title_number = null where id = ddddddd;
update document set case_number = null where id = ddddddd;
commit;
Transpose as appropriate
Now Run each line in turn from "update..." down to "commit;" by highlighting and hitting Run after each semicolon
I think you've massively over-complicated your sql. For a start, you can update multiple columns in an update statement, so there's no need to have an update statement per column.
I think you just need two statements:
update ir.application
set application_number = null,
ttl_id = null
where application_number = :app_num;
update document
set app_id = null,
title_number = null,
case_number = null
where app_id = (select app_id from ir.application where application_number = :app_num);
commit;

Database Upgrade - Invalid column name

I am trying to migrate data during a database upgrade and I don't understand why scenario 1 is working but scenario 2 is throwing an exception:
Scenario 1
Migrate data from ObsoleteTable into NewTable
Works if ObsoleteTable and NewTable both exists
No error if ObsoleteTable has been removed already
Query Scenario 1:
-- NewTable already created
IF EXISTS(select * from sys.tables where name = 'NewTable')
AND EXISTS(select * from sys.tables where name = 'ObsoleteTable')
BEGIN
UPDATE newTable
SET newTable.Name = obsoleteTable.Name
FROM dbo.NewTable newTable
INNER JOIN dbo.ObsoleteTable obsoleteTable
ON obsoleteTable.Id = newTable.Id
END
-- ObsoleteTable will be removed after this step
Scenario 2
Migrate from ObsoleteColumn to NewColumn
Works if ObsoleteColumn and NewColumn both exists
Gives error!!! if ObsoleteColumn is removed already
Query Scenario 2:
-- NewColumn has been created
IF EXISTS(select * from sys.columns where object_id = object_id('MyTable') AND name = 'ObsoleteColumn')
AND EXISTS(select * from sys.columns where object_id = object_id('MyTable') AND name = 'NewColumn')
BEGIN
UPDATE MyTable
SET NewColumn = ObsoleteColumn
END
-- Obsolete Column will be removed after this step
Msg 207, Level 16, State 1, Line 4
Invalid column name 'ObsoleteColumn'.
Both scenarios are basically the same right? Only do the migration to the new structure if the obsolete Table/Column exists. Otherwise ignore.
If I execute scenario one while ObsoleteTable is already removed. it won't fail. So why does scenario 2 fail?
It is a classic error, the column ObsoleteColumn does not exists. Which means the query will fail even when if the programflow never hits that row
This will also fail:
CREATE TABLE #xxx(a int)
IF 1 = 2
SELECT xyz FROM #xxx
To avoid it, you can use EXECUTE:
IF 1 = 2
EXEC('UPDATE MyTable SET NewColumn = ObsoleteColumn')

Selecting rows based on a SQL Server "bit" column

In a SQL Server table, I have a BIT column and based its value, I need to update that table's other columns with some values. I tried this
UPDATE tablename SET Completed = GETDATE() WHERE CheckTaskAvailable = TRUE
but I get the error
Msg 207, Level 16, State 1, Server SQLDEV01, Line 1
Invalid column name 'TRUE'.
How to do this in a T-SQL query?
if you want to set as true try
Update table set columnName = 1 where ...
if you want to set as false try
Update table set columnName = 0 where ...
In addition to using the values 0 and 1, the T-SQL documentation for bit says that
The string values TRUE and FALSE can be converted to bit values: TRUE is converted to 1 and FALSE is converted to 0.
so these work, too:
UPDATE tablename SET bitcolumn = 'TRUE' WHERE ...
UPDATE tablename SET othercolumn = 'something' WHERE bitcolumn = 'TRUE'
I had a need to do something similar where I was looking to update a field based on whether a record existed or not existed in another table so I used above code (thank you RezaRahmati) and added:
Update table set columnName = 1 where ID IN (SELECT ID FROM other table)
or for false
Update table set columnName = 0 where ID NOT IN (SELECT ID FROM other table)
I really enjoy Stack Overflow it has really helped me learn.

Trouble updating new column after adding it

Given the following SQL:
IF EXISTS (SELECT * FROM sys.columns WHERE name = 'NewFieldName' AND object_id = OBJECT_ID('dbo.MyTableName'))
RETURN
-- Add NewFieldName column to part of the Summer 2012 release cycle.
ALTER TABLE dbo.[MyTableName] ADD
[NewFieldName] SmallINT NOT NULL
CONSTRAINT DF_MyTableName_NewFieldName DEFAULT (2)
UPDATE [MyTableName] SET NewFieldName = 1 WHERE [Name] = 'FindMe' --Update one specific value
Produces the following error message:
Msg 207, Level 16, State 1, Line 10 Invalid column name
'NewFieldName'.
I'm sure I'm missing something basic, but trying to put "GO" after the alter makes the UPDATE run everytime and I don't want to do that.
How can I structure this statement so that it will check to see if the column exists and, if it doesn't add it and then set the values as stated in my UPDATE statements?
You need the statement referencing the new column to be compiled after the new column is added. One way of doing this is to run it as a child batch with EXEC.
IF NOT EXISTS (SELECT *
FROM sys.columns
WHERE name = 'NewFieldName'
AND object_id = OBJECT_ID('dbo.MyTableName'))
BEGIN
-- Add NewFieldName column to part of the Summer 2012 release cycle.
ALTER TABLE dbo.[MyTableName]
ADD [NewFieldName] SMALLINT NOT NULL
CONSTRAINT DF_MyTableName_NewFieldName DEFAULT (2)
EXEC(' UPDATE [MyTableName] SET NewFieldName = 1 WHERE [Name] = ''FindMe''')
END
The reason it worked for you originally is presumably because the table itself did not exist when the batch was compiled thus meaning that all statements in it referencing the table are subject to deferred compile.

Is it possible to tell SSMS not to check if a column exists in a t-sql script?

I tried to google it, but din't find a way
I have a t-sql script that adds a new column to a table, then fills that columns with values depending on some other columns in the same table and finally removes some columns. This all works fine.
The problem occures when I want to run the script again. I have a if clause that checks if the missing columns exists, but SSMS still complains and displays error messaged even though the code inside the if clause if not run. The script must be able to run more then once, and I don't want the error messages to be displayed!
In code (obviously test code, don't want to dump production code here...):
create table test (
Name text,
Switch int,
ValueA int,
ValueB int)
go
insert into test values ('Name', 0, 5, 10)
if not exists (select 1 from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME = 'ValueC' and TABLE_NAME = 'test')
begin
alter table test
add ValueC int
end
go
-- This batch rasies error when run more then once!
if exists (select 1 from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME = 'ValueA' and TABLE_NAME = 'test')
begin
update test
set ValueC = (select case Switch
when 0 then (select (ValueA - ValueB))
when 1 then (select (ValueB - ValueA))
end)
end
go
if exists (select 1 from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME = 'ValueA' and TABLE_NAME = 'test')
begin
alter table test drop column ValueA
end
go
select * from test
--Name 0 10 -5
Here is the error message:
Msg 207, Level 16, State 1, Line 6
Invalid column name 'ValueA'.
Msg 207, Level 16, State 1, Line 7
Invalid column name 'ValueA'.
Cheers
--Jocke
Yes it is possible without dynamic SQL but with a bit of a kludgey workaround. I would just use EXEC for this.
The behaviour in SQL 2000 is explained here
Erland Sommarskog mentions "once all tables in a query exist, SQL Server performs full checks on the query."
So by adding a no-op reference in the query to a table that doesn't exist compilation can be deferred. With this adjustment the script below can be run multiple times without getting the error.
insert into test values ('Name', 0, 5, 10)
if not exists (select 1 from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME = 'ValueC' and TABLE_NAME = 'test')
begin
alter table test
add ValueC int
end
go
create table #dummy
(i int)
-- This batch raised error when run more then once!
if exists (select 1 from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME = 'ValueA' and TABLE_NAME = 'test')
begin
update test
set ValueC = (select case Switch
when 0 then (select (ValueA - ValueB))
when 1 then (select (ValueB - ValueA))
end) where not exists(select * from #dummy)
end
drop table #dummy
go
if exists (select 1 from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME = 'ValueA' and TABLE_NAME = 'test')
begin
alter table test drop column ValueA
end
go
select * from test
--Name 0 10 -5
why don't you jsut use a temp table or variable table, add the last column to the declaration, and then you wouldn't have this problem?
I had this exact problem and the only thing that worked for me was to save the script. Close it. Then open it again in and run it in the query window.
Also, it looks like you have the proper GOs, but I found that if I was missing the GO after the check to add the column then not even re-opening the script worked.
Bit late to the party but I ran into this same scenario when trying to do conditional checks based on what version of SQL Server. I took the EXEC route mentioned above. In the below example as inline T-SQL, the SELECT against sys.tables would result in an invalid column name if ran on an earlier version of SQL Server that didn't have the column available.
To work around it, I put the SQL inside a variable and EXEC() it as part of a INSERT INTO to populate a table variable.
DECLARE #Status TABLE (
Result bit
)
DECLARE #Result bit
IF #SQLVer >= 11
SET #SQL='SELECT 1 FROM sys.tables WHERE object_id=' + CONVERT(varchar,#CurrTableObjID) + ' AND is_filetable=1'
DELETE FROM #Status
INSERT INTO #Status
EXEC (#SQL)
SELECT #Result=Result FROM #Status
IF IsNULL(#Result,0) = 1
BEGIN
PRINT 'Table ' + #CurrSchemaName + '.' + #CurrTableName + ' is a filetable'
SET #BadTables=1
END