Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generate DDL script from SQL Server database

How to generate DDL (with Foreign keys, indexes, etc.) script of all tables from SQL Server database using SQL (select/stored procedure/etc.)? i need everything except the data.

I can't use Sql Server Management Studio because i want to use it in a node.js script that will run over linux!

like image 637
Leibale Eidelman Avatar asked Jan 09 '17 21:01

Leibale Eidelman


2 Answers

For tables : (you can work as follows)

DECLARE @C VARCHAR(200)
DECLARE C CURSOR FOR
SELECT 'EXEC [DBO].[SP_GETDDL] '''+NAME+'''' FROM SYS.TABLES
OPEN C
FETCH NEXT FROM C INTO @C
WHILE @@FETCH_STATUS=0
BEGIN
EXEC (@C)
FETCH NEXT FROM C INTO @C
END
CLOSE C
DEALLOCATE C

The Procedure is as follows:

CREATE PROCEDURE [dbo].[Sp_getddl] @TBL VARCHAR(255) 
AS 
  BEGIN 
      SET nocount ON 

      DECLARE @TBLNAME            VARCHAR(200), 
              @SCHEMANAME         VARCHAR(255), 
              @STRINGLEN          INT, 
              @TABLE_ID           INT, 
              @FINALSQL           VARCHAR(max), 
              @CONSTRAINTSQLS     VARCHAR(max), 
              @CHECKCONSTSQLS     VARCHAR(max), 
              @RULESCONSTSQLS     VARCHAR(max), 
              @FKSQLS             VARCHAR(max), 
              @TRIGGERSTATEMENT   VARCHAR(max), 
              @EXTENDEDPROPERTIES VARCHAR(max), 
              @INDEXSQLS          VARCHAR(max), 
              @vbCrLf             CHAR(2) 

      SET @vbCrLf = Char(13) + Char(10) 

      SELECT @SCHEMANAME = Isnull(Parsename(@TBL, 2), 'dbo'), 
             @TBLNAME = Parsename(@TBL, 1) 

      SELECT @TABLE_ID = [object_id] 
      FROM   sys.objects 
      WHERE  [type] = 'U' 
             AND [name] <> 'dtproperties' 
             AND [name] = @TBLNAME 
             AND [schema_id] = Schema_id(@SCHEMANAME); 

      IF Isnull(@TABLE_ID, 0) = 0 
        BEGIN 
            SET @FINALSQL = 'Table object [' + @SCHEMANAME + '].[' 
                            + Upper(@TBLNAME) 
                            + '] does not exist in Database [' 
                            + Db_name() + ']' 

            SELECT @FINALSQL; 

            RETURN 0 
        END 

      SELECT @FINALSQL = 'CREATE TABLE [' + @SCHEMANAME + '].[' 
                         + Upper(@TBLNAME) + '] ( ' 

      SELECT @TABLE_ID = Object_id(@TBLNAME) 

      SELECT @STRINGLEN = Max(Len(sys.columns.[name])) + 1 
      FROM   sys.objects 
             INNER JOIN sys.columns 
                     ON sys.objects.[object_id] = sys.columns.[object_id] 
                        AND sys.objects.[object_id] = @TABLE_ID; 

      SELECT @FINALSQL = @FINALSQL + CASE WHEN sys.columns.[is_computed] = 1 
                         THEN 
                         @vbCrLf + 
                                '[' + Upper( 
                                sys.columns.[name]) + '] ' + Space(@STRINGLEN - 
                                Len(sys.columns.[name])) + 'AS ' + 
                                Isnull(CALC.definition, '') ELSE 
                                @vbCrLf + '[' + Upper(sys.columns.[name]) + '] ' 
                         + 
                         Space( 
                                @STRINGLEN - Len(sys.columns.[name])) + 
                                Upper(Type_name(sys.columns.[user_type_id])) + 
                         CASE 
                         WHEN 
                                Type_name(sys.columns.[user_type_id]) IN ( 
                         'decimal', 
                                'numeric') THEN '(' + CONVERT( 
                                VARCHAR, sys.columns.[precision]) + ',' + 
                         CONVERT( 
                         VARCHAR, 
                                sys.columns.[scale]) + ') ' + Space(6 - Len( 
                         CONVERT( 
                         VARCHAR, 
                                sys.columns.[precision]) + ',' + 
                                CONVERT(VARCHAR, sys.columns.[scale]))) + Space( 
                         2) 
                         -- + SPACE(16 - LEN(TYPE_NAME(sys.columns.[user_type_id])))  
                         + CASE WHEN Columnproperty ( @TABLE_ID, 
                         sys.columns.[name], 
                                'IsIdentity' ) = 0 THEN '              ' ELSE 
                         ' IDENTITY(' + 
                                CONVERT(VARCHAR, Isnull(Ident_seed(@TBLNAME), 1) 
                         ) 
                         + 
                         ',' + 
                                CONVERT(VARCHAR, Isnull(Ident_incr(@TBLNAME), 1) 
                         ) 
                         + 
                         ')' END 
                                + CASE WHEN sys.columns.[is_nullable] = 0 THEN 
                         ' NOT NULL' 
                                ELSE '     NULL' END WHEN 
                                Type_name(sys.columns.[user_type_id]) IN ( 
                         'float', 
                         'real') 
                                THEN CASE WHEN 
                                sys.columns.[precision] = 53 THEN Space(11 - 
                                Len(CONVERT(VARCHAR, sys.columns.[precision]))) 
                         + 
                         Space(7) + 
                                Space(16 - 
                                Len(Type_name(sys.columns.[user_type_id]))) + 
                         CASE 
                         WHEN 
                                sys.columns.[is_nullable] = 0 THEN 
                                ' NOT NULL' ELSE '     NULL' END ELSE '(' + 
                         CONVERT( 
                         VARCHAR, 
                                sys.columns.[precision]) + ') ' + Space(6 - Len( 
                         CONVERT( 
                                VARCHAR, sys.columns.[precision]))) + Space(7) + 
                         Space 
                         (16 
                                - Len(Type_name(sys.columns.[user_type_id]))) + 
                         CASE 
                         WHEN 
                                sys.columns.[is_nullable] = 0 THEN ' NOT NULL' 
                         ELSE 
                                '     NULL' END 
                                END WHEN Type_name(sys.columns.[user_type_id]) 
                         IN 
                         ( 
                         'char', 
                                'varchar') THEN CASE WHEN 
                         sys.columns.[max_length] 
                         = 
                         -1 THEN 
                                '(max)' + Space(6 - 
                                Len(CONVERT(VARCHAR, sys.columns.[max_length]))) 
                         + 
                         Space(7) + 
                                Space(16 - 
                                Len(Type_name(sys.columns.[user_type_id]))) + 
                         CASE 
                         WHEN 
                                sys.columns.collation_name IS NULL THEN '' 
                                ELSE ' COLLATE ' + sys.columns.collation_name 
                         END 
                         + 
                         CASE WHEN 
                                sys.columns.[is_nullable] = 0 THEN ' NOT NULL' 
                         ELSE 
                                '     NULL' END ELSE '(' + 
                                CONVERT(VARCHAR, sys.columns.[max_length]) + 
                         ') ' 
                         + 
                         Space(6 - 
                                Len(CONVERT(VARCHAR, sys.columns.[max_length]))) 
                         + 
                         Space(7) + 
                                Space(16 - 
                                Len(Type_name(sys.columns.[user_type_id]))) + 
                         CASE 
                         WHEN 
                                sys.columns.collation_name IS NULL THEN '' 
                                ELSE ' COLLATE ' + sys.columns.collation_name 
                         END 
                         + 
                         CASE WHEN 
                                sys.columns.[is_nullable] = 0 THEN ' NOT NULL' 
                         ELSE 
                                '     NULL' END END WHEN 
                                Type_name(sys.columns.[user_type_id]) IN ( 
                         'nchar', 
                         'nvarchar' 
                                ) THEN CASE WHEN 
                                sys.columns.[max_length] = -1 THEN '(max)' + 
                         Space 
                         (6 - 
Len(CONVERT(VARCHAR, (sys.columns.[max_length])))) 
+ 
Space(7) 
+ Space(16 - Len(Type_name( 
sys.columns.[user_type_id]))) + CASE WHEN 
sys.columns.collation_name IS NULL THEN '' ELSE 
' COLLATE ' + 
sys.columns.collation_name END + CASE WHEN 
sys.columns.[is_nullable] = 0 THEN 
' NOT NULL' ELSE '     NULL' END ELSE '(' + 
CONVERT( 
VARCHAR, 
(sys.columns.[max_length])) + ') ' + Space(6 - Len 
( 
CONVERT( 
VARCHAR, (sys.columns.[max_length])))) + Space(7) 
+ 
Space(16 
- Len(Type_name(sys.columns.[user_type_id]))) + 
CASE 
WHEN 
sys.columns.collation_name IS NOT NULL THEN '' 
ELSE 
' COLLATE ' + 
sys.columns.collation_name END + CASE WHEN 
sys.columns.[is_nullable] 
= 0 THEN ' NOT NULL' ELSE '     NULL' END END WHEN 
Type_name( 
sys.columns.[user_type_id]) IN ('datetime', 
'money', 
'text', 
'image') THEN Space(18 - 
Len(Type_name(sys.columns.[user_type_id]))) + 
'              ' + CASE WHEN 
sys.columns.[is_nullable] = 0 THEN ' NOT NULL' 
ELSE 
'     NULL' END ELSE Space(16 
- Len(Type_name(sys.columns.[user_type_id]))) + 
CASE 
WHEN 
Columnproperty ( @TABLE_ID, sys.columns.[name], 
'IsIdentity' 
) = 0 THEN '              ' ELSE ' IDENTITY(' + 
CONVERT( 
VARCHAR, Isnull(Ident_seed(@TBLNAME), 1) ) + ',' + 
CONVERT( 
VARCHAR, Isnull(Ident_incr(@TBLNAME), 1) ) + ')' 
END + 
Space( 
2) + CASE WHEN sys.columns.[is_nullable] = 0 THEN 
' NOT NULL' 
ELSE '     NULL' END END + CASE WHEN 
sys.columns.[default_object_id] = 0 THEN '' 
--ELSE ' DEFAULT '  + ISNULL(def.[definition] ,'')    
--optional section in case NAMED default cosntraints are needed:   
ELSE @vbCrLf + 'CONSTRAINT [' + def.NAME + '] DEFAULT ' + 
Isnull(def.[definition], '') 
--i thought it needed to be handled differently! NOT!         
END --CASE cdefault       
END --iscomputed         
+ ',' 
FROM   sys.columns 
LEFT OUTER JOIN sys.default_constraints DEF 
ON sys.columns.[default_object_id] = DEF.[object_id] 
LEFT OUTER JOIN sys.computed_columns CALC 
ON sys.columns.[object_id] = CALC.[object_id] 
AND sys.columns.[column_id] = CALC.[column_id] 
WHERE  sys.columns.[object_id] = @TABLE_ID 
ORDER  BY sys.columns.[column_id] 

SELECT @STRINGLEN = Max(Len([name])) + 1 
FROM   sys.objects 

DECLARE @Results TABLE 
( 
[schema_id]             INT, 
[schema_name]           VARCHAR(255), 
[object_id]             INT, 
[object_name]           VARCHAR(255), 
[index_id]              INT, 
[index_name]            VARCHAR(255), 
[rows]                  INT, 
[sizemb]                DECIMAL(19, 3), 
[indexdepth]            INT, 
[type]                  INT, 
[type_desc]             VARCHAR(30), 
[fill_factor]           INT, 
[is_unique]             INT, 
[is_primary_key]        INT, 
[is_unique_constraint]  INT, 
[index_columns_key]     VARCHAR(max), 
[index_columns_include] VARCHAR(max) 
) 

INSERT INTO @Results 
SELECT sys.schemas.schema_id, 
sys.schemas.[name] 
AS schema_name, 
sys.objects.[object_id], 
sys.objects.[name] 
AS object_name, 
sys.indexes.index_id, 
Isnull(sys.indexes.[name], '---') 
AS index_name, 
partitions.rows, 
partitions.sizemb, 
Indexproperty(sys.objects.[object_id], sys.indexes.[name], 
'IndexDepth') 
AS 
IndexDepth, 
sys.indexes.type, 
sys.indexes.type_desc, 
sys.indexes.fill_factor, 
sys.indexes.is_unique, 
sys.indexes.is_primary_key, 
sys.indexes.is_unique_constraint, 
Isnull(Index_Columns.index_columns_key, '---') 
AS index_columns_key, 
Isnull(Index_Columns.index_columns_include, '---') 
AS index_columns_include 
FROM   sys.objects 
JOIN sys.schemas 
ON sys.objects.schema_id = sys.schemas.schema_id 
JOIN sys.indexes 
ON sys.objects.[object_id] = sys.indexes.[object_id] 
JOIN (SELECT [object_id], 
index_id, 
Sum(row_count)                                        AS 
Rows, 
CONVERT(NUMERIC(19, 3), CONVERT(NUMERIC(19, 3), Sum( 
                  in_row_reserved_page_count 
                  + lob_reserved_page_count 
                  + 
                  row_overflow_reserved_page_count 
                  )) / 
                  CONVERT(NUMERIC(19, 3), 128)) AS 
SizeMB 
FROM   sys.dm_db_partition_stats 
GROUP  BY [object_id], 
index_id) AS partitions 
ON sys.indexes.[object_id] = partitions.[object_id] 
AND sys.indexes.index_id = partitions.index_id 
CROSS apply (SELECT LEFT(index_columns_key, 
 Len(index_columns_key) - 1) 
 AS 
index_columns_key 
, 
LEFT(index_columns_include, Len(index_columns_include) - 1) AS 
index_columns_include 
FROM   (SELECT (SELECT sys.columns.[name] + ',' + ' ' 
FROM   sys.index_columns 
JOIN sys.columns 
ON sys.index_columns.column_id = sys.columns.column_id 
AND sys.index_columns.[object_id] = 
sys.columns.[object_id] 
WHERE  sys.index_columns.is_included_column = 0 
AND sys.indexes.[object_id] = 
sys.index_columns.[object_id] 
AND sys.indexes.index_id = sys.index_columns.index_id 
ORDER  BY key_ordinal 
FOR xml path('')) AS index_columns_key, 
(SELECT sys.columns.[name] + ',' + ' ' 
FROM   sys.index_columns 
JOIN sys.columns 
ON sys.index_columns.column_id = sys.columns.column_id 
AND sys.index_columns.[object_id] = 
sys.columns.[object_id] 
WHERE  sys.index_columns.is_included_column = 1 
AND sys.indexes.[object_id] = 
sys.index_columns.[object_id] 
AND sys.indexes.index_id = sys.index_columns.index_id 
ORDER  BY index_column_id 
FOR xml path('')) AS index_columns_include) AS Index_Columns) AS 
Index_Columns 
WHERE  sys.schemas.[name] LIKE CASE 
       WHEN @SCHEMANAME = '' THEN 
       sys.schemas.[name] 
       ELSE @SCHEMANAME 
     END 
AND sys.objects.[name] LIKE CASE 
           WHEN @TBLNAME = '' THEN 
           sys.objects.[name] 
           ELSE @TBLNAME 
         END 
ORDER  BY sys.schemas.[name], 
sys.objects.[name], 
sys.indexes.[name] 

--@Results table has both PK,s Uniques and indexes in thme...pull them out for adding to funal results:    
SET @CONSTRAINTSQLS = '' 
SET @INDEXSQLS = '' 

SELECT @CONSTRAINTSQLS = @CONSTRAINTSQLS + CASE WHEN is_primary_key = 1 OR 
is_unique = 
      1 THEN @vbCrLf + 
      'CONSTRAINT   [' + index_name + '] ' + Space 
( 
@STRINGLEN 
      - Len(index_name)) + CASE WHEN 
is_primary_key = 
1 THEN 
      ' PRIMARY KEY ' ELSE CASE WHEN is_unique = 1 
THEN 
      ' UNIQUE      ' ELSE '' END END + type_desc 
+ 
CASE WHEN 
      type_desc='NONCLUSTERED' THEN '' ELSE '   ' 
END 
+ ' (' 
      + index_columns_key + ')' + CASE WHEN 
      index_columns_include <> '---' THEN 
' INCLUDE (' 
+ 
      index_columns_include + ')' ELSE '' END + 
CASE 
WHEN 
      fill_factor <> 0 THEN ' WITH FILLFACTOR = ' 
+ 
CONVERT( 
      VARCHAR(30), fill_factor) ELSE '' END ELSE 
'' 
END + ',' 
FROM   @RESULTS 
WHERE  [type_desc] != 'HEAP' 
AND is_primary_key = 1 
OR is_unique = 1 
ORDER  BY is_primary_key DESC, 
is_unique DESC 

SELECT @INDEXSQLS = @INDEXSQLS + CASE WHEN is_primary_key = 0 OR is_unique = 
0 THEN 
 @vbCrLf + 
 'CREATE INDEX [' + index_name + '] ' + Space( 
@STRINGLEN 
 - Len(index_name)) + ' ON [' + [object_name] + 
']' + 
' (' + 
 index_columns_key + ')' + CASE WHEN 
index_columns_include <> 
 '---' THEN ' INCLUDE (' + index_columns_include + 
')' 
ELSE 
 '' END + CASE WHEN fill_factor <> 0 THEN 
 ' WITH FILLFACTOR = ' + CONVERT(VARCHAR(30), 
fill_factor) 
 ELSE '' END END 
FROM   @RESULTS 
WHERE  [type_desc] != 'HEAP' 
AND is_primary_key = 0 
AND is_unique = 0 
ORDER  BY is_primary_key DESC, 
is_unique DESC 

IF @INDEXSQLS <> '' 
SET @INDEXSQLS = @vbCrLf + 'GO' + @vbCrLf + @INDEXSQLS 

SET @CHECKCONSTSQLS = '' 

SELECT @CHECKCONSTSQLS = @CHECKCONSTSQLS + @vbCrLf 
+ Isnull('CONSTRAINT   [' + sys.objects.[name] + 
'] ' + 
Space( 
      @STRINGLEN - Len(sys.objects.[name])) + 
' CHECK ' + 
      Isnull(sys.check_constraints.definition, '') 
+ 
',', '') 
FROM   sys.objects 
INNER JOIN sys.check_constraints 
ON sys.objects.[object_id] = 
sys.check_constraints.[object_id] 
WHERE  sys.objects.type = 'C' 
AND sys.objects.parent_object_id = @TABLE_ID 

SET @FKSQLS = ''; 

SELECT @FKSQLS = @FKSQLS + @vbCrLf + 'CONSTRAINT   [' 
+ Object_name(constid) + ']' 
+ Space(@STRINGLEN - Len(Object_name(constid) )) 
+ '  FOREIGN KEY (' + Col_name(fkeyid, fkey) 
+ ') REFERENCES ' + Object_name(rkeyid) + '(' 
+ Col_name(rkeyid, rkey) + '),' 
FROM   sysforeignkeys 
WHERE  fkeyid = @TABLE_ID 

SET @RULESCONSTSQLS = '' 

SELECT @RULESCONSTSQLS = @RULESCONSTSQLS 
+ Isnull( @vbCrLf + 
'if not exists(SELECT [name] FROM sys.objects WHERE TYPE=''R'' AND schema_id = ' 
+ CONVERT(VARCHAR(30), sys.objects.schema_id) + 
' AND [name] = ''[' + 
Object_name(sys.columns.[rule_object_id]) + ']'')' + 
@vbCrLf + 
sys.sql_modules.definition + @vbCrLf + 'GO' + @vbCrLf + 
'EXEC sp_binderule  [' 
+ sys.objects.[name] + '], ''[' + 
Object_name(sys.columns.[object_id]) + '].[' + 
sys.columns.[name] + 
']''' + @vbCrLf + 'GO', '') 
FROM   sys.columns 
INNER JOIN sys.objects 
ON sys.objects.[object_id] = sys.columns.[object_id] 
INNER JOIN sys.sql_modules 
ON sys.columns.[rule_object_id] = sys.sql_modules.[object_id] 
WHERE  sys.columns.[rule_object_id] <> 0 
AND sys.columns.[object_id] = @TABLE_ID 

