基于Python的SQL Server数据库对象同步轻量级实现

MSSQL123 2019-06-12 14:05:00 阅读数:22 评论数:0 收藏数:0

 

缘由

日常工作中经常遇到类似的问题:把某个服务器上的某些指定的表同步到另外一台服务器。
类似需求用SSIS或者其他ETL工作很容易实现,比如用SSIS的话,但是会存在相当一部分反复的手工操作。
建源的数据库信息,目标的数据库信息,如果是多个表,需要一个一个地拉source和target,然后一个一个地mapping,然后运行实现数据同步。
不过很可能,这个workflow使用也就这么一次,就寿终正寝了,但是一样要浪费时间去做这个ETL。

 

快速数据同步实现

于是在想,可不可能快速实现类似需求,尽最大程度减少重复的手工操作?类似基于命令行的方式,简单快捷,不需要太多的手动操作。
于是就有了本文,基于Python(目的是顺便熟悉一下Python的语法),快速实现SQL Server的数据库之间的数据同步操作,
后面又稍微扩展了一下,可以实现不同服务器的数据库之间的表结构,表对应的数据,存储过程,函数,用户自定义类型表(user define table type)的同步
目前支持在两个SQL Server数据源之间:每次同步一张或者多张表/存储过程,也可以同步整个数据库的所有表/存储过程(以及表/存储过程依赖的其他数据库对象)。

 

需要考虑到一些基本的校验问题:在源服务器上,需要同步的对象是否存在,或者输入的对象是否存在于源服务器的数据库里。

在目标服务器上,对于表的同步:
1,表的存在依赖于schema,需要考虑到表的schema是否存在,如果不存在先在target库上创建表对应的schema
2,target表中是否有数据?如果有数据,是否以覆盖的方式执行
对于存储过程的同步:
1,类似于表,需要考虑存储过程的schema是否存在,如果不存在先在target库上创建表对应的schema
2,类似于表,arget数据库中是否已经存在对应的存储过程,是否以覆盖的方式执行
3,存储过程可能依赖于某些函数,用户自定义表变量等等,同步存储过程的时候需要先同步依赖的对象,这一点比较复杂,实现过程中遇到在很多很多的坑
  可能存在对象A依赖于对象B,对象B依赖于对象C……,这里有点递归的意思
  这一点导致了重构大量的代码,一开始都是直来直去的同步,无法实现这个逻辑,切实体会到代码的“单一职责”原则

 

参数说明
参数说明如下,大的包括三类:
1,源服务器信息(服务器地址,实例名,数据库名称,用户名,密码),没有用户名密码的情况下,使用windows身份认证模式
2,目标服务器信息(服务器地址,实例名,数据库名称,用户名,密码),没有用户名密码的情况下,使用windows身份认证模式
3,同步的对象类型以及对象
4,同步的对象在目标服务器上存在的情况下,是否强制覆盖

其实在同步数据的时候,也可以把需要同步的行数提取出来做参数,比较简单,这里暂时没有做。
比如需要快速搭建一个测试环境,需要同步所有的表结构和每个表的一部分数据即可。

 

表以及数据同步

表同步的原理是,创建目标表,遍历源数据的表,生成insert into values(***),(***),(***)格式的sql,然后插入目标数据库,这里大概步骤如下:
1,表依赖于schema,所以同步表之前先同步schema
2,强制覆盖的情况下,会drop掉目标表(如果存在的话),方式目标表与源表结构不一致,非强制覆盖的情况下,如果字段不一致,抛出异常
3,同步表结构,包括字段,索引,约束等等,但是无法支持外键,刻意去掉了外键,想想为什么?因吹斯汀。
4,需要筛选出来非计算列字段,insert语句只能是非计算列字段(又导致重构了部分代码)
5,转义处理,在拼凑SQL的时候,需要进行转义处理,否则会导致SQL语句错误,目前处理了字符串中的’字符,二进制字段,时间字段的转义或者其他处理
6,鉴于insert into values(***),(***),(***)语法上允许的最大值是1000,因此每生成1000条数据,就同步一次

使用如下参数,同步源数据库的三张表到目标数据库,因为这里是在本机命名实例下测试,因此实例名和端口号输入

python SyncDatabaseObject.py -s_h="127.0.0.1" -s_i="sql2017" -s_P=49744 -s_d=DB01 -t_h=127.0.0.1 -t_i="sql2017" -t_P=49744 -t_d="DB02" -obj_type="tab" -obj="[dbo].[table01],schema1.table01,schema2.table01" -f="Y"

执行同步的效果

说明:
1,如果输入obj_type="tab" 且-obj=为None的情况下,会同步源数据库中的所有表。
2,这个效率取决于机器性能和网络传输,本机测试的话,每秒中可以提交3到4次,也就是每秒钟可以提交3000~4000行左右的数据。

已知的问题:
1,当表的索引为filter index的时候,无法生成包含where条件的索引创建语句,那个看起来蛋疼的表结构导出语句,暂时没时间改它。
2,暂时不支持其他少用的类型字段,比如地理空间字段什么的。

 

存储过程对象的同步

存储过程同步的原理是,在源数据库上生成创建存储过程的语句,然后写入目标库,这里大概步骤如下:
1,存储过程依赖于schema,所以同步存储过程之前先同步schema(同表)
2,同步的过程会检查依赖对象,如果依赖其他对象,暂停当前对象同步,先同步依赖对象
3,重复第二步骤,直至完成

使用如下参数,同步源数据库的两个存储过程到目标数据库,因为这里是在本机命名实例下测试,因此实例名和端口号输入

python SyncDatabaseObject.py -s_h="127.0.0.1" -s_i="sql2017" -s_P=49744 -s_d=DB01 -t_h=127.0.0.1 -t_i="sql2017" -t_P=49744 -t_d="DB02" -obj_type="p" -obj="[dbo].[sp_test01],[dbo].[sp_test02]" -f="Y"

说明:测试要同步的存储过程之一为[dbo].[sp_test01],它依赖于其他两个对象:dbo.table01和dbo.fn_test01()

create proc [dbo].[sp_test01]
as
begin
 set nocount on;
 delete from dbo.table01 where id = 1000
 select dbo.fn_test01()
end

而dbo.fn_test01()的如下,依赖于另外一个对象:dbo.table02

create function [dbo].[fn_test01]
(
)
RETURNS int
AS
BEGIN 
 declare @count int = 0
 select @count = count(1) from dbo.table02
 return @count
END

因此,这个测试的[dbo].[sp_test01]就依赖于其他对象,如果其依赖的对象不存在,同步的时候,仅仅同步这个存储过程本身,是没有意义的
同步某一个对象的依赖对象,使用过如下SQL查出来的,因此这里就层层深入,同步依赖对象。
这里就类似于同步A的时候,A依赖于B和C,然后停止同步A,先同步B和C,同步B或者C的时候,可能又依赖于其他对象,然后继续先同步其依赖对象。

效果如下

如果输入obj_type="sp" 且-obj=为None的情况下,会同步源数据库中的所有存储过程以及其依赖对象

已知的问题:
1,加密的存储过程或者函数是无法实现同步的,因为无法生成创建对象的脚本
1,table type的同步也是一个蛋疼的过程,目前支持,但是支持的并不好,原因是创建table type之前,先删除依赖于table type的对象,否则无法修改,创建。

 

特别说明

依赖对象的解决,还是比较蛋疼的
如果在默认schema为dbo的对象,在存储过程或者函数中没有写schema,使用 sys.dm_sql_referenced_entities这个系统函数是无法找到其依赖的对象的
但是奇葩的是可以找到schema的类型,却没有返回对象本身。
这一点导致在代码中层层深入,进行了长时间的debug,完全没有想到这个函数是这个鸟样子,因为这里找到依赖对象的类型,却找不到对象本身,次奥!!!
另外一种情况就是动态SQL了,无法使用 sys.dm_sql_referenced_entities这个系统函数找到其依赖的对象。

 

其他对象的同步

  支持其他数据库对象的同步,比如function,table type等,因为可以在同步其他存储过程对象的时候附带的同步function,table type比较简单,不做过多说明。 

 

需要改进的地方

1,代码结构优化,更加清晰和条例的结构(一开始用最直接简单粗暴的方式快速实现,后面重构了很多代码,现在自己看起来还有很多不舒服的痕迹)
2,数据同步的效率问题,对于多表的导入导出操作,依赖于单线程,多个大表导出串行的话,可能存在效率上的瓶颈,如何根据表的数据量,尽可能平均地分配多多个线程中,提升效率
3,更加友好清晰的异常提示以及日志记录,生成导出日志信息。
4,异构数据同步,MySQL《==》SQL Server《==》Oracle《==》PGSQL

代码端午节写好了,这几天抽空进行了一些测试以及bug fix,应该还潜在不少未知的bug,工作量比想象中的大的多了去了。

# -*- coding: utf-8 -*-
# !/usr/bin/env python3

__author__ = 'MSSQL123'
__date__ = '2019-06-07 09:36'

import os
import sys
import time
import datetime
import pymssql
from decimal import Decimal

