How to check if the Default Value Constraint exists? - sql

I am using SQL server 2008. I need to find if default value constraint does not exist then create it. Here is what I have tried.
IF (NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME ='MyConstraint'))
BEGIN
ALTER TABLE [XX] ADD CONSTRAINT [MyConstraint] DEFAULT ((-1)) FOR [XXXX]
END
GO

if not exists (
select *
from sys.all_columns c
join sys.tables t on t.object_id = c.object_id
join sys.schemas s on s.schema_id = t.schema_id
join sys.default_constraints d on c.default_object_id = d.object_id
where t.name = 'table'
and c.name = 'column'
and s.name = 'schema')
....

I find this to be easier:
IF OBJECT_ID('SchemaName.MyConstraint', 'D') IS NULL
BEGIN
-- create it here
END

I was a bit puzzled as to why this simple task was so complicated. In my case, I don't have constraint names - only table and column names. I want to check if they already have a default before trying to add one.
After a bit more digging, I came up with this:
IF (SELECT Column_Default FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'MY_TABLE' AND COLUMN_NAME = 'MY_COLUMN') is NULL
BEGIN
ALTER TABLE [dbo].[MY_TABLE]
ADD DEFAULT ('') FOR [MY_COLUMN]
END
GO
I have to implement this in a ginormous boilerplate script, so the shorter the better.

if not exists(select 1 from sys.default_constraints where name = 'SchemaName.MyConstraint')
begin
-- create it here
end

The following works for me on SQL Server 2016.
Assuming I have a table named MY_TABLE and a column MY_COLIUMN.
I would like to add a constrain (default to '-1' ) on MY_COLIUMN that need to add the constrain on.
/* Test for the specific column */
IF EXISTS (select 1 from sys.all_columns c where c.object_id= OBJECT_ID(N'MY_TABLE') and c.name='MY_COLIUMN')
BEGIN
/* Add default if not exits */
IF NOT EXISTS (
select 1 from sys.default_constraints c where c.object_id =
(
select default_object_id from sys.all_columns c where c.object_id = OBJECT_ID(N'MY_TABLE') and c.name='MY_COLIUMN'
)
)
BEGIN
ALTER TABLE MY_TABLE
ADD DEFAULT '-1' FOR MY_COLIUMN;
END
END
GO

