在 SQL Server 2008 中区分两个表架构的最简单方法是啥?
Posted
技术标签:
【中文标题】在 SQL Server 2008 中区分两个表架构的最简单方法是啥?【英文标题】:Easiest Way To Diff Two Table Schemas In SQL Server 2008?在 SQL Server 2008 中区分两个表架构的最简单方法是什么? 【发布时间】:2011-04-27 02:44:20 【问题描述】:我必须在开发和发布数据库之间进行检查并手动进行,这既慢又不是 100% 可靠(我只是目视检查表)。
有没有一种快速简便的方法来自动比较表模式?甚至可能是 SQL Server 中内置的一项功能?
编辑:我只是在比较结构,感谢您指出这一点。
【问题讨论】:
注意:OP 说的是结构,而不是数据。 @RedFilter:编辑了问题以澄清这一点,这确实令人困惑 当然,如果您编写更改脚本并将其放入源代码管理中以便与该软件版本的其余代码一起移动,这将有所帮助。那么你就不需要做所有这些差异化(并且可能不小心移动了一些尚未准备好进行生产的东西。) @HLGEM 脚本更改会使您无法使用任何涉及可视化模式设计工具的策略,除非该工具为您生成所述脚本。不可避免地,大多数优秀的架构设计工具只擅长这一点。 @Chris Moschini,我编写表格的速度远远快于我使用这些东西的速度,所以我从不使用它们。 【参考方案1】:数据或结构或两者兼而有之?试试 RedGate sql 比较或数据比较。他们都有免费试用,而且很棒。
http://www.red-gate.com/products/SQL_Compare/index.htm
http://www.red-gate.com/products/SQL_Data_Compare/index.htm
【讨论】:
只是结构。那只价值 400 美元的野兽有免费版本吗? 没有比 red_gate 的工具更好的免费版本。这是你应该花钱买的东西。 我刚刚下载了 DB Diff,它可以完成我所做的简单任务。不过,我以后会记住 Red Gate。【参考方案2】:我是SQL DBDiff 的粉丝,这是一个开源工具,您可以使用它来比较两个 SQL Server 数据库实例的表、视图、函数、用户等,并在源代码和源代码之间生成更改脚本目标数据库。
【讨论】:
差异工具有点欠佳,我在源和目标之间的结构上有明显的差异,它根本没有突出它们。这么说,它找到了一些,而不是全部..【参考方案3】:对于免费的解决方案,您可以使用SQL Server Managements Objects 为每个表、视图、索引、SP、UDF 等输出 DDL 脚本。然后您可以在代码中或使用 diff 工具(如@987654322)进行比较@。
【讨论】:
【参考方案4】:有一些商业产品可以做到这一点; Visual Studio 2010 Premium Edition 可以比较架构。
其他一些人:http://www.red-gate.com/products/SQL_Compare/index.htmhttp://www.apexsql.com/sql_tools_diff.aspx
【讨论】:
是的!使用 Visual Studio 2015 Professional:菜单工具 / SQL Server / 新架构比较...【参考方案5】:苏,
谷歌搜索:
for structures:
see also:
我以前的答案的链接由于某种原因不再起作用,所以这是TechNet 的另一个答案:
DECLARE @Sourcedb sysname
DECLARE @Destdb sysname
DECLARE @Tablename sysname
DECLARE @SQL varchar(max)
SELECT @Sourcedb = '<<SourceDatabaseName>>'
SELECT @Destdb = '<<DestinationDatabaseName>>'
SELECT @Tablename = '<<Tablename>>' -- '%' for all tables
SELECT @SQL = ' SELECT Tablename = ISNULL(Source.tablename,Destination.tablename)
,ColumnName = ISNULL(Source.Columnname,Destination.Columnname)
,Source.Datatype
,Source.Length
,Source.precision
,Destination.Datatype
,Destination.Length
,Destination.precision
,[Column] =
Case
When Source.Columnname IS NULL then ''Column Missing in the Source''
When Destination.Columnname IS NULL then ''Column Missing in the Destination''
ELSE ''''
end
,DataType = CASE WHEN Source.Columnname IS NOT NULL
AND Destination.Columnname IS NOT NULL
AND Source.Datatype <> Destination.Datatype THEN ''Data Type mismatch''
END
,Length = CASE WHEN Source.Columnname IS NOT NULL
AND Destination.Columnname IS NOT NULL
AND Source.Length <> Destination.Length THEN ''Length mismatch''
END
,Precision = CASE WHEN Source.Columnname IS NOT NULL
AND Destination.Columnname IS NOT NULL
AND Source.precision <> Destination.precision THEN ''precision mismatch''
END
,Collation = CASE WHEN Source.Columnname IS NOT NULL
AND Destination.Columnname IS NOT NULL
AND ISNULL(Source.collation_name,'''') <> ISNULL(Destination.collation_name,'''') THEN ''Collation mismatch''
END
FROM
(
SELECT Tablename = so.name
, Columnname = sc.name
, DataType = St.name
, Length = Sc.max_length
, precision = Sc.precision
, collation_name = Sc.collation_name
FROM ' + @Sourcedb + '.SYS.objects So
JOIN ' + @Sourcedb + '.SYS.columns Sc
ON So.object_id = Sc.object_id
JOIN ' + @Sourcedb + '.SYS.types St
ON Sc.system_type_id = St.system_type_id
AND Sc.user_type_id = St.user_type_id
WHERE SO.TYPE =''U''
AND SO.Name like ''' + @Tablename + '''
) Source
FULL OUTER JOIN
(
SELECT Tablename = so.name
, Columnname = sc.name
, DataType = St.name
, Length = Sc.max_length
, precision = Sc.precision
, collation_name = Sc.collation_name
FROM ' + @Destdb + '.SYS.objects So
JOIN ' + @Destdb + '.SYS.columns Sc
ON So.object_id = Sc.object_id
JOIN ' + @Destdb + '.SYS.types St
ON Sc.system_type_id = St.system_type_id
AND Sc.user_type_id = St.user_type_id
WHERE SO.TYPE =''U''
AND SO.Name like ''' + @Tablename + '''
) Destination
ON source.tablename = Destination.Tablename
AND source.Columnname = Destination.Columnname '
EXEC (@Sql)
【讨论】:
【参考方案6】:您可以使用 SQL Management Studio 工具从两个数据库“生成脚本”。然后使用您最喜欢的文本比较工具查看任何差异。
在过去,这很好用,但在 SQL 2005 中,生成脚本代码发生了变化,对象不再以相同的顺序创建,因此文本比较不太有用。我没有在更新的 SQL 版本中对此进行测试,因此它可能已被修复。您也可以尝试http://exportsqlscript.codeplex.com/,我已成功使用它来将 DDL 输出为用于源代码控制和比较版本的脚本。
参考资料:
https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=332400&wa=wsignin1.0 http://social.msdn.microsoft.com/Forums/en-US/sqltools/thread/505fd238-e0dc-42ae-8a54-2dceace81bb3/ http://exportsqlscript.codeplex.com/【讨论】:
当然,我最喜欢的文本比较工具是来自scootersoftware.com的Beyond Compare 我尝试了那个确切的东西(生成脚本,我什至使用了无可比拟的)。不幸的是,正如您的帖子所述,由于订购而失败...... exportsqlscript.codeplex.com 确实解决了这个问题。而且,当我将此作为错误报告给 Microsoft 时,有人在日志中说“它已在下一个版本中修复”。我从未见过 Microsoft 的修复程序。【参考方案7】:您可以查看http://cdttools.com/2011/10/sql-diff-erence/,它是一种低成本的替代方案,它将在两个数据库之间遍历模式并告诉您发生了什么变化。然后,您可以使用 SQL Mgmt studio 生成“script->As Alter”来构建更改脚本。 (警告:我写的)
【讨论】:
【参考方案8】:如果两个表在同一个数据库中,可以使用这个查询
select c2.table_name,c2.COLUMN_NAME
from [INFORMATION_SCHEMA].[COLUMNS] c2
where table_name='table1'
and c2.COLUMN_NAME not in (select column_name
from [INFORMATION_SCHEMA].[COLUMNS]
where table_name='table1')
【讨论】:
【参考方案9】:我玩游戏有点晚了......但是我制作的这个脚本对我来说效果很好。如果需要,它也可以跨链接服务器工作。
use master
go
DECLARE @Server1 VARCHAR(100) ='[CARNYSQLTEST1].'; --include a dot at the end
DECLARE @DB1 VARCHAR(100) = '[ZipCrim]';
DECLARE @Table1 VARCHAR(100) = 'IntAction';
DECLARE @Server2 VARCHAR(100) ='[CARNYSQLDEV].'; --include a dot at the end
DECLARE @DB2 VARCHAR(100) = '[ZipCrim]';
DECLARE @Table2 VARCHAR(100) = 'IntAction';
DECLARE @SQL NVARCHAR(MAX);
SET @SQL =
'
SELECT Table1.ServerName,
Table1.DBName,
Table1.SchemaName,
Table1.TableName,
Table1.ColumnName,
Table1.name DataType,
Table1.Length,
Table1.Precision,
Table1.Scale,
Table1.Is_Identity,
Table1.Is_Nullable,
Table2.ServerName,
Table2.DBName,
Table2.SchemaName,
Table2.TableName,
Table2.ColumnName,
Table2.name DataType,
Table2.Length,
Table2.Precision,
Table2.Scale,
Table2.Is_Identity,
Table2.Is_Nullable
FROM
(SELECT ''' + @Server1 + ''' ServerName,
''' + @DB1 + ''' DbName,
SCHEMA_NAME(t.schema_id) SchemaName,
t.Name TableName,
c.Name ColumnName,
st.Name,
c.Max_Length Length,
c.Precision,
c.Scale,
c.Is_Identity,
c.Is_Nullable
FROM ' + @Server1 + @DB1 + '.sys.tables t
INNER JOIN ' + @Server1 + @DB1 + '.sys.columns c ON t.Object_ID = c.Object_ID
INNER JOIN sys.types st ON St.system_type_id = c.System_Type_id AND st.user_type_id = c.user_type_id
WHERE t.Name = ''' + @Table1 + ''') Table1
FULL OUTER JOIN
(SELECT ''' + @Server2 + ''' ServerName,
''' + @DB2 + ''' DbName,
SCHEMA_NAME(t.schema_id) SchemaName,
t.name TableName,
c.name ColumnName,
st.Name,
c.max_length Length,
c.Precision,
c.Scale,
c.Is_Identity,
c.Is_Nullable
FROM ' + @Server2 + @DB2 + '.sys.tables t
INNER JOIN ' + @Server2 + @DB2 + '.sys.columns c ON t.Object_ID = c.Object_ID
INNER JOIN sys.types st ON St.system_type_id = c.System_Type_id AND st.user_type_id = c.user_type_id
WHERE t.Name = ''' + @Table2 + ''') Table2
ON Table1.ColumnName = Table2.ColumnName
ORDER BY CASE WHEN Table1.ColumnName IS NULL THEN 2 ELSE 1 END, Table1.ColumnName
'
EXEC sp_executesql @SQL
【讨论】:
我是否可以使用此脚本来比较两个单独的数据库以比较表的列差异等?【参考方案10】:修改了一点BD.'s query,所有功劳归他所有。 (将 SCHEMA_NAME(schema_id)
更改为 sys.schemas 连接,因为 SCHEMA_NAME(schema_id)
与当前数据库上下文 master
一起使用,更改了排序并更改了列名并添加了状态列)
USE master
GO
DECLARE
@Server1 VARCHAR(100) = 'Server1.', -- don't forget to include a dot at the end
@Server2 VARCHAR(100) = 'Server2.', -- don't forget to include a dot at the end
@DB1 VARCHAR(100) = 'Database1',
@DB2 VARCHAR(100) = 'Database2'
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = '
SELECT
CASE
WHEN s1.[Column] IS NOT NULL
AND s2.[Column] IS NULL
THEN ''New''
WHEN s1.[Column] IS NULL
AND s2.[Column] IS NOT NULL
THEN ''Deleted''
WHEN s1.[Column] IS NOT NULL
AND s2.[Column] IS NOT NULL
AND (s1.[Type] <> s2.[Type]
OR s1.[Length] <> s2.[Length]
OR s1.[Precision] <> s2.[Precision]
OR s1.Scale <> s2.Scale
OR s1.IsNullable <> s2.IsNullable
OR s1.IsIdentity <> s2.IsIdentity
OR s1.IdentitySeed <> s2.IdentitySeed
OR s1.IdentityIncrement <> s2.IdentityIncrement
OR s1.DefaultValue <> s2.DefaultValue)
THEN ''Changed''
ELSE ''Identical''
END [Status],
s1.[Database],
s1.[Schema],
s1.[Table],
s1.[Column],
s1.[Type],
s1.IsCharType,
s1.[Length],
s1.[Precision],
s1.Scale,
s1.IsNullable,
s1.IsIdentity,
s1.IdentitySeed,
s1.IdentityIncrement,
s1.DefaultValue,
s1.[Order],
s2.[Database],
s2.[Schema],
s2.[Table],
s2.[Column],
s2.[Type],
s2.IsCharType,
s2.[Length],
s2.[Precision],
s2.Scale,
s2.IsNullable,
s2.IsIdentity,
s2.IdentitySeed,
s2.IdentityIncrement,
s2.DefaultValue,
s2.[Order]
FROM (
SELECT
''' + @DB1 + ''' AS [Database],
s.name AS [Schema],
t.name AS [Table],
c.name AS [Column],
tp.name AS [Type],
CASE
WHEN tp.collation_name IS NOT NULL
THEN 1
ELSE 0
END AS IsCharType,
CASE
WHEN c.max_length = -1
THEN ''MAX''
ELSE CAST(c.max_length AS VARCHAR(4))
END AS [Length],
c.[precision],
c.scale,
c.is_nullable AS IsNullable,
c.is_identity AS IsIdentity,
CAST(ISNULL(ic.seed_value, 0) AS INT) AS IdentitySeed,
CAST(ISNULL(ic.increment_value, 0) AS INT) AS IdentityIncrement,
dc.definition AS DefaultValue,
c.column_id AS [Order]
FROM ' + @Server1 + @DB1 + '.sys.tables t
INNER JOIN ' + @Server1 + @DB1 + '.sys.schemas s ON s.schema_id = t.schema_id
INNER JOIN ' + @Server1 + @DB1 + '.sys.columns c ON c.object_id = t.object_id
INNER JOIN ' + @Server1 + @DB1 + '.sys.types tp ON tp.system_type_id = c.system_type_id
LEFT OUTER JOIN ' + @Server1 + @DB1 + '.sys.identity_columns ic ON ic.object_id = t.object_id AND ic.name = c.name
LEFT OUTER JOIN ' + @Server1 + @DB1 + '.sys.default_constraints dc ON dc.object_id = c.default_object_id
) s1
FULL OUTER JOIN (
SELECT
''' + @DB2 + ''' AS [Database],
s.name AS [Schema],
t.name AS [Table],
c.name AS [Column],
tp.name AS [Type],
CASE
WHEN tp.collation_name IS NOT NULL
THEN 1
ELSE 0
END AS IsCharType,
CASE
WHEN c.max_length = -1
THEN ''MAX''
ELSE CAST(c.max_length AS VARCHAR(4))
END AS [Length],
c.[precision],
c.scale,
c.is_nullable AS IsNullable,
c.is_identity AS IsIdentity,
CAST(ISNULL(ic.seed_value, 0) AS INT) AS IdentitySeed,
CAST(ISNULL(ic.increment_value, 0) AS INT) AS IdentityIncrement,
dc.definition AS DefaultValue,
c.column_id AS [Order]
FROM ' + @Server2 + @DB2 + '.sys.tables t
INNER JOIN ' + @Server2 + @DB2 + '.sys.schemas s ON s.schema_id = t.schema_id
INNER JOIN ' + @Server2 + @DB2 + '.sys.columns c ON c.object_id = t.object_id
INNER JOIN ' + @Server2 + @DB2 + '.sys.types tp ON tp.system_type_id = c.system_type_id
LEFT OUTER JOIN ' + @Server2 + @DB2 + '.sys.identity_columns ic ON ic.object_id = t.object_id AND ic.name = c.name
LEFT OUTER JOIN ' + @Server2 + @DB2 + '.sys.default_constraints dc ON dc.object_id = c.default_object_id
) s2
ON s2.[Schema] = s1.[Schema]
AND s2.[Table] = s1.[Table]
AND s2.[Column] = s1.[Column]
ORDER BY
CASE WHEN s1.[Database] IS NULL THEN s2.[Database] ELSE s1.[Database] END,
CASE WHEN s1.[Schema] IS NULL THEN s2.[Schema] ELSE s1.[Schema] END,
CASE WHEN s1.[Table] IS NULL THEN s2.[Table] ELSE s1.[Table] END,
CASE WHEN s1.[Order] IS NULL THEN s2.[Order] ELSE s1.[Order] END
'
EXEC sp_executesql @SQL
【讨论】:
以上是关于在 SQL Server 2008 中区分两个表架构的最简单方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
sql server 2008故障转移群集需要安装在仲裁盘里面吗?