在 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故障转移群集需要安装在仲裁盘里面吗?

在单个 SQL SELECT 语句中区分两行

如何在 SQL Server 2008 中进行分页

SQL sever 2008 如何根据一个表中的两个时间计算出时间差

从两个数组中区分额外的元素?

在Vim中区分两个选项卡