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)#输出结果

 





posted @ 2018-01-16 09:58  东郭仔  阅读(210)  评论(0)    收藏  举报