SQL SERVER: I would like to transfer my data to another column of the same table before droping the first one - sql

I am having problems with some of my SQL scripts on SQL SERVER, indeed I am trying to transfer data from a column A to a column B of the same table and then drop the column B,
However my problem is that I have to check for the existence of A beforehand because the code is meant to be executed on a server where I don't have access (I work as a third party developper on a professionnal app)
Here is my code:
-- Export the data from the column name
-- Drop the column name
USE p_mynacellelocation_db_ChecklistWPF
GO
IF COL_LENGTH('model_trolley_part','name') IS NOT NULL
BEGIN
UPDATE model_trolley_part
SET name_en=[name];
ALTER TABLE model_trolley_part
DROP COLUMN [name];
END
In the case of the column name being non existent I would like not to do anything
However on execution of the code in a database where the column name is non existent SQL Server returns me:
Msg 207, Level 16, State 1, Line 12 Invalid column name 'name'.

Instead of jumping through all these hoops simply rename your original column.
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-rename-transact-sql?view=sql-server-2017
exec sp_rename 'model_trolley_part.name', 'name_en', 'COLUMN'

You need to use dynamic SQL for this. The reason is that the parser will try to validate your code, even the code that won't be executed because its IF condition wouldn't be met.
The parser is smart enough to see there is no table named name, but it's not smart enough to realize that the code shouldn't get executed because of the IF, so it raises a parsing error.
Using dynamic SQL in the BEGIN..END block after the IF hides this from the parser so it will execute.

Try this:
IF EXISTS(SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'myTableName'
AND COLUMN_NAME = 'ColumnA')
BEGIN
// your update and drop code goes here
END
you might want to check your account privileges if you are modifying table structure etc..

Related

Check if column exists then alter column from the table?

I want to write sql script that should check if column exists in the table, and then remove the column if previous statement is true. The database I use is Sybase ASE, and this is the code that I tried to use:
IF EXISTS (SELECT 1 FROM syscolumns WHERE id = object_id('users') AND name = 'maiden_name')
BEGIN
ALTER TABLE security DROP maiden_name
END
The code above executed successfully first time I run it. The second time I goth the error:
Invalid column name 'maiden_name'
If column does not exist the ALTER TABLE block of code shouldn't run. Is there a way to achieve this is Sybase? Thank you.
You can use dynamic SQL:
IF EXISTS (SELECT 1 FROM syscolumns WHERE id = object_id('users') AND name = 'maiden_name')
BEGIN
EXEC('ALTER TABLE security DROP maiden_name')
END;
The problem is that the parser is trying to parse the ALTER during the compilation phase, and it gets an error if the column does not exist.

SQL Code Evaluation stopping a valid transaction

As part of the company I am working for at the moment I need to create some database upgrade scripts to replace some work of a previous contractor.
The code before the following block runs, creates the new ID column, and then this script looks to populate the values and then drop some columns.
IF EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[Central].[Core.Report].[ReportLessonComp]')
AND name = 'Name')
and
EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[Central].[Core.Report].[ReportLessonComp]')
AND name = 'Code')
BEGIN
UPDATE
[Central].[Core.Report].[ReportLessonComp]
SET
CompetencyId = rc.Id
FROM
[Central].[Core.Report].[ReportLessonComp] rlc
INNER JOIN
[Core.Lookup].ReportCompetency rc
ON
rc.Code = rlc.Code and rc.Name = rlc.Name
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN CODE
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN [Name]
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN [Description]
END
GO
When running the if exists \ not exists checks and then select getdate() this works perfeclty fine and gives me the result I expect.
However, when I run the code block above I get error
Msg 207, Level 16, State 1, Line 23
Invalid column name 'Code'.
Msg 207, Level 16, State 1, Line 23
Invalid column name 'Name'.
This script it part of a larger upgrade script and is used in a system calle RoundHouse https://github.com/chucknorris/roundhouse which is the system chosen by the company.
Prior to the above if exists check,
IF (SELECT COUNT(1) FROM sys.columns
WHERE OBJECT_ID = OBJECT_ID('[Central].[Core.Report].[ReportLessonComp]')
AND Name in ('Name','Code')) = 2
which also gave the same issue. I have five tables that I need to update and this is going to stop the team from working if I cant resolve this at my next PR
What can I do in order to stop this from causing the upgrade scripts to fail?
EDIT -- The reason I am linking on varchar fields also is because the previous developer did not create relationships between tables, and was just inserting strings into tables rather than relating by ID causing the potential for unlinked \ inconsistent data.
The table edit prior to this creates the new id column, and this script is getting the value and dropping columns that are no longer needed
SQL Server will parse the whole of the statement prior to execution, so the exists check does not protect you from the update being parsed. If the column has already been dropped, that makes the statement invalid and you get a parse error. The update statement would have to be executed as dynamic SQL, sp_execute basically so that the varchar of the update is not directly parsed.
For SQL Server 2016 and above the drop column can be protected a bit more as well:
ALTER TABLE [Central].[Core.Report].[ReportLessonComp] DROP COLUMN IF EXISTS CODE

