这主要是我学习一些SQL Server概念的实验。假设以下情形:
我在下面编写的脚本是针对“开发”数据库执行的,因此它将生成一个脚本,其中包含数据库的每一列的条件。然后应该使用该脚本来对其他数据库进行更新,并且条件应该添加测试数据库尚未具有的任何列或表:
DECLARE @CURRENT_COLUMN nvarchar(100)
DECLARE @COLUMN_LITERAL nvarchar(100)
DECLARE @CURRENT_DEFAULT nvarchar(20)
DECLARE @CURRENT_DATATYPE nvarchar(100)
DECLARE @CURRENT_SCHEMA nvarchar(100)
DECLARE @SQLA nvarchar(max)
DECLARE @SQLB nvarchar(max)
DECLARE @CURRENT_TABLE nvarchar(100)
DECLARE @COMPUTED smallint
SET @COMPUTED = 0
PRINT '
DECLARE @SQL nvarchar(max)
'
DECLARE CUR_SCHEMA CURSOR FOR
SELECT TABLE_SCHEMA from INFORMATION_SCHEMA.TABLES
OPEN CUR_SCHEMA
FETCH NEXT FROM CUR_SCHEMA
INTO @CURRENT_SCHEMA
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE CUR_TAB CURSOR FOR
SELECT ist.TABLE_NAME from INFORMATION_SCHEMA.TABLES ist
WHERE ist.TABLE_SCHEMA = @CURRENT_SCHEMA
AND EXISTS (
SELECT TOP 1 name
FROM sys.tables
where name = ist.TABLE_NAME)
ORDER BY ist.TABLE_NAME
OPEN CUR_TAB
FETCH NEXT FROM CUR_TAB
INTO @CURRENT_TABLE
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT '
IF OBJECT_ID('''+@CURRENT_TABLE+''') IS NULL
BEGIN
SET @SQL = ''
CREATE TABLE [' + @CURRENT_TABLE +'] (placeholder bit)''
EXEC sp_executesql @SQL
END
'
DECLARE CUR CURSOR FOR
SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @CURRENT_TABLE
AND TABLE_SCHEMA = @CURRENT_SCHEMA
ORDER BY ORDINAL_POSITION asc
OPEN CUR
FETCH NEXT FROM CUR
INTO @CURRENT_COLUMN, @CURRENT_DATATYPE
SET @COLUMN_LITERAL = '[' + @CURRENT_COLUMN + ']'
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQLB = ''
SET @COMPUTED = 0
/* Check if column is computed */
IF (SELECT is_computed FROM sys.columns
WHERE object_id = OBJECT_ID(@CURRENT_TABLE)
AND name = @CURRENT_COLUMN) = 1
BEGIN
SET @SQLB = @SQLB + 'IF NOT EXISTS(SELECT TOP 1 sc.name FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
WHERE sc.Name = ''' + @CURRENT_COLUMN + '''
AND st.Object_ID = OBJECT_ID('''+ @CURRENT_TABLE+ ''')
AND ss.name = ''' + @CURRENT_SCHEMA + ''')
BEGIN
ALTER TABLE ' + @CURRENT_SCHEMA + '.[' + @CURRENT_TABLE + ']
ADD ' + @CURRENT_COLUMN + ' AS ' +
(SELECT definition FROM sys.computed_columns
WHERE object_id = OBJECT_ID(@CURRENT_TABLE)
AND name = @CURRENT_COLUMN)
SET @COMPUTED = 1
END
/* Check for identity */
IF (SELECT is_identity FROM sys.columns WHERE object_id = OBJECT_ID(@CURRENT_TABLE)
AND name = @CURRENT_COLUMN) = 1
BEGIN
SET @SQLB = @SQLB + ' IDENTITY (' +
CAST((SELECT IDENT_SEED(@CURRENT_SCHEMA + '.[' + @CURRENT_TABLE + ']')) AS VARCHAR(4)) + ',' +
CAST((SELECT IDENT_INCR(@CURRENT_SCHEMA + '.[' + @CURRENT_TABLE + ']')) AS VARCHAR(4)) + ')'
END
/* Check if NULL is allowed */
IF (SELECT sc.is_nullable from sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
INNER JOIN sys.types sp ON sp.system_type_id = sc.system_type_id
WHERE st.name = @CURRENT_TABLE
AND sc.name = @CURRENT_COLUMN
AND ss.name = @CURRENT_SCHEMA
AND sp.name = @CURRENT_DATATYPE
) = 0
BEGIN
SET @SQLB = @SQLB + ' NOT NULL'
END
ELSE SET @SQLB = @SQLB + ' NULL'
/* Check for defaults */
IF (SELECT COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = @CURRENT_COLUMN
AND TABLE_SCHEMA = @CURRENT_SCHEMA
AND TABLE_NAME = @CURRENT_TABLE) IS NOT NULL
BEGIN
SET @CURRENT_DEFAULT = ' DEFAULT ' + (SELECT COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = @CURRENT_COLUMN
AND TABLE_SCHEMA = @CURRENT_SCHEMA
AND TABLE_NAME = @CURRENT_TABLE)
END
ELSE SET @CURRENT_DEFAULT = ''
IF @CURRENT_DATATYPE in ('date','datetime2','datetime','time',
'smalldatetime','datetimeoffset','text','ntext',
'varchar','char','nchar','nvarchar')
BEGIN
/* Check for date related data types */
IF @CURRENT_DATATYPE in ('date','datetime2','datetime','time',
'smalldatetime','datetimeoffset')
BEGIN
SET @SQLA = '
IF NOT EXISTS(SELECT TOP 1 sc.name FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
WHERE sc.Name = ''' + @CURRENT_COLUMN + '''
AND st.Object_ID = OBJECT_ID('''+ @CURRENT_TABLE+ ''')
AND ss.name = ''' + @CURRENT_SCHEMA + ''')
BEGIN
ALTER TABLE ' + @CURRENT_SCHEMA + '.['+ @CURRENT_TABLE + ']
ADD '+@COLUMN_LITERAL+'' + ' ' + ''+@CURRENT_DATATYPE+' '+@CURRENT_DEFAULT
END
/* Check for MAX column length */
IF (SELECT sc.max_length FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
INNER JOIN sys.types sp ON sp.system_type_id = sc.system_type_id
WHERE st.name = @CURRENT_TABLE
AND sc.name = @CURRENT_COLUMN
AND ss.name = @CURRENT_SCHEMA
AND sp.name = @CURRENT_DATATYPE) = -1
BEGIN
SET @SQLA = '
IF NOT EXISTS(SELECT TOP 1 sc.name FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
WHERE sc.Name = ''' + @CURRENT_COLUMN + '''
AND st.Object_ID = OBJECT_ID('''+ @CURRENT_TABLE+ ''')
AND ss.name = ''' + @CURRENT_SCHEMA + ''')
BEGIN
ALTER TABLE ' + @CURRENT_SCHEMA + '.['+ @CURRENT_TABLE + ']
ADD '+@COLUMN_LITERAL+'' + ' ' + ''+@CURRENT_DATATYPE+'(MAX)'+' ' + @CURRENT_DEFAULT
END
/* Check for string data types */
ELSE IF @CURRENT_DATATYPE in ('varchar','char','nchar','nvarchar')
BEGIN
SET @SQLA = '
IF NOT EXISTS(SELECT TOP 1 sc.name FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
WHERE sc.Name = ''' + @CURRENT_COLUMN + '''
AND st.Object_ID = OBJECT_ID('''+ @CURRENT_TABLE+ ''')
AND ss.name = ''' + @CURRENT_SCHEMA + ''')
BEGIN
ALTER TABLE ' + @CURRENT_SCHEMA + '.[' + @CURRENT_TABLE + ']
ADD '+@COLUMN_LITERAL+'' + ' ' + ''+@CURRENT_DATATYPE+''
+ '(' +
CAST(
( SELECT
CASE WHEN @CURRENT_DATATYPE IN ('nchar', 'nvarchar') THEN MAX(sc.max_length)/2
ELSE MAX(sc.max_length) END AS 'max_length' FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
INNER JOIN sys.types sp ON sp.system_type_id = sc.system_type_id
WHERE st.name = @CURRENT_TABLE
AND sc.name = @CURRENT_COLUMN
AND ss.name = @CURRENT_SCHEMA
AND sp.name = @CURRENT_DATATYPE
)
AS VARCHAR(10)) +')'+@CURRENT_DEFAULT
END
/* Check for text and ntext types (no column width) */
ELSE IF @CURRENT_DATATYPE in ('text','ntext')
BEGIN
SET @SQLA = '
IF NOT EXISTS(SELECT TOP 1 sc.name FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
WHERE sc.Name = ''' + @CURRENT_COLUMN + '''
AND st.Object_ID = OBJECT_ID('''+ @CURRENT_TABLE+ ''')
AND ss.name = ''' + @CURRENT_SCHEMA + ''')
BEGIN
ALTER TABLE ' + @CURRENT_SCHEMA + '.[' + @CURRENT_TABLE + ']
ADD '+@COLUMN_LITERAL+'' + ' ' + ''+@CURRENT_DATATYPE+' '+@CURRENT_DEFAULT
END
END
ELSE
/* Check for decimal and numeric types */
IF @CURRENT_DATATYPE in ('decimal','numeric')
BEGIN
SET @SQLA = '
IF NOT EXISTS(SELECT TOP 1 sc.name FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
WHERE sc.Name = ''' + @CURRENT_COLUMN + '''
AND st.Object_ID = OBJECT_ID('''+ @CURRENT_TABLE+ ''')
AND ss.name = ''' + @CURRENT_SCHEMA + ''')
BEGIN
ALTER TABLE ' + @CURRENT_SCHEMA + '.[' + @CURRENT_TABLE + ']
ADD '+@COLUMN_LITERAL+'' + ' ' + ''+@CURRENT_DATATYPE+''+'(' + CAST( (SELECT MIN(NUMERIC_PRECISION) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @CURRENT_TABLE
AND COLUMN_NAME = @CURRENT_COLUMN
AND TABLE_SCHEMA = @CURRENT_SCHEMA
AND DATA_TYPE = @CURRENT_DATATYPE
) AS VARCHAR(10)) + ',' +
CAST( (SELECT MIN(NUMERIC_SCALE) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @CURRENT_TABLE
AND COLUMN_NAME = @CURRENT_COLUMN
AND DATA_TYPE = @CURRENT_DATATYPE
) AS VARCHAR(10)) + ')'+ @CURRENT_DEFAULT
END
ELSE
BEGIN
SET @SQLA = '
IF NOT EXISTS(SELECT TOP 1 sc.name FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
WHERE sc.Name = ''' + @CURRENT_COLUMN + '''
AND st.Object_ID = OBJECT_ID('''+ @CURRENT_TABLE+ ''')
AND ss.name = ''' + @CURRENT_SCHEMA + ''')
BEGIN
ALTER TABLE ' + @CURRENT_SCHEMA + '.[' + @CURRENT_TABLE + ']
ADD '+@COLUMN_LITERAL+'' + ' ' + ''+@CURRENT_DATATYPE+''+@CURRENT_DEFAULT
END
IF @COMPUTED = 0
BEGIN
PRINT @SQLA + @SQLB + '
END
'
END
FETCH NEXT FROM CUR
INTO @CURRENT_COLUMN, @CURRENT_DATATYPE
SET @COLUMN_LITERAL = '[' + @CURRENT_COLUMN + ']'
END
CLOSE CUR;
DEALLOCATE CUR;
PRINT '
IF EXISTS
(SELECT TOP 1 sc.name FROM sys.columns sc
INNER JOIN sys.tables st ON st.object_id = sc.object_id
INNER JOIN sys.schemas ss ON ss.schema_id = st.schema_id
WHERE sc.Name = ''placeholder''
AND st.Object_ID = OBJECT_ID('''+ @CURRENT_TABLE+ ''')
AND ss.name = ''' + @CURRENT_SCHEMA + ''')
BEGIN
ALTER TABLE '+@CURRENT_SCHEMA+'.['+@CURRENT_TABLE+'] DROP COLUMN [placeholder]
END
'
FETCH NEXT FROM CUR_TAB
INTO @CURRENT_TABLE
END
CLOSE CUR_TAB
DEALLOCATE CUR_TAB
END
CLOSE CUR_SCHEMA
DEALLOCATE CUR_SCHEMA
问题:
谢谢,很抱歉提出这么多问题。如果您不想回答所有问题,请回答一个或几个!
** 注意 **
答案 0 :(得分:1)
所以我建议使用Sql Server数据工具和数据库项目。它允许您导入现有数据库的模式或创建新的数据库项目。您可以将它链接到TFS或Git,您对源代码管理的偏好。在这种情况下,您不必使用单独的SQL脚本来生成架构。如果您决定从SSDT转移到架构开发,那么代码库将始终具有最新的已知架构。然后,您可以生成用于部署新代码库和SSDT的脚本,或者Visual Studio会将SQL计算出来,我强烈建议在部署到prod之前检查这些脚本。 也可以从此工具发布对目标数据库的更改。