WEB开发网
开发学院数据库DB2 用 AWK 实现 DB2 数据库 Schema 的同步 阅读

用 AWK 实现 DB2 数据库 Schema 的同步

 2007-04-09 22:17:11 来源:WEB开发网   
核心提示: ·数据库人员面试:sql server(WINDOWS平台上强大的数据库平台)常用测试·Oracle(大型网站数据库平台)数据库客户端的安装和配置·PHP连接数据库的方法(3)·Oracle(大型网站数据库平台)数据库网络的安装和配置(1)·用js
    ·数据库人员面试:sql server(WINDOWS平台上强大的数据库平台)常用测试
    ·Oracle(大型网站数据库平台)数据库客户端的安装和配置
    ·PHP连接数据库的方法(3)
    ·Oracle(大型网站数据库平台)数据库网络的安装和配置(1)
    ·用jsp(SUN企业级应用的首选)从数据库中读取图片并显示在网页
    ·[冷枫推荐]:数据库操作,内外联查询
    ·PHP中使用类对数据库进行操作
    ·图解MySQL(和PHP搭配之最佳组合)数据库的安装和操作 (1)
    ·InterBase 数据库函数库
    ·利用外部命令Oralce数据库导入导出

格式化SCHEMA文件

为了比较新旧数据库的SCHEMA,我们需要将两个SCHEMA文件转换成统一格式,包括:将所有大写替换成小写;删除所有行首的空格;将多个空格合并成1个空格。其中,空格包括制表符(Tab)和空格字符(Space)。

使用以下命令组合格式化SCHEMA文件:


    sed -e "s/^[    ]*//" \    -e "s/[     ][      ]*/ /g" \    ${OLDDBSCHEMA} | tr [:upper:] [:lower:] > ${OLDDBSCHEMATMP}    

取得新旧数据库的table清单

定义如下函数,从数据库的SCHEMA文件中取得其中的table清单。这个函数适用于由db2look生成的、DB2数据库的DDL文件。


# 根据数据库的SCHEMA文件,取得其中的table清单# $1. 数据库的SCHMEA文件# $2. 输出的table清单文件gettbllist(){        grep -i "^[     ]*create[       ][      ]*table" $1 > $2.tmp        sed -e "s/^[    ]*CREATE[       ][      ]*TABLE//" \            -e "s/(.*$//" \            $2.tmp | sort > $2        rm $2.tmp}

找出仅在旧库或者仅在新库独有的表

定义如下函数,取出仅在指定数据库SCHEMA中存在的table的清单。这个函数适用于由db2look生成的、DB2数据库的DDL文件。


# 取出仅在第一个参数指定的数据库SCHEMA中存在的表的名称清单# $1: 待分析的数据库SCHEMA文件# $2: 用作参照的数据库SCHEMA文件# $3: 屏幕输出的提示信息gettableonlyinone(){if [ $# -eq 3 ]thenecho $3fiTABLEINBOTH=""for tblname in `awk -F"." '{printf("%s\n", $2);}' $1 | awk -F"\""'{printf("%s ", $2)}' | sort`dogrep -i "\"$tblname\"" $2 1>/dev/null 2>&1if [ ! $? -eq 0 ]thenif [ $# -eq 3 ]thenecho $tblnamefielseTABLEINBOTH="${TABLEINBOTH} ${tblname}"fidone}

对于仅在旧数据库中存在的表,需要从db2move.lst中删除该表对应的行。

对于仅在新数据库中存在的表,需要根据需要有选择的从新数据库中卸出数据并装入到新数据库中。

找出结构不同的表,并生成卸出数据的SQL脚本

通过以下步骤,找到在新旧数据库中都存在,并且结构发生了变化的table,并生成重新卸出数据的SQL语句。


