- 孤荷凌寒自学python第四十八天通用同一数据库中复制数据表函数
- 孤荷凌寒自学python第四十七天通用跨数据库同一数据库中复制数
- 孤荷凌寒自学python第四十九天继续研究跨不同类型数据库的通用
- 孤荷凌寒自学python第五十八天成功使用python来连接上远
- 孤荷凌寒自学python第十八天python变量的作用范围
- 孤荷凌寒自学python第二十八天python的datetime
- 孤荷凌寒自学python第五十二天初次尝试使用python读取F
- 孤荷凌寒自学python第四十八天通用同一数据库中复制数据表函数
- 孤荷凌寒自学python第五十三天使用python写入和修改Fi
- 孤荷凌寒自学python第五十四天使用python来删除Fire
#将各种复杂的对数据库类型的描述,如3,8等数值表示的字段类型与,windows系统中的system.string,之类的描述,统一修改为数据库能够在定义字段类型时直接使用的描述字符串
def getStandardFieldTypeGhlh(strin,dbtype='acc',isShowMsg=False):
'''
将各种复杂的对数据库类型的描述,如3,8等数值表示的字段类型与,windows系统中的system.string,之类的描述,统一修改为数据库能够在定义字段类型时直接使用的描述字符串
'''
globalmdbErrString
mdbErrString=''
strI=""
try:
strI=str(strin)
strI.lower()
strI=strI.replace('system.','') #windows系统中,以及其它一些语言中对数据类型的描述的字符串中,可以包含有system.前缀
strI=strI.replace('.','') #去掉多余的点
dbtype=dbtype.lower()
ifdbtype=='access':
dbtype='acc'
except:
pass
#--------------------------------------------------------
try:
if strI=='':
mdbErrString ="因为传入的要识别的数据库的字段类型为空,因此无法识别,只能识别成【文本类型】【text】。" + '\n此函数由【孤荷凌寒】创建qq:578652607'
ifisShowMsg == True:
msgbox(mdbErrString)
ifdbtype!='acc' and dbtype!='mysql':
return 'ntext'
else:
return 'text'
#---正式识别开始---------------------
if strI in ("int32", "3", "int","int16", "integer", "long","smallint","tinyint","mediumint"):
ifdbtype=='acc':
return 'long'
else:
return "int" #多数数据库在这种情况下要额外指定长度
#----------------------
if strI=='bigint':
ifdbtype=='acc' or dbtype=='sqlite':
return 'int'
else:
return 'bigint'
#-----------------
elif strI in ("memo","longtext","mediumtext"):
ifdbtype=='acc':
return "memo"
elifdbtype=='mysql':
return "longtext"
else:
return 'ntext'
#------------------
elif strI in ("str","string","8","varchar","char","text","nvarchar","tinytext"):
if dbtype=='mysql' ordbtype=='acc':
return "varchar" #在这种情况下都需要指定长度
else:
return "nvarchar" #在这种情况下都需要指定长度
#------------------
elif strI in ("datetime","7"):
ifdbtype=='sqlite':
return "date"
else:
return "datetime"
#----------------
elif strI=="date":
ifdbtype!='acc':
return "date"
else:
return "datetime"
#-----------------
elif strI=="time":
ifdbtype!='acc':
return "time"
else:
return "datetime"
#-----------------
elif strI in ("single", "4", "real"):
return "real"
#----------------
elif strI in ("double", "5", "float"):
return "float"
#----------------
elif strI in ("boolean", "11", "bit","bool"):
ifdbtype=='mssql' or dbtype=='acc':
return "bit"
else:
return 'boolean'
#-----------------
elif strI in ("byte[]", "8209", "image", "binary", "ole"):
#---image为微软专用的OLE,"Binary"为 二进制,在sqlite中使用blob,表示二进制大数据
ifdbtype=='acc' or dbtype=='mssql':
return "Image"
elifdbtype=='sqlite':
return 'blob'
else:
return 'binary'
#-------这是真正的全精度数据
elif strI in ("decimal", "14", "money","numeric"):
ifdbtype=='sqlite':
return 'numeric'
elifdbtype=='acc':
return 'money'
else:
return 'decimal'
#--------------
elif strI=="timestamp":
ifdbtype=='acc':
return 'double'
else:
return 'timestamp'
#------自动编号------
elif strI in ("auto", "autocount", "autonumber", "autono", "autoincrement","auto_increment"):
ifdbtype=='mysql':
return 'int NOT
NULL auto_increment'
elifdbtype=='acc':
return 'counter
NOT NULL PRIMARY KEY'
elifdbtype=='mssql':
return 'int
identity(1,1)'
else:
#--sqlite-----------------
return "integer
PRIMARY KEY AUTOINCREMENT NOT NULL"
#--------
else:
#其余情况,全部识别为 text
ifdbtype!='acc' and dbtype!='mysql':
return 'ntext'
else:
return 'text'
except Exception ase:
mdbErrString='尝试将各种不同的对数据库字段类型的描述转换为标准字段类型描述时出错:' + str(e) + '\n此函数由【孤荷凌寒】创建qq号是578652607'
ifisShowMsg==True:
msgbox(mdbErrString)
#------------------------------------------
ifdbtype!='acc' and dbtype!='mysql':
return 'ntext'
else:
return 'text'
else:
pass
finally:
pass
#-----复制表的操作----------------
def copyDbTableGhlh(con,strst,strtt,dbtype='acc',strfieldlist='*',strprimarykey='id',strprimarykey2='',isstrprimarykeyautoaccount=False,isstrprimarykey2autoaccount=False,strprimarykeytype='integer',strprimarykey2type='str',iscopydata=False,isDelExitsTable=False,isShowMsg=False):
'''
此函数在同一数据库内,进行表的复制,可以指定只复制表的结构还是连同表中数据也一起复制。不完美,部分情况下不能成功,特别是要同时复制表中的数据的情况下,有时不会成功。
con:数据库连接对象;
dbtype:指定数据为的标识:acc(access),mssql,mysql,sqlite;
strfieldlist:要从源表中复制哪些列,默认复制全部列。此参数对mysql数据库无效,mysql数据库始终为*即全部字段。
strprimarykey:指定复制表完成后,要指定哪个列名为 主键。此参数对Mysql数据库无效。
strprimarykey2:指定复制表完成后,要指定的第二个为主键的列名,此参数只对Mssql数据库有效,对其它数据库没有作用。但Mssql数据库也只能在纯复制表结构的情况下使用两个主键列。
isstrprimarykeyautoaccount:与上两个参数相关,指定要被 修改为主键的列,是否是一个自动计数 的数据类型的列。对Mysql数据库和mssql数据库无效。
isstrprimarykey2autoaccount:与strprimarykey2一样,只对纯复制表结构时的Mssql数据库有效,其它情况下都没有作用。
strprimarykeytype:要指定的主键列的数据类型,此参数对mysql和mssql数据库无效;
strprimarykey2type:与strprimarykey2一样,只对纯复制表结构时的mssq数据库有效。
iscopydata:是否要复制表中的数据,默认不复制,则只复制表的结构。如果此值为True则要复制表数据。
isDelExitsTable::如果要复制的目标表已经存在,则是否要删除旧表,重新复制产生新表,默认是不删除旧表。
isShowMsg:是否将错误信息以对话框的形式弹出。
'''
try:
cur=con.cursor()
strOnlyTargetTableNm=strtt
strOnlySourceTableNm=strst
strTemp=''
ifdbtype!='mysql': #mysql 不支持在sql语句中书写方括号
strst='[' + strst
+ ']'
strtt='[' + strtt
+ ']'
strprimarykey=strprimarykey.strip()
strprimarykey2=strprimarykey2.strip()
#如果要复制到的目标 表已经存在 ,应当作一定的处理--------
ifisTableExistGhlh(con,strtt,isShowMsg)==True:
#--如果旧表存在,就看是否要删除旧表---
ifisDelExitsTable==True:
ifdelTableGhlh(con,strtt,isShowMsg)==False:
#--旧表存在,但是却删除失败的情况----
mdbErrString ="在复制一个数据表时,因为同名的目标表的旧表已经存在了,但尝试删除旧表失败,所以无法复制一个新的目标表。" + '\n此函数由【孤荷凌寒】创建qq:578652607'
ifisShowMsg == True:
msgbox(mdbErrString)
return False
else:
#成功删除了旧表,那么就添加新表,直接顺序到后面执行代码即可。
pass
else:
#如果旧表存在,但又指定不删除旧表,那么只好结束 本函数 过程了
mdbErrString ="在复制一个数据表时,因为同名的目标表的旧表已经存在了,而又指定不能删除旧表,所以无法复制一个新的目标表。" + '\n此函数由【孤荷凌寒】创建qq是578652607'
if isShowMsg == True:
msgbox(mdbErrString)
return False
#--------------------------
strSql='SELECT ' +
strfieldlist + ' INTO ' + strtt + ' FROM '+ strst
ifdbtype=='sqlite':
strSql='CREATE TABLE ' + strtt
+ ' AS SELECT ' + strfieldlist + ' FROM '+ strst
ifiscopydata==False:
strSql=strSql +' WHERE
(1=2);'
else:
ifdbtype!='mssql':
strSql=strSql +';'
else:
ifstrprimarykey2!='':
#如果mssql数据库要增加两个Key字段,那么,只能先复制结构,再导入数据
strSql=strSql +' WHERE
(1=2);'
else:
#如果只增加一个key字段,则不受影响
strSql=strSql +';'
ifdbtype!='mysql':
#非Mysql的情况下,开始一步执行到位
ifdbtype!='sqlite':
#在非sqlite数据库的情况下,执行下面的操作
cur.execute(strSql)#除Mysql之外的数据库的复制结果都不能得到完整的数据表信息,至少 数据表的 主键信息不会复制过来
con.commit()
#因此下面必须手动再指定主键信息
ifstrprimarykey!='':
ifstrprimarykey2=='':
ifdbtype=='acc':
#access数据库第一步先删除失败的primary key 字段,
cur.execute('alter
table ' + strtt + ' drop COLUMN ' + strprimarykey + ';')
#然后新增一个字段:
strautoaccounter=''
ifisstrprimarykeyautoaccount==True:
strautoaccounter=' counter'
else:
strprimarykeytype=getStandardFieldTypeGhlh(strprimarykeytype)
strautoaccounter=' '+strprimarykeytype #如果不是自动增加字段,就使用预置的字段类型
cur.execute('alter
table ' + strtt + ' add COLUMN ' + strprimarykey +
strautoaccounter + ' NOT NULL PRIMARY KEY;')
ifdbtype=='mssql':
#mssql的处理也有两步:
#第一步感觉可以取消----
#cur.execute('alter
table ' + strtt + ' alter column ' + strprimarykey + ' int not null')
cur.execute('alter
table ' + strtt + ' add CONSTRAINT PK_' +
strOnlyTargetTableNm + ' PRIMARY KEY NONCLUSTERED ( ' +
strprimarykey + ' )')
#----------------------------------------
else:
#---------------------------------------------
#如果有第二个Primarykey
ifdbtype=='acc':
#---!!!!!!----access数据库并不适用此方法------------
#access数据库第一步先删除失败的primary key 字段,
cur.execute('alter table ' + strtt
+ ' drop COLUMN ' + strprimarykey + ',' +
strprimarykey2 + ';')
#然后新增一个字段:
strautoaccounter=''
ifisstrprimarykeyautoaccount==True:
strautoaccounter=' counter'
else:
strprimarykeytype=getStandardFieldTypeGhlh(strprimarykeytype)
strautoaccounter=' '+strprimarykeytype #如果不是自动增加字段,就使用预置的字段类型
#然后增加另一个字段:
strautoaccounter2=''
ifisstrprimarykey2autoaccount==True:
strautoaccounter2=' counter'
else:
strprimarykey2type=getStandardFieldTypeGhlh(strprimarykey2type)
strautoaccounter2=' '+strprimarykey2type #如果不是自动增加字段,就使用预置的字段类型
#执行---
cur.execute('alter
table ' + strtt + ' add COLUMN ' + strprimarykey +
strautoaccounter + ' NOT NULL;') #只能一次设置一个主键,因此默认让第二个字段为主键了
cur.execute('alter
table ' + strtt + ' add COLUMN ' + strprimarykey2 +
strautoaccounter2 + ' NOT NULL PRIMARY KEY;')
#---------------------------------------------------------
ifdbtype=='mssql':
#-!!!!---插入SQL语句失败---------
#mssql的处理也有两步:
strprimarykeytype=getStandardFieldTypeGhlh(strprimarykeytype,'mssql')
strprimarykey2type=getStandardFieldTypeGhlh(strprimarykey2type,'mssql')
#第一步感觉可以取消----
cur.execute('alter
table ' + strtt + ' alter column ' + strprimarykey + ' ' +
strprimarykeytype + ' not null')
cur.execute('alter
table ' + strtt + ' alter column ' + strprimarykey2 +' ' + strprimarykey2type + ' not null')
cur.execute('alter
table ' + strtt + ' add CONSTRAINT PK_' +
strOnlyTargetTableNm + ' PRIMARY KEY NONCLUSTERED ( ' +
strprimarykey + ',' + strprimarykey2 + ' )')
con.commit()
#如果要求导入数据,此时再导入数据
if iscopydata==True:
#应当先修改源表中指定字段的所有行的值都不为Null 再导入
#尝试取出所有列信息:
ifstrfieldlist=="" or strfieldlist=='*':
lstTemp=getTableAllFieldToAListGhlh(cur,strOnlySourceTableNm,'mssql')
else:
lstTemp=strfieldlist.split(',')
#---------------------
lstTemp2=[]
ifisstrprimarykeyautoaccount==True:
lstTemp2.append(strprimarykey)
ifisstrprimarykey2autoaccount==True:
lstTemp2.append(strprimarykey2)
#------------------------
lstTemp=_mty.delListSelYuanSu(lstTemp,lstTemp2)
strT=','.join(lstTemp)
#然后导入 #注意myssql的自增加字段不能赋值进去
strS='insert
into ' + strOnlyTargetTableNm + '(' + strT
+ ') select ' + strT + ' from ' + strst
+ ';'
cur.execute(strS)
#---------------------------------------------
else:
#sqlite数据库的执行比较特殊;
cur.execute('PRAGMA
table_info([pengwei])') #先取出源表的数据结构的一个列表
data=cur.fetchall()
strr=''
strfieldlist='' #提出源表中的所有字段列表,如果 有自增字段 则书写为null
#---下面将源表的创建语句还原成字符串
for i indata:
tpl=i
if strr=='':
strr=tpl[1] + ' ' + tpl[2]
else:
strr=strr +',' + tpl[1] + ' ' + tpl[2]
if tpl[5]>0:
#说明是primarykey
strr=strr +'
PRIMARY KEY'
#---下面对自增字段的处理
ifstrprimarykey!='': #sqlite只需要检查一个关键字段,它只支持一个Primary key
if tpl[1]==strprimarykey:
ifisstrprimarykeyautoaccount==True:
#如果当前字段是自增加字段,那么
strTemp='null' #sqlite的自增加字段不能赋值进去
#给创建表的语句,添加上:
strr=strr +'
AUTOINCREMENT'
else:
strTemp=tpl[1]
else:
strTemp=tpl[1] #当前字段
#取出字段列表----
if strfieldlist=='':
strfieldlist=strTemp
else:
strfieldlist=strfieldlist +','+ strTemp
#--检查当前字段的约束是否为null
if tpl[3]>0:
#说明是不为null
strr=strr +' NOT
NULL'
#------------------------------------------------------------------------
#----汇总生成的创建表的sql语句-------
strr='CREATE TABLE ' + strOnlyTargetTableNm
+ '(' + strr + ');'
#----执行创建表----------
cur.execute(strr)
con.commit()
#---如果要将数据一起复制过来
ifiscopydata==True:
cur.execute('INSERT
INTO ' + strtt + ' SELECT ' + strfieldlist + ' FROM ' + strst
+ ';')
#------------------------------
else:
#mysql的执行比较特殊,分两步完成
#第一步复制表的结构,只有mysql是完整复制了数据表的全部信息,包括主键(primary key)的信息
cur.execute('CREATE
TABLE ' + strtt + ' LIKE ' + strst + ';')
#第二步是将源表的数据插入到复制后的新表
ifiscopydata==True:
cur.execute('INSERT
INTO ' + strtt + ' SELECT * FROM ' + strst + ';')
#------下面提交-------------
con.commit()
return True
except Exception ase:
mdbErrString='尝试在同一数据库中复制数据表时出错:' + str(e) + '\n此函数由【孤荷凌寒】创建qq号是578652607'
ifisShowMsg==True:
msgbox(mdbErrString)
return False
else:
pass
finally:
try:
cur.close()
except:
pass
#此函数方法将返回一个表的所有字段名称
def getTableAllFieldToAListGhlh(cur,strtable,dbtype='acc',isShowMsg=False):
'''
此函数将返回指定的一个表中的所有字段名称组成的一个列表list对象,需要指定数据库类型
cur:cursor指针对象
strtable:表的名称
dbtype:数据库类型
isshowmsg:是否显示错误信息对话框
'''
try:
lstR=[]
ifdbtype=='mssql':
cur.execute("Select
Name From SysColumns Where id=Object_Id('" + strtable + "')")
data=cur.fetchall
lstTemp=data()#data是一个函数方法,所以可以直接执行。
for i inlstTemp:
lstR.append(i[0]) #每一个i对象都是一个元组,因此要取出其中的第0个元素,就是字段名称
returnlstR
except Exception ase:
mdbErrString='尝试取出一张数据表中的所有字段名称并返回列表时出错:' + str(e) + '\n此函数由【孤荷凌寒】创建qq号是578652607'
ifisShowMsg==True:
msgbox(mdbErrString)
return None
else:
pass
finally:
pass
二、今天只在windows10环境下进行了反复测试:
证实无论目标表是否已在原数据库中存在,都可根据给函数传递的参数而自动处理。
具体过程参见本文最后提供的操作过程的录屏记录视频 。
欢迎并感谢大家能够对函数进行更好的修正,并给予我指导,不胜感激!
——————————
今天整理的学习笔记完成,最后例行说明下我的自学思路:
根据过去多年我自学各种编程语言的经历,认为只有真正体验式,解决实际问题式的学习才会有真正的效果,即让学习实际发生。在2004年的时候我开始在一个乡村小学自学电脑 并学习vb6编程语言,没有学习同伴,也没有高师在上,甚至电脑都是孤岛(乡村那时还没有网络),有的只是一本旧书,在痛苦的自学摸索中,我找到适应自己零基础的学习方法:首先是每读书的一小节就作相应的手写笔记,第二步就是上机测试每一个笔记内容是否实现,其中会发现书中讲的其实有出入或错误,第三步就是在上机测试之后,将笔记改为电子版,形成最终的修订好的正确无误的学习笔记。
通过反复尝试错误,在那个没有分享与交流的黑暗时期我摸黑学会了VB6,尔后接触了其它语言,也曾听过付费视频课程,结果发现也许自己学历果然太低,就算是零基础的入门课程,其实也难以跟上进度,讲师的教学多数出现对初学者的实际情况并不了解的情况,况且学习者的个体也存在差异呢?当然更可怕的是收费课程的价格往往是自己难以承受的。
于是我的所有编程学习都改为了自学,继续自己的三步学习笔记法的学习之路。
当然自学的最大问题是会走那么多的弯路,没有导师直接输入式的教学来得直接,好在网络给我们带来无限搜索的机会,大家在网络上的学习日志带给我们共享交流的机会,而QQ群等交流平台、网络社区的成立,我们可以一起自学,互相批评交流,也可以获得更有效,更自主的自学成果。
于是我以人生已过半的年龄,决定继续我的编程自学之路,开始学习python,只希望与大家共同交流,一个人的独行是可怕的,只有一群人的共同前进才是有希望的。
诚挚期待您的交流分享批评指点!欢迎联系我加入从零开始的自学联盟。
这个时代互联网成为了一种基础设施的存在,于是本来在孤独学习之路上的我们变得不再孤独,因为网络就是一个新的客厅,我们时刻都可以进行沙龙活动。
非常乐意能与大家一起交流自己自学心得和发现,更希望大家能够对我学习过程中的错误给予指点——是的,这样我就能有许多免费的高师了——这也是分享时代,社区时代带来的好福利,我相信大家会的,是吧!
根据完全共享的精神,开源互助的理念,我的个人自学录制过程是全部按4K高清视频录制的,从手写笔记到验证手写笔记的上机操作过程全程录制,但因为4K高清文件太大均超过5G以上,所以无法上传至网络,如有需要可联系我QQ578652607对传,乐意分享。上传分享到百度网盘的只是压缩后的720P的视频。
我的学习过程录像百度盘地址分享如下:(清晰度:1280x720)
链接:https://pan.baidu.com/s/1iOf11tkYOzMOpkHZ5wxfsg
提取码:fsjy
喜马拉雅语音笔记:
网友评论