尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Oracle 存储过程用游标循环插入数据:TaoToken 统一 Key 配置与 settings.json 骨架

Oracle 存储过程用游标循环插入数据:TaoToken 统一 Key 配置与 settings.json 骨架 1. 从一次考勤补录说起Oracle 游标循环插入到底解决什么问题如果你在 Oracle 里遇到过这种需求——「把 A 表里符合条件的人挑出来针对每个人、每一天判断 B 表里有没有记录没有就补一条」——那你其实已经站在游标循环插入的门口了。这类活儿的典型场景就是考勤补录培训名单里有一批人培训周期内每天上午、下午各该有一次打卡但实际表里缺记录需要按规则把缺失的补上时间还得带点随机性看起来像真实打卡。纯用一条INSERT ... SELECT很难搞定因为「判断上午有没有、下午有没有、再决定插哪一条」是逐行、逐日的条件分支。这时候存储过程 游标循环就是最顺手的工具外层游标遍历人员内层循环遍历日期循环体里用CASE WHEN判断并插入。它跑在数据库侧不用把数据拉到应用层几万行也就是分分钟的事。这篇就围绕这个场景给你一份可直接复制的存储过程骨架再把 TaoToken 统一 Key 在settings.json里的配置骨架和连通性验证动作补齐让你从写 SQL 到确认调用链路可用一次走通。适合已经会写基础 PL/SQL、但想把「游标 循环 条件插入」这套组合拳打扎实的开发者。2. TaoToken 前置统一 Key 与 settings.json 骨架在动手写存储过程之前先把工具链的「钥匙」配好。TaoToken 的作用是给你一个统一的 API Key让模型对话、编码辅助、Agent 调用都走同一个入口不用每个工具单独配一套凭证。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 。配置的核心是一个settings.json骨架。你可以把它理解成「告诉工具去哪里、用哪把钥匙」的清单。下面这份骨架覆盖了最常见的字段按需替换即可{ provider: taotoken, api_base: https://taotoken.net/api, api_key: sk-你的统一Key, model: claude-sonnet, timeout: 60, retry: { max_attempts: 3, backoff_ms: 800 }, features: { chat: true, coding: true, agent: true } }几个字段说明一下。api_base固定填https://taotoken.net/api不要带多余路径api_key就是你在控制台生成的统一 Key所有下游工具共用它timeout给 60 秒长上下文场景可以调到 120retry是网络抖动时的重试策略backoff_ms用指数退避更稳。features是开关按你实际用到的能力打开。注意api_key不要提交到 Git 仓库建议用环境变量注入比如在启动脚本里export TAOTOKEN_KEYsk-xxx再在settings.json里写api_key: ${TAOTOKEN_KEY}。Key 的生成和查看在控制台的 API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。生成后先复制保存页面刷新后就不再完整显示。3. 可复制配置游标循环插入存储过程骨架现在进入正题。下面这份存储过程骨架把「外层游标遍历人员 内层循环遍历日期 CASE WHEN 条件插入」三件事拆得清清楚楚。你可以直接改表名和字段名套用。CREATE OR REPLACE PROCEDURE restore_attendance AS -- 培训起止时间 v_start DATE; v_end DATE; v_day DATE; -- 上午/下午已有记录数 v_am_cnt INT; v_pm_cnt INT; -- 外层游标取出需要补录的人员 CURSOR c_person IS SELECT sfz, zwbh FROM ncldlpx WHERE xxid 0001 AND pxqb 2013001; BEGIN -- 取培训周期 SELECT pxkssj INTO v_start FROM kbqb WHERE xxid 0001 AND qb 2013001; SELECT pxjssj INTO v_end FROM kbqb WHERE xxid 0001 AND qb 2013001; -- 外层逐人 FOR p IN c_person LOOP v_day : v_start; -- 内层逐日 WHILE v_day v_end LOOP -- 判断上午是否已有记录 SELECT COUNT(*) INTO v_am_cnt FROM zw_kq WHERE ksj BETWEEN TO_DATE(TO_CHAR(v_day,yyyy-MM-dd)|| 07:00:00,yyyy-MM-dd hh24:mi:ss) AND TO_DATE(TO_CHAR(v_day,yyyy-MM-dd)|| 09:00:00,yyyy-MM-dd hh24:mi:ss) AND zwbh p.zwbh AND sfz p.sfz; -- 判断下午是否已有记录 SELECT COUNT(*) INTO v_pm_cnt FROM zw_kq WHERE ksj BETWEEN TO_DATE(TO_CHAR(v_day,yyyy-MM-dd)|| 17:00:00,yyyy-MM-dd hh24:mi:ss) AND TO_DATE(TO_CHAR(v_day,yyyy-MM-dd)|| 19:00:00,yyyy-MM-dd hh24:mi:ss) AND zwbh p.zwbh AND sfz p.sfz; -- 条件插入缺上午补上午缺下午补下午 CASE WHEN v_am_cnt 0 THEN INSERT INTO zw_kq(ksj, type, zwbh, sfz, qdtype) VALUES ( TO_DATE(TO_CHAR(v_day,yyyy-MM-dd)|| 07: ||ROUND(DBMS_RANDOM.VALUE(50,59),0)||: ||ROUND(DBMS_RANDOM.VALUE(0,59),0), yyyy-MM-dd hh24:mi:ss), 1, p.zwbh, p.sfz, 0); WHEN v_pm_cnt 0 THEN INSERT INTO zw_kq(ksj, type, zwbh, sfz, qdtype) VALUES ( TO_DATE(TO_CHAR(v_day,yyyy-MM-dd)|| 17: ||ROUND(DBMS_RANDOM.VALUE(0,10),0)||: ||ROUND(DBMS_RANDOM.VALUE(0,59),0), yyyy-MM-dd hh24:mi:ss), 1, p.zwbh, p.sfz, 0); ELSE DBMS_OUTPUT.PUT_LINE(正常考勤: ||p.sfz|| ||TO_CHAR(v_day,yyyy-MM-dd)); END CASE; v_day : v_day 1; END LOOP; END LOOP; COMMIT; END restore_attendance; /几个关键点值得单独说。第一FOR p IN c_person LOOP是隐式游标循环不用手动OPEN/FETCH/CLOSEOracle 自动管理出错概率低。第二内层用WHILE v_day v_end而不是FOR因为日期递增需要手动控制v_day : v_day 1就是步进。第三CASE WHEN里先判断上午再判断下午如果上午缺就补上午否则看下午两个都不缺才走ELSE打印日志。第四DBMS_RANDOM.VALUE(50,59)生成 50 到 59 之间的随机数让打卡时间落在 07:50 到 07:59 之间看起来更自然。提示DBMS_OUTPUT.PUT_LINE需要先SET SERVEROUTPUT ON才能在客户端看到输出否则日志会被吞掉。如果你想让插入更高效可以把COMMIT从循环外挪到每 N 条提交一次避免大事务回滚段压力。但注意别在循环体内每条都提交那样反而慢。4. 验证请求与成功结果从编译到数据核对存储过程写完先编译再验证。编译命令很简单ALTER PROCEDURE restore_attendance COMPILE;如果编译报错用下面这条查具体错误行SHOW ERRORS PROCEDURE restore_attendance;编译通过后执行过程SET SERVEROUTPUT ON; EXEC restore_attendance;执行完核对结果。先看补录了多少条SELECT COUNT(*) FROM zw_kq WHERE qdtype 0 AND ksj TO_DATE(2013-01-01,yyyy-MM-dd);再抽查某个人的记录确认上午下午都补上了SELECT sfz, TO_CHAR(ksj,yyyy-MM-dd hh24:mi:ss) AS ksj, qdtype FROM zw_kq WHERE sfz 某个身份证号 ORDER BY ksj;正常的话你会看到每个人在培训周期内每天都有两条记录时间分别在 07:5x 和 17:0x 附近qdtype都是0。如果某天只有一条说明另一条判断逻辑没命中回去检查BETWEEN的时间边界是否把已有记录算进去了。TaoToken 侧的连通性验证也顺手做一下。用 curl 打一次模型对话接口确认 Key 和基址都对curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet, messages: [{role:user,content:ping}] }返回里带choices字段就说明链路通了。如果返回 401检查 Key 是否复制完整返回 404检查api_base是不是多写了路径。模型对话的入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以直接在页面上试。5. 本篇常见错排查游标循环插入的六个坑坑一SELECT INTO返回多行报 ORA-01422。取培训起止时间时如果kbqb表里同一个xxid和qb有多条记录SELECT INTO直接炸。解决方法是加AND ROWNUM 1或者用聚合函数再或者确认业务上确实唯一。坑二SELECT INTO返回零行报 ORA-01403。如果kbqb里根本没有对应记录v_start拿不到值。加异常处理BEGIN SELECT pxkssj INTO v_start FROM kbqb WHERE xxid0001 AND qb2013001; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE(未找到培训周期); RETURN; END;坑三日期比较漏掉时间部分。v_day是DATE类型带时分秒。如果v_start是2013-01-01 00:00:00v_day v_end在最后一天可能因为时间部分提前退出。稳妥做法是把日期截断到天v_day : TRUNC(v_start)v_end : TRUNC(v_end)。坑四DBMS_RANDOM.VALUE参数顺序写反。VALUE(50,59)是 50 到 59VALUE(59,50)会报错。另外ROUND后可能产生 60因为ROUND(59.6)是 60所以上界给 59 时实际可能到 60秒数同理。要精确控制就用TRUNC或者把上界减一。坑五游标里查的表在循环中被修改。如果c_person游标查的ncldlpx表在循环体里被插入或更新可能触发「快照太旧」或者游标数据不一致。原则是游标只读循环体只写目标表。坑六忘记COMMIT。存储过程里COMMIT写在END LOOP之后、END之前确保所有插入一起提交。如果中途异常整个事务回滚不会留下半截数据。注意生产环境跑之前先在测试库用ROLLBACK验证一遍确认插入条数和时间分布符合预期再正式提交。6. 把调用链路固定下来Coding Plan 与接入文档存储过程跑通、TaoToken 连通性验证通过之后建议把这条链路固定成日常习惯。如果你后续还要写更多类似的 PL/SQL 脚本或者让 Agent 帮你生成和审查存储过程可以用 Coding Plan 把编码辅助能力接进来长期用比每次手动配 Key 省事https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。接入细节和字段说明都在文档里遇到settings.json字段不确定、或者 curl 返回码看不懂的时候直接查文档最快https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。Key 管理还是回到 API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后留一个实用技巧把restore_attendance里的表名、xxid、pxqb抽成参数改成带入参的版本这样同一套逻辑能复用到不同批次不用每次改代码重新编译。参数化之后配合定时任务就能自动补录省掉手动执行的步骤。
返回列表