# 根据数据库的SCHEMA文件,取得指定table的SCHEMA# $1: table名称# $2: 数据库的SCHEMA文件,需要先做格式化# $3: 输出的表的SCHEMA文件gettableschema(){#echo "table name: " $1#echo "dbschema name: " $2#echo "outfile name: " $3awk -v_tblname=$1 'BEGIN{isThisTable = 0;}{if($1 == "create" && $2 == "table" && match($0, "\""_tblname"\"") > 0){isThisTable = 1;printf("create table %s (\n", _tblname); #### )}else if(isThisTable == 1){if(match($0, ";") > 0){isThisTable = 0;if($1 == "in")printf("; \n", $0);elseprintf("%s\n", $0);}else if(match($0, "timestamp not null with default ,") > 0){printf("%s timestamp not null with default current timestamp , \n", $1);}else{printf("%s\n", $0);}}}' $2 > $3}# 生成卸出指定表的数据的SQL脚本# $1. 旧数据库的SCHEMA文件# $2. 新数据库的SCHEMA文件# $3. 输出的卸出指定表的数据的SQL脚本文件名# $4. 指定的表名# $5. db2move卸出文件时的清单文件genunloadsql(){TMPSQLFILE=.tmpsql.sql.sqlTMPNEWTBLFLD=.tmpfld.fld.fldrm -f ${TMPSQLFILE}# 1. 用新的表结构创建一个临时表awk '{if(NR > 1){gsub("\"", "", $1); # remove character "printf("%s\n", $0);}else{printf("create table sihitranstmptbl (\n"); # )}}' $2 > ${TMPSQLFILE}# 2. 生成insert into transtmptbl (...) select ... from <oldtbl>的SQL# 2.1. 生成新旧两个表的字段列表awk '{if(NR > 1 && $1 != ";"){gsub("\"", "", $1); # remove character "printf("%s\n", $1);}}' $2 > ${TMPNEWTBLFLD}isFirstFeild=1Select=""Into=""for fldname in `cat ${TMPNEWTBLFLD}`dogrep "\"${fldname}\"" $1 1>/dev/null 2>&1if [ $? -eq 0 ]then# 2.2. 取出在新旧两表中都有的字段名,加入到select子句和into子句中if [ ${isFirstFeild} -eq 0 ]thenSelect="${Select},"Into="${Into},"fiSelect="${Select} ${fldname}"Into="${Into} ${fldname}"isFirstFeild=0else# 2.3. 取出仅在新表中出现的字段,如果该字段不允许null,#      且没有设置default值,则按以下原则取默认值放到select子句中,#      并将字段名放到into子句中grep "\"${fldname}\"" $2 | grep "not null" 1>/dev/null 2>&1if [ $? -eq 0 ]thengrep "\"${fldname}\"" $2 | grep "with default" 1>/dev/null 2>&1if [ ! $? -eq 0 ]thenif [ ${isFirstFeild} -eq 0 ]thenSelect="${Select},"Into="${Into},"fi# 计算默认值# 对于新增的字符型字段,默认值为'';# 对于新增的数值型字段,默认值为0;# 对于新增的TIMESTAMP字段,默认值为'';# 对于新增的SERIAL开字段,默认值为0;# 对于新增的DATE字段,默认值为;# 对于新增的DATETIME字段,默认值为;Const=`grep "\"${fldname}\"" $2 | awk '{if(match($2, "int") > 0) # integer, smallint, bigintprintf("0");else if(match($2, "numeric") > 0)printf("0.0");else if(match($2, "decimal") > 0)printf("0.0");else if(match($2, "double") > 0)printf("0.0");else if(match($2, "float") > 0)printf("0.0");else if(match($2, "real") > 0)printf("0.0");else if(match($2, "char") > 0) # char, varcharprintf("\" \"");else if($2 == "timestamp")printf("current timestamp");else if($2 == "date")printf("current date");else if($2 == "time")printf("current time");elseprintf("\" \"");}'`Select="${Select} ${Const}"Into="${Into} ${fldname}"isFirstFeild=0fififidonetablefullname=`grep -i "\"$4\"" $5 | awk -F"!" '{printf("%s", $2);}'`echo "insert into sihitranstmptbl (${Into}) select ${Select} from${tablefullname} ;" >> ${TMPSQLFILE}# 3. 将临时表中的数据导出到文件中Unloadfile=`grep -i "\"$4\"" $5 | awk -F"!" '{printf("%s", $3);}'`echo "export to ${Unloadfile} of ixf select * from sihitranstmptbl ;">> ${TMPSQLFILE}# 4. 删除临时表echo "drop table sihitranstmptbl ;" >> ${TMPSQLFILE}cat ${TMPSQLFILE} >> $3rm -f ${TMPSQLFILE}rm -f ${TMPNEWTBLFLD}}echo "table in both database:"TABLEINBOTH="`echo ${TABLEINBOTH} | tr [:upper:] [:lower:]`"echo > ${UNLOADSQLFILE}for tblname in ${TABLEINBOTH}dogettableschema ${tblname} ${OLDDBSCHEMATMP} ${OLDTBLSCHEMA}gettableschema ${tblname} ${NEWDBSCHEMATMP} ${NEWTBLSCHEMA}diff ${OLDTBLSCHEMA} ${NEWTBLSCHEMA} 1>/dev/null 2>&1if [ ! $? -eq 0 ]then# 如果有不同,则生成卸出数据的SQL脚本echo "different table:" ${tblname}genunloadsql ${OLDTBLSCHEMA} ${NEWTBLSCHEMA} ${UNLOADSQLFILE} ${tblname} ${DB2MOVELISTFILE}elseecho "same table:" ${tblname}fidone