usage = '''
         -----parameter explain-----
         
         source database parameter
         -s_h           : soure database host                                          ----- must require parameter
         -s_i           : soure database instace name                                  ----- default instance name MSSQL
         -s_d           : soure database name                                          ----- must require parameter
         -s_u           : soure database login                                         ----- default windows identifier
         -s_p           : soure database login password                                ----- must require when s_u is not null
         -s_P           : soure database instance port                                 ----- default port 1433
         
         target database parameter
         -t_h           : target database host                                         ----- must require parameter
         -t_i           : target database instace name                                 ----- default instance name MSSQL
         -t_d           : target database name                                         ----- must require parameter
         -t_u           : target database login                                        ----- default windows identifier
         -t_p           : target database login password                               ----- must require when s_u is not null
         -t_P           : target database instance port                                ----- default port 1433

         sync object parameter
         -obj_type      : table or sp or function or other databse object              ----- tab or sp or fn or tp
         -obj           : table|sp|function|type name                                  ----- whick table or sp sync
         
         overwirte parameter
         -f             : force overwirte target database object                           ----- F or N 


         --help: help document
         Example:
         python DataTransfer.py -s_h=127.0.0.1 -s_P=1433 -s_i="MSSQL" -s_d="DB01" -obj_type="tab"  -obj="dbo.t1,dbo.t2"  -t_h=127.0.0.1 -t_P=1433 -t_i="MSSQL" -t_d="DB02"  -f="Y"                   
         python DataTransfer.py -s_h=127.0.0.1 -s_P=1433 -s_i="MSSQL" -s_d="DB01" -obj_type="sp"  -obj="dbo.sp1,dbo.sp2" -t_h=127.0.0.1 -t_P=1433 -t_i="MSSQL" -t_d="DB02"  -f="Y"
         '''