I've used the following in the past:
DECLARE #default sysname
SELECT #default = object_name( cdefault ) FROM syscolumns WHERE id = object_id( 'DBO.TABLE' ) AND name = 'COLUMN'
IF ( not #default is null )
BEGIN
...
END

Search the system table where the default costraints of the database are stored, without the schema name:
IF EXISTS(SELECT 1 FROM sys.default_constraints WHERE [name] = 'MyConstraint')
print 'Costraint exists!';
ELSE
print 'Costraint doesn''t exist!';

I know I'm coming to the party late here, but I am a big fan of OBJECTPROPERTY. Here is how to set a default of 1 on a column if the default does not yet exist.
IF (OBJECTPROPERTY(OBJECT_ID('My_constraint_name'),'CnstIsColumn') IS NULL
ALTER TABLE Mytable ADD CONSTRAINT [MY_constraint_name] DEFAULT ((1)) FOR [My_column_name]

Related

SQL multiple if's not running on DbUp

The following is my code
IF NOT EXISTS (SELECT 1 FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id
WHERE
o.name = 'portfolioAttributeCodes'
AND c.name = 'isDisplayed'
)
BEGIN
ALTER TABLE
[cosmos].[portfolioAttributeCodes]
ADD
[isDisplayed] bit DEFAULT 1;
END
IF EXISTS (SELECT 1 FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id
WHERE
o.name = 'portfolioAttributeCodes'
AND c.name = 'isDisplayed')
BEGIN
UPDATE [cosmos].[portfolioAttributeCodes] SET [isDisplayed] = 1;
END
Now what is happening is it will not create a column (skips the first Id statement and gets into the second one and fails with Invalid column name 'isDisplayed'
Can some one help?
If the table doesn't have the column isDisplayed already the entire batch will fail, as the parser will generate an Invalid column name error. This occurs before any of the SQL is run, so it's not that the second IF is being entered, none of the SQL is run at all. It's effectively a compilation error (like when you try to build you C# application and you have a reference to an object you haven't defined).
You cannot reference a new column in the same scope it was created. You would need to use 2 batches or put the reference to the column in a separate scope, so that its validation is deferred.
A deferred validation would seem fine here:
IF NOT EXISTS (SELECT 1
FROM sys.objects o
INNER JOIN sys.columns c ON o.object_id = c.object_id
WHERE o.name = 'portfolioAttributeCodes'
AND c.name = 'isDisplayed')
BEGIN
ALTER TABLE [cosmos].[portfolioAttributeCodes]
ADD [isDisplayed] bit CONSTRAINT DF_isDisplayed DEFAULT 1 WITH VALUES;
END;
ELSE
BEGIN
EXEC sys.sp_executesql N'UPDATE [cosmos].[portfolioAttributeCodes] SET [isDisplayed] = 1;';
END;
I also switch to an ELSE as there is little point updating the column after you've created it; just create the column with the values in the first place. I name the DEFAULT CONSTRAINT as well as that's just good habit.

Looping through different tables of different dates

We have a legacy application which created multiple tables with the following naming convention: table_20140618, table_20140623, etc where the date is when the program run. I am trying to clean up the database now, and drop some of these tables.
In each table there are two fields: DateStarted and DateFinished. I want to select the tables (and then drop them) where DateStarted has value and DateFinished is NOT null.
At the moment I am using the following query to select all the tables that start with 'table_'
such as:
Select (TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE 'table_%';
I am not sure how to get all the tables together by searching within their fields. I could do it through the code, but that should mean multiple hits on the database. Any ideas?
Made this after my first comment above, but you should be able to alter the code to fit your specs. Basically, this will use dynamic SQL to generate the commands based on your filters and conditions. So you can use whatever conditions you want in the SELECT #SQL = ... part, to check for the dates, and then add the table name when the conditions are met.
The script returns a list with tablenames and the drop command, so you can check what you're doing before you do it. But from there you can just copy the drop command list and execute it if you want.
IF OBJECT_ID('tempdb..#TABLES') IS NOT NULL
DROP TABLE #TABLES
CREATE TABLE #TABLES (ROWNMBER INT IDENTITY(1,1), TABLENAME VARCHAR(256) COLLATE DATABASE_DEFAULT)
/*
-- Old code to fetch ALL tables with specified name
INSERT INTO #TABLES
SELECT name
FROM sys.tables
WHERE name LIKE 'table[_]%'
*/
-- Updated code to fetch only those tables which contain the DateStarted and DateFinished columns
INSERT INTO #TABLES
SELECT TAB.name
FROM sys.tables TAB
LEFT JOIN sys.columns C1 on C1.object_id = TAB.object_id
AND C1.name = 'DateStarted'
LEFT JOIN sys.columns C2 on C2.object_id = TAB.object_id
AND C2.name = 'DateFinished'
WHERE TAB.name LIKE 'table[_]%'
AND C1.name IS NOT NULL AND C2.name IS NOT NULL
IF OBJECT_ID('tempdb..#DROPPABLE_TABLES') IS NOT NULL
DROP TABLE #DROPPABLE_TABLES
CREATE TABLE #DROPPABLE_TABLES (TABLENAME VARCHAR(256) COLLATE DATABASE_DEFAULT)
DECLARE #ROW_NOW INT, #ROW_MAX INT, #SQL VARCHAR(MAX), #TABLENAME VARCHAR(256)
SELECT #ROW_NOW = MIN(ROWNMBER), #ROW_MAX = MAX(ROWNMBER) FROM #TABLES
WHILE #ROW_NOW <= #ROW_MAX
BEGIN
SELECT #TABLENAME = TABLENAME FROM #TABLES WHERE ROWNMBER = #ROW_NOW
SELECT #SQL =
'IF (SELECT COUNT(*) FROM '+#TABLENAME+' WHERE DateStarted IS NOT NULL) > 0
AND (SELECT COUNT(*) FROM '+#TABLENAME+' WHERE DateFinished IS NOT NULL) > 0
SELECT '''+#TABLENAME+''''
INSERT INTO #DROPPABLE_TABLES
EXEC(#SQL)
SET #ROW_NOW = #ROW_NOW+1
END
SELECT *, 'DROP TABLE '+TABLENAME DROPCOMMAND FROM #DROPPABLE_TABLES
EDIT:
As per your comment, it seems not all such tables have those columns. You can use the following script to identify said tables and which column is missing, so you can check into them further. And you can use the same idea to filter the results of the first query to only count in tables which have those columns.
SELECT TAB.name TABLENAME
, CASE WHEN C1.name IS NULL THEN 'Missing' ELSE '' END DateStarted_COL
, CASE WHEN C2.name IS NULL THEN 'Missing' ELSE '' END DateFinished_COL
FROM sys.tables TAB
LEFT JOIN sys.columns C1 on C1.object_id = TAB.object_id
AND C1.name = 'DateStarted'
LEFT JOIN sys.columns C2 on C2.object_id = TAB.object_id
AND C2.name = 'DateFinished'
WHERE TAB.name LIKE 'table[_]%'
AND (C1.name IS NULL
OR C2.name IS NULL)

Finding out if a column is NOT NULL

I have a column in my DB which is currently defined as NOT NULL.
I would like to update this column to allow NULLs.
I have the following script to do this however I would like to check first if the column is already NULL (or NOT NULL), as it may have been changed previously.
ALTER TABLE [dbo].[aud]
ALTER COLUMN [actname] nvarchar(50) NULL
Any help appreciated.
Use COLUMNPROPERTY to get column property . You may write something like
SELECT COLUMNPROPERTY(OBJECT_ID('dbo.aud'),'actname','AllowsNull') AS 'AllowsNull';
For more information please visit this link
select is_nullable from sys.columns c inner join sys.tables t on
t.object_id = c.object_id where t.name = 'aud' and c.name = 'actname'
Will give you a BIT representing whether it is nullable or not.
So you could switch on this like
IF EXISTS(SELECT * from sys.columns c inner join sys.tables t on
t.object_id = c.object_id where t.name = 'aud' and c.name = 'actname' AND
is_nullable = 1)
BEGIN
--What to do if nullable
END
ELSE
BEGIN
--What to do if not nullable
END
END
That of course assumes that the table and column exist at all...
There isn't really a need to do that, because if it's already Nullable, changing a column from Nullable to Nullable will have no negative effect.
However you can do it with this query:
SELECT is_nullable
FROM sys.columns
WHERE object_id=object_id('YourTable') AND name = 'yourColumn'

Drop table if exist with similar name in two schema

I use this command to drop a table in sql-server 2008
IF EXISTS(SELECT name FROM [DBName]..sysobjects WHERE name = N'TableName' AND xtype='U')
DROP TABLE [DBName].[SchemaName].[TableName];
But now I have 2 tables with same name in different schema:
[DBName].[Schema1].[Members]
And
[DBName].[Schema2].[Members]
So, what is your suggestion for check if exist this tables? How can I check table names with schema?
UPDATE:
OK, there is 3 different answers and all of them worked, so I don't know which one is better, does any one know about use object_id or sys.tables?
IF EXISTS(
SELECT *
FROM [DBName].sys.tables t
JOIN [DBName].sys.schemas s
ON t.SCHEMA_ID = s.schema_id
WHERE
t.name = N'TableName' AND t.type='U'
AND s.NAME = 'SchemaName'
)
DROP TABLE [DBName].[SchemaName].[TableName];
Update:
object_id in sys.tables is the same as object_id in sysobjects for the same table. And is completely the same as function OBJECT_ID returns for the same table name. See the following illustrating examples.
So, you may simplify the query:
IF exists
(
SELECT *
FROM DBName.sys.tables
WHERE object_id = OBJECT_ID('[DBName].[SchemaName].[TableName]')
AND type = 'U'
)
DROP TABLE [DBName].[SchemaName].[TableName];
or in this way:
IF exists
(
SELECT *
FROM DBName.sys.objects
WHERE object_id = OBJECT_ID('[DBName].[SchemaName].[TableName]')
AND type = 'U'
)
DROP TABLE [DBName].[SchemaName].[TableName];
or for sql2000-styled tables:
IF exists
(
SELECT *
FROM DBName..sysobjects
WHERE object_id = OBJECT_ID('[DBName].[SchemaName].[TableName]')
AND xtype = 'U'
)
DROP TABLE [DBName].[SchemaName].[TableName];
Use this:
IF EXISTS
(
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[DBName].[Schema1].[Member]')
AND type in (N'U')
)
PRINT 'Yes'
ELSE
PRINT 'No';
Don't use sysobjects. Use the modern system views in the sys schema (introduced in 2005):
select * from sys.tables
where
schema_id = SCHEMA_ID('Schema1') and
name='tablename'
As soon as you have one "modern" schema in a 2005 or later database, you cannot reliably use sysobjects to match with schemas. If you only have "old" schemas (objects belonging to users and roles), you may be able to query based on user_id.
Wouldn't it be simplest just to:
IF object_id('[schema].[table]') > 0
DROP TABLE [schema].[table]
For non existent tables object_id() returns NULL
For some system tables it returns a negative int

How to identify whether the table has identity column

I want to find out whether the table has an identity column or not. Table is unknown to me. I have not done the structure of the table. Using Query?
I am using Sql Server Compact Edition.
IF (OBJECTPROPERTY(OBJECT_ID('TABLE_NAME'), 'TableHasIdentity') = 1)
ObjectProperty is available starting sql server 2008 Reference:
OBJECTPROPERTY
This query returns a table's identity column name:
CREATE PROCEDURE dbo.usp_GetIdentity
#schemaname nvarchar(128) = 'dbo'
,#tablename nvarchar(128)
AS
BEGIN
SELECT OBJECT_NAME(OBJECT_ID) AS TABLENAME,
NAME AS COLUMNNAME,
SEED_VALUE,
INCREMENT_VALUE,
LAST_VALUE,
IS_NOT_FOR_REPLICATION
FROM SYS.IDENTITY_COLUMNS
WHERE OBJECT_NAME(OBJECT_ID) = #tablename
AND OBJECT_SCHEMA_NAME(object_id) = #schemaname
END
Then form the code side.
Call this stored procedure using the datareader role, then check datareader.hasrows(). If the condition value is true (1), then the table has identity column if set. If not then it doesn't have an identity column.
I know it's long time ago but i found this helpful
try this :
IF EXISTS (SELECT * from syscolumns where id = Object_ID(#TABLE_NAME) and colstat & 1 = 1)
BEGIN
-- Do your things
END
Any of the below queries can be used to check if an Identity Column is present in the table
1)
SELECT *
FROM sys.identity_columns
WHERE OBJECT_NAME(object_id) = 'TableName'
2)
SELECT *
FROM sys.identity_columns
WHERE object_id = (
SELECT id
FROM sysobjects
WHERE name = 'TableName'
)
I would just like to add this option as well as I think it is the simplest
SELECT COLUMNPROPERTY(OBJECT_ID('TableName'),'ColumnName','isidentity')
One way to do this would be to make use of the stored procedure sp_help. I.e:
sp_help MyTable
This will return a DataSet that has all the information you would need on the table. There is a specific Table that has information on identities.
I.e:
If it does not contain an identity field, the Identity column will say: "No identity column defined".
#Pranay: he said Compact Edition. Stored procedures aren't supported, and there is no sys.anything.
This is the call:
SELECT Count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE AUTOINC_INCREMENT IS NOT NULL AND TABLE_NAME='this_table'
It will return either 1 (true) or 0 (false).
...
declare #tblhasIdentCol bit = IF (IDENT_CURRENT( #dbName +'.'+ #schemaName +'.'+ #tableName ) IS NOT NULL , 1 , 0 )
You get numeric value if table has identity
Very simple answer would be to run this:
SELECT IDENT_CURRENT('TABLE-NAME')
This would give max value of identity column if exists, if the column doesn't exist, it gives 1 as result.
Based on max value, you can identify which column is having that and determine the identity column.
This the query that get u all the tableNames, columnnames of the table, and is_identity or not in the selected database
SELECT
sys.columns.name
, sys.tables.name
, is_identity
FROM sys.columns
INNER JOIN sys.tables ON sys.tables.object_id = sys.columns.object_id
AND sys.columns.is_identity = 1
CREATE FUNCTION dbo.fnTableHasIdentity(#Tbl sysname)
RETURNS TINYINT
BEGIN
RETURN OBJECTPROPERTY(OBJECT_ID(#Tbl), 'TableHasIdentity')
END
--As simple as that!
select t.name as TableName,c.name as ColumnName
from sys.identity_columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = 'TableName'
If you like me, needed to be able to do this for tables in an arbitrary database, then I found the following solution:
IF EXISTS (
SELECT 1
FROM [database name].sys.identity_columns AS id_col
INNER JOIN [database name].sys.objects
ON objects.object_id = id_col.object_id
INNER JOIN [database name].sys.schemas
ON schemas.schema_id = objects.schema_id
AND schemas.name = 'schema name'
WHERE OBJECT_NAME(id_col.object_id, DB_ID('database name')) = 'table name'
) SELECT 1 ELSE SELECT 0
you can get the 1 or 0 Boolean Form if the current table has identity Columns by using this
SELECT Count(Column_ID) FROM sys.identity_columns WHERE OBJECT_NAME(object_id) = 'tableName'
One way to list all Tables with their identity column if it exists
to get you desired table add at the end of the filter "and o.name='TableName'"
where Tbale Nam is the table you are looking for
SELECT o.[Name][TableName],i.[name][IdentityColName] FROM
sys.objects o
left outer join sys.identity_columns i on i.object_id=o.object_id
where o.type='U'