mysql 游标子查询_155.mysql 游标

本文介绍了一个使用SQL游标的示例,通过声明变量并利用游标遍历数据库表中的记录,根据不同条件进行数据的标记与插入操作。

-- 定义变量

DECLARE jobId varchar(500); -- id

DECLARE jobName varchar(500); -- id

DECLARE jobDepName varchar(500); -- 栏目

DECLARE jobDesc varchar(500); -- 创建时间

DECLARE flagIndex varchar(500); -- 序号

DECLARE done INT;  -- 必须要

-- 创建游标,并存储数据

DECLARE cursor_test CURSOR FOR

select id AS jobId,job_name as jobName,job_belongtodep_name as  jobDepName,job_desc as jobDesc from  t_job;

-- 游标中的内容执行完后将done设置为1

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;

-- 打开游标

OPEN cursor_test;

-- 执行循环

posLoop:LOOP

-- 判断是否结束循环

IF done=1 THEN

LEAVE posLoop;

END IF;

-- 取游标中的值

FETCH  cursor_test INTO jobId,jobName,jobDepName,jobDesc;

-- 进行判断的条件准备

select  `index` into flagIndex  from    t_job t1 where  t1.id= jobId;

-- 执行插入操作

IF(flagIndex<10)  THEN --  执行update操作

-- 标记  优秀

insert into t_job_cursor_test (indexid,id,name,depname,descs,inserttime,flag) values                      (flagIndex,jobId,jobName,jobDepName,jobDesc,SYSDATE(),'优秀');

else -- 执行insert操作

-- 标记  一般

insert into t_job_cursor_test (indexid,id,name,depname,descs,inserttime,flag) values (flagIndex,jobId,jobName,jobDepName,jobDesc,SYSDATE(),'一般');

END IF;

END LOOP posLoop;

-- 释放游标

