zoukankan      html  css  js  c++  java
  • 模拟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 '''



  • 相关阅读:
    PHP中单引号与双引号的区别分析
    utf8_unicode_ci与utf8_general_ci的区别
    [mysql-Ver5.6.23] windows版my.ini配置
    Gateway/Worker模型 数据库使用示例
    php 字符串 以 开头 以结尾 startWith endWith
    MySQL错误ERROR 2002 (HY000): Can't connect to local MySQL server
    vim变ide
    在Vue中使用样式
    Vue指令之`v-model`和`双向数据绑定
    Vue指令之事件修饰符
  • 原文地址:https://www.cnblogs.com/Lollipop1/p/8084938.html
Copyright © 2011-2022 走看看