change column name in sql server without using sp_rename

I want to change my column name in sql server using a query, without using sp_rename command. Can you please tell me if anybody know it?
I tried as:
alter table table_name alter column 'column1' to 'column2'
and it gave an error message as:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'column1'.
It is not possible to rename a column using the ALTER TABLE statement in SQL Server. Reference.
Use sp_rename instead.
OR
You can right click on the table -> select rename -> type new name.
And example is here.
alter table table_name add column 'column2'
update table_name set column2 = column1
alter table table_name drop column column1
PSEUDOCODE, need data types, likely to turn off triggers, etc. Quite ugly, but does "get the job done".
NOT very good for large tables, of course...

SQL: Why does a CREATE TRIGGER need to be preceded by GO

When making a SQL script to create a trigger on a table, I wanted to check that the trigger doesn't already exist before I create it. Otherwise the script cannot be run multiple times.
So I added a statement to first check whether the trigger exists. After adding that statement, the CREATE TRIGGER statement no longer works.
IF NOT EXISTS (SELECT name FROM sysobjects
WHERE name = 'tr_MyTable1_INSERT' AND type = 'TR')
BEGIN
CREATE TRIGGER tr_MyTable1_INSERT
ON MyTable1
AFTER INSERT
AS
BEGIN
...
END
END
GO
This gives:
Msg 156, Level 15, State 1, Line 5
Incorrect syntax near the keyword 'TRIGGER'.
The solution would be to drop the existing trigger and then create the new one:
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'tr_MyTable1_INSERT' AND type = 'TR')
DROP TRIGGER tr_MyTable1_INSERT
GO
CREATE TRIGGER tr_MyTable1_INSERT
ON MyTable1
AFTER INSERT
AS
BEGIN
...
END
GO
My question is: why is the first example failing? What is so wrong with checking the trigger exists?
Certain statements need to be the first in a batch (as in, group of statements separated by GO ).
Quote:
CREATE DEFAULT, CREATE FUNCTION, CREATE PROCEDURE, CREATE RULE, CREATE SCHEMA, CREATE TRIGGER, and CREATE VIEW statements cannot be combined with other statements in a batch. The CREATE statement must start the batch. All other statements that follow in that batch will be interpreted as part of the definition of the first CREATE statement.
It's simply one of the rules for SQL Server batches (see):
http://msdn.microsoft.com/en-us/library/ms175502.aspx
Otherwise you could change an object, say a table, and then refer to the change in the same batch, before the change was actually made.
Schema changes should always be seperate batch calls...I am guessing they do it to gaurantee your SELECT will succeed, if you modify schema in the same batch they may not be able to gaurantee that. Just a guess...

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'. Msg
207, Level 16, State 1, Line 4 Invalid column name 'Another'.
even though the predicate for both IF statements always evaluates to 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). Is there a way to achieve this without resorting to my arch-enemy Dynamic SQL? I understand that my SQL must always be well-formed (i.e. 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!
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.
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. It isn't procedural like .net or Java code. 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". 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
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)
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. It's not really dynamic SQL if the code never actually changes.
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
You can also try Martin Smith's "Workaround" using a non-existing table to get "deferred name resolution" for columns.
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.
Best regards,
Chen
Derived from the answer by #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. This will make the 2 queries to be run as separate batches thereby ensuring your 'Another' column is there before the SELECT query.