zoukankan      html  css  js  c++  java
  • 两个数据库比较 对比视图存储过程及表结构差异增加外键差异

    两个数据库比较 对比视图存储过程及表结构差异

    一、视图和存储过程比较

    【原理】利用系统表“sysobjects"和系统表“syscomments”,将数据库中的视图和存储过程进行对比。系统表"sysobjects"之前有详细介绍过,有兴趣可以看看:SQL Server系统表sysobjects介绍与使用

    如果你看到这段文字,说明您正使用RSS阅读或转自《一棵树-博客园》,原文地址:http://www.cnblogs.com/atree/p/db-compare-structure.html

    【代码】

    /*--调用示例
    exec p_compdb 'DBNAME1','DBNAME2'
    exec p_compdb 'DBNAME2','DBNAME3'
    --*/
    CREATE proc p_compdb
    @db1 sysname, --第一个库
    @db2 sysname --第二个库
    as
    exec('
    select 类型=case isnull(a.xtype,b.xtype) when ''V'' then ''视图'' else ''存储过程'' end
    ,匹配情况=case
    when a.name is null then ''库 ['+@db1+'] 中无''
    when b.name is null then ''库 ['+@db2+'] 中无''
    else ''结构不同'' end
    ,对象名称=isnull(a.name,b.name),a.text as atext, b.text as btext
    from(
    select a.name,a.xtype,b.colid,b.text
    from ['+@db1+']..sysobjects a,['+@db1+']..syscomments b
    where a.id=b.id and a.xtype in(''V'',''P'') and a.status>=0
    )a full join(
    select a.name,a.xtype,b.colid,b.text
    from ['+@db2+']..sysobjects a,['+@db2+']..syscomments b
    where a.id=b.id and a.xtype in(''V'',''P'') and a.status>=0
    )b on a.name=b.name and a.xtype=b.xtype and a.colid=b.colid
    where a.name is null
    or b.name is null
    or isnull(a.text,'''') <>isnull(b.text,'''')
    --group by a.name,b.name,a.xtype,b.xtype
    --order by 类型,匹配情况,对象名称')

    【执行结果】

     

    二、数据表结构比较

    【原理】利用系统表“sysobjects"、"sysindexes"、"sysindexkeys"、“syscomments”、"sysclumns"、"systypes"、"extended_properties",将数据库中的表结构进行对比。(涉及到系统表比较多。就不一一介绍。直接上代码。)

    【代码】

    /*--比较两个数据库的表结构差异--*/
      
    /*--调用示例
    exec p_comparestructure 'DBNAME1','DBNAME2'
    exec p_comparestructure 'DBNAME2','DBNAME3'
    --*/
    create proc p_comparestructure
    @dbname1 varchar(250),--要比较的数据库名1
    @dbname2 varchar(250) --要比较的数据库名2
    as
    create table #tb1(表名1 varchar(250),字段名 varchar(250),序号 int,标识 bit,主键 bit,类型 varchar(250),
    占用字节数 int,长度 int,小数位数 int,允许空 bit,默认值 sql_variant,字段说明 sql_variant)
      
    create table #tb2(表名2 varchar(250),字段名 varchar(250),序号 int,标识 bit,主键 bit,类型 varchar(250),
    占用字节数 int,长度 int,小数位数 int,允许空 bit,默认值 sql_variant,字段说明 sql_variant)
      
    --得到数据库1的结构
    exec('insert into #tb1 SELECT
    表名=d.name,字段名=a.name,序号=a.colid,
    标识=case when a.status=0x80 then 1 else 0 end,
    主键=case when exists(SELECT 1 FROM '+@dbname1+'..sysobjects where xtype=''PK'' and parent_obj=a.id and name in (
    SELECT name FROM '+@dbname1+'..sysindexes WHERE indid in(
    SELECT indid FROM '+@dbname1+'..sysindexkeys WHERE id = a.id AND colid=a.colid
    ))) then 1 else 0 end,
    类型=b.name,占用字节数=a.length,长度=a.prec,小数位数=a.scale,允许空=a.isnullable,
    默认值=isnull(e.text,''''),字段说明=isnull(g.[value],'''')
    FROM '+@dbname1+'..syscolumns a
    left join '+@dbname1+'..systypes b on a.xtype=b.xusertype
    inner join '+@dbname1+'..sysobjects d on a.id=d.id  and d.xtype=''U'' and  d.name <>''dtproperties''
    left join '+@dbname1+'..syscomments e on a.cdefault=e.id
    left join sys.extended_properties g
    ON
    a.ID=g.major_id AND a.COLID=g.minor_id
    order by a.id,a.colorder')
      
    --得到数据库2的结构
    exec('insert into #tb2 SELECT
    表名=d.name,字段名=a.name,序号=a.colid,
    标识=case when a.status=0x80 then 1 else 0 end,
    主键=case when exists(SELECT 1 FROM '+@dbname2+'..sysobjects where xtype=''PK'' and parent_obj=a.id and name in (
    SELECT name FROM '+@dbname2+'..sysindexes WHERE indid in(
    SELECT indid FROM '+@dbname2+'..sysindexkeys WHERE id = a.id AND colid=a.colid
    ))) then 1 else 0 end,
    类型=b.name,占用字节数=a.length,长度=a.prec,小数位数=a.scale,允许空=a.isnullable,
    默认值=isnull(e.text,''''),字段说明=isnull(g.[value],'''')
    FROM '+@dbname2+'..syscolumns a
    left join '+@dbname2+'..systypes b on a.xtype=b.xusertype
    inner join '+@dbname2+'..sysobjects d on a.id=d.id  and d.xtype=''U'' and  d.name <>''dtproperties''
    left join '+@dbname2+'..syscomments e on a.cdefault=e.id
    left join sys.extended_properties g
    ON
    a.ID=g.major_id AND a.COLID=g.minor_id
    order by a.id,a.colorder')
    --and not exists(select 1 from #tb2 where 表名2=a.表名1)

    select 比较结果=case when not exists(select 1 from #tb1 where 表名1=isnull(a.表名1,b.表名2)) then '库1缺少表:'+b.表名2
    when not exists(select 1 from #tb2 where 表名2=isnull(a.表名1,b.表名2)) then '库2缺少表:'+a.表名1
    when a.字段名 is null then '库1 ['+b.表名2+'] 缺少字段:'+b.字段名
    when b.字段名 is null then '库2 ['+a.表名1+'] 缺少字段:'+a.字段名

    when a.字段名 <> b.字段名 then '字段名不同'

    when a.标识 <>b.标识 then '标识不同'
    when a.主键 <>b.主键 then '主键设置不同'
    when a.类型 <>b.类型 then '字段类型不同'
    when a.占用字节数 <>b.占用字节数 then '占用字节数'
    when a.精度 <>b.精度 then '精度不同'
    when a.小数位数 <>b.小数位数 then '小数位数不同'
    when a.允许空 <>b.允许空 then '是否允许空不同'
    when a.默认值 <>b.默认值 then '默认值不同'
    when a.字段说明 <>b.字段说明 then '字段说明不同'
    else '' end,
    *
    from #tb1 a
    full join #tb2 b on a.表名1=b.表名2 and (a.序号=b.序号)
    where a.表名1 is null or a.字段名 is null or b.表名2 is null or b.字段名 is null
    or a.标识 <>b.标识 or a.主键 <>b.主键 or a.类型 <>b.类型 or a.字段名 <> b.字段名
    or a.占用字节数 <>b.占用字节数 or a.精度 <>b.精度 or a.小数位数 <>b.小数位数
    or a.允许空 <>b.允许空 or REPLACE(REPLACE(convert(varchar,a.默认值),'(',''),')','') <>REPLACE(REPLACE(convert(varchar,b.默认值),'(',''),')','') 

     --默认值剥去特殊符号:外括号(),(()),之后比较是否一致  ****SQLserver自定义默认特殊符号

    or a.字段说明 <>b.字段说明
    order by isnull(a.表名1,b.表名2),isnull(a.序号,b.序号)--isnull(a.字段名,b.字段名)
    go

    【执行结果】

     ps:以上SQL执行请采用系统管理员(sysadmin)角色账号。其他角色我没有试过,有时间可以尝试一下。当我采用只映射了库”owner"权限的账号测试时,报如下错误:拒绝了对对象 'p_compdb' (数据库 'master',架构 'dbo')的 EXECUTE 权限。

    表差异查询2:  红色字体为与查询一差异最大处

    DECLARE @dbname1 varchar(250)--要比较的数据库名1
    DECLARE @dbname2 varchar(250) --要比较的数据库名2

    set @dbname1='demodtcms'
    set @dbname2='wangkejidatabase'

    create table #tb1(表名1 varchar(250),字段名 varchar(250),序号 int,标识 bit,主键 bit,类型 varchar(250),
    占用字节数 int,精度 int,小数位数 int,允许空 bit,默认值 sql_variant,字段说明 sql_variant)

    create table #tb2(表名2 varchar(250),字段名 varchar(250),序号 int,标识 bit,主键 bit,类型 varchar(250),
    占用字节数 int,精度 int,小数位数 int,允许空 bit,默认值 sql_variant,字段说明 sql_variant)

    --得到数据库1的结构
    exec('insert into #tb1 SELECT
    表名1=d.name,字段名=a.name,序号=a.colid,
    标识=case when a.status=0x80 then 1 else 0 end,
    主键=case when exists(SELECT 1 FROM '+@dbname1+'..sysobjects where xtype=''PK'' and parent_obj=a.id and name in (
    SELECT name FROM '+@dbname1+'..sysindexes WHERE indid in(
    SELECT indid FROM '+@dbname1+'..sysindexkeys WHERE id = a.id AND colid=a.colid
    ))) then 1 else 0 end,
    类型=b.name,占用字节数=a.length,精度=a.prec,小数位数=a.scale,允许空=a.isnullable,
    默认值=isnull(e.text,''''),字段说明=isnull(g.[value],'''')
    FROM '+@dbname1+'..syscolumns a
    left join '+@dbname1+'..systypes b on a.xtype=b.xusertype
    inner join '+@dbname1+'..sysobjects d on a.id=d.id and d.xtype=''U'' and d.name <>''dtproperties''
    left join '+@dbname1+'..syscomments e on a.cdefault=e.id
    left join sys.extended_properties g
    ON
    a.ID=g.major_id AND a.COLID=g.minor_id
    order by a.id,a.colorder')

    --SELECT * FROM #tb1 WHERE 表名1 = 'gggggggggg'

    --得到数据库2的结构
    exec('insert into #tb2 SELECT
    表名2=d.name,字段名=a.name,序号=a.colid,
    标识=case when a.status=0x80 then 1 else 0 end,
    主键=case when exists(SELECT 1 FROM '+@dbname2+'..sysobjects where xtype=''PK'' and parent_obj=a.id and name in (
    SELECT name FROM '+@dbname2+'..sysindexes WHERE indid in(
    SELECT indid FROM '+@dbname2+'..sysindexkeys WHERE id = a.id AND colid=a.colid
    ))) then 1 else 0 end,
    类型=b.name,占用字节数=a.length,精度=a.prec,小数位数=a.scale,允许空=a.isnullable,
    默认值=isnull(e.text,''''),字段说明=isnull(g.[value],'''')
    FROM '+@dbname2+'..syscolumns a
    left join '+@dbname2+'..systypes b on a.xtype=b.xusertype
    inner join '+@dbname2+'..sysobjects d on a.id=d.id and d.xtype=''U'' and d.name <>''dtproperties''
    left join '+@dbname2+'..syscomments e on a.cdefault=e.id
    left join sys.extended_properties g
    ON
    a.ID=g.major_id AND a.COLID=g.minor_id
    order by a.id,a.colorder')
    --and not exists(select 1 from #tb2 where 表名2=a.表名1)

    --SELECT * FROM #tb2 --WHERE 表名2 = 'gggggggggg'

    select 比较结果=case when a.表名1 is null and b.序号=(SELECT min(x.colorder)as minColorder FROM demodtcms..syscolumns x
    inner join wangkejidatabase..sysobjects y on x.id=y.id and y.xtype='U' and y.name <>'dtproperties'
    WHERE y.name =b.表名2
    GROUP BY x.id) then '库1缺少表:'+b.表名2
    when b.表名2 is null and a.序号 =(SELECT min(x.colorder)as minColorder FROM demodtcms..syscolumns x
    inner join demodtcms..sysobjects y on x.id=y.id and y.xtype='U' and y.name <>'dtproperties'
    WHERE y.name =b.表名2
    GROUP BY x.id) then '库2缺少表:'+a.表名1
    when a.字段名 is null and exists(select 1 from #tb1 where 表名1=b.表名2) then '库1 ['+b.表名2+'] 缺少字段:'+b.字段名
    when b.字段名 is null and exists(select 1 from #tb2 where 表名2=a.表名1) then '库2 ['+a.表名1+'] 缺少字段:'+a.字段名
    when a.字段名 <> b.字段名 then '字段名不同'
    when a.标识 <>b.标识 then '标识不同'
    when a.主键 <>b.主键 then '主键设置不同'
    when a.类型 <>b.类型 then '字段类型不同'
    when a.占用字节数 <>b.占用字节数 then '占用字节数'
    when a.精度 <>b.精度 then '精度不同'
    when a.小数位数 <>b.小数位数 then '小数位数不同'
    when a.允许空 <>b.允许空 then '是否允许空不同'
    when a.默认值 <>b.默认值 then '默认值不同'
    when a.字段说明 <>b.字段说明 then '字段说明不同'
    else '' end,
    *
    from #tb1 a
    full join #tb2 b on a.表名1=b.表名2 and (a.序号=b.序号 )
    where a.表名1 is null or a.字段名 is null or b.表名2 is null or b.字段名 is null
    or a.标识 <>b.标识 or a.主键 <>b.主键 or a.类型 <>b.类型 or a.字段名 <> b.字段名
    or a.占用字节数 <>b.占用字节数 or a.精度 <>b.精度 or a.小数位数 <>b.小数位数
    or a.允许空 <>b.允许空 or a.默认值 <>b.默认值 or a.字段说明 <>b.字段说明
    order by isnull(a.表名1,b.表名2),isnull(b.表名2,a.表名1)--,isnull(a.序号,b.序号)--isnull(a.字段名,b.字段名)
    go

    三.外键差异查询

    DECLARE @dbname1 varchar(250)--要比较的数据库名1
    DECLARE @dbname2 varchar(250) --要比较的数据库名2

    set @dbname1='demodtcms'
    set @dbname2='wangkejidatabase'

    create table #fk1(外键名 varchar(250),子表名 varchar(250),子表列 varchar(250),被参考表 varchar(250),被参考列 varchar(250),启用 bit,
    删除操作 varchar(50),更新操作 varchar(50))

    create table #fk2(外键名 varchar(250),子表名 varchar(250),子表列 varchar(250),被参考表 varchar(250),被参考列 varchar(250),启用 bit,
    删除操作 varchar(50),更新操作 varchar(50))

    --得到数据库1的外键
    exec('use ['+ @dbname1 + ']
    insert into #fk1 SELECT
    外键名=f.name --AS foreign_key_name
    ,子表名=OBJECT_NAME(f.parent_object_id) --AS table_name
    ,子表列=COL_NAME(fc.parent_object_id, fc.parent_column_id) --AS constraint_column_name
    ,被参考表=OBJECT_NAME (f.referenced_object_id) ---AS referenced_object
    ,被参考列=COL_NAME(fc.referenced_object_id, fc.referenced_column_id) --AS referenced_column_name
    ,启用=is_disabled
    ,删除操作=delete_referential_action_desc
    ,更新操作=update_referential_action_desc
    FROM sys.foreign_keys AS f
    INNER JOIN sys.foreign_key_columns AS fc
    ON f.object_id = fc.constraint_object_id
    WHERE f.parent_object_id in (SELECT id from sysobjects WHERE xtype=''U'') ORDER BY 子表名')

    --SELECT * FROM #fk1

    --得到数据库2的外键
    exec('use ['+ @dbname2 + ']
    insert into #fk2 SELECT
    外键名=f.name --AS foreign_key_name
    ,子表名=OBJECT_NAME(f.parent_object_id) --AS table_name
    ,子表列=COL_NAME(fc.parent_object_id, fc.parent_column_id) --AS constraint_column_name
    ,被参考表=OBJECT_NAME (f.referenced_object_id) ---AS referenced_object
    ,被参考列=COL_NAME(fc.referenced_object_id, fc.referenced_column_id) --AS referenced_column_name
    ,启用=is_disabled
    ,删除操作=delete_referential_action_desc
    ,更新操作=update_referential_action_desc
    FROM sys.foreign_keys AS f
    INNER JOIN sys.foreign_key_columns AS fc
    ON f.object_id = fc.constraint_object_id
    WHERE f.parent_object_id in (SELECT id from sysobjects WHERE xtype=''U'') ORDER BY 子表名')

    --SELECT * FROM #fk2

    select 比较结果=case when a.外键名 is null then '库1缺少外键:'+b.外键名
    when b.外键名 is null then '库2缺少外键::'+a.外键名
    when a.子表名 <>b.子表名 then '子表名不同'
    when a.子表列 <>b.子表列 then '子列名不同'
    when a.被参考表 <>b.被参考表 then '主被参考表不同'
    when a.被参考列 <> b.被参考列 then '被参考列不同'
    when a.启用 <>b.启用 then '启用不同'
    when a.删除操作 <>b.删除操作 then '删除操作不同'
    when a.更新操作 <>b.更新操作 then '更新操作不同'
    else '' end,
    *
    from #fk1 a
    full join #fk2 b on a.外键名=b.外键名
    where a.外键名 is null or b.外键名 is null
    or a.子表名 <>b.子表名 or a.子表列 <>b.子表列 or a.被参考表 <>b.被参考表 or a.被参考列 <> b.被参考列
    or a.启用 <>b.启用 or a.删除操作 <>b.删除操作 or a.更新操作 <>b.更新操作
    order by isnull(a.子表名,b.子表名)--isnull(a.字段名,b.字段名)
    go

  • 相关阅读:
    IO 单个文件的多线程拷贝
    day30 进程 同步 异步 阻塞 非阻塞 并发 并行 创建进程 守护进程 僵尸进程与孤儿进程 互斥锁
    day31 进程间通讯,线程
    d29天 上传电影练习 UDP使用 ScketServer模块
    d28 scoket套接字 struct模块
    d27网络编程
    d24 反射,元类
    d23 多态,oop中常用的内置函数 类中常用内置函数
    d22 封装 property装饰器 接口 抽象类 鸭子类型
    d21天 继承
  • 原文地址:https://www.cnblogs.com/guanshan/p/guan124.html
Copyright © 2011-2022 走看看