ALTER TABLE Executing regardless of Condition Evaluational Results - sql-server

Below is an excerpt of a SQL Query that I am using to update a table to the correct datatypes if needed.
If NOT Exists(Select * From Information_Schema.Columns
Where Table_Name = N'RXINFO'
And Table_Schema = N'scriptassist'
And Column_Name = N'LastChanged'
And DATA_Type = N'TIMESTAMP'
AND IsNull(CHARACTER_MAXIMUM_LENGTH, 0) = 0)
BEGIN
Print 'LastChanged Field needed type updating'
Alter Table [scriptassist].[RXINFO] Alter Column LastChanged TIMESTAMP
END
Currently the problem is as follows:
If I run the statement With the Alter Table present SQL Server throws this error at me.
Msg 4927, Level 16, State 1, Line 12
Cannot alter column 'LastChanged' to be data type timestamp.
The problem isn't that it can't change the Datatype the problem is that it is attempting to execute that code block regardless of the evaluation of the Condition.
It should evaluate to False in this case.
If I take it out, nothing happens, the print statement doesn't even fire.
The only thing that I can think of thus far is that somehow MS SQL is evaluation the SQL beforehand and determining if all the code paths can execute, and since they can't it throws the error. However this doesn't make that much sense.

SQL Server parses your SQL before it executes it. The error is raised during parsing.
To delay parsing until the line is actually run, use exec:
exec ('Alter Table [scriptassist].[RXINFO] Alter Column LastChanged TIMESTAMP')

I believe you're getting this error because SQL cannot perform a conversion from the previous datatype of your TimeStamp column to an actual TimeStamp datatype. You'll need to drop and then add the column instead.
If NOT Exists(Select * From Information_Schema.Columns
Where Table_Name = N'RXINFO'
And Table_Schema = N'scriptassist'
And Column_Name = N'LastChanged'
And DATA_Type = N'TIMESTAMP'
AND IsNull(CHARACTER_MAXIMUM_LENGTH, 0) = 0)
BEGIN
Print 'LastChanged Field needed type updating'
Alter Table [scriptassist].[RXINFO] Drop Column LastChanged
Alter Table [scriptassist].[RXINFO] Add LastChanged TimeStamp
END

Related

SQL Server: if column exists; invalid column name

I need to write a query that will run on different versions of a database. Some of them have a column named Delflag and some don't. If the column exists, it should be included in the select statement and the WHERE clause.
I tried it with the following code:
IF EXISTS
(
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Bericht'
AND column_name = 'DelFlag'
)
...
ELSE
...
In the IF block, I included the column. In the ELSE block it is not mentioned. However, if the column doesn't exist, I just get the an error "Msg 207 - invalid column name". I checked that the column name is only included in the IF EXISTS block.
I tried to select and filter a column if it exists and if not just leave the part out. I expected the query to run on different databases where the column sometimes exists, sometimes not. If the column exists, it runs, but if it doesn't exist, the query throws
Msg 207
Invalid column name
The query is failing at the binding stage as a column you are referencing doesn't exist.
You are going to have use dynamic sql to build a string based on your logical check and then execute the resulting string using sp_executesql
This would look something like
DECLARE #sql NVARCHAR(MAX) = 'SELECT ColumnA, ColumnB';
IF EXISTS
(
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Bericht' AND
column_name = 'DelFlag'
)
BEGIN
SET #sql += ', DelFlag';
END
SET #sql += ' FROM Bericht;';
EXEC sp_executesql #command = #sql;

Why is the table inside a non-met IF being validated before condition is met, resulting in error if table does not exist?

