SQL: multiple statements within a BEGIN and END - sql

I'm trying to add a new column to an existing table which will be populated by a unique Guid value. I'm trying the following code:
IF NOT EXISTS(select * from sys.columns
where Name = N'Product_GUID' and Object_ID = Object_ID(N'dbo.Product'))
BEGIN
PRINT 'Creating new GUID column in dbo.Product table'
ALTER TABLE dbo.Product
ADD Product_GUID uniqueidentifier NULL
UPDATE dbo.Product
SET Product_Guid=NEWID()
ALTER TABLE dbo.Product
ALTER COLUMN Product_Guid uniqueidentifier NOT NULL
END
This won't work becasue the second statement doesn't recognise the new column name. I can't put GO or ; at the end of each statement though, presumably because I'm in the middle of the BEGIN/END block.
What's the best way of solving this dilemma?

The statement doing the update must be compiled after the column is added.
The way this is usually done is wrapping the statements in an EXEC:
EXEC(' UPDATE dbo.Product
SET Product_Guid = NEWID()
ALTER TABLE dbo.Product
ALTER COLUMN Product_Guid uniqueidentifier NOT NULL
')

It seems like you want to set the default value and have the column be not null. You'll get the same effect if you just set the default value to NEWID()
IF NOT EXISTS(select * from sys.columns
where Name = N'Product_GUID' and Object_ID = Object_ID(N'dbo.Product'))
BEGIN
PRINT 'Creating new GUID column in dbo.Product table'
ALTER TABLE dbo.Product
ADD Product_GUID uniqueidentifier NOT NULL DEFAULT NEWID()
END
If you need to remove the constraint after, you can create the DEFAULT constraint after you define the column in the alter statement and then drop the named constraint right after. If you don't name the constraint you'll have to get the name from sys.objects and then do dynamic sql to remove it.
IF NOT EXISTS(select * from sys.columns
where Name = N'Product_GUID' and Object_ID = Object_ID(N'dbo.Product'))
BEGIN
PRINT 'Creating new GUID column in dbo.Product table'
ALTER TABLE dbo.Product
ADD Product_GUID uniqueidentifier NOT NULL,
CONSTRAINT Default_Product_GUID DEFAULT NEWID() FOR Product_GUID;
ALTER TABLE dbo.Product DROP CONSTRAINT Default_Product_GUID
END

You could just update the table afterwards and then alter it in another code block, a little something like this:
IF NOT EXISTS(select * from sys.columns
where Name = N'Product_GUID' and Object_ID = Object_ID(N'dbo.Product'))
BEGIN
PRINT 'Creating new GUID column in dbo.Product table'
ALTER TABLE dbo.Product
ADD Product_GUID uniqueidentifier NULL
END
GO
UPDATE dbo.Product
SET Product_Guid=NEWID()
Where Product_Guid is null
if ##ROWCOUNT <> 0
Begin
ALTER TABLE dbo.Product
ALTER COLUMN Product_Guid uniqueidentifier NOT NULL
End

Related

How to add column to if not exist and update value

I have this script
ALTER TABLE [dbo].TableName ADD ColumnName BIT DEFAULT(1)
GO
UPDATE [dbo].TableName SET ColumnName = 1
I have to add condition to check is column already exist, but then there is error with go
This script is also not working
IF EXISTS(SELECT 1 FROM sys.columns
WHERE Name = N'ColumnName'
AND Object_ID = Object_ID(N'dbo.TableName'))
BEGIN
ALTER TABLE [dbo].TableName ADD ColumnName BIT DEFAULT(1)
UPDATE [dbo].TableName SET ColumnName = 1
END
There must be IF condition. How to fix that?
Your IF EXISTS should be an IF NOT EXISTS. More importantly, you need to execute the ALTER and the UPDATE separately, like so:
IF NOT EXISTS(SELECT 1 FROM sys.columns
WHERE Name = N'ColumnName'
AND Object_ID = Object_ID(N'dbo.TableName'))
BEGIN
EXEC sys.sp_executesql N'ALTER TABLE [dbo].TableName ADD ColumnName BIT DEFAULT(1)';
EXEC sys.sp_executesql N'UPDATE [dbo].TableName SET ColumnName = 1';
END
You should check with IF NOT EXISTS, you are missing the NOT.
And I expect you want to UPDATE the column outside the IF statement, because it won't do anything on a new column with that same default value.
The Go statement is used to split one request into multiple smaller requests. That is why you cannot split within an IF statement.
IF NOT EXISTS(SELECT 1 FROM sys.columns
WHERE Name = N'ColumnName'
AND Object_ID = Object_ID(N'dbo.TableName'))
BEGIN
ALTER TABLE [dbo].TableName ADD ColumnName BIT DEFAULT(1)
END
GO
UPDATE [dbo].TableName SET ColumnName = 1

SQL - Continue running all SQL statements even after error

I have some queries like this
Alter Table Table1 ALTER COLUMN T1 varchar(MAX);
Alter Table Table1 ALTER COLUMN T2 varchar(MAX);
Alter Table Table1 ALTER COLUMN T3 varchar(MAX);
--Table2 does not have a column "R1" and is likely to give error
Alter Table Table2 ALTER COLUMN R1 varchar(MAX);
Alter Table Table2 ALTER COLUMN T1 varchar(MAX);
Alter Table Table2 ALTER COLUMN T2 varchar(MAX);
Alter Table Table2 ALTER COLUMN T3 varchar(MAX);
Possible Error
Now in the 4th statement it is likely that a message would pop because there is no field in Table2 named R1.
Need
I need a way so that all the statement gets executed even after receiving the error.
My Approach
I tried to execute these statements individually to receive error message for every line but it takes too much time as it makes 7 times connection to a server which is connected to the PC by internet . So, i used all those query together to get records in one connection but it breaks the command on 4th line as the statement is invalid.
Any suggestion or piece of code is appreciated
You should use 'GO' between instructions in order to contine the execution no matter on the errors:
Alter Table Table1 ALTER COLUMN T1 varchar(MAX);
GO
Alter Table Table1 ALTER COLUMN T2 varchar(MAX);
GO
Alter Table Table1 ALTER COLUMN T3 varchar(MAX);
GO
Alter Table Table2 ALTER COLUMN R1 varchar(MAX);
GO
Alter Table Table2 ALTER COLUMN T1 varchar(MAX);
GO
Alter Table Table2 ALTER COLUMN T2 varchar(MAX);
GO
Alter Table Table2 ALTER COLUMN T3 varchar(MAX);
GO
This will give you all messages and will execute all the sentences one after each other. Those are my logs on a similar situation. As you will see, various errors are notified, and not only one:
NOTE: The catch behavior depends on the severity of the error, this
link from the MSDOC explains how try_catch works
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/try-catch-transact-sql?view=sql-server-2017
Hope it helps :)
Use a try-catch block:
Alter Table Table1 ALTER COLUMN T1 varchar(MAX);
Alter Table Table1 ALTER COLUMN T2 varchar(MAX);
Alter Table Table1 ALTER COLUMN T3 varchar(MAX);
BEGIN TRY
Alter Table Table2 ALTER COLUMN R1 varchar(MAX);
END TRY
BEGIN CATCH
print 'error altering column R1 of Table2';
END CATCH;
Alter Table Table2 ALTER COLUMN T1 varchar(MAX);
Alter Table Table2 ALTER COLUMN T2 varchar(MAX);
Alter Table Table2 ALTER COLUMN T3 varchar(MAX);
If Table2 does not have column R1 then the statement 'Alter Table Table2 ALTER COLUMN R1 varchar(MAX);' will not be a valid sql statement so the statement will not try to run so the catch will not happen. If instead you execute the statement it will try to run and the catch will work.
Alter Table Table1 ALTER COLUMN T1 varchar(MAX);
Alter Table Table1 ALTER COLUMN T2 varchar(MAX);
Alter Table Table1 ALTER COLUMN T3 varchar(MAX);
BEGIN TRY
execute ('Alter Table Table2 ALTER COLUMN R1 varchar(MAX);')
END TRY
BEGIN CATCH
print 'error altering column R1 of Table2';
END CATCH;
Alter Table Table2 ALTER COLUMN T1 varchar(MAX);
Alter Table Table2 ALTER COLUMN T2 varchar(MAX);
Alter Table Table2 ALTER COLUMN T3 varchar(MAX);
I have noticed that we get the desired behavior if the commands are run from inside an open session.
mysql -u root -p myDB < commands.sql >> stops on the first error
mysql -u root -p myDB
(after login)
source commands.sql
^^^ continues even after errors occur