SET @TRIGGERSTATEMENT = '' 

SELECT @TRIGGERSTATEMENT = @TRIGGERSTATEMENT + @vbCrLf 
 + sys.sql_modules.[definition] + @vbCrLf + 'GO' 
FROM   sys.sql_modules 
WHERE  [object_id] IN(SELECT [object_id] 
FROM   sys.objects 
WHERE  type = 'TR' 
   AND [parent_object_id] = @TABLE_ID) 

IF @TRIGGERSTATEMENT <> '' 
SET @TRIGGERSTATEMENT = @vbCrLf + 'GO' + @vbCrLf + @TRIGGERSTATEMENT 

SET @EXTENDEDPROPERTIES = '' 

SELECT @EXTENDEDPROPERTIES = @EXTENDEDPROPERTIES + @vbCrLf 
   + 'EXEC sys.sp_addextendedproperty           @name = N''' + [name] 
   + ''', @value = N''' 
   + Replace(CONVERT(VARCHAR(max), [value]), '''', 
   '''''') 
   + 
''',           @level0type = N''SCHEMA'', @level0name = [' 
   + @SCHEMANAME 
   + 
'],           @level1type = N''TABLE'', @level1name = [' 
   + @TBLNAME + '];' 
FROM   Fn_listextendedproperty (NULL, 'schema', @SCHEMANAME, 'table', 
@TBLNAME, NULL, 
NULL); 

IF @EXTENDEDPROPERTIES <> '' 
SET @EXTENDEDPROPERTIES = @vbCrLf + 'GO' + @vbCrLf + @EXTENDEDPROPERTIES 

SELECT @FINALSQL = @FINALSQL + @CONSTRAINTSQLS + @CHECKCONSTSQLS 
+ @FKSQLS 

SET @FINALSQL = Substring(@FINALSQL, 1, Len(@FINALSQL) - 1); 
SET @FINALSQL = @FINALSQL + ')' + @vbCrLf; 

SELECT @FINALSQL + @INDEXSQLS + @RULESCONSTSQLS 
+ @TRIGGERSTATEMENT + @EXTENDEDPROPERTIES 
END 

go 
like image 160
Ranjana Ghimire Avatar answered Nov 07 '22 18:11

Ranjana Ghimire


You can use mssql-scripter direct from Microsoft, it is quite new and requires a recent Python runtime... but works on Linux, Macos and Windows

like image 43
Michail Avatar answered Nov 07 '22 18:11

Michail