1. 程式人生 > >資料庫表結構比對工具

資料庫表結構比對工具

一、概述

       在軟體實施過程中,我遇到了這麼一個問題,我在客戶那邊安裝了整個ERP程式並且向資料庫中匯入了客戶提供給我的基礎資料,程式進入試執行階段,在試執行期間,客戶反映出程式的各種問題,需要提交給公司去糾正這些問題,在糾正問題的時候伴隨的問題的解決,程式開發人員向資料庫中添加了資料庫表或者向已有表中添加了欄位,這個時候開發員沒有一個良好的習慣用SQL語法來操作這些新增,而是直接在資料庫設計器中新增,在實施人員給客戶更新程式的時候需要重新還原資料庫,導致之前已經匯入的基礎資料需要重新做處理,做了重複工作量,我作為一個實施人員為了讓自己工作更輕鬆,編寫了這麼一個小工具,網上搜索了一下,很多這種的小工具但是並不適合我,自己動手豐衣足食,接下來我們探討一下這個小工具的實現。

二、小工具設計思路

      需要兩個資料庫進行比較,那麼我們需要兩個不同的資料庫甚至連線兩個不同的資料庫伺服器,針對不同的資料庫伺服器中的兩個資料庫進行表結構比對(大家可以考慮儲存過程,函式等的比對,比對過程都不會難),想到這些我們就可以開始著手開始設計程式了,設計介面如下圖所示:

三、程式設計

獲取表結構的SQL語法:

USE DBName--換成你自己的資料庫名稱

SELECT distinct 表名 = OBJECT_NAME(c.object_id),
                    表描述 = (SELECT top 1 a.[value] FROM sys.extended_properties a left JOIN  sysobjects b ON a.major_id=b.id WHERE b.name=OBJECT_NAME(c.object_id) and a.minor_id=0 ),
                    欄位名 = c.name, 欄位描述 = ex.value, 欄位型別 = t.name, 欄位長度 = c.max_length, 位數 = c.precision, 小數位 = c.scale
                    FROM sys.columns c LEFT OUTER JOIN sys.extended_properties ex
                    ON ex.major_id = c.object_id AND ex.minor_id = c.column_id AND ex.name = 'MS_Description'
                    left outer join systypes t on c.system_type_id = t.xtype WHERE
                    OBJECTPROPERTY(c.object_id, 'IsMsShipped') = 0 AND
                    t.name != 'sysname'

編寫一個方法放入上述SQL 返回一個datatable。

獲取資料庫中表的建立語法:

USE DBName--此處替換為你自己的資料庫名稱

SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET NUMERIC_ROUNDABORT OFF

declare @crlf char(2)
SET @crlf=char(13)+char(10)

