How to Generate All Constraints Scripts

How to generate create script of tables with their constraints using SQL query in SQL Server 2008

Try this one -

DECLARE @object_id INT, @object_name SYSNAME

DECLARE cur CURSOR FAST_FORWARD READ_ONLY LOCAL FOR
SELECT o.[object_id], '[' + s.name + '].[' + o.name + ']'
FROM sys.objects o WITH (NOWAIT)
JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
WHERE o.[type] = 'U'
AND o.is_ms_shipped = 0

OPEN cur

FETCH NEXT FROM cur INTO @object_id, @object_name

WHILE @@FETCH_STATUS = 0 BEGIN

DECLARE @SQL NVARCHAR(MAX) = ''

;WITH index_column AS
(
SELECT
ic.[object_id]
, ic.index_id
, ic.is_descending_key
, ic.is_included_column
, c.name
FROM sys.index_columns ic WITH (NOWAIT)
JOIN sys.columns c WITH (NOWAIT) ON ic.[object_id] = c.[object_id] AND ic.column_id = c.column_id
WHERE ic.[object_id] = @object_id
),
fk_columns AS
(
SELECT
k.constraint_object_id
, cname = c.name
, rcname = rc.name
FROM sys.foreign_key_columns k WITH (NOWAIT)
JOIN sys.columns rc WITH (NOWAIT) ON rc.[object_id] = k.referenced_object_id AND rc.column_id = k.referenced_column_id
JOIN sys.columns c WITH (NOWAIT) ON c.[object_id] = k.parent_object_id AND c.column_id = k.parent_column_id
WHERE k.parent_object_id = @object_id
)
SELECT @SQL = 'CREATE TABLE ' + @object_name + CHAR(13) + '(' + CHAR(13) + STUFF((
SELECT CHAR(9) + ', [' + c.name + '] ' +
CASE WHEN c.is_computed = 1
THEN 'AS ' + cc.[definition]
ELSE UPPER(tp.name) +
CASE WHEN tp.name IN ('varchar', 'char', 'varbinary', 'binary', 'text')
THEN '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(5)) END + ')'
WHEN tp.name IN ('nvarchar', 'nchar', 'ntext')
THEN '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length / 2 AS VARCHAR(5)) END + ')'
WHEN tp.name IN ('datetime2', 'time2', 'datetimeoffset')
THEN '(' + CAST(c.scale AS VARCHAR(5)) + ')'
WHEN tp.name = 'decimal'
THEN '(' + CAST(c.[precision] AS VARCHAR(5)) + ',' + CAST(c.scale AS VARCHAR(5)) + ')'
ELSE ''
END +
CASE WHEN c.is_nullable = 1 THEN ' NULL' ELSE ' NOT NULL' END +
CASE WHEN dc.[definition] IS NOT NULL THEN ' DEFAULT' + dc.[definition] ELSE '' END +
CASE WHEN ic.is_identity = 1 THEN ' IDENTITY(' + CAST(ISNULL(ic.seed_value, '0') AS CHAR(1)) + ',' + CAST(ISNULL(ic.increment_value, '1') AS CHAR(1)) + ')' ELSE '' END
END + CHAR(13)
FROM sys.columns c WITH (NOWAIT)
JOIN sys.types tp WITH (NOWAIT) ON c.user_type_id = tp.user_type_id
LEFT JOIN sys.computed_columns cc WITH (NOWAIT) ON c.[object_id] = cc.[object_id] AND c.column_id = cc.column_id
LEFT JOIN sys.default_constraints dc WITH (NOWAIT) ON c.default_object_id != 0 AND c.[object_id] = dc.parent_object_id AND c.column_id = dc.parent_column_id
LEFT JOIN sys.identity_columns ic WITH (NOWAIT) ON c.is_identity = 1 AND c.[object_id] = ic.[object_id] AND c.column_id = ic.column_id
WHERE c.[object_id] = @object_id
ORDER BY c.column_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, CHAR(9) + ' ')
+ ISNULL((SELECT CHAR(9) + ', CONSTRAINT [' + k.name + '] PRIMARY KEY (' +
(SELECT STUFF((
SELECT ', [' + c.name + '] ' + CASE WHEN ic.is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END
FROM sys.index_columns ic WITH (NOWAIT)
JOIN sys.columns c WITH (NOWAIT) ON c.[object_id] = ic.[object_id] AND c.column_id = ic.column_id
WHERE ic.is_included_column = 0
AND ic.[object_id] = k.parent_object_id
AND ic.index_id = k.unique_index_id
FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, ''))
+ ')' + CHAR(13)
FROM sys.key_constraints k WITH (NOWAIT)
WHERE k.parent_object_id = @object_id
AND k.[type] = 'PK'), '') + ')' + CHAR(13)
+ ISNULL((SELECT (
SELECT CHAR(13) +
'ALTER TABLE ' + @object_name + ' WITH'
+ CASE WHEN fk.is_not_trusted = 1
THEN ' NOCHECK'
ELSE ' CHECK'
END +
' ADD CONSTRAINT [' + fk.name + '] FOREIGN KEY('
+ STUFF((
SELECT ', [' + k.cname + ']'
FROM fk_columns k
WHERE k.constraint_object_id = fk.[object_id]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
+ ')' +
' REFERENCES [' + SCHEMA_NAME(ro.[schema_id]) + '].[' + ro.name + '] ('
+ STUFF((
SELECT ', [' + k.rcname + ']'
FROM fk_columns k
WHERE k.constraint_object_id = fk.[object_id]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
+ ')'
+ CASE
WHEN fk.delete_referential_action = 1 THEN ' ON DELETE CASCADE'
WHEN fk.delete_referential_action = 2 THEN ' ON DELETE SET NULL'
WHEN fk.delete_referential_action = 3 THEN ' ON DELETE SET DEFAULT'
ELSE ''
END
+ CASE
WHEN fk.update_referential_action = 1 THEN ' ON UPDATE CASCADE'
WHEN fk.update_referential_action = 2 THEN ' ON UPDATE SET NULL'
WHEN fk.update_referential_action = 3 THEN ' ON UPDATE SET DEFAULT'
ELSE ''
END
+ CHAR(13) + 'ALTER TABLE ' + @object_name + ' CHECK CONSTRAINT [' + fk.name + ']' + CHAR(13)
FROM sys.foreign_keys fk WITH (NOWAIT)
JOIN sys.objects ro WITH (NOWAIT) ON ro.[object_id] = fk.referenced_object_id
WHERE fk.parent_object_id = @object_id
FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)')), '')
+ ISNULL(((SELECT
CHAR(13) + 'CREATE' + CASE WHEN i.is_unique = 1 THEN ' UNIQUE' ELSE '' END
+ ' NONCLUSTERED INDEX [' + i.name + '] ON ' + @object_name + ' (' +
STUFF((
SELECT ', [' + c.name + ']' + CASE WHEN c.is_descending_key = 1 THEN ' DESC' ELSE ' ASC' END
FROM index_column c
WHERE c.is_included_column = 0
AND c.index_id = i.index_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')'
+ ISNULL(CHAR(13) + 'INCLUDE (' +
STUFF((
SELECT ', [' + c.name + ']'
FROM index_column c
WHERE c.is_included_column = 1
AND c.index_id = i.index_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')', '') + CHAR(13)
FROM sys.indexes i WITH (NOWAIT)
WHERE i.[object_id] = @object_id
AND i.is_primary_key = 0
AND i.[type] = 2
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
), '') + CHAR(13) + 'GO'

PRINT @SQL

FETCH NEXT FROM cur INTO @object_id, @object_name

END

CLOSE cur
DEALLOCATE cur

Output -

CREATE TABLE [dbo].[test1]
(
[ID] INT NOT NULL
, CONSTRAINT [PK_test1_ID] PRIMARY KEY ([ID] ASC)
)
GO
CREATE TABLE [dbo].[tbl_name]
(
[ID] INT NOT NULL
, CONSTRAINT [PK_tbl_name_ID] PRIMARY KEY ([ID] ASC)
)
GO

how to generate a script for the entire database

This is indeed because you didn't name your constraints, so the second time it attempts to drop the old name then add an additional constraint.

The first time you run the script it checks for a default constraint called DF__LookupCol__IsPri__46DD686B, which of course does not exist.

Then it runs

ALTER TABLE [cfg].[LookupColumns] ADD DEFAULT (CONVERT([bit],(0))) FOR [IsPrimaryKey]

Which creates a new constraint with a new auto-generated name. Next time you run the script, it tries to drop DF__LookupCol__IsPri__46DD686B again, which still doesn't exist, and then tries to add a new constraint, which fails.

So to be able to re-run this script, you should name all your constraints and indexes before generating the scripts.

You can find the system-named default constraints like this:

select name, object_name(object_id) table_name 
from sys.default_constraints
where is_system_named = 1

select name, object_name(object_id) table_name
from sys.check_constraints
where is_system_named = 1

select name, object_name(object_id) table_name
from sys.key_constraints
where is_system_named = 1

etc

Or you can look for the __ in the names, but you would want to manually review those of course.

Running database creation script with constraints

There are two issues with the foreign key constraints:

1. Adding the Constraints

When there are FKs that link subsets of tables in cycles you can create the tables first, and then add the constraints later.

For example:

CREATE TABLE store (
id INTEGER NOT NULL,
nome VARCHAR(255) NOT NULL,
document VARCHAR(80) NOT NULL,
store_product INTEGER NOT NULL,
PRIMARY KEY (id)
);

CREATE TABLE product (
id INTEGER NOT NULL,
nome VARCHAR(255) NOT NULL,
price NUMERIC(15,2) NOT NULL,
store_id INTEGER NOT NULL,
inventory_id INTEGER NOT NULL,
PRIMARY KEY (id)
);

CREATE TABLE inventory (
id INTEGER NOT NULL PRIMARY KEY,
amount INTEGER NOT NULL,
product_id INTEGER NOT NULL
);

And then:

alter table store add constraint fk1 
FOREIGN KEY (store_product) REFERENCES product (id)
deferrable initially deferred;

alter table product add constraint fk2
FOREIGN KEY (store_id) REFERENCES store (id);

alter table product add constraint fk3
FOREIGN KEY (inventory_id) REFERENCES inventory (id);

alter table inventory add constraint fk4
FOREIGN KEY (product_id) REFERENCES product (id);
2. Inserting Data

When inserting data that depends on each other you'll need to decide which row in which table you want to insert first. That's why the example above includes DEFERRABLE INITIALLY DEFERRED in the first constraint.

This way you can insert in sequence:

  1. Begin the transaction.
  2. Insert into store -- fk1 is not validated yet.
  3. Insert into inventory. Validates fk4.
  4. Insert into product. Validates fk2 and fk3.
  5. Commit the transaction. At this point fk1 will be finally validated.

How to script primary key constraints from existing database

Powershell and SMO are going to be your friends here:

$option_drop = new-object Microsoft.SqlServer.Management.Smo.ScriptingOptions;
$option_drop.ScriptDrops = $true;

"" > drop_primary_keys.sql
"" > create_primary_keys.sql

$server = new-object Microsoft.SqlServer.Management.Smo.Server ".";
$db = $server.Databases['AdventureWorks'];
foreach ($table in $db.Tables) {
foreach ($index in $table.Indexes) {
if ($index.IndexKeyType -eq "DriPrimaryKey") {
$index.Script( $option_drop ) >> drop_primary_keys.sql
$index.Script() >> create_primary_keys.sql
}
}
}

A couple of notes here:

  • Running this script will nuke any existing files of the name "drop_primary_keys.sql" and "create_primary_keys.sql", so proceed with caution
  • The script doesn't take into account any foreign keys since you said you already have a way to do that.
  • You may have to tweak the ScriptingOptions object to fit your needs. Specifically, I'm using the defaults on the create, so you may need to create another ScriptingOptions object and set whichever options you think appropriate.

Other than that, good hunting.

How to: Script Out Unique Constraint creation script

You can try something like this:

SELECT 
ColumnName = c.name,
TableName = t.name,
CreateCmd = 'ALTER TABLE ' + OBJECT_SCHEMA_NAME(t.object_id) + '.' + t.name + ' ADD CONSTRAINT ' + i.name + ' UNIQUE(' + c.name + ')'
FROM
sys.indexes i
INNER JOIN
sys.index_columns ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id
INNER JOIN
sys.columns c ON ic.column_id = c.column_id AND ic.object_id = c.object_id
INNER JOIN
sys.tables t ON c.object_id = t.object_id
WHERE
is_unique_constraint = 1

This gives you a listing of columns and tables where a unique constraint is applied to, and it gives you the T-SQL command to newly create that UNIQUE CONSTRAINT

Multiple constraints in table: How to get all violations?

In the meantime I found a lean solution using deferred constraints:

CREATE TABLE A_TABLE_TEST (
COL_1 NUMBER NOT NULL DEFERRABLE INITIALLY DEFERRED,
COL_2 NUMBER NOT NULL DEFERRABLE INITIALLY DEFERRED,
COL_3 NUMBER NOT NULL DEFERRABLE INITIALLY DEFERRED,
COL_4 NUMBER NOT NULL DEFERRABLE INITIALLY DEFERRED
);

INSERT INTO A_TABLE_TEST values (1,null,null,2);

DECLARE
CHECK_CONSTRAINT_VIOLATED EXCEPTION;
PRAGMA EXCEPTION_INIT(CHECK_CONSTRAINT_VIOLATED, -2290);

REF_CONSTRAINT_VIOLATED EXCEPTION;
PRAGMA EXCEPTION_INIT(REF_CONSTRAINT_VIOLATED , -2292);

CURSOR CheckConstraints IS
SELECT TABLE_NAME, CONSTRAINT_NAME, COLUMN_NAME
FROM USER_CONSTRAINTS
JOIN USER_CONS_COLUMNS USING (TABLE_NAME, CONSTRAINT_NAME)
WHERE TABLE_NAME = 'A_TABLE_TEST'
AND DEFERRED = 'DEFERRED'
AND STATUS = 'ENABLED';
BEGIN
FOR aCon IN CheckConstraints LOOP
BEGIN
EXECUTE IMMEDIATE 'SET CONSTRAINT '||aCon.CONSTRAINT_NAME||' IMMEDIATE';
EXCEPTION
WHEN CHECK_CONSTRAINT_VIOLATED OR REF_CONSTRAINT_VIOLATED THEN
DBMS_OUTPUT.PUT_LINE('Constraint '||aCon.CONSTRAINT_NAME||' at Column '||aCon.COLUMN_NAME||' violated');
END;
END LOOP;
END;

It works with any check constraint (not only NOT NULL). Checking FOREIGN KEY Constraint should work as well.

Add/Modify/Delete of constraints does not require any further maintenance.



Related Topics



Leave a reply



Submit