现需要对这个员工信息文件,实现增删改查操作
#
# 可进行模糊查询,语法至少支持下面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 ‘‘‘