其中,TABLEINBOTH是由上一步(找出仅在旧库或者新库中独有的表)的副产品。

注意,上述程序中,并没有处理新旧table中均有并且字段类型不同的字段,这种情况可以在卸出数据时按需要手工编辑生成的SQL脚本。

生成的SQL脚本名称叫"unload.sql"。在PC机上的DB2命令窗口中执行:


db2 -z result.txt -tvf unload.sql

其中,"-z"选项将执行结果同时输出到屏幕及文件result.txt中。执行结束时,需要查看result.txt,如果其中有错误提示,请按需要修改unload.sql。修改之后,再重新执行上述命令,直到所有SQL命令均执行无错为止。

取得新SCHEMA的表空间名称

通过以下步骤,找出新数据库使用的表空间的名称,并给出创建数据库缓冲池及表空间的SQL的建议。


# 8. 根据新数据库SCHEMA文件取得tablespace的名称清单#    并给出创建缓冲池及tablespace的SQL建议echo "创建缓冲池的命令: "echo "create bufferpool BF81 size 10000 pagesize 8 K"echo "创建表空间的命令: "echo "--------------------------------------------------------------"for tblspace in ` grep -i "^[ ]*in[ ]" ${NEWDBSCHEMA} | grep ";" | awk '{printf("%s\n", $2);if(NF > 3){if($3 == "INDEX" && $4 == "IN"){printf("%s\n", $5);}}}' | sort | uniq `doecho "CREATE TABLESPACE ${tblspace} PAGESIZE 8K MANAGED BY DATABASE USING(FILE '<filename>' 50000) bufferpool bf81"doneecho "--------------------------------------------------------------"

执行结果类似于:

创建缓冲池的命令:


create bufferpool BF81 size 10000 pagesize 8 K

创建表空间的命令:


--------------------------------------------------------------CREATE TABLESPACE "DATATBS00_8K" PAGESIZE 8K MANAGED BY DATABASE USING (FILE'<filename>' 50000) bufferpool bf81CREATE TABLESPACE "DATATBS01_8K" PAGESIZE 8K MANAGED BY DATABASE USING (FILE'<filename>' 50000) bufferpool bf81CREATE TABLESPACE "DATATBS02_8K" PAGESIZE 8K MANAGED BY DATABASE USING (FILE'<filename>' 50000) bufferpool bf81CREATE TABLESPACE "IDXTBS00_8K" PAGESIZE 8K MANAGED BY DATABASE USING (FILE'<filename>' 50000) bufferpool bf81CREATE TABLESPACE "IDXTBS02_8K" PAGESIZE 8K MANAGED BY DATABASE USING (FILE'<filename>' 50000) bufferpool bf81CREATE TABLESPACE "STATICTBS00_8K" PAGESIZE 8K MANAGED BY DATABASE USING(FILE '<filename>' 50000) bufferpool bf81CREATE TABLESPACE "USERSPACE1" PAGESIZE 8K MANAGED BY DATABASE USING (FILE'<filename>' 50000) bufferpool bf81--------------------------------------------------------------

在实际创建表空间时,需要将其中的"<filename>"替换成Windows系统下的一个文件名称,每一个表空间使用不同的文件名。也可以根据对数据库中数据分布的估计,调整表空间的大小。

上一页  1 2 3 4 5  下一页

Tags:AWK 实现 DB

编辑录入:coldstar [复制链接] [打 印]
赞助商链接