当前位置:Gxlcms > 数据库问题 > 实现SQL基本语法

实现SQL基本语法

时间:2021-07-01 10:21:17 帮助过:15人阅读

#!/usr/bin/env python 2 # writen by Lisp at 2017/5/15 3 4 """ 5 对员工信息文件,实现增删改查操作 6 7 1. 可进行模糊查询,语法至少支持下面3种: 8 9 a. select user_name,user_age from db.emp where user_age > 22 10 b. select * from db.emp where user_dept = "IT" 11 c. select * from db.emp where user_date like "2013" 12 d. select * from db.emp limit 3 13 e. select * from db.emp where user_id > 12 and user_id < 15 or user_name like 李 14 f. select * from db.emp where not user_id > 3 15 16 查到的信息,打印后,最后面还要显示查到的条数 17 18 2. 可创建新员工纪录,以phone做唯一键,staff_id需自增 19 20 a. insert into db.emp values 张光棍,31,13111111111,CEO,2011-11-11 21 22 3. 可删除指定员工信息纪录,输入员工id,即可删除 23 24 a. delete from db.emp where id >25 25 26 4. 可修改员工信息,语法如下: 27 28 a. UPDATE db.emp SET dept="Market" WHERE user_dept = "IT" 29 30 注意:以上需求,要充分使用函数,请尽你的最大限度来减少重复代码! 31 32 33 思路: 34 1. 先从文件读出所有数据到列表,每行数据按字典的格式存储 35 2. 更新,插入,删除操作均操作列表,操作完以后,执行文件写入操作 36 37 """ 38 # 记录 input 输入的历史命令, 可以使用上下左右箭头; 不同环境可能不一样. 39 import readline 40 import os 41 42 43 def get_all_info(file_name): 44 """ 45 通过db file 得到所有用户信息; 此处无需判断异常, 因为在调用此函数之前, 均已做好判断 46 :param file_name: str db_filename 47 :return: list 返回所有用户信息的列表, 用户信息以dict形式保存 48 """ 49 user_info_list = [] 50 with open(file_name, r, encoding=utf-8) as r_f: 51 for each_line in r_f.readlines(): 52 each_list = each_line.strip().split(,) 53 user_info_list.append(dict(zip(tk_temp, each_list))) 54 return user_info_list 55 56 57 def write_to_file(db_name, write_list): 58 """ 59 将内容写入文件; 此处同样无需判断异常 60 :param db_name get_filename()函数可得到 61 :param write_list 要往文件中写入的数据 [{},{},{}...] 形式 62 :return: 无返回,只写文件 63 """ 64 # 将字段名字组成字符串 先列表生成,再join 65 temp_str = ,.join([{ + x + } for x in tk_temp]) 66 with open(db_name, w+, encoding=utf-8) as w_f: 67 for each_dic in write_list: # 遍历要写的数据列表 68 if write_list[0] == each_dic: # 判断首行 69 temp_data = {0}.format(temp_str).format_map(each_dic) 70 else: 71 temp_data = \n{0}.format(temp_str).format_map(each_dic) 72 w_f.writelines(temp_data) 73 74 75 def get_where_clause(para_str, para_item): 76 """ 77 处理where后面的字符串 78 id -> 每行记录的ID, user_name -> 每行记录的user_name ... 79 and 和 or 和 not 可以不做处理 80 like -> like前后值翻转, like变为in 81 limit 最后处理 82 :param para_item: dict 用户详细信息 -- 文件中的每行记录 83 :param para_str: content -- where后的字符串 84 :return: union 85 """ 86 # 遍历字段名,把where后面的字段名全部替换为字段值 87 # temp_str = para_str 88 for ITEM in tk_temp: 89 # 如: where user_id > 10 --> where 1 > 10 90 para_str = para_str.replace(ITEM, para_item[ITEM].lower()) 91 92 if " in para_str: 93 para_str = para_str.replace(", ‘‘) 94 if "" in para_str: 95 para_str = para_str.replace("", ‘‘) 96 # 处理like关键字 97 temp_list = para_str.split() # 定义临时列表, 用空格分开替换后的where子句 98 if like in para_str: # 判断是否有like语句 99 if like in para_str: # 如果有like, 则判断是否被空格分开;因为上面的列表是按照空格分割的list 100 for temp in temp_list: # 遍历temp_list 101 if temp == like: # 如果有like的列表元素 102 like_flag = temp_list.index(temp) # 找出like的下标 103 temp_list[like_flag] = in # 把like替换为in 104 if temp_list[like_flag - 1] != not: # 找出like的下标后,判断like的前面是否有not关键字 105 # 没有,则前后两个元素互换; 操作空间是temp_list 106 temp_list[like_flag - 1], temp_list[like_flag + 1] = "" + str( 107 temp_list[like_flag + 1]) + "", "" + str(temp_list[like_flag - 1]) + "" 108 else: 109 # 有,则not前一个元素与like后一个元素互换 110 temp_list[like_flag - 2], temp_list[like_flag + 1] = "" + str( 111 temp_list[like_flag + 1]) + "", "" + str(temp_list[like_flag - 2]) + "" 112 else: 113 return 901, like关键字附近 # 返回语法错误和提示 114 para_str = .join(temp_list) # 再用空格将处理过like的列表组成字符串 115 # 处理 类似 user_dept=it 有一个等号的情况; 需要把一个等号变为两个等号 user_dept==it 才可以被eval 116 for temp in temp_list: # 遍历临时列表 117 if = in temp and == not in temp: # 如果列表元素中有=, 而且还没被替换; 匹配[‘user_id=2‘, ‘=‘, ‘user_dept‘, ‘=it‘] 118 if <= not in temp and >= not in temp: # 如果是 >= , <= 则不处理 119 if temp != =: # 匹配user_id=2, user_id=, =2的情况 120 temp_para = temp.split(=) # 则,将item用=分割, 获取=两边的内容 121 if temp.startswith(=): # =2 122 bf_temp_index = temp_list.index(temp) - 1 123 bf_temp = temp_list[bf_temp_index] 124 para_str = para_str.replace(temp, ==" + temp_para[-1] + ") 125 para_str = para_str.replace(bf_temp + , "{}".format(bf_temp)) 126 elif temp.endswith(=): # user_id= 127 bh_temp_index = temp_list.index(temp) + 1 128 bh_temp = temp_list[bh_temp_index] 129 para_str = para_str.replace(temp, \" + temp_para[0] + \"==) 130 para_str = para_str.replace(bh_temp + , "{}".format(bh_temp)) 131 else: # user_id=2 132 # 替换原字符串中的temp, 替换为 ‘user_dept‘==‘IT‘ 133 para_str = para_str.replace(temp, "" + temp_para[0] + "‘==‘" + temp_para[1] + "") 134 else: # 匹配‘=‘的情况,则说明=两边是空格, 那直接替换原字符串 = 为 == 135 temp_index = temp_list.index(temp) 136 old_str = temp_list[temp_index - 1] + = + temp_list[temp_index + 1] 137 new_str = "{}" == "{}".format(temp_list[temp_index - 1], temp_list[temp_index + 1]) 138 para_str = para_str.replace(old_str, new_str) 139 return para_str 140 141 142 def get_ok_dic_id(para_str, user_info_list): 143 """ 144 遍历整个用户信息表, 返回符合where后面条件的dic在user_info_list中下标的列表, 使用与delete,select,update 145 :param user_info_list: 用户信息列表 146 :param para_str 传给get_where_clause函数, 返回能被eval的字符串 147 :return: union 148 """ 149 res_list = [] 150 if not para_str: 151 return list(range(len(user_info_list))) 152 for dic_item in user_info_list: # 遍历user_info_list, 153 # 调用函数,处理where子句,返回可以eval的字符串 154 eval_str = get_where_clause(para_str, dic_item) 155 if eval_str[0] == 901: 156 return eval_str 157 try: 158 if eval(eval_str): # 判断eval的字符串是否成立; 成立则追加成立的字典下标到返回列表 159 res_list.append(user_info_list.index(dic_item)) 160 except (NameError, SyntaxError): 161 return 901, Where子句 162 return res_list 163 164 165 def get_filename(para_str): 166 """ 167 这个函数用来解决 sql 语句当中 db.emp 对应文件的问题 168 :param para_str: 小写字符串 db.emp 169 :return: union 170 """ 171 # 获取当前文件的绝对路径(不包含文件名) 172 real_path = os.path.dirname(os.path.realpath(__file__)) 173 # 替换参数中字符串的.为/ 174 db_path = para_str.replace(., /) 175 # 字符串拼接,组成数据库文件的绝对路径 176 file_path = real_path + / + db_path 177 # 判断文件是否存在 178 if os.path.isfile(file_path): 179 return 950, db_path # 返回数据文件的相对路径 180 else: 181 return 951, {}不存在.format(db_path) # 数据文件不存在 182 183 184 def get_res_list(content, user_info_list, cl_name=‘‘): 185 """ 186 select函数专用; 简化 select * from ... 和 select column1, column2 from ... 的情况 187 :param cl_name: 查询字段,默认为空代表* 188 :param user_info_list: 用户信息列表 189 :param content: where子句 190 :return: res_list 191 """ 192 t_flag = False 193 res_list = [] 194 cont_list = [] 195 # 获取字符串形式的字段名{user_name},{user_age}... 196 # 因查询的字段,显示不同 197 if not cl_name: 198 temp_str = ,.join([{ + x + } for x in tk_temp]) 199 else: 200 new_cl_list = cl_name.split(,) 201 for each_cl in new_cl_list: 202 if each_cl not in tk_temp: 203 return 921, 字段名 {} 不存在.format(each_cl) 204 temp_str = ,.join([{ + x + } for x in new_cl_list]) 205 206 if content == ‘‘: 207 for item in user_info_list: 208 temp = [{0}].format(temp_str).format_map(item) 209 res_list.append(temp) 210 # select * from db.emp [ where... | limit... ] 211 else: 212 # 如果有limit,把limit后面那个值取出来,content变为limit前的str;更改limit标志位 213 if limit in content: 214 cont_list = content.split(limit) 215 if cont_list[0]: 216 content = cont_list[0] 217 else: 218 content = ‘‘ 219 t_flag = True 220 # 根据content 取出匹配到的dic的下标 221 se_id = get_ok_dic_id(content, user_info_list) 222 if se_id: 223 if se_id[0] == 901: 224 return se_id 225 else: 226 # 遍历下标,将内容先追加到一个列表 227 for each_id in se_id: 228 temp = [{0}].format(temp_str).format_map(dict(user_info_list[each_id])) 229 res_list.append(temp) 230 else: 231 res_list = se_id 232 233 if t_flag: 234 return res_list[:int(cont_list[-1])] 235 else: 236 return res_list 237 238 239 def my_sql_select(para_str): 240 """ 241 查询 242 :param: para_str: 接收用户输入的字符串 小写 243 :return: 244 """ 245 para_list = para_str.split() 246 247 try: 248 # 找到from关键字的下标 249 from_id = para_list.index(ky_list[5]) 250 except ValueError: 251 # 无关键字 252 return 901, 关键字{}缺失.format(ky_list[5]) 253 254 # select 到 from 之间 判断长度 255 if len(para_list[1:from_id]) >= 1: 256 cl_name = ‘‘.join(para_list[1:from_id]) 257 else: 258 return 901, {}与{}之间.format(ky_list[0], ky_list[5]) 259 260 if len(para_list[from_id + 1:]) >= 2: 261 try: 262 # 查找where的下标 263 where_id = para_list.index(ky_list[6]) 264 if len(para_list[from_id + 1:where_id]) != 1: 265 return 901, 数据文件部分有语法错误 266 if len(para_list[where_id + 1:]) > 0: 267 content = para_str.split(ky_list[6])[-1].strip() 268 else: 269 return 901, 关键字{}后缺少条件.format(ky_list[6]) 270 271 except ValueError: 272 # 没有where 273 try: 274 limit_id = para_list.index(ky_list[-2]) 275 if len(para_list[from_id + 1:limit_id]) != 1: 276 return 901, 关键字{}位置不对.format(ky_list[-2]) 277 if len(para_list[limit_id:]) == 2: 278 content = .join(para_list[limit_id:]) 279 else: 280 return 901, {} 后参数异常.format(ky_list[-2]) 281 except ValueError: 282 return 901, 缺少 {} 或者 {} 关键字.format(ky_list[-3], ky_list[-2]) 283 elif len(para_list[from_id + 1:]) == 1: 284 content = ‘‘ 285 else: 286 return 901, 缺少数据文件 287 288 db_name = para_list[from_id + 1] 289 # 分割关键字之间的str结束, 得到: 290 # select-->from = cl_name 291 # from-->where = db_name 292 # where--> = content(maybe include limit) 293 294 # 通过get_filename函数将db.emp类型转文件路径db/emp 295 file_tup = get_filename(db_name) 296 file_name = file_tup[1] 297 # 将文件内容读取出来,保存到user_info_list列表 298 if file_tup[0] == 951: 299 return file_tup 300 user_info_list = get_all_info(file_name) 301 302 # select * from ... 303 if cl_name == *: 304 # select * from db.emp + content 305 # 这里这种情况直接调用函数, 因为就cl_name不一样,其他都基本一致. 306 # 把cl_name传进去,进行匹配判断. 307 res_list = get_res_list(content, user_info_list) 308 if res_list: 309 if res_list[0] == 901 or res_list[0] == 921: 310 return res_list 311 else: 312 # select user_id ,name , xx from db.emp + content 313 res_list = get_res_list(content, user_info_list, cl_name) 314 if res_list: 315 if res_list[0] == 901 or res_list[0] == 921: 316 return res_list 317 318 for each_res in res_list: 319 print(each_res) 320 return 920, 总共{}条记录.format(len(res_list)) 321 322 323 def my_sql_insert(para_str): 324 """ 325 往数据文件插入数据. 326 1. 可以直接将数据插入到文件; 327 2. 先append到列表,然后再将列表覆盖写入文件的方式; 328 这里为了练习函数的使用,采用方法2。 329 :param para_str: 小写字符串 insert into [db_file] values xxx 330 :return: 331 """ 332 # 将接收的参数通过空格来分割,转为列表 333 para_list = para_str.split() 334 335 try: 336 values_id = para_list.index(ky_list[4]) # 找到values关键字的位置;ky_list[4]=values 337 except ValueError: 338 return 901, 关键字{}缺失.format(ky_list[4]) # 无values关键字 339 340 if len(para_list[2:values_id]) != 1: # 判断into之后到values关键字之间是否只有一个元素 341 return 901, 数据文件部分有语法错误 # 否,则返回选择的数据库和表有误 342 else: 343 db_name = para_list[2] # 是,数据文件暂定 344 345 if len(para_list[values_id + 1:]) < 1: # 判断values关键字之后是否再有无空格 346 return 901, 未发现要插入的数据 # 如果有,插入的数据格式有误 347 else: 348 # 如果有values,则以values分割,取后面的字符串,以,分割得到一个列表 349 temp_list = para_str.split(ky_list[4])[1].split(,) 350 # 匹配列表长度,与用户信息dict长度是否一致 351 if len(temp_list) == 5: 352 for temp_item in temp_list: 353 # 去掉空格 354 temp_index = temp_list.index(temp_item) 355 temp_list[temp_index] = temp_item.strip() 356 else: 357 return 921, 要插入的数据 格式有误 358 content = ,.join(temp_list) # 没有,则确定插入的数据 359 360 # 通过上述判断,可得出要插入的内容content和要插入的文件名db_name 361 # 通过get_filename函数将db.emp类型转文件路径db/emp 362 file_tup = get_filename(db_name) 363 file_name = file_tup[1] 364 # 将文件内容读取出来,保存到user_info_list列表 365 if file_tup[0] == 951: 366 return file_tup 367 user_info_list = get_all_info(file_name) 368 369 # 遍历user_info_list,判断手机号是否唯一 370 for item in user_info_list: 371 if content.split(,)[2] in item.values(): 372 return 911, 手机号{}已经存在.format(content.split(,)[2]) # 返回手机号已经存在 373 374 # 上述判断通过,则这里表明输入的参数中,数据文件以及要插入的数据都是合法的 375 # 得到主键ID 376 insert_id = int(user_info_list[-1][tk_temp[0]]) + 1 377 378 # 得到要插入的完整内容 id,name,age,phone,dept,date 379 insert_str = str(insert_id) + , + content 380 381 # 先将得到的内容通过,分割得到列表;再与字段名的列表tk_temp组成dict,追加到user_info_list 382 user_info_list.append(dict(zip(tk_temp, insert_str.split(,)))) 383 384 # 将user_info_list写入文件 385 write_to_file(file_name, user_info_list) 386 # 打印插入成功提示 387 print({2} func: insert(), db_file: {0}, values: {1} {3}.format(file_name, content, {, })) 388 return 910, 当前数据库中最大主键 ID = {0}.format(str(insert_id)) # 返回插入成功 389 390 391 def my_sql_delete(para_str): 392 """ 393 删除 394 delete from db.emp where id >25 395 delete * from db.emp 396 删除成功提示 397 :param: para_str: str 398 :return: 399 """ 400 # 清空文件标识 401 tc_flag = False 402 403 # 将接收的参数通过空格来分割,转为列表 404 para_list = para_str.split() 405

人气教程排行