class SyncDatabaseObject(object):
    # source databse
    s_h = None
    s_i = None
    s_P = None
    s_u = None
    s_p = None
    s_d = None

    # obj type
    s_obj_type = None
    # sync objects
    s_obj = None

    # target database
    t_h = None
    t_i = None
    t_P = None
    t_u = None
    t_p = None
    t_d = None

    f = None

    file_path = None

    def __init__(self, *args, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)



    # connect to sqlserver
    def get_connect(self, _h, _i, _P, _u, _p, _d):
        cursor = False
        try:
            if ( _u) and (_p):
                conn = pymssql.connect(host=_h,
                                       server=_i,
                                       port=_P,
                                       user = _u,
                                       password = _p,
                                       database=_d)
            else:
                conn = pymssql.connect(host=_h,
                                       server=_i,
                                       port=_P,
                                       database=_d)
            if (conn):
                return conn
        except:
            raise
        return conn

    # check connection
    def validated_connect(self, _h, _i, _P, _u,_p, _d):
        if not (self.get_connect(_h, _i, _P,_u,_p, _d)):
            print("connect to " + str(_h) + " failed,please check you parameter")
            exit(0)


    '''
    this is supposed to be a valid object name just like xxx_name,or dbo.xxx_name,or [schema].xxx_name or schema.[xxx_name]
    then transfer this kind of valid object name to format object name like [dbo].[xxx_name](give a default dbo schema name when no schema name)
    other format object name consider as unvalid,will be rasie error in process
    format object name
        1,xxx_name              ======> [dbo].[xxx_name]
        2,dbo.xxx_name          ======> [dbo].[xxx_name]
        3,[schema].xxx_name     ======> [dbo].[xxx_name]
        3,schema.xxx_name       ======> [schema].[xxx_name]
        4,[schema].[xxx_name]   ======> [schema].[xxx_name]
        5,[schema].[xxx_name    ======> rasie error format message
    '''

    @staticmethod
    def format_object_name(name):
        format_name = ""
        if ("." in name):
            schema_name = name[0:name.find(".")]
            object_name = name[name.find(".") + 1:]
            if not ("[" in schema_name):
                schema_name = "[" + schema_name + "]"
            if not ("[" in object_name):
                object_name = "[" + object_name + "]"
            format_name = schema_name + "." + object_name
        else:
            if ("[" in name):
                format_name = "[dbo]." + name
            else:
                format_name = "[dbo]." + "[" + name + "]"
        return format_name

    '''
    check user input object is a valicated object
    '''

    def exits_object(self, conn, name):
        conn = conn
        cursor_source = conn.cursor()
        # get object by name from source db
        sql_script = r'''select top 1 1 from
                                (
                                    select  concat(QUOTENAME(schema_name(schema_id)),'.',QUOTENAME(name)) as obj_name from sys.objects  
                                    union all
                                    select  concat(QUOTENAME(schema_name(schema_id)),'.',QUOTENAME(name)) as obj_name  from sys.types  
                                )t where obj_name = '{0}'
                                 '''.format(self.format_object_name(name))
        cursor_source.execute(sql_script)
        result = cursor_source.fetchall()
        if not result:
            return 0
        else:
            return 1
        conn.cursor.close()
        conn.close()

    def sync_table_variable(self, tab_name):
        conn_source = self.get_connect(self.s_h, self.s_i, self.s_P, self.s_u, self.s_p, self.s_d)
        conn_target = self.get_connect(self.t_h, self.t_i, self.t_P, self.t_u, self.t_p, self.t_d)
        cursor_source = conn_source.cursor()
        cursor_target = conn_target.cursor()
        arr_table = []
        if (tab_name):
            arr_table = tab_name.split(",")
            for tab_name in arr_table:
                if (self.exits_object(conn_source, self.format_object_name(tab_name))) > 0:
                    pass
                else:
                    arr_table.remove(tab_name)
                    print("----------------------- warning message -----------------------")
                    print( "--------warning: object " + tab_name + " not existing in source database ------------")
                    print("----------------------- warning message -----------------------")
                    print()

        else:
            # get all table in database when not define table name
            sql_script = r'''  select concat(QUOTENAME(schema_name(tp.schema_id)),'.',QUOTENAME(tp.name)) 
                                    from sys.table_types tp
                                    where is_user_defined = 1
                        '''
            if (tab_name) and self.exits_object(conn_target, tab_name) > 0:
                sql_script = sql_script + " and concat(QUOTENAME(schema_name(tp.schema_id)),'.',QUOTENAME(tp.name))  {0}".format(
                    self.format_object_name(tab_name))
            cursor_source.execute(sql_script)

            for row in cursor_source.fetchall():
                arr_table.append(str(row[0]))

        # weather exists in target server database
        for tab_name in arr_table:
            if (self.f == "Y"):
                # skiped,table type can not drop when used by sp
                sql_script = r'''
                                if OBJECT_ID('{0}') is not null
                                    drop table {0}
                            '''.format(self.format_object_name(tab_name))
                # cursor_target.execute(sql_script)
                # conn_target.commit()

                sql_script = r'''select top 1 1
                            from sys.table_types tp
                            where is_user_defined = 1 
                            and concat(QUOTENAME(schema_name(tp.schema_id)),'.',QUOTENAME(tp.name)) = '{0}' '''\
                    .format((self.format_object_name(tab_name)))
                # if the table schema exists in target server,skip
                cursor_target.execute(sql_script)
                exists = cursor_target.fetchall()
                if exists:
                    arr_table.remove(tab_name)
                    print("----------------------- warning message -----------------------")
                    print("the target table type " + tab_name + " exists ,skiped sync table type from source")
                    print("----------------------- warning message -----------------------")
                    print()
                    continue
            else:
                sql_script = r'''select top 1 1
                            from sys.table_types tp
                            where is_user_defined = 1 
                            and concat(QUOTENAME(schema_name(tp.schema_id)),'.',QUOTENAME(tp.name)) = '{0}' ''' \
                    .format((self.format_object_name(tab_name)))
                # if the table schema exists in target server,skip
                cursor_target.execute(sql_script)
                exists = cursor_target.fetchall()
                if exists:
                    arr_table.remove(tab_name)
                    print("----------------------- warning message -----------------------")
                    print("the target table type " + tab_name + " exists ,skiped sync table type from source")
                    print("----------------------- warning message -----------------------")
                    print()
                    continue

        for tab_name in arr_table:
            sql_script = r'''      
                            DECLARE @SQL NVARCHAR(MAX) = ''

                            SELECT @SQL =
                            'CREATE TYPE ' + '{0}' + 'AS  TABLE' + CHAR(13) + '(' + CHAR(13) +
                            STUFF((
                                            SELECT CHAR(13) + '    , [' + c.name + '] ' +
                                                CASE WHEN c.is_computed = 1
                                                    THEN 'AS ' + OBJECT_DEFINITION(c.[object_id], c.column_id)
                                                    ELSE
                                                        CASE WHEN c.system_type_id != c.user_type_id
                                                            THEN '[' + SCHEMA_NAME(tp.[schema_id]) + '].[' + tp.name + ']'
                                                            ELSE '[' + UPPER(y.name) + ']'
                                                        END  +
                                                        CASE
                                                            WHEN y.name IN ('varchar', 'char', 'varbinary', 'binary')
                                                                THEN '(' + CASE WHEN c.max_length = -1


                                                                                THEN 'MAX'
                                                                                ELSE CAST(c.max_length AS VARCHAR(5))
                                                                            END + ')'
                                                            WHEN y.name IN ('nvarchar', 'nchar')
                                                                THEN '(' + CASE WHEN c.max_length = -1
                                                                                THEN 'MAX'
                                                                                ELSE CAST(c.max_length / 2 AS VARCHAR(5))
                                                                            END + ')'
                                                            WHEN y.name IN ('datetime2', 'time2', 'datetimeoffset')
                                                                THEN '(' + CAST(c.scale AS VARCHAR(5)) + ')'
                                                            WHEN y.name = 'decimal'
                                                                THEN '(' + CAST(c.[precision] AS VARCHAR(5)) + ',' + CAST(c.scale AS VARCHAR(5)) + ')'
                                                            ELSE ''
                                                        END +
                                                        CASE WHEN c.collation_name IS NOT NULL AND c.system_type_id = c.user_type_id
                                                            THEN ' COLLATE ' + c.collation_name
                                                            ELSE ''
                                                        END +
                                                        CASE WHEN c.is_nullable = 1
                                                            THEN ' NULL'
                                                            ELSE ' NOT NULL'
                                                        END +
                                                        CASE WHEN c.default_object_id != 0
                                                            THEN ' CONSTRAINT [' + OBJECT_NAME(c.default_object_id) + ']' +
                                                                    ' DEFAULT ' + OBJECT_DEFINITION(c.default_object_id)
                                                            ELSE ''
                                                        END
                                                END
                                            From sys.table_types tp
                                            Inner join sys.columns c on c.object_id = tp.type_table_object_id
                                            Inner join sys.types y ON y.system_type_id = c.system_type_id 
                                            WHERE tp.is_user_defined = 1 and y.name<>'sysname'
                                            and concat(QUOTENAME(schema_name(tp.schema_id)),'.',QUOTENAME(tp.name)) = '{0}'
                                            ORDER BY c.column_id

                            FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 7, '      ')
                                + ');'

                            select @SQL  as  script
                        '''.format(self.format_object_name(self.format_object_name((tab_name))))
            cursor_target = conn_target.cursor()
            cursor_source.execute(sql_script)
            for row in cursor_source.fetchall():
                try:
                    # execute the script on target server
                    cursor_target.execute(str(row[0]))  # drop current stored_procudre if exists
                    conn_target.commit()
                    print("*************table type " + self.format_object_name(tab_name) + " synced *********************")
                    print()  # give a blank row when finish
                except:
                    print("-----------table type " + self.format_object_name(  tab_name) + " synced error ---------------")
                    # raise

        cursor_source.close()
        conn_source.close()
        cursor_target.close()
        conn_target.close()

    def sync_schema(self):
        conn_source = self.get_connect(self.s_h, self.s_i, self.s_P,self.s_u,self.s_p, self.s_d)
        conn_target = self.get_connect(self.t_h, self.t_i, self.t_P,self.t_u,self.t_p, self.t_d)
        cursor_source = conn_source.cursor()
        cursor_target = conn_target.cursor()
        arr_schema = []
        # get all table in database when not define table name
        schema_result = cursor_source.execute(r'''
                                                  select name from sys.schemas where schema_id>4 and schema_id<16384
                                                ''')
        for row in cursor_source.fetchall():
            cursor_target.execute(r''' if not exists(select * from sys.schemas where name = '{0}')
                                                  begin
                                                      exec('create schema [{0}]')
                                                  end
                                              '''.format(str(row[0])))
            conn_target.commit()

        cursor_source.close()
        conn_source.close()
        cursor_target.close()
        conn_target.close()

    def sync_table_schema_byname(self, tab_name):
        conn_source = self.get_connect(self.s_h, self.s_i, self.s_P, self.s_u, self.s_p, self.s_d)
        conn_target = self.get_connect(self.t_h, self.t_i, self.t_P, self.t_u, self.t_p, self.t_d)
        cursor_source = conn_source.cursor()
        cursor_target = conn_target.cursor()

        if (self.exits_object(conn_source, self.format_object_name(tab_name))) == 0:
            print("----------------------- warning message -----------------------")
            print("---------------warning: object " + tab_name + " not existing in source database ----------------")
            print("----------------------- warning message -----------------------")
            print()
        if (self.exits_object(conn_target, self.format_object_name(tab_name))) > 0:
            if (self.f != "Y"):
                print("----------------------- warning message -----------------------")
                print("---------------warning: object " + tab_name + " not existing in source database ----------------")
                print("----------------------- warning message -----------------------")
                print()
                return

        arr_table = []
        sql_script = ''' SELECT QUOTENAME(s.name)+'.'+ QUOTENAME(o.name)
                         FROM sys.objects o WITH (NOWAIT)
                        JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
                        WHERE  o.[type] = 'U'
                        AND o.is_ms_shipped = 0
                        AND QUOTENAME(s.name)+'.'+ QUOTENAME(o.name) = '{}'
                    '''.format(self.format_object_name(tab_name))
        cursor_source.execute(sql_script)
        for row in cursor_source.fetchall():
            arr_table.append(str(row[0]))

        for tab_name in arr_table:
            sql_script = r''' select 1 from sys.tables 
                             where type_desc = 'USER_TABLE' 
                             and concat(QUOTENAME(schema_name(schema_id)),'.',QUOTENAME(name)) = '{0}' 
                          '''.format((self.format_object_name(tab_name)))
            # if the table schema exists in target server,skip
            cursor_target.execute(sql_script)
            exists = cursor_target.fetchall()
            if exists:
                if (self.f == "Y"):
                    cursor_target.execute("drop table {0}".format(tab_name))
                # print("----------------------- warning message -----------------------")
                # print("the target table type " + tab_name + " exists ,skiped sync table type from source")
                # print("----------------------- warning message -----------------------")


            sql_script = r'''      DECLARE 
                                          @object_name SYSNAME
                                        , @object_id INT

                                    SELECT 
                                          @object_name = '[' + s.name + '].[' + o.name + ']'
                                        , @object_id = o.[object_id]
                                    FROM sys.objects o WITH (NOWAIT)
                                    JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
                                    WHERE QUOTENAME(s.name) + '.' + QUOTENAME(o.name) = '{0}'
                                        AND o.[type] = 'U'
                                        AND o.is_ms_shipped = 0

                                    DECLARE @SQL NVARCHAR(MAX) = ''

                                    ;WITH index_column AS 
                                    (
                                        SELECT 
                                              ic.[object_id]
                                            , ic.index_id
                                            , ic.is_descending_key
                                            , ic.is_included_column
                                            , c.name
                                        FROM sys.index_columns ic WITH (NOWAIT)
                                        JOIN sys.columns c WITH (NOWAIT) ON ic.[object_id] = c.[object_id] AND ic.column_id = c.column_id
                                        WHERE ic.[object_id] = @object_id
                                    ),
                                    fk_columns AS 
                                    (
                                         SELECT 
                                              k.constraint_object_id
                                            , cname = c.name
                                            , rcname = rc.name
                                        FROM sys.foreign_key_columns k WITH (NOWAIT)
                                        JOIN sys.columns rc WITH (NOWAIT) ON rc.[object_id] = k.referenced_object_id AND rc.column_id = k.referenced_column_id 
                                        JOIN sys.columns c WITH (NOWAIT) ON c.[object_id] = k.parent_object_id AND c.column_id = k.parent_column_id
                                        WHERE k.parent_object_id = @object_id
                                    )
                                    SELECT @SQL = 'CREATE TABLE ' + @object_name + '' + '(' + '' + STUFF((
                                        SELECT '' + ', [' + c.name + '] ' + 
                                            CASE WHEN c.is_computed = 1
                                                THEN 'AS ' + cc.[definition] 
                                                ELSE UPPER(tp.name) + 
                                                    CASE WHEN tp.name IN ('varchar', 'char', 'varbinary', 'binary', 'text')
                                                           THEN '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(5)) END + ')'
                                                         WHEN tp.name IN ('nvarchar', 'nchar')
                                                           THEN '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length / 2 AS VARCHAR(5)) END + ')'
                                                         WHEN tp.name IN ('datetime2', 'time2', 'datetimeoffset') 
                                                           THEN '(' + CAST(c.scale AS VARCHAR(5)) + ')'
                                                         WHEN tp.name = 'decimal' 
                                                           THEN '(' + CAST(c.[precision] AS VARCHAR(5)) + ',' + CAST(c.scale AS VARCHAR(5)) + ')'
                                                        ELSE ''
                                                    END +
                                                    CASE WHEN c.collation_name IS NOT NULL THEN ' COLLATE ' + c.collation_name ELSE '' END +
                                                    CASE WHEN c.is_nullable = 1 THEN ' NULL' ELSE ' NOT NULL' END +
                                                    CASE WHEN dc.[definition] IS NOT NULL THEN ' DEFAULT' + dc.[definition] ELSE '' END + 
                                                    CASE WHEN ic.is_identity = 1 THEN ' IDENTITY(' + CAST(ISNULL( /*ic.seed_value*/ 1, '0') AS CHAR(1)) + ',' + CAST(ISNULL(ic.increment_value, '1') AS CHAR(1)) + ')' ELSE '' END 
                                            END + ''
                                        FROM sys.columns c WITH (NOWAIT)
                                        JOIN sys.types tp WITH (NOWAIT) ON c.user_type_id = tp.user_type_id
                                        LEFT JOIN sys.computed_columns cc WITH (NOWAIT) ON c.[object_id] = cc.[object_id] AND c.column_id = cc.column_id
                                        LEFT JOIN sys.default_constraints dc WITH (NOWAIT) ON c.default_object_id != 0 AND c.[object_id] = dc.parent_object_id AND c.column_id = dc.parent_column_id
                                        LEFT JOIN sys.identity_columns ic WITH (NOWAIT) ON c.is_identity = 1 AND c.[object_id] = ic.[object_id] AND c.column_id = ic.column_id
                                        WHERE c.[object_id] = @object_id
                                        ORDER BY c.column_id
                                        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '' + ' ')
                                        + ISNULL((SELECT '' + ', CONSTRAINT [' + k.name + '] PRIMARY KEY (' + 
                                                        (SELECT STUFF((
                                                             SELECT ', [' + c.name + '] ' + CASE WHEN ic.is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END
                                                             FROM sys.index_columns ic WITH (NOWAIT)
                                                             JOIN sys.columns c WITH (NOWAIT) ON c.[object_id] = ic.[object_id] AND c.column_id = ic.column_id
                                                             WHERE ic.is_included_column = 0
                                                                 AND ic.[object_id] = k.parent_object_id 
                                                                 AND ic.index_id = k.unique_index_id     
                                                             FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, ''))
                                                + ')' + ''
                                                FROM sys.key_constraints k WITH (NOWAIT)
                                                WHERE k.parent_object_id = @object_id 
                                                    AND k.[type] = 'PK'), '') + ')'  + ''
                                        + ISNULL((SELECT (
                                            SELECT '' +
                                                 'ALTER TABLE ' + @object_name + ' WITH' 
                                                + CASE WHEN fk.is_not_trusted = 1 
                                                    THEN ' NOCHECK' 
                                                    ELSE ' CHECK' 
                                                  END + 
                                                  ' ADD CONSTRAINT [' + fk.name  + '] FOREIGN KEY(' 
                                                  + STUFF((
                                                    SELECT ', [' + k.cname + ']'
                                                    FROM fk_columns k
                                                    WHERE k.constraint_object_id = fk.[object_id] and 1=2
                                                    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
                                                   + ')' +
                                                  ' REFERENCES [' + SCHEMA_NAME(ro.[schema_id]) + '].[' + ro.name + '] ('
                                                  + STUFF((
                                                    SELECT ', [' + k.rcname + ']'
                                                    FROM fk_columns k
                                                    WHERE k.constraint_object_id = fk.[object_id]
                                                    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
                                                   + ')'
                                                + CASE 
                                                    WHEN fk.delete_referential_action = 1 THEN ' ON DELETE CASCADE' 
                                                    WHEN fk.delete_referential_action = 2 THEN ' ON DELETE SET NULL'
                                                    WHEN fk.delete_referential_action = 3 THEN ' ON DELETE SET DEFAULT' 
                                                    ELSE '' 
                                                  END
                                                + CASE 
                                                    WHEN fk.update_referential_action = 1 THEN ' ON UPDATE CASCADE'
                                                    WHEN fk.update_referential_action = 2 THEN ' ON UPDATE SET NULL'
                                                    WHEN fk.update_referential_action = 3 THEN ' ON UPDATE SET DEFAULT'  
                                                    ELSE '' 
                                                  END 
                                                + '' + 'ALTER TABLE ' + @object_name + ' CHECK CONSTRAINT [' + fk.name  + ']' + ''
                                            FROM sys.foreign_keys fk WITH (NOWAIT)
                                            JOIN sys.objects ro WITH (NOWAIT) ON ro.[object_id] = fk.referenced_object_id
                                            WHERE fk.parent_object_id = @object_id
                                            FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)')), '')
                                        + ISNULL(((SELECT
                                             '' + 'CREATE' + CASE WHEN i.is_unique = 1 THEN ' UNIQUE' ELSE '' END 
                                                    + ' NONCLUSTERED INDEX [' + i.name + '] ON ' + @object_name + ' (' +
                                                    STUFF((
                                                    SELECT ', [' + c.name + ']' + CASE WHEN c.is_descending_key = 1 THEN ' DESC' ELSE ' ASC' END
                                                    FROM index_column c
                                                    WHERE c.is_included_column = 0
                                                        AND c.index_id = i.index_id
                                                    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')'  
                                                    + ISNULL('' + 'INCLUDE (' + 
                                                        STUFF((
                                                        SELECT ', [' + c.name + ']'
                                                        FROM index_column c
                                                        WHERE c.is_included_column = 1
                                                            AND c.index_id = i.index_id
                                                        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')', '')  + ''
                                            FROM sys.indexes i WITH (NOWAIT)
                                            WHERE i.[object_id] = @object_id
                                                AND i.is_primary_key = 0
                                                AND i.[type] = 2
                                            FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
                                        ), '')

                                    select @SQL  as  script '''.format(self.format_object_name(tab_name))
            cursor_target = conn_target.cursor()
            cursor_source.execute(sql_script)
            for row in cursor_source.fetchall():
                try:
                    # print(row[0])
                    # execute the script on target server
                    cursor_target.execute(row[0])  # drop current stored_procudre if exists
                    conn_target.commit()
                    print("*************schema " + self.format_object_name(tab_name) + " synced *************")
                    print()  # give a blank row when finish
                except:
                    print("----------------------- warning message -----------------------")
                    print("-----------schema " + self.format_object_name(tab_name) + " synced failed---------------")
                    print("----------------------- warning message -----------------------")
                    print()
                    raise

        cursor_source.close()
        conn_source.close()
        cursor_target.close()
        conn_target.close()

    def get_table_column(self, conn, tab_name):
        column_names = ""
        conn = conn
        cursor_source = conn.cursor()
        # get object by name from source db
        sql_script = r'''select name from sys.columns 
                         where object_id = object_id('{0}') and is_computed=0 order by object_id
                                 '''.format(self.format_object_name(tab_name))
        cursor_source.execute(sql_script)
        result = cursor_source.fetchall()
        for row in result:
            column_names = column_names + row[0] + ","

        return column_names[0:len(column_names) - 1]
        conn.cursor.close()
        conn.close()

    def sync_table_schema(self):
        conn_source = self.get_connect(self.s_h, self.s_i, self.s_P, self.s_u, self.s_p, self.s_d)
        conn_target = self.get_connect(self.t_h, self.t_i, self.t_P, self.t_u, self.t_p, self.t_d)
        cursor_source = conn_source.cursor()
        cursor_target = conn_target.cursor()
        arr_table = []
        if (self.s_obj):
            for tab_name in self.s_obj.split(","):
                if (tab_name) and (self.exits_object(conn_source, tab_name)) > 0:
                    self.sync_table_schema_byname(tab_name)
        else:
            # sync all tables
            # get all table in database when not define table name
            sql_script = ''' SELECT QUOTENAME(s.name)+'.'+ QUOTENAME(o.name)
                             FROM sys.objects o WITH (NOWAIT)
                             JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
                             WHERE  o.[type] = 'U' AND o.is_ms_shipped = 0
                         '''
            cursor_source.execute(sql_script)
            for row in cursor_source.fetchall():
                self.sync_table_schema_byname(str(row[0]))

    # sync data from soure table to target table
    def sync_table_data(self):
        conn_source = self.get_connect(self.s_h, self.s_i, self.s_P, self.s_u, self.s_p, self.s_d)
        conn_target = self.get_connect(self.t_h, self.t_i, self.t_P, self.t_u, self.t_p, self.t_d)
        cursor_source = conn_source.cursor()
        cursor_target = conn_target.cursor()
        arr_table = []
        if (self.s_obj):
            arr_table = self.s_obj.split(',')
            for tab_name in arr_table:
                if (self.exits_object(conn_target, self.format_object_name(tab_name))) > 0:
                    if (self.f != "Y"):
                        arr_table.remove(tab_name)
                        print("----------------------- warning message -----------------------")
                        print("-----------------warning: object " + tab_name + " existing in target database ---------------------")
                        print("----------------------- warning message -----------------------")
        else:
            # get all table in database when not define table name
            tab_result = cursor_source.execute(r''' SELECT QUOTENAME(s.name)+'.'+ QUOTENAME(o.name)
                                                    FROM sys.objects o WITH (NOWAIT)
                                                    JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
                                                    WHERE  o.[type] = 'U'
                                                        AND o.is_ms_shipped = 0
                                            ''')
            for row in cursor_source.fetchall():
                arr_table.append(str(row[0]))


        insert_columns = ""
        insert_columns = self.get_table_column(conn_source, tab_name)

        for tab_name in arr_table:
            if (self.f != "Y"):
                sql_script = "select top 1 {0} from {1} ".format(insert_columns,tab_name)
                # if exists data in target table,break
                cursor_target.execute(sql_script)
                exists = cursor_target.fetchone()
                if exists:
                    print("----------------------- warning message -----------------------")
                    print("the target table type " + tab_name + " exists ,skiped sync table type from source")
                    print("----------------------- warning message -----------------------")
                    print()
                    continue
            else:
                sql_script = "truncate table {0} ".format(tab_name)
                # if exists data in target table,break
                cursor_target.execute(sql_script)
                conn_target.commit()

                
            insert_columns = ""
            insert_columns = self.get_table_column(conn_source, tab_name)

            insert_prefix = ""

            # weather has identity column
            cursor_source.execute(r'''select 1 from sys.columns 
                                    where object_id = OBJECT_ID('{0}') and is_identity =1
                                    '''.format(tab_name))
            exists_identity = None
            exists_identity = cursor_source.fetchone()
            if (exists_identity):
                insert_prefix = "set identity_insert {0} on; ".format(tab_name)

            # data source
            insert_sql = ""
            values_sql = ""
            current_row = ""
            counter = 0
            sql_script = r''' select {0} from {1}   '''.format(insert_columns, tab_name)
            cursor_source.execute(sql_script)

            # create insert columns
            '''
            for field in cursor_source.description:
                insert_columns = insert_columns + str(field[0]) + ","
            insert_columns = insert_columns[0:len(insert_columns) - 1]
            '''

            insert_prefix = insert_prefix + "insert into {0} ({1}) values ".format(tab_name, insert_columns)

            for row in cursor_source.fetchall():
                counter = counter + 1
                for key in row:
                    if (str(key) == "None"):
                        current_row = current_row + r''' null, '''
                    else:
                        if (type(key) is datetime.datetime):
                            current_row = current_row + r''' '{0}', '''.format(str(key)[0:23])
                        elif (type(key) is str):
                            # 我槽,这里又有一个坑:https://blog.csdn.net/dadaowuque/article/details/81016127
                            current_row = current_row + r''' '{0}', '''.format(
                                key.replace("'", "''").replace('\u0000', '').replace('\x00', ''))
                        elif (type(key) is Decimal):
                            d = Decimal(key)
                            s = '{0:f}'.format(d)
                            current_row = current_row + r''' '{0}', '''.format(s)
                        elif (type(key) is bytes):
                            # print(hex(int.from_bytes(key, 'big', signed=True) ))
                            current_row = current_row + r''' {0}, '''.format(
                                hex(int.from_bytes(key, 'big', signed=False)))
                        else:
                            current_row = current_row + r''' '{0}', '''.format(key)

                current_row = current_row[0:len(current_row) - 2]  # remove the the last one char ","
                values_sql = values_sql + "(" + current_row + "),"
                current_row = ""

                # execute the one batch when
                if (counter == 1000):
                    insert_sql = insert_prefix + values_sql
                    insert_sql = insert_sql[0:len(insert_sql) - 1]  # remove the the last one char ","
                    if (exists_identity):
                        insert_sql = insert_sql + " ;set identity_insert {0} off;".format(tab_name)
                    try:
                        cursor_target.execute(insert_sql)
                    except:
                        print(
                            "----------------------error " + tab_name + " data synced failed-------------------------")
                        raise

                    conn_target.commit()
                    insert_sql = ""
                    values_sql = ""
                    current_row = ""
                    counter = 0
                    print(time.strftime("%Y-%m-%d %H:%M:%S",
                                        time.localtime()) + "*************** " + self.format_object_name(
                        tab_name) +" "+ str(1000) + " rows synced *************")

            if (values_sql):
                insert_sql = insert_prefix + values_sql
                insert_sql = insert_sql[0:len(insert_sql) - 1]  # remove the the last one char ","
                if (exists_identity):
                    insert_sql = insert_sql + " ; set identity_insert {0} off;".format(tab_name)
                # execute the last batch
                try:
                    cursor_target.execute(insert_sql)
                except:
                    print("------------------error " + tab_name + " data synced failed------------------------")
                    raise

                conn_target.commit()
                insert_sql = ""
                values_sql = ""
                current_row = ""
                print(time.strftime("%Y-%m-%d %H:%M:%S",
                                    time.localtime()) + "*************** " + self.format_object_name(tab_name) +" "+ str(
                    counter) + " rows synced *************")
                print(time.strftime("%Y-%m-%d %H:%M:%S",
                                    time.localtime()) + "----------------synced " + self.format_object_name(tab_name) + " data finished---------------")
                print()
        cursor_source.close()
        conn_source.close()
        cursor_target.close()
        conn_target.close()

    def sync_dependent_object(self, obj_name):
        conn_source = self.get_connect(self.s_h, self.s_i, self.s_P, self.s_u, self.s_p, self.s_d)
        conn_target = self.get_connect(self.t_h, self.t_i, self.t_P, self.t_u, self.t_p, self.t_d)
        cursor_source = conn_source.cursor()
        cursor_target = conn_target.cursor()
        '''
        find dependent objects
        if exists dependent objects,sync Dependent objects objects in advance
        '''
        sql_check_dependent = r'''              
                             SELECT * FROM
                            (
                                SELECT
                                distinct rtrim(lower(s.type)) COLLATE  Chinese_PRC_CI_AS as obj_type, QUOTENAME(d.referenced_schema_name)+'.'+QUOTENAME(d.referenced_entity_name) COLLATE  Chinese_PRC_CI_AS as obj
                                FROM sys.dm_sql_referenced_entities('{0}','OBJECT')  as d
                                    inner join sys.sysobjects s on s.id = d.referenced_id
                                union all
                                SELECT
                                distinct rtrim(lower(d.referenced_class_desc)) COLLATE  Chinese_PRC_CI_AS  as obj_type,QUOTENAME(d.referenced_schema_name)+'.'+QUOTENAME(d.referenced_entity_name) COLLATE  Chinese_PRC_CI_AS as obj
                                FROM sys.dm_sql_referenced_entities('{0}','OBJECT')  as d
                                    inner join sys.types s on s.user_type_id = d.referenced_id
                            )t
                             '''.format(self.format_object_name(obj_name))

        cursor_source.execute(sql_check_dependent)
        result = cursor_source.fetchall()
        for row in result:
            if row[1]:
                if (row[0] == "u"):
                    if (row[1]):
                        self.sync_table_schema_byname(row[1])
                elif (row[0] == "fn" or row[0] == "if"):
                    if (row[1]):
                        self.sync_procudre_by_name("f", row[1])
                elif (row[0] == "type"):
                    if (row[1]):
                        self.sync_table_variable(row[1])


    def sync_procudre_by_name(self, type, obj_name):
        conn_source = self.get_connect(self.s_h, self.s_i, self.s_P, self.s_u, self.s_p, self.s_d)
        conn_target = self.get_connect(self.t_h, self.t_i, self.t_P, self.t_u, self.t_p, self.t_d)
        cursor_source = conn_source.cursor()
        cursor_target = conn_target.cursor()

        if (self.exits_object(conn_source, self.format_object_name(obj_name))) == 0:
            print("---------------warning: object " + obj_name + " not existing in source database ----------------")

        if (self.exits_object(conn_target, self.format_object_name(obj_name))) > 0:
            if (self.f != "Y"):
                print("---------------warning: object " + obj_name + " not existing in source database ----------------")
                return

        ''' 
        本来想直接生成删除语句的:    
        这里有一个该死的转义,怎么都弄不好,中午先去吃饭吧,
        下午回来想了一下,换一种方式,不要死磕转义问题了
        sql_script =  
                    select
                    'if object_id('+''''+QUOTENAME(schema_name(uid))+ '' + QUOTENAME(name)+''''+') is not null '
                    +' drop proc '+QUOTENAME(schema_name(uid))+ '.' + QUOTENAME(name) ,
                    OBJECT_DEFINITION(id)
                    from sys.sysobjects where xtype = 'P' and  uid not in (16,19)

        '''
        sql_script = r'''
                    select
                    QUOTENAME(schema_name(uid))+'.'+QUOTENAME(name),
                    OBJECT_DEFINITION(id)
                    from sys.sysobjects where xtype in ('P','IF','FN') and  uid not in (16,19)
                  '''
        if (obj_name):
            sql_script = sql_script + " and  QUOTENAME(schema_name(uid))+ '.' + QUOTENAME(name) ='{}' ".format(
                self.format_object_name(obj_name))



        cursor_source.execute(sql_script)
        for row in cursor_source.fetchall():
            try:
                if type == "f":
                    sql_script = r'''
                                             if object_id('{0}') is not null  
                                             drop function {0}
                                             '''.format(self.format_object_name(row[0]))
                elif type == "p":
                    sql_script = r'''
                                             if object_id('{0}') is not null  
                                             drop proc {0}
                                             '''.format(self.format_object_name(row[0]))
                cursor_target.execute(sql_script)  # drop current stored_procudre if exists
                conn_target.commit()
                # sync object it self
                cursor_target.execute(str(row[1]))  # execute create stored_procudre script
                conn_target.commit()
                print("*************sync sp: " + self.format_object_name(row[0]) + " finished *****************")
            except:
                print("------------------  sync "+row[0]+"sp error --------------------------")

        cursor_source.close()
        conn_source.close()
        cursor_target.close()
        conn_target.close()

    def sync_procudre(self, type):
        conn_source = self.get_connect(self.s_h, self.s_i, self.s_P, self.s_u, self.s_p, self.s_d)
        conn_target = self.get_connect(self.t_h, self.t_i, self.t_P, self.t_u, self.t_p, self.t_d)
        cursor_source = conn_source.cursor()
        cursor_target = conn_target.cursor()
        if (self.s_obj):
            for proc_name in self.s_obj.split(","):
                self.sync_dependent_object(proc_name)
                self.sync_procudre_by_name(type, proc_name)
        # sync all sp and function
        else:
            sql_script = r'''
                        select
                        QUOTENAME(schema_name(uid))+'.'+QUOTENAME(name),
                        OBJECT_DEFINITION(id)
                        from sys.sysobjects where xtype = upper('{0}') and  uid not in (16,19)
                     '''.format(type)
            cursor_source.execute(sql_script)
            for row in cursor_source.fetchall():
                self.sync_dependent_object(row[0])
                self.sync_procudre_by_name(type, row[0])



