模拟sql实现对员工列表的增删改查

现需要对这个员工信息文件,实现增删改查操作
#
# 可进行模糊查询,语法至少支持下面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_parsing
    • 分发SQL给对应语句的函数来做解析
      • increase_parsing
      • deleting_parsing
      • reform_parsing
      • check_parsing
    • 解析后交给handle_parsing,来控制返回
    • 解析SQL语句中的多条件
      • where_parsing
      • three_parsing
    • 返回解析后的SQL

第二部分:SQL执行

  • 1.接收解析后的SQL

  • 2.SQL执行主函数sql_perform

    • 分发SQL给对应函数来执行
      • insert
      • delete
      • update
      • select
    • 执行SQL语句时的多条件
      • where_action
      • logic_action
      • limit_action
      • search_action
    • 返回执行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) + '
'
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
'}
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 33[41;1m%s33[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('33[43;1m%s33[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 '''



原文地址:https://www.cnblogs.com/Lollipop1/p/8084938.html