现需要对这个员工信息文件,实现增删改查操作
#
# 可进行模糊查询,语法至少支持下面3种:
#
# select * from staff_table where dept = "IT"
# select * from staff_table where enroll_date like "2013"
# 查到的信息,打印后,最后面还要显示查到的条数
# 可创建新员工纪录,以phone做唯一键,staff_id需自增
# 可删除指定员工信息纪录,输入员工id,即可删除
# 可修改员工信息,语法如下:
# UPDATE staff_table SET dept="Market" WHERE where dept = "IT"
思维导图
流程分析
第一部分:SQL解析
- 1.接收用户SQL
- 判断用户输入是否为SQL
- 2.SQL解析主函数sql_parse
- 分发SQL给对应语句的函数来做解析
- insert_parse
- delete_parse
- update_parse
- select_parse
- 解析后交给handle_parse,来控制返回
- 解析SQL语句中的多条件
- where_parse
- three_parse
- 返回解析后的SQL
- 分发SQL给对应语句的函数来做解析
第二部分:SQL执行
-
1.接收解析后的SQL
-
2.SQL执行主函数sql_action
- 分发SQL给对应函数来执行
- insert
- delete
- update
- select
- 执行SQL语句时的多条件
- where_action
- logic_action
- limit_action
- search_action
- 返回执行SQL的结果。
- 代码
- 分发SQL给对应函数来执行
1 import os 2 #第一部分sql解析 3 def sql_parsing(sql): 4 ‘‘‘ 5 把sql字符串切分提取命令信息,分发给函数去解析 6 :param sql: 7 :return: 8 ‘‘‘ 9 # sql命令操作 解析函数的字典 根据用户的命令来找相对应的函数 10 parsing_func={ 11 ‘insert‘:increase_parsing, #增 12 ‘delete‘:deleting_parsing, #删 13 ‘update‘:reform_parsing, #改 14 ‘select‘:check_parsing, #查 15 16 } 17 print(‘sql str is %s‘ %sql) #打印用户输入的sql 18 sql_l=sql.split(‘ ‘) #按空格切分 赋值给列表 19 func=sql_l[0] #取出用户的sql命名 20 res=‘‘ 21 if func in parsing_func: #判断用户的命令 是否在pares_func里,不再返回空 22 res=parsing_func[func](sql_l) #把切分后的用户列表传人sql对应的函数里 23 res=parsing_func[func](sql_l) #把切分后的用户列表传人sql对应的函数里 24 return res 25 26 def increase_parsing(sql_l): 27 ‘‘‘ 28 增加功能 29 :param sql: 30 :return: 31 ‘‘‘ 32 sql_dic={ 33 ‘func‘:insert, 34 ‘delete‘: [], # delete选项,留出扩展 35 ‘into‘: [], # 表名 36 ‘values‘: [], # filter条件 37 38 } 39 return handle_parsing(sql_l,sql_dic) 40 41 42 43 def reform_parsing(sql_l): 44 ‘‘‘ 45 修改功能 46 :param sql: 47 :return: 48 ‘‘‘ 49 sql_dic={ 50 ‘func‘:update, 51 ‘update‘: [], # delete选项,留出扩展 52 ‘set‘: [], # 表名 53 ‘where‘: [], # filter条件 54 55 } 56 return handle_parsing(sql_l,sql_dic) 57 58 59 60 def deleting_parsing(sql_l): 61 ‘‘‘ 62 删除功能 63 :param sql: 64 :return: 65 ‘‘‘ 66 sql_dic={ 67 ‘func‘:delete, 68 ‘delete‘: [], # delete选项,留出扩展 69 ‘from‘: [], # 表名 70 ‘where‘: [], # filter条件 71 72 } 73 return handle_parsing(sql_l,sql_dic) 74 75 76 def check_parsing(sql_l): 77 ‘‘‘ 78 79 :param sql: 80 :return: 81 ‘‘‘ 82 sql_dic={ 83 ‘func‘:select, 84 ‘select‘: [], # 查询字段 85 ‘from‘: [], # 数据库.表 86 ‘where‘: [], # 条件 87 ‘limit‘: [], # 条件,限制 88 89 } 90 91 return handle_parsing(sql_l,sql_dic) 92 93 def handle_parsing(sql_l,sql_dic): #解析sql 94 ‘‘‘ 95 执行sql解析操作,返回sql_dic 96 :param sql_l: 97 :param sql_dic: 98 :return: 99 ‘‘‘ 100 101 tag=False #设置警报 102 for item in sql_l: #for循环体 控制用户的sql列表 103 if tag and item in sql_dic: #if判断警报是否是真,并且用户sql的条件 在条件select语句字典里面,则关闭警报 104 tag=False # tag为假,关闭警报 105 if not tag and item in sql_dic: #判断警报没有拉响 并且用户sql的条件 在条件select语句字典里面 106 tag=True #警报拉响 107 key=item # 108 continue 109 if tag: 110 sql_dic[key].append(item) #for循环体取出的值做判断,成立把值添加到条件对应的字典里 111 if sql_dic.get(‘where‘): 112 sql_dic[‘where‘]=where_parsing(sql_dic.get(‘where‘)) #调用where_parse函数 把整理好的用户sql的where语句 覆盖之前没整理好的 113 114 return sql_dic #返回解析结果到字典里 115 116 def where_parsing(where_l): 117 ‘‘‘ 118 :param where_l: 119 :return: 120 ‘‘‘ 121 res=[] #定义空列表 返回return的值放进列表里 122 key=[‘and‘,‘or‘,‘not‘] # 123 char=‘‘ #拼接好的字符串 124 for i in where_l: #循环体 125 if len(i) ==0:continue #判断长度如果是0跳出本次循环 126 if i in key: #判断i的值里是不是有kuy 127 if len(char) !=0: #char的长度必须是大于0 128 char=three_parsing(char) 129 res.append(char) 130 res.append(i) 131 char=‘‘ 132 else:char+=i 133 134 else: 135 char=three_parsing(char) 136 res.append(char) 137 return res 138 139 def three_parsing(exp_str): 140 ‘‘‘ 141 将每一个小的过滤条件如,name>=1转换成[‘name‘,‘>=‘,‘1‘] 142 :param exp_str: 143 :return: 144 ‘‘‘ 145 key=[‘>‘,‘<‘,‘=‘] 146 res=[] 147 char=‘‘ 148 opt=‘‘ 149 tag=False 150 for i in exp_str: 151 if i in key: 152 tag=True 153 if len(char)!=0: 154 res.append(char) 155 char=‘‘ 156 opt+=i 157 if not tag: 158 char+=i 159 if tag and i not in key: 160 tag=False 161 res.append(opt) 162 opt=‘‘ 163 char+=i 164 else: 165 res.append(char) 166 if len(res) ==1: 167 res=res[0].split(‘like‘) 168 res.insert(1,‘like‘) 169 170 return res #返回res列表结果 171 172 173 174 175 176 177 # siq执行 178 def sql_perform(sql_dic): 179 ‘‘‘ 180 :param sql: 181 :return: 182 ‘‘‘ 183 return sql_dic.get(‘func‘)(sql_dic) 184 185 def insert(sql): 186 ‘‘‘ 187 188 :param sql: 189 :return: 190 ‘‘‘ 191 print(‘insert %s‘ %sql_dic) 192 db,table=sql_dic.get(‘into‘)[0].split(‘.‘) 193 with open(‘%s/%s‘ %(db,table),‘ab+‘) as fh: 194 offs=-100 195 while True: 196 fh.seek(offs,2) 197 lines=fh.readlines() 198 if len(lines)>1: 199 last=lines[-1] 200 break 201 202 offs *=2 203 last=last.decode(encoding=‘utf-8‘) 204 last_id=int(last.split(‘,‘)[0]) 205 new_id=last_id+1 206 record=sql_dic.get(‘values‘)[0].split(‘,‘) 207 record.insert(0, str(new_id)) 208 record_str = ‘,‘.join(record) + ‘\n‘ 209 fh.write(bytes(record_str, encoding=‘utf-8‘)) # 把添加 id后的用户想添加的sql 用bytes写入文件 210 fh.flush() 211 return [[‘insert successful‘]] 212 213 def update(sql_dic): 214 #update db1.emp set id=‘sb‘ where name like alex 215 db,table=sql_dic.get(‘update‘)[0].split(‘.‘) 216 set=sql_dic.get(‘set‘)[0].split(‘,‘) 217 set_l=[] 218 for i in set: 219 set_l.append(i.split(‘=‘)) 220 bak_file=table+‘_bak‘ 221 with open("%s/%s" %(db,table),‘r‘,encoding=‘utf-8‘) as r_file,222 open(‘%s/%s‘ %(db,bak_file),‘w‘,encoding=‘utf-8‘) as w_file: 223 update_count=0 224 for line in r_file: 225 title="id,name,age,phone,dept,enroll_date" 226 dic=dict(zip(title.split(‘,‘),line.split(‘,‘))) 227 filter_res=logic_action(dic,sql_dic.get(‘where‘)) 228 if filter_res: 229 for i in set_l: 230 k=i[0] 231 v=i[-1].strip("‘") 232 print(‘k v %s %s‘ %(k,v)) 233 dic[k]=v 234 print(‘change dic is %s ‘ %dic) 235 line=[] 236 for i in title.split(‘,‘): 237 line.append(dic[i]) 238 update_count+=1 239 line=‘,‘.join(line) 240 w_file.write(line) 241 242 w_file.flush() 243 os.remove("%s/%s" % (db, table)) 244 os.rename("%s/%s" %(db,bak_file),"%s/%s" %(db,table)) 245 return [[update_count],[‘update successful‘]] 246 247 def delete(sql): 248 db,table=sql_dic.get(‘from‘)[0].split(‘.‘) 249 bak_file=table+‘_bak‘ 250 with open("%s/%s" %(db,table),‘r‘,encoding=‘utf-8‘) as r_file,251 open(‘%s/%s‘ %(db,bak_file),‘w‘,encoding=‘utf-8‘) as w_file: 252 del_count=0 253 for line in r_file: 254 title="id,name,age,phone,dept,enroll_date" 255 dic=dict(zip(title.split(‘,‘),line.split(‘,‘))) 256 filter_res=logic_action(dic,sql_dic.get(‘where‘)) 257 if not filter_res: 258 w_file.write(line) 259 else: 260 del_count+=1 261 w_file.flush() 262 os.remove("%s/%s" % (db, table)) 263 os.rename("%s/%s" %(db,bak_file),"%s/%s" %(db,table)) 264 return [[del_count],[‘delete successful‘]] 265 266 def select(sql_dic): 267 ‘‘‘ 268 :param sql_dic: 269 :return: 270 ‘‘‘ 271 db,table=sql_dic.get(‘from‘)[0].split(‘.‘) # 切分出库名和表名,就是文件路径 272 fh=open("%s/%s" % (db,table),‘r‘, encoding=‘utf-8‘) # 打开文件 根据取到的路径 273 filter_res=where_action(fh,sql_dic.get(‘where‘)) 274 fh.close() 275 limit_res=limit_action(filter_res,sql_dic.get(‘limit‘)) #定义limit执行函数,限制行数 276 # for record in limit_res: # 循环打印 显示用户sql limit的执行结果 277 # print(‘limit res is %s‘ %record) 278 279 #lase:select 280 search_res=search_action(limit_res,sql_dic.get(‘select‘)) #定义select执行函数 281 # for record in search_res: # 循环打印 显示用户sql select的执行结果 282 # print(‘select res is %s‘ %record) 283 284 return search_res 285 286 287 288 def logic_action(dic, where_l): 289 ‘‘‘ 290 用户sql select的where多条件 执行对比文件内容 291 文件内容 跟所有的 where_l 的条件比较 292 :param dic: 293 :param where_l: 294 :return: 295 ‘‘‘ 296 # print(‘from logic_action %s‘ %dic) #from logic_action {‘id‘: ‘23‘, ‘name‘: ‘翟超群‘, ‘age‘: ‘24‘, ‘phone‘: ‘13120378203‘, ‘dept‘: ‘运维‘, ‘enroll_data‘: ‘2013-3-1\n‘} 297 # print(‘---- %s‘ %where_l) #[[‘name‘, ‘like‘, ‘李‘], ‘or‘, [‘id‘, ‘<=‘, ‘4‘]] 298 res = [] # 存放 bool值 结果的空列表 299 # where_l=[[‘name‘, ‘like‘, ‘李‘], ‘or‘, [‘id‘, ‘<=‘, ‘4‘]] 300 for exp in where_l: # 循环where条件列表,跟dic做比较 301 # dic与exp做bool运算 302 if type(exp) is list: # 只留下 where_l列表里 相关的条件 303 # 如果是列表 做bool运算 #[[‘name‘, ‘like‘, ‘李‘] 304 exp_k, opt, exp_v = exp # 匹配 一个where条件列表的格式 305 if exp[1] == ‘=‘: # 如果 列表的运算符是 =号 306 opt = "%s=" % exp[1] # 用字符串拼接出 两个 ==号 307 if dic[exp_k].isdigit(): # 判断是否数字 用户的条件是否对应文件内容(字典) 308 dic_v = int(dic[exp_k]) # 文件内容的数字 转成整形 做比较 309 exp_v = int(exp_v) # where_l列表的数字 转成整形 做比较 310 else: 311 dic_v = "‘%s‘" % dic[exp_k] # 不是数字的时候 存取出来 312 if opt != ‘like‘: # 如果运算符 不是 like 313 exp = str(eval("%s%s%s" % (dic_v, opt, exp_v))) # 转成字符串(逻辑判断后是bool值):做逻辑判断:文件数字,运算符,用户数字 314 else: # 如果 运算符位置是 like 315 if exp_v in dic_v: # 判断 sql里like的值 是否在 文件内容里 316 exp = ‘True‘ 317 else: 318 exp = ‘False‘ 319 res.append(exp) # [‘True‘,‘or‘,‘False‘,‘or‘,‘true‘] 320 321 # print(‘---------- %s‘ %res) 322 res = eval(" ".join(res)) # 把bool值列表转成字符串 然后再做逻辑判断 结果是bool值 323 return res # 返回 res结果 324 325 def limit_action(filter_res,limit_l): #执行limit条件 限制行数 326 res=[] #最后的返回值列表 327 if len(limit_l) != 0: #判断 用户sql 是否有 limit条件 328 index=int(limit_l[0]) #取出 用户sql limit条件的数字 329 res=filter_res[0:index] 330 else: #如果 用户sql 没有 limit条件 就整个返回 331 res=filter_res 332 return res #返回最后的sql结果 333 334 def search_action(limit_res,select_l): #执行select执行函数 335 res=[] #最后的返回值列表 336 fileds_l = [] 337 title = "id,name,age,phone,dept,enroll_data" #title = select的条件 338 if select_l[0] == ‘*‘ : #判断 如果 用户sql 的select 条件是 * 339 fields_l=title.split(‘,‘) #用户sql 的select 条件是 * ,则匹配所有条件 340 res=limit_res #如果 用户sql 的select 条件是 * 则返回全部 341 else: #判断 如果用户sql的select条件不是 * ,提取用户的select语句条件 342 for record in limit_res: #循环 匹配好的where语句和limit语句的结果 343 dic=dict(zip(title.split(‘,‘),record)) #每条记录都对应 select条件,生成字典 344 r_l=[] #存放用户sql的select条件 345 fields_l=select_l[0].split(‘,‘) #取出用户sql 的select条件 346 for i in fields_l: #循环用户sql的select条件,区分多条件,id,name 347 r_l.append(dic[i].strip()) #把用户sql的select多条件 加入 r_l列表 348 res.append(r_l) #把r_l列表 加入res 349 350 return (fields_l,res) #返回用户sql的select条件,selcet执行结果 351 352 def where_action(fh,where_l): #执行where条件语句 where_l=where的多条件解析后的列表 353 #id,name,age,phone,dept,enroll_data 354 #10,吴东杭,21,17710890829,运维,1995-08-29 355 #[‘id>7‘, ‘and‘, ‘id<10‘, ‘or‘, ‘namelike‘] 356 357 # print(‘in where_action \033[41;1m%s\033[0m‘ %where_l) 358 res=[] #定义最后返回值的列表 359 logic_l=[‘and‘,‘or‘,‘not‘] #定义逻辑运算符 360 title="id,name,age,phone,dept,enroll_data" #定义好表文件内容的标题 361 if len(where_l) != 0: #判断用户sql 是否有where语句 362 for line in fh: #循环 表文件 363 dic=dict(zip(title.split(‘,‘),line.split(‘,‘))) #一条记录 让标题和文件内容一一对应 364 #逻辑判断 365 logic_res=logic_action(dic,where_l) #让 logic_action函数来操作对比 366 if logic_res: #如果逻辑判断为True 367 res.append(line.split(‘,‘)) #加入res 368 else: 369 res=fh.readlines() #用户sql 没有where语句,则返回表文件所有内容 370 371 # print(‘>>>>>>>> %s‘ %res) 372 return res #返回执行 where 后的结果 373 374 375 if __name__==‘__main__‘: #主函数 376 while True: 377 sql=input("sql>:").strip() #用户输入sql 命令 378 if sql ==‘exit‘: #exit退出登录 379 break 380 if len(sql)==0: #用户输入为空字符继续输入 381 continue 382 383 sql_dic=sql_parsing(sql) #用户输入sql转成机构化字典 384 if len(sql_dic) == 0:continue # 385 res=sql_perform(sql_dic) #执行结果赋值给src 386 print(‘\033[43;1m%s\033[0m‘ % res[0]) 387 for i in res[-1]: 388 print(i) 389 390 ‘‘‘ 391 测试执行 select语句 392 select * from db.emp 393 select * from db.emp limit 2 394 select * from db.emp where name like 李 or id <= 9 or id = 24 limit 9 395 select id,name from db.emp where name like 李 or id <= 9 or id = 24 limit 9 396 397 测试执行 insert语句 398 insert into db.emp values gyf,30,18500841678,运维,2007-8-1 399 400 测试执行 delete语句 401 delete from db.emp where id>47 402 403 测试执行 update语句 404 update db.emp set gyf=‘haha‘ where id=47 405 ‘‘‘