if __name__ == "__main__":

    '''
    sync = SyncDatabaseObject(s_h="127.0.0.1",
                              s_i = "sql2017",
                              s_P = 49744,
                              s_d="DB01",

                              t_h="127.0.0.1",
                              t_i="sql2017",
                              t_P=49744,
                              t_d="DB02",

                              s_obj_type = "sp",
                              s_obj = "dbo.sp_test01",

                              f="Y")
    sync.sync_procudre("p")
    '''

    p_s_h = ""
    p_s_i = "MSSQL"
    p_s_P = 1433
    p_s_d = ""

    p_s_u = None
    p_s_p = None

    p_s_obj = ""
    p_type = ""


    p_t_s = ""
    p_t_i = "MSSQL"
    p_t_P = ""
    p_t_d = ""

    p_t_u = None
    p_t_p = None

    # force overwrite target database object,default not force cover target database object
    p_f = "N"

    # sync obj type table|sp
    p_obj_type = None
    # sync whick database object
    p_obj = None

    if len(sys.argv) == 1:
        print(usage)
        sys.exit(1)
    elif sys.argv[1] == '--help':
        print(usage)
        sys.exit()
    elif len(sys.argv) >= 2:
        for i in sys.argv[1:]:
            _argv = i.split('=')

            # source server name
            if _argv[0] == '-s_h':
                p_s_h = _argv[1]
            # source server instance name
            if _argv[0] == '-s_i':
                if (_argv[1]):
                    p_s_i = _argv[1]
            # source server instance PORT
            if _argv[0] == '-s_P':
                if (_argv[1]):
                    p_s_P = _argv[1]
            # source database name
            if _argv[0] == '-s_d':
                p_s_d = _argv[1]

            if _argv[0] == '-s_u':
                p_s_u = _argv[1]

            if _argv[0] == '-s_p':
                p_s_p = _argv[1]



            if _argv[0] == '-t_h':
                p_t_h = _argv[1]

            if _argv[0] == '-t_i':
                if (_argv[1]):
                    p_t_i = _argv[1]

            if _argv[0] == '-t_P':
                if (_argv[1]):
                    p_t_P = _argv[1]

            if _argv[0] == '-t_d':
                p_t_d = _argv[1]


            if _argv[0] == '-t_u':
                p_t_u = _argv[1]

            if _argv[0] == '-t_p':
                p_t_p = _argv[1]



            if _argv[0] == '-f':
                if (_argv[1]):
                    p_f = _argv[1]


            # object type
            if _argv[0] == '-obj_type':
                if not (_argv[1]):
                    print("-obj_type can not be null (-obj=tab|-obj=sp|-obj=fn|-obj=type)")
                    exit(0)
                else:
                    p_obj_type = _argv[1]

            # object name
            if _argv[0] == '-obj':
                if (_argv[1]):
                    p_obj = _argv[1]




        # require para
        if p_s_h.strip() == "":
            print("source server host cannot be null")
            exit(0)
        if p_s_d.strip() == "":
            print("source server host database name cannot be null")
            exit(0)

        if p_t_h.strip() == "":
            print("target server host cannot be null")
            exit(0)

        if p_t_d.strip() == "":
            print("target server host database name cannot be null")
            exit(0)

        sync = SyncDatabaseObject(s_h=p_s_h,
                                  s_i=p_s_i,
                                  s_P=p_s_P,
                                  s_d=p_s_d,
                                  s_u=p_s_u,
                                  s_p=p_s_p,


                                  s_obj=p_obj,

                                  t_h=p_t_h,
                                  t_i=p_t_i,
                                  t_P=p_t_P,
                                  t_d=p_t_d,
                                  t_u=p_t_u,
                                  t_p=p_t_p,

                                  f=p_f)

        sync.validated_connect(p_s_h, p_s_i, p_s_P, p_s_d, p_s_u, p_s_p)
        sync.validated_connect(p_t_h, p_t_i, p_t_P, p_t_d, p_t_u, p_t_p)

        if(p_f.upper()=="Y"):
            confirm = input("confirm you want to overwrite the target object? ")
            if confirm.upper() != "Y":
                exit(0)



        print("-------------------------- sync begin ----------------------------------")
        print()

        if (p_obj_type == "tab"):
            # sync schema
            sync.sync_schema()
            # sync table schema
            sync.sync_table_schema()
            # sync data
            sync.sync_table_data()
        elif (p_obj_type == "sp"):
            # sync schema
            sync.sync_schema()
            # sync sp
            sync.sync_procudre("p")
        elif (p_obj_type == "fn"):
            # sync schema
            sync.sync_schema()
            # sync sp
            sync.sync_procudre("fn")
        elif (p_obj_type == "tp"):
            # sync schema
            sync.sync_schema()
            # sync sp
            sync.sync_table_variable(None)
        else:
            print("-obj_type is not validated")
        print()
        print("-------------------------- sync finish ----------------------------------")

 


