day 4 作业, 员工信息程序,模拟SQL 语句
作业要求:
1、可进行模糊查询,语法至少支持下面3种:
select name,age from db1.staff_table where age > 22
select * from db1.staff_table where dept = "IT"
select * from db1.staff_table where enroll_date like "2013"
select name,age from db1.staff_table where id > = 1 and id < = 5 or name like 李 limit 4
查到的信息,打印后,最后面还要显示查到的条数
2、可创建新员工纪录,以phone做唯一键,staff_id需自增
insert into db1.staff_table values alex,30,18500841678,运维,2007-8-1
3、可删除指定员工信息纪录,输入员工id,即可删除
delete from db1.staff_table where id = 1
4、可修改员工信息,语法如下:
update db1.staff_table set dept = "Market" where dept = "IT"
*注意:以上需求,要充分使用函数,请尽你的最大限度来减少重复代码

数据库文件,在目录下新建 db1, 在db1 下面新建 staff_table
1,张德,25,18330267967,IT,2017-5-27 2,李四,25,19230267967,运维,2016-5-27 3,王五,35,15673026796,IT,2017-6-27 4,赵六,29,18122263467,测试,2017-5-28 5,董七,25,18556267967,运维6,2014-5-27 6,李张明,26,18122677967,测试,2017-5-21 7,赵四,28,18523267967,运维,2014-5-22 8,董七,25,18556267967,运维,2014-5-27 9,alex,30,18500841678,运维,2007-8-1
1 import os 2 3 #定义查询函数,传入解析完成的sql_dict 4 def select(sql_dict): 5 #print("select",sql_dict) 6 #1. from 7 db, table = sql_dict.get('from')[0].split('.') # 切分出库名和表名,就是文件路径 8 fh = open("%s/%s" % (db, table), 'r', encoding='utf-8') # 打开文件 根据取到的路径 9 #2:where 调用where_action 函数,处理where 条件。 10 where_l=sql_dict.get('where') 11 filter_res = where_action(fh,where_l) # 定义where执行函数,查询条件 12 fh.close() 13 #3:limit 调用 limit 函数,处理limit 条件 14 limit_res=limit_action(filter_res,sql_dict.get("limit")) 15 #4.select #调用 search_action 函数,处理查询字段条件 16 search_res=search_action(limit_res,sql_dict.get("select")) 17 #print(search_res) 18 count_select= len(search_res[1]) 19 return [search_res,"共查询到{}条记录".format(count_select)] 20 21 #{'insert': [], 'into': ['db1.emp'], 'values': ['alex,30,18500841678,运维,2007-8-1']} 22 def insert(sql_dict): 23 #print(sql_dict) 24 db,table=sql_dict.get("into")[0].split(".") #提取数据库字段 25 title="id,name,age,phone,dept,enroll_date" #定义数据库字段标题 26 max_id,count_insert=0,0 #定义 最大id,及插入计数器 27 tmp=[] #定义临时空字典 28 values_l=sql_dict.get('values')[0].split(",") 29 #处理 sql_dict 字典中values ['alex,30,18500841678,运维,2007-8-1'] 成 30 #['alex','30','18500841678','运维','2007-8-1'] 31 phone=values_l[2] #获取新增数据中的电话号码 32 with open("{}/{}".format(db,table),"r",encoding="utf-8") as f_r: #打开数据库表文件 33 for line in f_r: #循环表中的数据 34 f_a_dict=dict(zip(title.split(","),line.split(",")))#把每一行跟抬头,合并成字典 35 if phone in f_a_dict.get("phone"): #对比输入字段中的电话,与表中数据的电话, 36 return ("phone 已存在,请检查,重新输入") #如果电话号码已经存在,返回提示。 37 a=int(f_a_dict.get("id")) #否则开始取出id 38 #print(a) 39 max_id = a if a>max_id else max_id #获取字典最大的ID 值 40 new_id=max_id+1 #新增字段ID值 41 42 with open ("{}/{}".format(db,table),"a",encoding="utf-8") as f_a: #以append 方式打开数据库表文件 43 tmp.append(str(new_id)) #将ID号转成字符串,(否则join 数据类型 int 方法会出错),添加到tmp 临时列表中 44 tmp.extend(values_l) #合并临时列表和 用户输入的values 列表 45 line=",".join(tmp) #将列表处理成数据库中表的格式 46 #print(line) 47 f_a.write("\n{}".format(line)) #将数据写入数据库文件 48 f_a.flush() #刷新磁盘 49 count_insert+=1 #新增计数器 +1 50 return [count_insert,"insert sucessful"] #返回数据 51 52 #{'update': ['db1.staff_table'], 'set': ['dept', '=', '"Market"'], 'where': [['dept', '=', '"IT"']]} 53 def update(sql_dict): 54 #print(sql_dict) 55 count_update = 0 #定义 修改计数器 56 db,table=sql_dict.get("update")[0].split(".") #获取表文件路径 57 table_new="new_"+table #新建一个表明 58 title="id,name,age,phone,dept,enroll_date" #定义数据库表文件,标题 59 with open("{}/{}".format(db, table), 'r', encoding='utf-8') as f_r: #打开原表文件 60 with open("{}/{}".format(db, table_new), "w", encoding="utf-8") as f_w: #新建一个新表文件 61 for line in f_r: #循环旧表 62 f_r_d=dict(zip(title.split(","),line.split(",")))#合并旧表文件为字典 63 filter_res=logic_p(f_r_d,sql_dict.get("where")) #调用logic_p 函数,判断这一行数据是否符合where 条件,返回布尔值 64 tmp=[] #定义临时空列表 65 if filter_res: #如果符合where 条件 66 f_r_d[sql_dict.get("set")[0]]=sql_dict.get("set")[2] #根据set 修改相应的值 67 for i in f_r_d.values(): 68 tmp.append(i) 69 line=",".join(tmp) #将字典处理成字符串 70 #print(line) 71 f_w.write(line) #写入新表中 72 count_update += 1 #计数器+1 73 else: #如果没有满足where 条件 74 f_w.write(line) #将数据 写到新表中 75 f_w.flush() #刷新磁盘 76 os.remove("{}/{}".format(db,table)) #移除旧数据文件 77 os.rename("{}/{}".format(db,table_new),"{}/{}".format(db,table)) #将新数据表,重命名问旧表的名称 78 return [count_update,"update sucessful"] 79 80 81 #{'delete': [], 'from': ['db1.emp'], 'where': [['id', '>', '1']]} 82 def delete(sql_dict): 83 #print(sql_dict) 84 db, table = sql_dict.get("from")[0].split(".") #同上面,不做解释了 85 table_new = "new_" + table 86 where_l=sql_dict.get("where") 87 title="id,name,age,phone,dept,enroll_date" 88 count_delete=0 89 with open("{}/{}".format(db,table),"r",encoding="utf-8") as f_r: #打开旧文件 90 with open("{}/{}".format(db, table_new), "w", encoding="utf-8") as f_w:#打开新文件 91 for line in f_r: #循环旧文件 92 f_r_dict=dict(zip(title.split(","),line.split(","))) #合成字典 93 filter_res = logic_p(f_r_dict, where_l)#调用函数对比 行是否符合where 条件 94 #print(filter_res) 95 if filter_res: #如果符合 96 count_delete+=1 #计数器+1 ,不处理,相当于删除 97 else: 98 f_w.write(line) #如果不满足,写到新文件。 99 f_w.flush() 100 os.remove("{}/{}".format(db, table)) #同上面函数,不解释了。。。。 101 os.rename("{}/{}".format(db, table_new), "{}/{}".format(db, table)) 102 return [count_delete, "delete sucessful"] 103 104 def sql_action(sql): #定义sql 分发处理函数 105 sql_l=sql.strip().split(" ") 106 #定义 4种功能能的字典,对应4种函数 107 kw={ 108 "select":select_p, 109 "insert":insert_p, 110 "update":update_p, 111 "delete":delete_p 112 } 113 #print(sql_l[0],kw.keys) 114 if sql_l[0] in kw: #如果用户输入的第一个单词符合 4种语法,调用相对于的函数处理 115 res=kw.get(sql_l[0])(sql_l) 116 else: # 否则提示输入错误 117 res=("语法错误请重新输入!") 118 return res 119 120 def select_p(sql_l): #定义select_p 函数,将函数处理 获取对应语法的字段 121 sql_dict={ 122 "select":[], 123 "from":[], 124 "where":[], 125 "limit":[], 126 } 127 sql_dict=handle_p(sql_l,sql_dict) #将定义的字典,传给解析sql 、定义的字典,语句的函数 128 #print("s_p",sql_dict) 129 res=select(sql_dict) #将处理好的 sql 字典,交个对应的函数,处理。 130 return res 131 132 def insert_p(sql_l): #同上定义 insert_p 函数, 133 sql_dict={ 134 "insert":[], 135 "into":[], 136 "values":[] 137 } 138 sql_dict=handle_p(sql_l,sql_dict) 139 res=insert(sql_dict) 140 return res 141 142 143 144 #UPDATE db1.staff_table SET dept = "Market" where dept = "IT" 145 def update_p(sql_l): #同上定义 update_p 函数, 146 sql_dict={ 147 "update":[], 148 "set":[], 149 "where":[], 150 } 151 sql_dict = handle_p(sql_l, sql_dict) 152 #print("u_p",sql_dict) 153 #sql_dict = (sql_dict) 154 res=update(sql_dict) 155 return res 156 157 #delete from db1.emp where id = 1 158 def delete_p(sql_l): #同上定义 delete_p 函数, 159 sql_dict={ 160 "delete":[], 161 "from":[], 162 "where":[], 163 } 164 sql_dict= handle_p(sql_l,sql_dict) 165 res=delete(sql_dict) 166 return res 167 168 169 def handle_p(sql_l,sql_dict): #定义解析 sql 语句的函数 170 tag=False #定义警报器 171 for i in sql_l: # 循环 sql_l 语句,将sql 语句相应的字段,填充的sql_dict 字典中 172 if len(i) != 0: 173 if i in sql_dict: 174 key=i 175 tag=True 176 if tag and i not in sql_dict: 177 sql_dict[key].append(i) 178 if sql_dict.get("where"): #如果有where 条件,将where 中字典 调用 where_p 函数,处理 字段不连续问题 179 while_l=sql_dict.get("where") 180 sql_dict["where"]=where_p(while_l) 181 #print("wherel_".format(sql_dict.get("where"))) 182 #print("handle {}".format(sql_dict.get("where"))) 183 return sql_dict 184 185 #定义函数 将[id > = 1 and id < = 5 or name like 李 limit 4] 处理成[[id > = 1] and [id < = 5] or [name like 李 limit 4]] 186 def where_p(where_l): 187 key=["and","or","not"] #定义关键字 188 tmp=[] 189 res=[] 190 #print("where_p",where_l) 191 for i in where_l: #循环 字段 192 #print("where_p",i) 193 if i.strip() not in key: #如果不是关键字,加到临时列表中 194 tmp.append(i) 195 if i in key: #如果是关键字,将上面的临时列表,添加到返回的列表中,并添加关键字到列表 196 #tmp=three_p(tmp) 197 res.append(tmp) 198 tmp=[] 199 res.append(i) 200 else:#还有最后的关键字后面的条件,也需要添加,例如 or name like 三 201 #print("开始",tmp) 202 res.append(tmp) 203 #print("over w_p",res) 204 205 for l in res: #将['id','>','=','1'] 处理成 ["id',">=","1"] 方便做布尔运算 206 if (l not in key) and ("like" not in l): #设置需要处理的条件,需要的情况才处理 ,不同于视频讲解的思路 207 index=res.index(l) #获取需要处理的字段,在where_l 中的索引。 208 res.remove(l)#在where_l 中删除掉,需要处理的 字段列表 209 l=three_p(l) #调用 处理函数 210 res.insert(index,l)#将处理好的字段列表重新,添加到where_l 列表的位置 211 #print(res) 212 return res 213 214 215 def three_p(l): #定义处理 将['id','>','=','1'] 处理成 ["id',">=","1"] 的函数 216 key=[">","<","="] #定义关键字符串 217 res=[] #定义空列表用于防治返回值 218 char="" #定义空字符串 219 #print(l) 220 for i in key: #遍历['id','>','=','1'] where_l 子列表 221 if i in l: #判断当 遇到关键字 222 l.remove(i) #从子列表中删除 223 char+=i# 拼接字符串,使得 类似 '>','=' 变成'>=' 224 l.insert(1,char) #将字符串添加到仔列表的中间 225 #print(char,l) 226 return l #返回子列表 227 228 229 def where_action(fh,where_l): #定义 处理 where 条件的函数,用于查询时调用,判断遍历的文件是否符合 where 条件 230 title="id,name,age,phone,dept,enroll_date" #定义数据库文件中,字符串的标题 231 logic=["and","or","not"] #定义逻辑判断的关键字 232 res=[] #定义两个空列表,用于防止返回值 233 logic_res=[] 234 if len(where_l) != 0: # 判断传入的sql 语句 是否有where 条件,如果有才进行处理, 235 for line in fh: 236 #print(line) 237 f_dict=dict(zip(title.split(","),line.split(","))) #每一行合成字典 238 #print(f_dict) 239 logic_res=logic_p(f_dict,where_l) #调用逻辑判断的函数 240 #print(logic_res) 241 if logic_res: #如果逻辑判断结果为 True 242 res.append(line.split(",")) #将结果放置在空列表中 243 else: #如果没有where 条件语句就返回 遍历的文件的行 244 res=fh.readlines() 245 return res 246 247 def logic_p(f_dict,where_l): #逻辑判断函数 248 res=[] 249 #print("logic_p",where_l) 250 for exp in where_l: #遍历where 条件列表 251 #print(exp) 252 if type(exp) is list: #遍历 类似 ['id','>=','2'] ,["name","like","李"]这样的条件 253 exp_k,opt,exp_v=exp #多元赋值,类似上面的列表三个值,全部取出 254 #exp_v=exp_v.strip('""') 255 if opt == "=": #因为用于布尔运算,用户输入的"=",需要替换为"==", 256 opt = "==" 257 258 if exp_v.isdigit(): # 判断用户输入的 条件,值是否为 数字 字符串 259 exp_v=int(exp_v) #将用户输入的 条件转换为 数字,便于进行布尔运算 260 f_dict_v=int(f_dict[exp_k]) #取出数据库 文件中 对应字段的 值 261 else: #如果 不是 数字 类型,添加 引号 262 f_dict_v="'{}'".format(f_dict[exp_k]) 263 #print("1",f_dict_v) 264 265 if opt != "like": #判断 如果 操作条件不是是 like 266 #a=f_dict[exp_k] 267 # 利用eval 执行布尔运算,返回时改变类型为字符串,因为,还需要再次整个"where 是有条件进行布尔运算, 268 #eval 只接受 字符串类型。 269 exp=str(eval('{}{}{}'.format(f_dict_v,opt,exp_v))) 270 else: #如果是 like 的情况 ,是字符串的判断 271 exp_v=exp_v.strip('""') #这是个坑,把用户输入的 例如"IT" ,这样的去掉"" 272 #print(exp_v) 273 if exp_v in f_dict_v: #如果where 条件中的 like 在文件中, 274 exp="True" #返回 True 275 else: 276 exp="False" #否则 返回False 277 res.append(exp) #将 ['id','>=','2'] 类似的判断的结果,返回到列表中, 278 #print(res) 279 logic_l=" ".join(res) #把列表变成 字符串,中间空格 ,分割 方便再次用 280 #print(logic_l) 281 res=eval("{}".format(logic_l))# 整个 where 条件做布尔运算 282 #print(res) 283 return res 284 285 def limit_action(filter_res,limit_l): #用于处理 查询语句中的limit条件 的函数 286 res=[] 287 if len(limit_l) !=0: #对结果列表,进行切片,根据 用户输入的 limit 字段 288 index=int(limit_l[0]) 289 res=filter_res[0:index] 290 else: 291 res=filter_res 292 return res 293 294 def search_action(limit_res,select_l): #定义search_action 函数,用于处理 select 条件字段的限制 295 res=[] 296 f_l=[] 297 title = "id,name,age,phone,dept,enroll_date" 298 #title_l=["id","name","age","phone","dept","enroll_date"] 299 if select_l[0] == "*": #判断,当select 条件是“*”,输出是有字段 300 res=limit_res 301 f_l=["id","name","age","phone","dept","enroll_date"] 302 else: #否则遍历查询结果的列表, 303 for i in limit_res: 304 dic=dict(zip(title.split(","),i))#合成字典 305 r_l=[] 306 f_l=select_l[0].split(",")#取出select 条件的字段,用于返回,作为对应结果的标题 307 for j in f_l:#遍历条件 308 r_l.append(dic.get(j).strip())#从临时行字典中取出相应的字段,加入到结果列表中 309 res.append(r_l) 310 return [f_l,res] #返回限制条件的标题及结果 311 312 print(''' 313 支持SQL 增,删,改,查。语法如下,输入“exit”退出。 314 查:select name,age from db1.staff_table where age > 22 315 select * from db1.staff_table where dept = "IT" 316 select * from db1.staff_table where enroll_date like "2013" 317 select name,age from db1.staff_table where id > = 1 and id < = 5 or name like 李 limit 4 318 增:insert into db1.staff_table values alex,30,18500841678,运维,2007-8-1 319 删:delete from db1.staff_table where id = 1/id > = 2 等 320 改:update db1.staff_table set dept = "Market" where dept = "IT" 同上条件 321 ''') #打印主程序的一些,语法说明 322 while True: #循环 323 sql=input("sql>").strip() #输入前后去除空格 324 res=[] 325 if sql == "exit": #判断用户输入,是否退出 326 break 327 if len(res)== 0: #判断是否有返回值,如果没有继续循环让用户输入 328 continue 329 res=sql_action(sql) #调用分发处理函数 330 print(res)#输出结果

浙公网安备 33010602011771号