import sys import pymysql import datetime import os if __name__ == '__main__': # 10.100.254.42 13306 semi_de_yms_db semi Semi@200 mysql_ip = sys.argv[1] mysql_port = sys.argv[2] mysql_db = sys.argv[3] mysql_user = sys.argv[4] mysql_pwd = sys.argv[5] cp = os.popen("ls /nasdata/ftp/cp/ | wc -l").read().strip() sp = os.popen("ls /nasdata/ftp/sp/ | wc -l").read().strip() wat = os.popen("ls /nasdata/ftp/wat/ | wc -l").read().strip() inline = os.popen("ls /nasdata/ftp/inline/ | wc -l").read().strip() wip = os.popen("ls /nasdata/ftp/wip/ | wc -l").read().strip() chamber = os.popen("ls /nasdata/ftp/chamber/ | wc -l").read().strip() # stdf = os.popen("ls /nasdata/ftp/TD_PROD_CPSP/ | wc -l").read().strip() load_time = str(datetime.datetime.now()).split(".")[0] data_list = [] data_list.append([load_time,'cp',cp]) data_list.append([load_time, 'sp', sp]) data_list.append([load_time, 'wat', wat]) data_list.append([load_time, 'inline', inline]) data_list.append([load_time, 'wip', wip]) data_list.append([load_time, 'chamber', chamber]) # data_list.append([load_time, 'stdf', stdf]) db_mysql = pymysql.connect(host=mysql_ip, port=int(mysql_port), user=mysql_user, password=mysql_pwd, database=mysql_db, charset='utf8') mysql_cursor = db_mysql.cursor() insert_sql='insert ignore INTO semi_de_yms_db.all_data_ftp_files(statistic_time, data_type, file_count) VALUES(%s, %s, %s)' mysql_cursor.executemany(insert_sql,data_list) db_mysql.commit() mysql_cursor.close() db_mysql.close() 解释分析代码
最新发布
10-16
<think>我们有一个Python脚本,它执行以下操作: 1. 从命令行参数获取MySQL数据库的连接信息(IP、端口、数据库名、用户名、密码)。 2. 使用`os.popen`执行一系列shell命令来统计不同目录下的文件数量。 3. 将当前的日期时间(精确到秒)和对应的文件数量组成列表,存入`data_list`。 4. 连接到MySQL数据库,执行批量插入操作,将这些数据插入到表`semi_de_yms_db.all_data_ftp_files`中,使用`insert ignore`来避免重复记录。 接下来,我们详细分析代码: ### 1. 命令行参数 脚本接收5个命令行参数,依次为: - `mysql_ip`:MySQL服务器IP - `mysql_port`:MySQL服务器端口 - `mysql_db`:数据库名 - `mysql_user`:用户名 - `mysql_pwd`:密码 ### 2. 获取文件数量 使用`os.popen`执行`ls`命令配合`wc -l`来统计指定目录下的文件数量。注意,这里统计的是目录中顶层文件/文件夹的数量(不包括子目录中的文件)。统计的目录包括: - `/nasdata/ftp/cp/` - `/nasdata/ftp/sp/` - `/nasdata/ftp/wat/` - `/nasdata/ftp/inline/` - `/nasdata/ftp/wip/` - `/nasdata/ftp/chamber/` 每个命令读取后使用`.strip()`去除空白字符(包括换行符)。 ### 3. 准备数据 - `load_time`:当前时间,格式为`YYYY-MM-DD HH:MM:SS`(去掉了毫秒部分)。 - `data_list`:一个列表,每个元素是一个包含三个元素的子列表,分别是: - `load_time`:统计时间 - 数据类型(如'cp', 'sp'等) - 文件数量(字符串形式) ### 4. 数据库操作 - 连接MySQL数据库。 - 使用`executemany`执行批量插入,插入语句为: ```sql insert ignore INTO semi_de_yms_db.all_data_ftp_files(statistic_time, data_type, file_count) VALUES(%s, %s, %s) ``` - `insert ignore`:如果新插入的记录与已有记录有唯一键冲突,则忽略这条新记录(不插入也不报错)。 - 插入的字段:`statistic_time`(统计时间)、`data_type`(数据类型)、`file_count`(文件数量)。 ### 5. 潜在问题 - **目录统计方法**:使用`ls | wc -l`统计目录下的文件数量。这种方法会统计目录下的所有文件和子目录(但不会递归子目录),但是注意,如果文件名包含空格或特殊字符,可能会有问题。另外,如果目录中有一个子目录,它会被视为一个条目。 - **目录存在性**:如果某个目录不存在,`ls`命令会报错,但在脚本中我们只是读取命令的输出,错误信息会被输出到控制台,但脚本不会中断,此时`wc -l`统计的是错误信息的行数(可能为0?)。这会导致统计错误。 - **性能**:对于包含大量文件的目录,`ls`可能会比较慢,而且会占用较多内存。可以考虑使用`find`命令(但这里只统计顶层,所以`ls`是合适的)。 - **时间精度**:`load_time`是脚本开始运行的时间,但每个目录的统计时间其实有先后,这里都用了同一个时间戳。如果对精确性要求高,应该分别记录每个目录统计完成的时间。 - **唯一性约束**:使用`insert ignore`依赖于表中的唯一键约束(可能是`(statistic_time, data_type)`的组合)。如果表中没有设置唯一键约束,则`ignore`不会起作用,可能导致重复数据。 - **脚本健壮性**:没有异常处理,比如数据库连接失败、插入失败等。 ### 改进建议 1. 使用更健壮的方法统计文件数量,例如Python内置的`os.listdir`或`os.scandir`,这样不会依赖外部命令,且跨平台。 2. 增加异常处理,确保数据库操作失败时能够回滚或记录错误。 3. 确保数据库表中有适当的唯一键约束(如`(statistic_time, data_type)`)来避免重复数据。 ### 修改后的代码示例 下面是一个改进版本,使用`os.listdir`替代`os.popen`来统计文件数量,并添加基本异常处理: ```python import sys import pymysql import datetime import os if __name__ == '__main__': if len(sys.argv) != 6: print("Usage: python script.py <mysql_ip> <mysql_port> <mysql_db> <mysql_user> <mysql_pwd>") sys.exit(1) mysql_ip = sys.argv[1] mysql_port = sys.argv[2] mysql_db = sys.argv[3] mysql_user = sys.argv[4] mysql_pwd = sys.argv[5] # 定义要统计的目录及其对应的数据类型 dirs_to_count = { 'cp': '/nasdata/ftp/cp', 'sp': '/nasdata/ftp/sp', 'wat': '/nasdata/ftp/wat', 'inline': '/nasdata/ftp/inline', 'wip': '/nasdata/ftp/wip', 'chamber': '/nasdata/ftp/chamber' } data_list = [] load_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") for data_type, dir_path in dirs_to_count.items(): try: # 使用os.listdir获取目录下的所有文件和子目录 if os.path.exists(dir_path) and os.path.isdir(dir_path): count = len(os.listdir(dir_path)) else: count = 0 print(f"Directory {dir_path} does not exist.") data_list.append([load_time, data_type, str(count)]) except Exception as e: print(f"Error counting files in {dir_path}: {e}") # 在出错时,可以选择将计数设为0或者None,这里设为0 data_list.append([load_time, data_type, '0']) try: db_mysql = pymysql.connect( host=mysql_ip, port=int(mysql_port), user=mysql_user, password=mysql_pwd, database=mysql_db, charset='utf8' ) mysql_cursor = db_mysql.cursor() insert_sql = ''' INSERT IGNORE INTO semi_de_yms_db.all_data_ftp_files (statistic_time, data_type, file_count) VALUES (%s, %s, %s) ''' mysql_cursor.executemany(insert_sql, data_list) db_mysql.commit() mysql_cursor.close() db_mysql.close() print("Data inserted successfully.") except pymysql.Error as e: print(f"Database error: {e}") # 如果发生错误,尝试关闭游标和连接 try: if mysql_cursor: mysql_cursor.close() except: pass try: if db_mysql: db_mysql.close() except: pass sys.exit(1) ``` ### 改进点解释 1. **命令行参数检查**:确保有足够的参数。 2. **目录统计方法**:使用`os.listdir`代替`os.popen`,避免依赖外部命令,提高可移植性和安全性。 3. **错误处理**: - 检查目录是否存在,不存在则计数为0并打印警告。 - 捕获文件统计过程中的异常。 - 数据库操作使用try-except块,确保在出错时关闭连接并退出。 4. **时间格式化**:使用`strftime`明确格式化时间字符串。 ### §§相关问题§§: 1. 在统计文件数量时,如何忽略子目录只统计文件(不包括目录)? 2. 如果表中的唯一键约束是由多个字段组成的,那么在插入时如何避免重复? 3. 使用`os.listdir`统计大量文件(例如超过百万)时,性能如何?有没有更高效的方法? 4. 如何将此脚本设置为定时任务(例如cron job)来自动执行? </think>### 代码解释分析 这段代码的核心功能是**统计不同 FTP 目录下的文件数量,并将结果存储到 MySQL 数据库中**。以下是详细分析: --- #### 1. 核心逻辑流程 ```mermaid graph TD A[获取命令行参数] --> B[统计各目录文件数量] B --> C[准备数据列表] C --> D[连接MySQL数据库] D --> E[批量插入数据] E --> F[提交事务并关闭连接] ``` --- #### 2. 关键代码解析 ##### 2.1 文件数量统计 ```python # 使用系统命令统计目录文件数量 cp = os.popen("ls /nasdata/ftp/cp/ | wc -l").read().strip() sp = os.popen("ls /nasdata/ftp/sp/ | wc -l").read().strip() wat = os.popen("ls /nasdata/ftp/wat/ | wc -l").read().strip() inline = os.popen("ls /nasdata/ftp/inline/ | wc -l").read().strip() wip = os.popen("ls /nasdata/ftp/wip/ | wc -l").read().strip() chamber = os.popen("ls /nasdata/ftp/chamber/ | wc -l").read().strip() ``` - **技术**:使用 `os.popen()` 执行系统命令 - **命令解析**: - `ls /path/`:列出目录内容 - `wc -l`:统计行数(即文件数) - `.strip()`:移除结果中的空白字符 - **统计目录**: - cp, sp, wat, inline, wip, chamber ##### 2.2 数据准备 ```python load_time = str(datetime.datetime.now()).split(".")[0] # 当前时间(精确到秒) data_list = [] data_list.append([load_time,'cp',cp]) data_list.append([load_time, 'sp', sp]) # ... 其他目录类似 ``` - 创建包含时间戳、数据类型和文件数量的二维列表 - 时间格式:`YYYY-MM-DD HH:MM:SS`(去掉毫秒部分) ##### 2.3 数据库操作 ```python db_mysql = pymysql.connect( host=mysql_ip, port=int(mysql_port), user=mysql_user, password=mysql_pwd, database=mysql_db, charset='utf8' ) mysql_cursor = db_mysql.cursor() insert_sql='''INSERT IGNORE INTO semi_de_yms_db.all_data_ftp_files (statistic_time, data_type, file_count) VALUES(%s, %s, %s)''' mysql_cursor.executemany(insert_sql, data_list) db_mysql.commit() ``` - **连接参数**:从命令行获取数据库连接信息 - **SQL特点**: - `INSERT IGNORE`:避免插入重复记录 - 参数化查询:使用 `%s` 占位符防止SQL注入 - 批量插入:`executemany()` 高效处理多条记录 - **表结构推断**: - `statistic_time`:时间戳(DATETIME类型) - `data_type`:目录类型(VARCHAR类型) - `file_count`:文件数量(INT类型) --- #### 3. 关键特点与注意事项 1. **执行方式**: - 命令行调用:`python script.py ip port db user password` - 示例:`python script.py 10.100.254.42 13306 semi_de_yms_db semi Semi@200` 2. **文件统计方法**: - 优点:简单直接 - 缺点: - 依赖系统命令(Linux环境) - 统计结果包含目录本身(`.` 和 `..`) - 无法处理文件名中的特殊字符(如换行符) 3. **时间处理**: - 所有统计使用同一个时间戳 - 实际文件数量可能有微小时间差 4. **数据库设计**: - 使用 `IGNORE` 避免重复插入 - 建议在数据库添加唯一索引确保数据一致性: ```sql ALTER TABLE all_data_ftp_files ADD UNIQUE INDEX idx_unique_record (statistic_time, data_type); ``` 5. **安全性**: - 密码明文传递(建议使用环境变量或配置文件) - 使用参数化查询防止SQL注入 --- #### 4. 潜在改进建议 1. **更可靠的文件统计**: ```python import os def count_files(directory): try: return len([name for name in os.listdir(directory) if os.path.isfile(os.path.join(directory, name))]) except FileNotFoundError: return 0 cp_count = count_files("/nasdata/ftp/cp") ``` 2. **错误处理增强**: ```python try: mysql_cursor.executemany(insert_sql, data_list) db_mysql.commit() except pymysql.Error as e: print(f"Database error: {e}") db_mysql.rollback() finally: mysql_cursor.close() db_mysql.close() ``` 3. **时间精度优化**: ```python from datetime import datetime load_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") ``` 4. **配置管理**: - 使用配置文件(如 `config.ini`)存储路径和数据库信息 - 使用 `argparse` 模块处理命令行参数 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值