如何用PL/SQL和C#将硬编码派生列转为动态自动化列
自动化每月客户收支汇总方案
核心优化方向
- 动态计算目标月份:通过系统时间自动获取当前月份,推导需要处理的上月及当年1月至上月的区间,彻底替代硬编码的月份值
- 动态生成SQL逻辑:用动态SQL替代固定列的PL/SQL脚本,自动适配上月的预算、差异、完成率字段,同时保留历史月份的收支数据
- 代码参数化:C#端通过时间参数传递目标月份,不再手动修改代码中的月份常量
PL/SQL脚本自动化改造
1. 动态获取时间参数
先定义变量获取当前年、当前月、上月,同时处理1月对应上年12月的特殊情况:
DECLARE v_current_year NUMBER := EXTRACT(YEAR FROM SYSDATE); v_current_month NUMBER := EXTRACT(MONTH FROM SYSDATE); v_last_month NUMBER := v_current_month - 1; v_target_year NUMBER := CASE WHEN v_last_month = 0 THEN v_current_year - 1 ELSE v_current_year END; v_target_month NUMBER := CASE WHEN v_last_month = 0 THEN 12 ELSE v_last_month END; BEGIN -- 后续逻辑基于上述变量展开 END;
2. 动态生成列与预算字段
替换硬编码的月份列,用循环生成1到上月的收支列,仅对上月追加预算、差异、完成率字段:
DECLARE v_column_list VARCHAR2(4000); v_month NUMBER; BEGIN FOR v_month IN 1..v_last_month LOOP -- 普通月份仅取收支数据 v_column_list := v_column_list || 'SUM(CASE WHEN MONTH = ' || v_month || ' THEN AMOUNT ELSE 0 END) AS "MON_' || v_month || '_AMOUNT",'; -- 上月追加预算相关字段 IF v_month = v_last_month THEN v_column_list := v_column_list || 'SUM(BUDGET_AMOUNT) AS "MON_' || v_month || '_BUDGET",' || 'SUM(AMOUNT - BUDGET_AMOUNT) AS "MON_' || v_month || '_DIFF",' || 'ROUND(SUM(AMOUNT)/SUM(BUDGET_AMOUNT)*100,2) AS "MON_' || v_month || '_COMPLETION_RATE",'; END IF; END LOOP; -- 移除最后一个多余的逗号 v_column_list := RTRIM(v_column_list, ','); -- 动态执行查询或更新逻辑 EXECUTE IMMEDIATE 'SELECT ' || v_column_list || ' FROM YOUR_TABLE WHERE YEAR = ' || v_current_year; END;
3. PBT汇总自动追加
动态判断上月数据是否已加入PBT汇总,若未则自动插入:
-- 检查上月数据是否存在,不存在则插入 IF NOT EXISTS (SELECT 1 FROM PBT_SUMMARY WHERE YEAR = v_target_year AND MONTH = v_target_month) THEN INSERT INTO PBT_SUMMARY (YEAR, MONTH, AMOUNT, BUDGET, DIFF, COMPLETION_RATE) SELECT v_target_year, v_target_month, SUM(AMOUNT), SUM(BUDGET_AMOUNT), SUM(AMOUNT-BUDGET_AMOUNT), ROUND(SUM(AMOUNT)/SUM(BUDGET_AMOUNT)*100,2) FROM YOUR_TABLE WHERE YEAR = v_target_year AND MONTH = v_target_month; END IF;
C#代码优化
1. 动态计算目标月份
替换硬编码的月份,用系统时间自动推导:
// 获取上月的年和月 DateTime lastMonth = DateTime.Now.AddMonths(-1); int targetYear = lastMonth.Year; int targetMonth = lastMonth.Month; int currentYear = DateTime.Now.Year; // 生成当年1月至上月的月份范围 var monthsRange = Enumerable.Range(1, targetMonth == 12 ? 12 : targetMonth);
2. 参数化调用存储过程
将PL/SQL逻辑封装为存储过程,C#端传递年、月参数调用,不再手动修改SQL字符串:
using (SqlConnection conn = new SqlConnection(yourConnString)) { conn.Open(); SqlCommand cmd = new SqlCommand("SP_AUTO_UPDATE_SUMMARY", conn); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@CurrentYear", currentYear); cmd.Parameters.AddWithValue("@TargetYear", targetYear); cmd.Parameters.AddWithValue("@TargetMonth", targetMonth); cmd.ExecuteNonQuery(); }
3. 解决之前循环无效的问题
之前用DateTime.Now.Month-1循环无效,大概率是循环逻辑未结合动态列生成或数据库条件过滤。现在通过参数化+动态SQL的方式,直接基于计算出的月份范围生成对应逻辑,无需手动适配列名。
验证与调度
- 测试:手动修改系统时间(如改为8月),执行脚本和代码,检查是否自动适配7月的预算字段、替换6月预算数据,且7月数据成功加入PBT汇总
- 调度:将C#程序或PL/SQL脚本设置为每月1日自动执行(通过Windows任务计划或数据库Job)
内容的提问来源于stack exchange,提问作者Jonaθn
相关产品推荐
相关产品推荐