版权声明:本文为[MSSQL123]原创文章
转载请带上:http://copyfuture.com/blogs-details/201906121409533082rop3ssjry9fudf
或:https://www.cnblogs.com/wy123/p/10991343.html



  1. nginx部署h5项目
  2. 性价比是王道,红米Note7系列全球销量已接近400万台
  3. 又到咳嗽“高发”的季节,我们都要重视!可别对孩子做这几种事!
  4. 宠物经济站上风口,中国市场能否诞生PetSmart这样的行业巨头
  5. 每日育儿——第16天 0-1岁育儿知识
  6. 首富的车就是不一样,一辆宝马顶10辆迈巴赫,光车玻璃就6厘米厚
  7. harbor使用自签名证书实现https
  8. 你投资德国房产了么?德国政府要“没收”了!
  9. Golang 连接 MongoDB
  10. 多媒体开发(14):媒体格式的概念
  11. 是真的?Google Earth发现:南极冰帽下有纳粹潜艇?
  12. 浅谈计算机系统——系统模式优化(WEB)
  13. 以当下人类的技术,可以造一艘排水量100万吨的航空母舰吗?
  14. 改变日本战国时代的谋反——本能寺之变的真相
  15. 父母最该警惕的事:1岁之后使用奶瓶的风险多,还不快戒掉!
  16. shiro简单的密码加盐与密码验证
  17. 军视界丨高清炫酷的军旅壁纸来啦
  18. 美国核动力无人机计划——复活的概念
  19. 苏宁最后的底牌——被“遗忘”的拉米雷斯
  20. WP7有约(一):课程安排
  21. 2019年IT互联网"春寒":百度腾讯换血 头条逆势扩招
  22. 【进制转换】
  23. [读书笔记]《刻意学习》
  24. 公众号如何利用流量广告变现?
  25. 车载双目ADAS(三):ADAS与自动驾驶相关公司
  26. 币市横盘3周之际,一文看懂比特币等5大主流币上涨动力
  27. Java 中的按值传递
  28. Java设计模式系列-工厂方法模式
  29. 腹有诗书气自华,今日推荐,纳兰容若-《蝶恋花》
  30. 一项正规制度为啥很快走歪了:以清朝的军费报销制度为例
  31. .Net Core 微服务容器系列基础目录篇
  32. 经济学人全球早报:腾讯10%中干去职,茅台股价800元,波音自己安全认证
  33. “未来公司”适合在哪生长? 西湖未来产业畅谈吸引海内外独角兽目光
  34. 柔宇否认碰瓷小米,但效果已经达到了
  35. 苹果第二季度大中华区营收同比下滑21.5%
  36. 相当有意思:华为芯片已遍布美国?
  37. PSA成“绯闻”对象!外媒日内瓦再访FCA,玛莎拉蒂与吉利确认无缘
  38. 范志毅与前妻的女儿21岁同济学编导 范大将军每月只给1千元生活费
  39. 在英国买房后会后悔吗?结果远比我想象的更美好!
  40. 《算法竞赛进阶指南》1.8总结与练习(2)
  41. 老司机:路上看到此几种车牌赶紧躲开,就算你开的豪车也一样
  42. 网易财经前端开发总结
  43. 辛芷蕾现身巴黎街头 自爆街头大片三组造型都很惊艳
  44. 首席出行要闻丨日本政府敲定自动驾驶汽车上路规则;Model 3推迟交付
  45. 安装与配置Flutter开发环境
  46. 中国历史上流传至今的十大家族
  47. DOTA2:梦幻联赛第七日 秘密2-0J.S VP苦战三局打破“恐EG”魔咒
  48. 台积电一季度营收71亿美元 下滑12%
  49. 网易开始学腾讯,模仿自走棋玩法!腾讯更厉害,模仿打败正版!
  50. 辽宁浪漫之行,这六个地方必须去一次,你必不可少的旅程
  51. 她是“台湾一姐”,因演戏被搭档一耳光打到脑震荡,留下后遗症
  52. 减少该死的 if else 嵌套
  53. 能让普拉多屈服的,只有哈弗H9
  54. 医生苦劝:想要为肝好,这5个习惯建议尽快戒掉
  55. 横扫勇士失败,赛后德帅大怒,公开批评新人,承诺将重用豪斯
  56. 人人车“嗑”瓜子 二手车电商奏响冰与火之歌
  57. 胜利被曝在家进行性交易,同伙承认为日本投资人招妓
  58. 关于程序员在30岁、35岁之后怎么办的新思考
  59. 为什么没有球状星系?这些科学研究一句点破。
  60. 韩雪主演音乐剧《白夜行》现场用录唱,制作方致歉并退票
  61. 服务端线程模型-线程池服务模型
  62. 科技: 数字断路器获得商用认证
  63. 5场3负!皇马欧冠将爆大冷?铁卫停赛或送荷甲豪门挺进8强
  64. 星系是如何形成的?如银河系,仙女座星系等?
  65. 设计模式(十六)迭代器模式 Iterator
  66. uml-----什么是UML
  67. 一男子玩江苏快三输的家破人亡是否真的有回血技巧规律呢!
  68. Sincere与RNG搭上末班车,DOTA2巴黎Major海选结束
  69. 安卓10代码披露:谷歌效仿苹果开发人脸识别
  70. 最高降12万!这四款合资品牌车型都将换代,现在购买性价比最高!
  71. SAP 客户信贷重建一则
  72. MinHook库的使用 64位下,过滤LoadLibraryExW
  73. 内核ring buffer -- kfifo
  74. 张钧甯新恋情曝光?高中好友出面证实,粉丝感觉无法理解
  75. 一线|趣头条回应总编辑离职:对现有业务没有影响 已有人选
  76. [洛谷P1731][NOI1999]生日蛋糕(dfs)(剪枝)
  77. 从零开始实现放置游戏(二)——框架搭建
  78. 当年我国获得瓦良格号后,为何没有马上开始改装,而是等了三年?
  79. 因涉嫌性贿赂,BIGBANG胜利退出演艺圈,多达十位女性受到牵连!
  80. 使用Lucene.Net实现全文检索
  81. linux下socket的心跳机制
  82. 豪车的世界你不懂 令人咋舌的选装件价格
  83. 贾跃亭做出艰难决定,4000万美元出售造车用地,FF91依然难产
  84. 新能源补贴将削减,各车企该何去何从?
  85. 企业网管用linux搭建邮件服务器为公司降本增效
  86. 61. 旋转链表
  87. MD文件图片base64自动编码
  88. 《鬼泣5》打通后 你觉得游戏又有哪些缺点?
  89. 在太空边缘出任务 美军U-2侦察机傲视全球
  90. 什么是贡嘎?
  91. EF生成实体自动添加数据库字段注释
  92. 程序员热议996工作制度:我生来不是为了工作的,我还要有生活
  93. 乾隆帝南巡的故事
  94. 在网页中实现对称加密传输
  95. 进口发动机配全新CVT,这才是广汽丰田C-HR好开又省油的原因
  96. 车友浅谈沃尔沃XC60,论安全,我只服沃尔沃!
  97. Visual Studio Code 中文界面设置
  98. 《C程序设计II》简易计算器,杨辉,数字杯子图形
  99. 最简大数据Spark-2.1.0
  100. IT产业的繁荣期已过,印度码农陷入失业潮

  1. 前端笔记之NodeJS(一)初识NodeJS&内置模块&特点(1744)
  2. Matlab 2019a 安装包下载以及安装和激活(1661)
  3. Delphi 开发微信公众平台 (二) 用户管理(1580)
  4. Python开发:部分第三方库无法在线安装解决方法(1550)
  5. React 与 React-Native 使用同一个 meteor 后台(1409)
  6. 《跃迁-成为高手的技术》之联机学习(1400)
  7. [深度应用]·实战掌握Dlib人脸识别开发教程(1323)
  8. 币安称 4000 万美元比特币被盗(1288)
  9. 使用 C 语言实现一个 HTTP GET 连接(1261)
  10. 独家 | 寒武纪二代芯片发布在即,提前解密如何挑战英伟达!(1259)
  11. WebGL three.js学习笔记 纹理贴图模拟太阳系运转(1215)
  12. C#读取excel文件提示未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序(1172)
  13. 【译】.NET Core 是 .NET 的未来(1133)
  14. 微软宣布 .NET 5 计划,支持跨平台、移动开发(1081)
  15. Linux学习(三):XShell连接虚拟机+开通22端口(1077)
  16. layui的table参数条件缓存问题(1050)
  17. 75条笑死人的知乎神回复,用60行代码就爬完了(997)
  18. Sublime Text3 最新版3207 安装及破解(918)
  19. 2019年程序员最值得学习的思维利器——任务分解(868)
  20. 10亿元巨贪山西吕梁原副市长张中生二审维持死刑判决(861)
  21. 小米有品员工签军令状,自动放弃年终奖!(815)
  22. 美方拟升级关税措施?中方:反制!(792)
  23. 科学家在太平洋水域发现奇特的“砷呼吸”微生物(788)
  24. 声明与定义的区别(786)
  25. 绿盟科技互联网安全威胁周报NSFOCUS-19-13(775)
  26. 【预警通告】Weblogic反序列化远程代码执行漏洞(769)
  27. css-博客样式初体验(741)
  28. Visual Studio 2019 正式发布,重磅更新,支持live share(728)
  29. Vue之路由(725)
  30. 【预警通告】Apache Tomcat远程代码执行漏洞CVE-2019-0232(710)
  31. 【威胁通告】Oracle全系产品2019年4月关键补丁更新(687)
  32. SQL简介及MySQL的安装目录详解(671)
  33. 5月13日公告精读丨一字跌停后,这只300亿市值的白马股出来澄清了(641)
  34. 如果想转行学习WEB前端,这样学也许更加利于找工作(632)
  35. 彭博社:苹果A13芯片即将产量 新iPhone"浴霸"无疑(575)
  36. K8s集群安装--最新版 Kubernetes 1.14.1(547)
  37. MongoDB创建数据库和删除数据库05-14学习笔记(529)
  38. 吴奇隆当爹!前妻马雅舒开心复出拍戏,颜值吸睛气质超赞(519)
  39. PJzhang:Lucifer1993的struts-scan漏洞全量检测工具(516)
  40. Confluence SSRF及远程代码执行漏洞处置手册(515)
  41. 英媒:阿里将允许外国零售商在阿里平台上销售商品(512)
  42. 舍命生子产妇吴梦丈夫怒斥:没抢肺源不是精神分裂,网友断章取义(506)
  43. Visual Studio 2019 正式发布(499)
  44. [翻译] Visual Studio 2019: 极速编码. 智能工作. 创造未来.(472)
  45. 机器学习 ML.NET 发布 1.0 RC(464)
  46. 刘强东身边的CXO还有谁“幸存”(458)
  47. 阿里巴巴2018年纳税516亿元 同比增40%(458)
  48. 针对django2.2报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 9737: ill....(441)
  49. 马光远:全球货币政策进入摇摆期,包括房价的资产价格何去何从(417)
  50. 【硬盘版】下载利器IDM+优特(uTorrent)BT下载器类(416)
  51. 太奇葩!买100元债只给1.63元购物券和1.11元现金?网友炸锅:得买多少债券才能换一双鞋(408)
  52. 雷军清华演讲实录:小米9年的创新、变革与未来(408)
  53. 我司使用了六年的分布式锁(406)
  54. Webpack 4教程 - 第八部分 使用prefetch和preload进行动态加载(392)
  55. Spring Boot 2.1.5 正式发布,1.5.x 即将结束使命!(390)
  56. 他联系叙恐怖分子“卖军火”,称能搞到2000枚导弹,关键时刻中国警察出手(390)
  57. F#周报2019年第14期(389)
  58. 《最强大脑》要垮?桑洁魏坤琳出轨细节被扒,戚薇才是神助攻(373)
  59. 直认与老公感情淡了!27岁TVB上位女星:我们不是好熟(369)
  60. 报告显示:一季度中国家庭总资产缩水而消费支出增加(360)
  61. 谁是苏小明饭局爆粗偷拍者?知情人称另有其人(348)
  62. 苹果应用商店被判垄断?然而并没有(342)
  63. 那些年,我们一起看的毛片(340)
  64. linux系统安装cdcfordb2udb(339)
  65. 迪玛希好惨!昨晚《歌手》为声入人心男团帮帮唱,却再被指控侵权(339)
  66. 华电教授孙玉兵被指与昔日同学共同学术造假,多所高校调查(333)
  67. 女友被曝插足许志安郑秀文婚姻 知情人透露马国明已下定决心分手(331)
  68. 智慧停车场系统开发建设解决方案(329)
  69. 如何设置使chrome新标签页中打开链接自动跳转到新标签页?(327)
  70. F#周报2019年第15期(321)
  71. spring-cloud-sleuth+zipkin源码探究(321)
  72. 威廉王子出轨凯特王妃闺蜜? 外媒称婚外情致兄弟反目(312)
  73. 深度学习python的配置(Windows)(311)
  74. 许志安出轨视频系蓄谋偷拍?司机被曝收40万装红外摄像头(309)
  75. 真实!这部8.5分的缉毒剧,毒贩公然贿赂警察:80万,把我放出去(306)
  76. NodeJs之邮件(email)发送(303)
  77. 视觉中国深夜道歉:全面配合监管部门彻底积极整改(301)
  78. 赌命生子九个月后,吴梦离世:前半辈子任性了,我用生命买单(299)
  79. 新更新kb4493472导致无法正常开机(294)
  80. 她做个半永久眉毛就被说整容了?(288)
  81. 山东庆云民企3000亩土地被贱卖 国企接盘拟转性(286)
  82. 韦杰落网,金诚集团终局(285)
  83. 华为推出方舟编译器 称可提升安卓系统效率(284)
  84. 机器学习基石笔记:01 The Learning Problem(282)
  85. Google AI 系统 DeepMind 高中数学考试不及格(282)
  86. 张丹峰出轨最新锤来了!毕滢的朋友圈简直刷新下限啊!(277)
  87. 不要996!程序员创建955.WLB不加班公司名单,GitHub周榜第二(275)
  88. 第一次使用VS Code时你应该知道的一切配置(274)
  89. 读书笔记之《漫画算法:小灰的算法之旅》(273)
  90. React Native升级方法——升级到最新版本0.59(273)
  91. axios(封装使用、拦截特定请求、判断所有请求加载完毕)(272)
  92. “国防”靠美国? 韩国瑜=马英九2.0? 走着瞧(269)
  93. 吹爆惠英红,《铁探》这位霸道总警司超带感!真乃港剧罕见大女主(262)
  94. 河南汝州农商行“百万丢款案”调查,两级法院现“判决书打架”(258)
  95. Codejam Qualification Round 2019(251)
  96. 堪称神器的Chrome插件(249)
  97. Weblogic CVE-2019-2647等相关XXE漏洞分析(248)
  98. Leetcode刷题指南和top100题目(248)
  99. CentOS7 部署zabbix4.2及添加客户端(241)
  100. 中国海军的逆袭之路(240)

  1. 两个搭班子的“老虎”,在省会城市大肆敛财
  2. Redis set(集合)相关命令
  3. python算法与数据结构-希尔排序(35)
  4. 火星发现高浓度甲烷:火星存在生命?看了网友评论。。。
  5. 为什么植物不会死于癌症?
  6. 阿里P8架构师详解Java性能调优策略
  7. Linux编程之gdb(二)
  8. MYSQL 第四天 表子查询
  9. mysql 有关子查询的特定关键字
  10. 多线程学习(二)
  11. iOS六年开发经验被实习生替代,所谓的“经验”一文不值 ?
  12. HDU-盐水的故事
  13. 《数据挖掘导论》实验课——实验七、数据挖掘之K-means聚类算法
  14. Python:设计模式之状态模式
  15. [清华集训2017] 生成树计数
  16. Matlab Robotics Toolbox 仿真计算:Kinematics, Dynamics, Trajectory Generation
  17. Java多线程(二):Thread类
  18. Windows性能计数器监控实践
  19. 量子逻辑门
  20. 张家口投资4000万水幕电影被指层层转包拖欠工程款,官方称正在了解情况
  21. 本田诉长城汽车两起专利侵权案开庭,索赔2000余万元
  22. MongoVUE(1.6.9.0)登录提示:Connection was refused的解决办法
  23. 山东16岁女孩中考前被父亲杀害:长期遭遇家暴,被催着早点打工挣钱
  24. 净利润暴涨221倍,两次创业成功,澜起科技冲击科创板芯片第一股
  25. SAP中的数据库表索引
  26. 【搜索引擎】Solr最新安装以及通过关系型数据库(MySQL,Oracle,PostgreSQL)导入数据
  27. 高阶函数 - Higher Order Function
  28. 饿了么推代扔垃圾:一单12块 跑腿范围3公里
  29. 介绍几款有用的工具
  30. OO第四单元作业小结
  31. 使用 docker 部署常用的开发环境
  32. Python————魔术方法
  33. 阿里巴巴 Java 开发手册 1.4.0
  34. 使用Docker部署Spring Boot项目
  35. Java NIO学习系列一:Buffer
  36. 【nodejs原理&源码杂记(8)】Timer模块与基于二叉堆的定时器
  37. Java SimpleDateFormat 日期-时间格式参数
  38. ElasticSearch简介
  39. Redis list(列表)相关命令
  40. Java多线程(二):Thread类
  41. 每日一问:不一样的角度吐槽下 DataBinding
  42. 优动漫PAINT提取线稿功能-亮度转化透明度
  43. 黄磊不仅把黄多多教得很好,他对张子枫、彭昱畅的态度也有学问
  44. ConcurrentHashMap之tableSizeFor()方法透析(位运算运用)
  45. 郭台铭此时离开是不是一个好选择?
  46. 检察机关依法对缪瑞林、邢云、钱引安三案提起公诉
  47. Python 装饰器
  48. 不被大神Hinton认同,否定现有同行成果,谷歌这篇烧脑研究最终拿下ICML2019最佳论文
  49. 人人车再陷危局:总部裁员60% 资金迷雾仍待揭开
  50. 『Python基础』第二节: Python简介及入门
  51. 社科院:后续需求不足 部分三四线城市房价将下跌
  52. 刚刚,格力官宣再怼奥克斯!董明珠称将战斗进行到底
  53. HTTP认证之摘要认证——Digest(一)
  54. 印度要求摩托车厂商在2个星期内提交电动化转型计划
  55. 绿盟科技互联网安全威胁周报 NSFOCUS-19-25
  56. 中国银行新掌门敲定:刘连舸出任党委书记、拟任董事长
  57. 这家公司把三星、联想、微软等7家公司给告了 侵犯其触摸屏专利
  58. 比尔盖茨痛惜微软没成为安卓,但微软到底错哪了?
  59. Python:使用2to3将Python2转Python3
  60. 5个你可能不知道的html5语义化标签
  61. Redis(三)、Redis主从复制
  62. 守护“人造小太阳”!我国成功研制高速高精度激光汤姆逊散射仪
  63. 马云发布“英雄帖”:征集世界十大难题与罗汉堂西湖论剑
  64. DDD中的聚合和UML中的聚合以及组合的关系
  65. 构建和管理有效API市场的关键步骤
  66. http客户端-性能比较系列-第一篇-单线程
  67. C#中await/async闲说
  68. 1970年前中国造的最大军舰是谁?清朝一艘风帆战舰保持纪录98年
  69. C# Winfrom 简单的运用Timer控件
  70. 36小时极客嘉年华!FISCO BCOS黑客马拉松报名启动
  71. 这部8年前的电影,见证了舒淇的完整魅力
  72. NVIDIA统治了AI加速云市场 已占4大云平台97.4%份额
  73. python环境搭建
  74. Maven 虐我千百遍,我待 Maven 如初恋
  75. 二进制和十进制相互转换、位移运算
  76. OO第四单元总结暨学期总结
  77. Haproxy 开启日志记录
  78. kubernetes高级之pod安全策略
  79. 印度最大电商Flipkart拟2022年前上市 沃尔玛或退出
  80. Nordic SDK nrf_setion和nrf_section_iter模块分析
  81. pandas越来越难学,只能自己找趣味了,你该这么学,No.11
  82. 农业农村部谈乡村治理:天价彩礼让人“娶不起”
  83. skywalking-agent 与docker组合使用
  84. 冻,也不冻——冻土中的冰和水
  85. Web Api之Cors跨域(干货)---大家一定要看清我写的内容哦
  86. 金立手机加速退场:拍卖多项专利
  87. 15天全清洁能源供电,青海刷新世界纪录
  88. 13.Python略有小成(装饰器)
  89. Java并发——阿里架构师是如何巧用线程池的!
  90. 长沙中考乌龙:试题没有正确答案 所有考生满分
  91. 前端Vue项目——初始化及导航栏
  92. 淘宝服务端高并发分布式架构演进之路
  93. BigDecimal 使用浅析
  94. wget下载阿里云oss的文件报错403
  95. CMDB(资产管理系统) day1
  96. Fabric1.4源码解析:Peer节点背书提案过程
  97. 程序员除了会CRUD之外,还应该知道什么叫CQRS!
  98. Redis hash(哈希)相关命令
  99. 超级无线充:东京大学研发出3㎡+360°无线充电技术
  100. ElasticSearch导入txt文本或者json文本