Drop a column with a default constraint in SQL Server (IF EXISTS)

I am writing a sql script for dropping column and a default constraint. The following script works fine but i like to know if it is a right way of doing it.
Can i drop a default constraint with a column in one statement instead of using two separate ones?
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF_Employees_EmpID]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[Employees] DROP CONSTRAINT [DF_Employees_EmpID]
END
GO
BEGIN
ALTER TABLE [dbo].[Employees] DROP COLUMN [EmpID]
END
In SQL Server 2005 upwards you can drop both the constraint and the column in one statement.
The syntax is
ALTER TABLE [ database_name . [ schema_name ] . | schema_name . ] table_name
DROP { [ CONSTRAINT ] constraint_name | COLUMN column } [ ,...n ]
The emphasis is on [ ,...n ], indicating multiple terms.
NB! Since the terms are processed sequentially, if the column being dropped is part of the constraint being dropped, then the constraint must be the first term, followed by the column term.
In your example:
ALTER TABLE [dbo].[Employees] DROP CONSTRAINT [DF_Employees_EmpID], COLUMN [EmpID]
So your code would be:
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF_Employees_EmpID]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[Employees] DROP CONSTRAINT [DF_Employees_EmpID], COLUMN [EmpID]
END
GO
In SQL Server 2016 they have introduced the IF EXISTS clause which removes the need to check for the existence of the constraint first e.g.
ALTER TABLE [dbo].[Employees] DROP CONSTRAINT IF EXISTS [DF_Employees_EmpID], COLUMN IF EXISTS [EmpID]
Here is another way to drop a column & default constraints with checking if they exist before dropping them:
-------------------------------------------------------------------------
-- Drop COLUMN
-- Name of Column: Column_EmployeeName
-- Name of Table: table_Emplyee
--------------------------------------------------------------------------
IF EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table_Emplyee'
AND COLUMN_NAME = 'Column_EmployeeName'
)
BEGIN
IF EXISTS ( SELECT 1
FROM sys.default_constraints
WHERE object_id = OBJECT_ID('[dbo].[DF_table_Emplyee_Column_EmployeeName]')
AND parent_object_id = OBJECT_ID('[dbo].[table_Emplyee]')
)
BEGIN
------ DROP Contraint
ALTER TABLE [dbo].[table_Emplyee] DROP CONSTRAINT [DF_table_Emplyee_Column_EmployeeName]
PRINT '[DF_table_Emplyee_Column_EmployeeName] was dropped'
END
-- ----- DROP Column -----------------------------------------------------------------
ALTER TABLE [dbo].table_Emplyee
DROP COLUMN Column_EmployeeName
PRINT 'Column Column_EmployeeName in images table was dropped'
END
--------------------------------------------------------------------------
-- ADD COLUMN Column_EmployeeName IN table_Emplyee table
--------------------------------------------------------------------------
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table_Emplyee'
AND COLUMN_NAME = 'Column_EmployeeName'
)
BEGIN
----- ADD Column & Contraint
ALTER TABLE dbo.table_Emplyee
ADD Column_EmployeeName BIT NOT NULL
CONSTRAINT [DF_table_Emplyee_Column_EmployeeName] DEFAULT (0)
PRINT 'Column [DF_table_Emplyee_Column_EmployeeName] in table_Emplyee table was Added'
PRINT 'Contraint [DF_table_Emplyee_Column_EmployeeName] was Added'
END
GO
How you have it is fine.
An alternative would be
IF OBJECT_ID('DF_Employees_EmpID', 'D') IS NULL
BEGIN
ALTER TABLE dbo.Employees
DROP COLUMN EmpID
END
ELSE
BEGIN
ALTER TABLE dbo.Employees
DROP CONSTRAINT DF_Employees_EmpID,
COLUMN EmpID
END
In the event that the constraint does exist this combines the two operations into a single statement/transaction.
Another solution:
DECLARE #TableName sysname,
#Schema sysname,
#colname sysname,
#sql VARCHAR(1000)
SELECT #Schema = 'dbo',
#TableName = 'mytable',
#colname = 'mycol'
IF COL_LENGTH(#Schema+'.'+#TableName, #colname) IS NULL
BEGIN
PRINT 'Column does not exist!'
END
ELSE
BEGIN
SET #sql = ''
SELECT #sql += N' ALTER TABLE ' + #TableName + ' DROP CONSTRAINT ' + default_constraints.name + ';'
FROM sys.all_columns
INNER JOIN sys.tables
ON all_columns.object_id = TABLES.object_id
INNER JOIN sys.schemas
ON TABLES.schema_id = schemas.schema_id
INNER JOIN sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE schemas.name = #Schema
AND tables.name = #TableName
AND all_columns.name = #colname
SET #sql += N' ALTER TABLE ' + #TableName + ' DROP COLUMN ' + #colname + ';'
PRINT ISNULL(#sql, 'NULL')
EXECUTE(#sql)
END

Why does SQL Server keep creating a DF constraint?

I'm trying to create upgrade and backout scripts in SQL. The upgrade script adds a column like so:
IF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'ColumnName'
AND object_id = OBJECT_ID(N'[dbo].[TableName]'))
ALTER TABLE TableName
ADD ColumnName bit NOT NULL DEFAULT(0)
The backout script removes the column like so:
IF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ColumnName'
AND object_id = OBJECT_ID(N'[dbo].[TableName]'))
ALTER TABLE TableName
DROP COLUMN ColumnName
However, the backout script throws this error:
Msg 5074, Level 16, State 1, Line 5
The object 'DF__TableName__ColumnName__1BF3D5BD' is dependent on column 'ColumnName'.
Msg 4922, Level 16, State 9, Line 5
ALTER TABLE DROP COLUMN ColumnName failed because one or more objects access this column.
I know how to drop the constraint, but the constraint's name changes everytime (the suffix changes). I either need SQL Server to stop creating this randomly-named constraint OR I need to be able to remove the constraint in my script using wild-card characters, since the name changes.
This is the default constraint that is added because of the DEFAULT(0) in your newly added column.
You can name this yourself so it has a known fixed name rather than relying on the auto name generation.
ALTER TABLE TableName
ADD ColumnName bit NOT NULL CONSTRAINT DF_Some_Fixed_Name DEFAULT(0)
Then to remove the column and constraint together
ALTER TABLE dbo.TableName
DROP CONSTRAINT DF_Some_Fixed_Name, COLUMN ColumnName
Run this:
declare #name as nvarchar(255);
SELECT #name = name FROM dbo.sysobjects
WHERE name LIKE 'DF__XXX__YYY__%' and type = 'D'
IF #name IS NOT NULL BEGIN
EXEC('ALTER TABLE XXX DROP CONSTRAINT ' + #name);
END
Run this if you want remove constraint:
DECLARE #tableName NVARCHAR(255) = '[INSERT]';
DECLARE #first5CharsFromColumnName NVARCHAR(255) = '[INSERT]';
DECLARE #name NVARCHAR(255);
SELECT #name = d.name FROM dbo.sysobjects d
INNER JOIN dbo.sysobjects t ON t.id = d.parent_obj
WHERE d.name LIKE '%'+#first5CharsFromColumnName+'%' AND d.type = 'D' AND t.name = #tableName
IF #name IS NOT NULL BEGIN
EXEC('ALTER TABLE '+#tableName+' DROP CONSTRAINT ' + #name);
END

Drop column and all dependent objects using data definition language

I need to remove a column from a table, but when I try to remove it:
The object 'object_name' is dependent
on column 'column_name'.
ALTER TABLE DROP COLUMN column_name failed because
one or more objects access this
column.
I can look for the dependency in the system tables and remove it manually, but I need to do a migration (using SQL DDL) so all others members of the team just do the update, run the migration and donĀ“t have to mess up up system objects.
Try this code:
Declare #TABLENAME varchar(max), #COLUMN varchar(max)
SET #TABLENAME = 'YOURTableName'
SET #COLUMN = 'YOURColumnName'
Declare #CONSTRAINT varchar(max)
set #CONSTRAINT ='ALTER TABLE '+#TABLENAME+' DROP CONSTRAINT '
set #CONSTRAINT = #CONSTRAINT + (select SYS_OBJ.name as CONSTRAINT_NAME
from sysobjects SYS_OBJ
join syscomments SYS_COM on SYS_OBJ.id = SYS_COM.id
join sysobjects SYS_OBJx on SYS_OBJ.parent_obj = SYS_OBJx.id
join sysconstraints SYS_CON on SYS_OBJ.id = SYS_CON.constid
join syscolumns SYS_COL on SYS_OBJx.id = SYS_COL.id
and SYS_CON.colid = SYS_COL.colid
where
SYS_OBJ.uid = user_id() and SYS_OBJ.xtype = 'D'
and SYS_OBJx.name=#TABLENAME and SYS_COL.name=#COLUMN)
exec(#CONSTRAINT)
and then run your regular alter table:
ALTER TABLE YOURTABLENAME
DROP COLUMN YOURCOLUMNNAME
With the first code you remove all the dependencies on that column and then you can remove it without problems.
EDIT - Removing Default Values Constraints:
The code above does not seems to remove DEFAULT_CONSTRAINTS so, in that case you must also use:
DECLARE #ConstraintName nvarchar(200)
SELECT #ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('__TableName__') AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns WHERE NAME = N'__ColumnName__' AND object_id = OBJECT_ID(N'__TableName__'))
IF #ConstraintName IS NOT NULL
EXEC('ALTER TABLE __TableName__ DROP CONSTRAINT ' + #ConstraintName)