;WITH ColumnDefs as
(
    select TableObj=c.[object_id]
        ,ColSeq=c.column_id
        ,ColumnDef=quotename(c.Name)+' '
                    +case
                        when c.is_computed=1 then 'as '+coalesce(k.[definition],'')
                            +case when k.is_persisted=1 then ' PERSISTED'+case when k.is_nullable=0 then ' NOT NULL' else '' end else '' end
                        else DataType
                            +case
                            when DataType in ('decimal','numeric') then '('+cast(c.precision as varchar(10))+case when c.scale<>0 then ','+cast(c.scale as varchar(10)) else '' end +')'
                            when DataType in ('char','varchar','nchar','nvarchar','binary','varbinary') then '('+case when c.max_length=-1 then 'max' else case when DataType in ('nchar','nvarchar') then cast(c.max_length/2 as varchar(10)) else cast(c.max_length as varchar(10)) end end +')'
                            when DataType='float' and c.precision<>53 then '('+cast(c.precision as varchar(10))+')'
                            when DataType in ('time','datetime2','datetimeoffset') and c.scale<>7 then '('+cast(c.scale as varchar(10))+')'
                            else ''
                            end
                    end
                    +case when c.is_identity=1 then ' IDENTITY('+cast(IDENT_SEED(quotename(object_schema_name(c.[object_id]))+'.'+quotename(object_name(c.[object_id]))) as varchar(30))+','+cast(ident_incr(quotename(object_schema_name(c.[object_id]))+'.'+quotename(object_name(c.[object_id]))) as varchar(30))+')' else '' end
                    +case when c.is_rowguidcol=1 then ' ROWGUIDCOL' else '' end
                    +case when c.xml_collection_id>0 THEN ' (CONTENT '+QUOTENAME(SCHEMA_NAME(x.SCHEMA_ID))+'.'+ QUOTENAME(x.name)+')' ELSE '' end
                    +case
                        when c.is_computed=0 and UserDefinedFlag=0
                        then case
                            when c.collation_name<>cast(databasepropertyex(db_name() ,'collation') as nvarchar(128))
                            then ' COLLATE '+c.collation_name
                            else ''
                            end
                        else ''
                    end
                    +case when c.is_computed=0 then case when c.is_nullable=0 then ' NOT' else '' end+' NULL' else '' end
                    +case
                        when c.default_object_id>0
                        then ' CONSTRAINT '+quotename(d.name)+' DEFAULT '+coalesce(d.[definition],'')
                        else ''
                    end
                
    from sys.columns c
    cross apply ( 
    select DataType=type_name(c.user_type_id)
            ,UserDefinedFlag=case
                                when c.system_type_id=c.user_type_id
                                then 0
                                else 1
                                end) F1
    left join sys.default_constraints d ON c.default_object_id=d.[object_id]
    left join sys.computed_columns k ON c.[object_id]=k.[object_id]
                                    and c.column_id=k.column_id
    left join  sys.xml_schema_collections x ON c.xml_collection_id = x.xml_collection_id                           
)
,IndexDefs as
(
    select TableObj=i.[object_id]
        ,IxName=quotename(i.name)
        ,IxPKFlag=i.is_primary_key
        ,IxType=case when i.is_primary_key=1 then 'PRIMARY KEY ' when i.is_unique=1 then 'UNIQUE ' else '' end
                +lower(type_desc)
        ,IxDef='('+IxColList+')'
                +coalesce(' INCLUDE ('+IxInclList+')','')
        ,IxOpts=IxOptList       
    from sys.indexes i
    left join sys.stats s ON i.index_id=s.stats_id and i.[object_id]=s.[object_id]
    cross apply ( 
    select stuff((select case when i.is_padded=1 then ', PAD_INDEX=ON' else '' end
                        +case when i.fill_factor<>0 then ', FILLFACTOR='+cast(i.fill_factor as varchar(10)) else '' end
                        +case when i.ignore_dup_key=1 then ', IGNORE_DUP_KEY=ON' else '' end
                        +case when s.no_recompute=1 then ', STATISTICS_RECOMPUTE=ON' else '' end
                        +case when i.allow_row_locks=0 then ', ALLOW_ROW_LOCKS=OFF' else '' end
                        +case when i.allow_page_locks=0 then ', ALLOW_PAGE_LOCKS=OFF' else '' end)
                    ,1,2,'')) F_IxOpts(IxOptList)
    cross apply ( 
    select stuff((select ','+quotename(c.name)
                        +case
                            when ic.is_descending_key=1 AND i.type<>3
                            then ' DESC'
                            WHEN ic.is_descending_key=0 AND i.type<>3
                            THEN ' ASC'
                            ELSE ''
                            end
                    from sys.index_columns ic
                    join sys.columns c ON ic.[object_id]=c.[object_id]
                                        and ic.column_id=c.column_id
                    where ic.[object_id]=i.[object_id]
                    and ic.index_id=i.index_id
                    and ic.is_included_column=0
                    order by ic.key_ordinal
                    FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,1,'')) F_IxCols(IxColList)
    cross apply ( 
    select stuff((select ','+quotename(c.name)
                    from sys.index_columns ic
                    join sys.columns c ON ic.[object_id]=c.[object_id]
                                        and ic.column_id=c.column_id
                    where ic.[object_id]=i.[object_id]
                    and ic.index_id=i.index_id
                    and ic.is_included_column=1
                    order by ic.key_ordinal
                    FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,1,'')) F_IxIncl(IxInclList)
    where i.type_desc<>'HEAP'
)
,FKDefs as
(
    select TableObj=f.parent_object_id
        ,FKName=quotename(f.name)
        ,FKRef=quotename(object_schema_name(f.referenced_object_id))+'.'
                +quotename(object_name(f.referenced_object_id))
        ,FKColList=ParentColList
        ,FKRefList=RefColList
        ,FKDelOpt=case f.delete_referential_action
                    when 1 then 'CASCADE'
                    when 2 then 'SET NULL'
                    when 3 then 'SET DEFAULT'
                    end
        ,FKUpdOpt=case f.update_referential_action
                    when 1 then 'CASCADE'
                    when 2 then 'SET NULL'
                    when 3 then 'SET DEFAULT'
                    end
        ,FKNoRepl=f.is_not_for_replication
    from sys.foreign_keys f
    cross apply ( 
    select stuff((select ','+quotename(c.name)
                    from sys.foreign_key_columns k
                    join sys.columns c ON k.parent_object_id=c.[object_id]
                                        and k.parent_column_id=c.column_id
                    where k.constraint_object_id=f.[object_id]
                    order by constraint_column_id
                    FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,1,'')) F_Parent(ParentColList)
    cross apply (
    select stuff((select ','+quotename(c.name)
                    from sys.foreign_key_columns k
                    join sys.columns c ON k.referenced_object_id=c.[object_id]
                                        and k.referenced_column_id=c.column_id
                    where k.constraint_object_id=f.[object_id]
                    order by constraint_column_id
                    FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,1,'')) F_Ref(RefColList)
)
select TableName
        ,[definition]
from sys.tables t
cross apply ( 
    select TableName=quotename(object_schema_name(t.[object_id]))+'.'
                    +quotename(object_name(t.[object_id]))) F_Name
cross apply (
    select stuff((select @crlf+'  ,'+ColumnDef
                from ColumnDefs
                where TableObj=t.[object_id]
                order by ColSeq
                FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,5,'')) F_Cols(ColumnList)
cross apply (
    select stuff((select @crlf+'  ,CONSTRAINT '+quotename(name)+' CHECK '
                        +case when is_not_for_replication=1 then 'NOT FOR REPLICATION ' else '' end
                        +coalesce([definition],'')
                from sys.check_constraints
                where parent_object_id=t.[object_id]
                FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,2,'')) F_Const(ChkConstList)
cross apply (
    select stuff((select @crlf+'  ,CONSTRAINT '+IxName+' '+IxType+' '+IxDef+coalesce(' WITH ('+IxOpts+')','')
                from IndexDefs
                where TableObj=t.[object_id]
                    and IxPKFlag=1
                FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,2,'')) F_IxConst(IxConstList)
cross apply (
    select stuff((select @crlf+'  ,CONSTRAINT '+FKName+' FOREIGN KEY '+'('+FKColList+')'+' REFERENCES '+FKRef+' ('+FKRefList+')'
                        +case when FKDelOpt is NOT NULL then ' ON DELETE '+FKDelOpt else '' end
                        +case when FKUpdOpt is NOT NULL then ' ON UPDATE '+FKUpdOpt else '' end
                        +case when FKNoRepl=1 then ' NOT FOR REPLICATION' else '' end
                from FKDefs
                where TableObj=t.[object_id]
                FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,2,'')) F_Keys(FKConstList)
cross apply (
    select stuff((select @crlf+'CREATE '+IxType+' INDEX '+IxName+' ON '+TableName+' '+IxDef+coalesce(' WITH ('+IxOpts+')','')
                from IndexDefs
                where TableObj=t.[object_id]
                    and IxPKFlag=0
                FOR xml path(''),type).value('.','nvarchar(max)')
                ,1,2,'')) F_Indexes(IndexList)
cross apply (
    select [definition]=(select 'CREATE TABLE

'[email protected]+'('[email protected]+'   '+ColumnList+coalesce(@crlf+ChkConstList,'')+coalesce(@crlf+IxConstList,'')+coalesce(@crlf+FKConstList,'')[email protected]+')'+coalesce(@crlf+IndexList,'')[email protected]
    FOR xml path(''),type).value('.','nvarchar(max)')) F_Link

這個SQL語法是網上某位大神的,我收藏了很久了都忘記在哪裡了,這裡不能提供出處,望見諒。

在此處也一樣的編寫一個方法來執行上述SQL 返回一個datatable

做好上述準備以後我們就可以來實現 表結構比對方法了,此時我們需要考慮一下幾點:

1.目標資料庫中無來源資料庫中表的情況下,獲取建立表語法

2.目標資料庫中存在來源資料庫中表的情況下,進行表字段比較

3.綜合第2點,目標資料表中無來源資料表中的欄位,則在目標資料表中新增來源表的欄位

滿足上述這些要求我們就可以設計出一個比對方法了。接下來提供資料庫表字段的新增SQL語法和欄位描述的SQL語法如下:

--新增資料庫欄位的語法

strbSQLScript.Append("IF NOT EXISTS(select * from syscolumns where id=object_id('" + dr["表名"].ToString() + "') and name='" + dr["欄位名"].ToString() + "') \r\n");
                            strbSQLScript.Append("Alter table " + dr["表名"].ToString() + " Add " + dr["欄位名"].ToString() + " " + dr["欄位型別"].ToString() + "(" + dr["欄位長度"].ToString() + ") null \r\n");
                            strbSQLScript.Append("GO \r\n");

--新增資料庫欄位描述的語法
                            strbSQLScript.Append("IF NOT EXISTS (SELECT * FROM ::fn_listextendedproperty(N'MS_Description' , N'SCHEMA',N'dbo', N'TABLE',N'" + dr["表名"].ToString() + "', N'COLUMN',N'" + dr["欄位名"].ToString() + "')) \r\n");
                            strbSQLScript.Append("EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'" + dr["欄位描述"].ToString() + "' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'" + dr["表名"].ToString() + "', @level2type=N'COLUMN',@level2name=N'" + dr["欄位名"].ToString() + "' \r\n");
                            strbSQLScript.Append("GO \r\n");

這兩個語法我直接放程式碼上來了,我用的foreach迴圈。  

相關推薦

資料庫結構工具

一、概述        在軟體實施過程中,我遇到了這麼一個問題,我在客戶那邊安裝了整個ERP程式並且向資料庫中匯入了客戶提供給我的基礎資料,程式進入試執行階段,在試執行期間,客戶反映出程式的各種問題,需要提交給公司去糾正這些問題,在糾正問題的時候伴隨的問題的解決,程式開發人

SQL Compare 10 資料庫結構工具 下載 及 破解工具 操作手冊

原文連結:      http://www.tuicool.com/articles/mmyQna 資源下載:        SQLCompare10_withCrack.zip     ( 18 MB)       連結:http://pan.baidu.com/s/1

mysql兩個資料庫結構的方法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

查詢不同sqlserver資料庫兩張欄位結構是否相同

package com.cn.sis;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;im

軟體工具——PowerDesigner逆向工程匯出Oracle資料庫結構

一、準備工作: 準備工作包括,安裝或已經有建立好的oracle資料庫,建立好user、tablespace、table等;安裝Oracle客戶端、PLSQL等軟體並配置好資料庫連線,安裝PowerDesigner軟體。可以參考我的博文: 二、PowerDesi

好用的資料庫結構匯出工具,支援Oracle,MySQL,SQL SERVER

好用的資料庫表結構匯出工具 之前遇到公司需要匯出表結構的word文件,在網上找了一大堆關於匯出資料庫表結構成word文件的工具,發現只有一款DBExportDoc,而且還需要操作巨集,而且還需要2003的word版本,所以我就自己搞了一個開源工具.(支援 Ora

資料庫結構生成工具使用說明

 對於開發來說,如何規範化你的資料庫表結構文件是灰常之重要的一件事情。但是當你的庫,你的表排山倒海滴多的時候,你就會很頭疼了。 推薦一款工具DBExportDocV1.0 For MySQL(MySQL資料庫表結構匯出器)。 介紹: DBExportDoc V1.0 Fo

工具

輸出結果 data ase api 我們 model orm clas last (green) short pairwise alignment / detailed edit model; (yellow) database search / divergent

mysql資料庫結構定義檔案和儲存引擎檔案

目錄 1.表結構定義檔案:      2.儲存引擎檔案 2.1表空間檔案 2.2重做日誌檔案 3. 如何用frm檔案恢復資料庫結構 1.表結構定義檔案:      *.frm 檔案是所有m

資料庫結構設計原則

先談談我這些年趟過的資料庫的坑: 同義多詞。例如:在訂單表中申請單號用appseetserialno,而在支付日誌表中用appno。 同詞多義。例如:渠道這個欄位,可以用channel表示,在委託表中表示請求的來源渠道,eg:安卓、IOS、官網;在支付日誌表中表示支付的

mysql alter修改資料庫結構用法

1.alter操作表字段 (1)增加欄位   alter table 表名 add 欄位名 欄位型別;   alter table student add name varchar(10); (2)修改欄位    alter table 表名 change 舊

VCF工具的安裝及使用

過程參考https://vcftools.github.io/examples.html 首先下載並編譯安裝vcftools git clone https://github.com/vcftools/vcftools.git cd vcftools ./autogen.s

【Normal Form】資料庫結構設計所遵從的正規化

目錄 1. 第一正規化:原子性,不可再分    1.1. 是否為原子性    1.2. 典型的例子:多個資訊用分隔符拼接記錄 2. 第二正規化:非主鍵必須完全依賴於主鍵,而不能只依賴於主鍵的

清空資料庫結構的幾種方式

一、SQL中的語法    1、drop table 表名稱                         eg: drop

centos安裝MySQL結構自動同步-工具 mysql-schema-sync

下載即用 mysql-schema-sync 是一款使用 Go 開發跨平臺的 MySQL 表結構自動同步工具。主要用於解決多個環境資料庫表結構不同步問題。 mysql-schema-sync 支援功能: 同步新表 同步欄位 變動:新增、修改 同步索引 變動:新增、修改 支援預覽(

資料庫結構轉成設計書,PowerDesigner 表格匯出為excel

資料庫中的表匯入到PowerDesigner中並轉為excel文件 1、開啟PowerDesigner12,在選單中按照如下方式進行操作    file->Reverse Engineer->DataBase    點選後,彈出 New Physica

資料庫結構同步

1.同步對比工具--workbench 首先選擇模板資料庫生成model, 然後選擇database->synchronize model...->選擇要同步的資料來源->選擇要同步的資料庫,點選override target, 一直點擊向下執行, 生成變動的sql指令碼.

activiti資料庫結構剖析

1、結構設計 1.1、    邏輯結構設計 Activiti使用到的表都是ACT_開頭的。 ACT_RE_*: ’RE’表示repository(儲存),RepositoryService介面所操作的表。帶此字首的表包含的是靜態資訊,如,流程定義,流程的資源(圖片,規

資料庫結構比較SQL

--查詢A資料庫存在,B資料庫不存在的表 select * from user_tables t where not exists(select 1 from [email protected] t1 where t.TABLE_NAME=t1.TABLE_NAME

反向讀取Mysql資料庫結構到PowerDesigner中

    使用PowerDesigner挺長時間了,只是一些簡單的表結構設計,因需要對當前資料庫進行再設計,需要看一下資料庫中所有的表,及表之間的關係,並重新修改表結構,因此需求就是怎麼把資料庫中的表結構反向生成到PowerDesigner中,以下是對該過程的實踐,當前也搜尋了其他同學的方法,便於後期使用即其他