I am trying to execute a procedure with a parameter, and depending on the value of the parameter, three different IF conditions will be evaluated to verify which query it will execute from a linked server.
But when I execute the query, it seems to be checking if the tables inside all the IF exists before starting the query. And I know that only one of the table exists, that is why I am using the parameter, so it shouldn't fail. but I anyhow get the following error:
Msg 7314, Level 16, State 1, Line 25
The OLE DB provider "Microsoft.ACE.OLEDB.16.0" for linked server "LinkedServer" does not contain the table "D100". The table either does not exist or the current user does not have permissions on that table.
So in this code, assume that the parameter is 300. then I get the message above.
Do you know, if there is a way, to limit the query to do not check all the tables, but only the one where the IF condition will be met?
ALTER PROCEDURE[dbo].[Import_data]
#p1 int = 0
AS
BEGIN
SET NOCOUNT ON;
IF(#p1 = 100)
BEGIN
DROP TABLE IF EXISTS Table1
SELECT [Field1], [Field2], [Field3], [Field4], [Field5], [Field6]
INTO Table1
FROM[LinkedServer]...[D100]
END
IF(#p1 = 200)
BEGIN
DROP TABLE IF EXISTS Table2
SELECT[Field1], [Field2], [Field3], [Field4], [Field5], [Field6]
INTO Table2
FROM[LinkedServer]...[D200]
END
IF(#p1 = 300)
BEGIN
DROP TABLE IF EXISTS Table3
SELECT[Field1], [Field2], [Field3], [Field4], [Field5], [Field6]
INTO Table3
FROM[LinkedServer]...[D300]
END
END
I have tried googling it, but I found mostly workarounds as running a sub procedure, but it is not really a clean solution, I think.
Okay, it seems I that I found the answer. Even with an IF statement, the SQL Server validates the entire query before executing it, so the way to overcome it, is to use a Dynamic SQL Query.
"SQL Server Dynamic SQL is a programming technique that allows you to construct SQL statements dynamically at runtime. It allows you to create more general purpose and flexible SQL statement because the full text of the SQL statements may be unknown at compilation."
This is how the query looks now. so instead of multiple IF statements, the query changes dynamically depending on the parameter.
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = N'DROP TABLE IF EXISTS Table1;
SELECT [Field1]
,[Field2]
,[Field3]
,[Field4]
,[Field5]
,[Field6]
INTO Table1
FROM [LinkedServer]...[D' + CONVERT(nvarchar(3),#p1) + N']'
EXEC sp_executesql #SQL

Dynamically increase SQL Column length

Is there a way to dynamically increase Database Column length if an incoming data is larger than the length specified. Which database software can handle this ? Or is it something that needs to be handled by the application that inserts this data into the database ?
I support #Ed Mendez and #HLGEM that you shouldn't do this but still if you want to do this then you should write a Procedure to do this. You should check the column size with SELECT COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH
FROM information_schema.columns
WHERE table_schema = DATABASE() AND -- name of your database
table_name = 'table_name' AND -- name of your table
column_name = 'name_of_column' -- name of the column in IF condition and then ALTER the table with ALTER Query. But while checking again in Procedure you will have to take care of input size. So better you can go for VARCHAR. If still you are unable to do please give the demo of your column I'll write the procedure code. Hope this help you.

SQL script runs fine on one database, errors on another

We have a script that must allow for being re-run several times.
We have an MS-SQL script that updates a table if a (now obsolete) column exists, then deletes the column. To ensure that the script can be run several times, it first checks for the existence of a column before performing the updates.
The script works as expected on our dev database, updating the data on the first run, then displaying the message 'Not updating' on subsequent runs.
On our test database the script runs fine on the first run, but errors with "Invalid column name 'OldColumn'" on subsequent runs; if I comment out the UPDATE and ALTER statements it runs as expected.
Is there a way to force the script to run even if there's a potential error, or is it something to do with how the database was set-up? (fingers crossed I'm not looking like a complete noob!)
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'MyTable' AND COLUMN_NAME = 'OldColumn')
BEGIN
PRINT 'Updating and removing old column...'
UPDATE MyTable SET NewColumn='X' WHERE OldColumn=1;
ALTER TABLE MyTable DROP COLUMN OldColumn;
END
ELSE
PRINT 'Not updating'
GO
As a work around you could do
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'MyTable' AND COLUMN_NAME = 'OldColumn')
BEGIN
PRINT 'Updating and removing old column...'
EXEC ('UPDATE MyTable SET NewColumn=''X'' WHERE OldColumn=1;');
ALTER TABLE MyTable DROP COLUMN OldColumn;
END
ELSE
PRINT 'Not updating'

MODIFY COLUMN in oracle - How to check if a column is nullable before setting to nullable?

I'm trying to fill in for a colleague in doing some Oracle work, and ran into a snag. In attempting to write a script to modify a column to nullable, I ran into the lovely ORA-01451 error:
ORA-01451: column to be modified to NULL cannot be modified to NULL
This is happening because the column is already NULL. We have several databases that need to be udpated, so in my faulty assumption I figured setting it to NULL should work across the board to make sure everybody was up to date, regardless of whether they had manually set this column to nullable or not. However, this apparently causes an error for some folks who already have the column as nullable.
How does one check if a column is already nullable so as to avoid the error? Something that would accomplish this idea:
IF( MyTable.MyColumn IS NOT NULLABLE)
ALTER TABLE MyTable MODIFY(MyColumn NULL);
You could do this in PL/SQL:
declare
l_nullable user_tab_columns.nullable%type;
begin
select nullable into l_nullable
from user_tab_columns
where table_name = 'MYTABLE'
and column_name = 'MYCOLUMN';
if l_nullable = 'N' then
execute immediate 'alter table mytable modify (mycolumn null)';
end if;
end;
just do the alter table and catch the exception.
DECLARE
allready_null EXCEPTION;
PRAGMA EXCEPTION_INIT(allready_null, -1451);
BEGIN
execute immediate 'ALTER TABLE TAB MODIFY(COL NULL)';
EXCEPTION
WHEN allready_null THEN
null; -- handle the error
END;
/
if you don't want to use PL/SQL
set feedback off
set echo off
set feedback off
set pages 0
set head off
spool to_null.sql
select 'alter table TAB modify (COL NULL);'
from user_tab_columns
where table_name = 'TAB'
and column_name = 'COL'
and nullable = 'N';
spool off
set feedback on
set echo on
set termout on
##to_null.sql
host rm -f to_null.sql
or just do the alter table and ignore the error.

Resources