频道直达 - 专题 - 新闻 - 技巧 - 组网 - 开发 - 安全 - web编程 - 图像 - 操作系统 - 数据库 - 教育 - 旅游 - 健康 - 时尚 - 驱动 - 软件 - 游戏 - 多媒体 - ERP - 讨论组

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

来源: 作者:郑靖华, 出处:巧巧读书 2007-04-09 进入讨论组
上一页 1 2 3 4 5 下一页 

格式化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 ]	then		echo $3	fi	TABLEINBOTH=""	for tblname in `awk -F"." '{printf("%s\n", $2);}' $1 | awk -F"\""	'{printf("%s ", $2)}' | sort`	do		grep -i "\"$tblname\"" $2 1>/dev/null 2>&1		if [ ! $? -eq 0 ]		then			if [ $# -eq 3 ]			then				echo $tblname			fi		else			TABLEINBOTH="${TABLEINBOTH} ${tblname}"		fi	done}

对于仅在旧数据库中存在的表,需要从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: " $3	awk -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);				else					printf("%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.sql	TMPNEWTBLFLD=.tmpfld.fld.fld	rm -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=1	Select=""	Into=""	for fldname in `cat ${TMPNEWTBLFLD}`	do		grep "\"${fldname}\"" $1 1>/dev/null 2>&1		if [ $? -eq 0 ]		then			# 2.2. 取出在新旧两表中都有的字段名,加入到select子句和into子句中			if [ ${isFirstFeild} -eq 0 ]			then				Select="${Select},"				Into="${Into},"			fi			Select="${Select} ${fldname}"			Into="${Into} ${fldname}"			isFirstFeild=0		else			# 2.3. 取出仅在新表中出现的字段,如果该字段不允许null,			#      且没有设置default值,则按以下原则取默认值放到select子句中,			#      并将字段名放到into子句中			grep "\"${fldname}\"" $2 | grep "not null" 1>/dev/null 2>&1			if [ $? -eq 0 ]			then				grep "\"${fldname}\"" $2 | grep "with default" 1>/dev/null 2>&1				if [ ! $? -eq 0 ]				then					if [ ${isFirstFeild} -eq 0 ]					then						Select="${Select},"						Into="${Into},"					fi					# 计算默认值					# 对于新增的字符型字段,默认值为'';					# 对于新增的数值型字段,默认值为0;					# 对于新增的TIMESTAMP字段,默认值为'';					# 对于新增的SERIAL开字段,默认值为0;					# 对于新增的DATE字段,默认值为;					# 对于新增的DATETIME字段,默认值为;					Const=`grep "\"${fldname}\"" $2 | awk '{						if(match($2, "int") > 0) # integer, smallint, bigint							printf("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, varchar							printf("\" \"");						else if($2 == "timestamp")							printf("current timestamp");						else if($2 == "date")							printf("current date");						else if($2 == "time")							printf("current time");						else							printf("\" \"");					}'`					Select="${Select} ${Const}"					Into="${Into} ${fldname}"					isFirstFeild=0				fi			fi		fi	done	tablefullname=`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} >> $3	rm -f ${TMPSQLFILE}	rm -f ${TMPNEWTBLFLD}}echo "table in both database:"TABLEINBOTH="`echo ${TABLEINBOTH} | tr [:upper:] [:lower:]`"echo > ${UNLOADSQLFILE}for tblname in ${TABLEINBOTH}do	gettableschema ${tblname} ${OLDDBSCHEMATMP} ${OLDTBLSCHEMA}	gettableschema ${tblname} ${NEWDBSCHEMATMP} ${NEWTBLSCHEMA}	diff ${OLDTBLSCHEMA} ${NEWTBLSCHEMA} 1>/dev/null 2>&1	if [ ! $? -eq 0 ]	then		# 如果有不同,则生成卸出数据的SQL脚本		echo "different table:" ${tblname}		genunloadsql ${OLDTBLSCHEMA} ${NEWTBLSCHEMA} ${UNLOADSQLFILE} ${tblname} ${DB2MOVELISTFILE}	else		echo "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 `do	echo "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系统下的一个文件名称,每一个表空间使用不同的文件名。也可以根据对数据库中数据分布的估计,调整表空间的大小。

本文:http://www.qqread.com/db2/d307987.html 更多文章 更多内容请看DB2DB2中的数据处理数据库专栏专题,或进入讨论组讨论。
上一页 1 2 3 4 5 下一页 
收藏此文】【 】【打印】【关闭
相关图文阅读
频道图文推荐
健 康 咨 询
时 尚 咨 询
巧巧读书宗旨
相关专题
讨论组问题推荐
站内各频道最新更新文档
站内最新制作专题
热门关键字导读
Photoshop教 程照片处理 照片制作 PS快捷键 抠图
计 算 机 故 障XP系统修复
艺 术 与 设 计设计 流媒体 设计欣赏 边框
计 算 机 安 全ARP
站内频道文章精选
巧巧电脑频道编辑信箱  告诉我们您想看的专题或文章