使用PHP将Oracle查询的工资数据行转列生成月度员工工资报表
员工月度工资交叉报表实现方案
方案1:Oracle端直接PIVOT生成交叉结构(性能最优)
直接在数据库层面完成行转列,单次查询即可返回符合交叉表结构的数据,无需额外后端处理:
SELECT * FROM ( SELECT empno, nam, sal, TO_CHAR(dat, 'yyyy-mm') AS salary_month -- 统一日期为年月格式 FROM emp_sal WHERE dat BETWEEN :firstdate AND :lastdate -- 用参数绑定避免注入 ) PIVOT ( MAX(sal) -- 同一员工单月仅一条工资记录,SUM/MAX/MIN均可 FOR salary_month IN ( -- 此处可根据查询的时间范围动态生成所有目标月份列 '2024-01' AS "2024-01", '2024-02' AS "2024-02", '2024-03' AS "2024-03" ) ) ORDER BY empno
方案2:PHP端单次查询后数组重组(灵活性最高)
保留你原有的查询逻辑,仅在后端通过一次遍历完成结构转换,全程仅访问数据库一次,不会增加额外负载:
实现代码:
// 修复原查询的笔误,改用参数绑定避免SQL注入 $stmt = oci_parse($con, "SELECT empno, nam, TO_CHAR(dat, 'yyyy-mm') AS month, sal FROM emp_sal WHERE dat BETWEEN :firstdate AND :lastdate"); oci_bind_by_name($stmt, ':firstdate', $firstdate); oci_bind_by_name($stmt, ':lastdate', $lastdate); oci_execute($stmt); $empMap = []; // 按员工编号存储的映射数组 $monthList = []; // 存储所有出现过的月份,自动去重 // 单次遍历查询结果,构建中间结构 while ($row = oci_fetch_assoc($stmt)) { $empNo = $row['EMPNO']; $month = $row['MONTH']; // 收集月份列表 if (!in_array($month, $monthList)) { $monthList[] = $month; } // 初始化员工基础信息 if (!isset($empMap[$empNo])) { $empMap[$empNo] = [ 'EMPNO' => $empNo, 'NAME' => $row['NAM'] ]; } // 存储对应月份工资 $empMap[$empNo][$month] = $row['SAL']; } // 月份按时间升序排序 sort($monthList); // 生成最终交叉表结构 $crossReport = []; foreach ($empMap as $empItem) { $reportRow = $empItem; // 补全所有月份列,无工资数据时默认留空 foreach ($monthList as $month) { $reportRow[$month] = $empItem[$month] ?? ''; } $crossReport[] = $reportRow; }
最终$crossReport就是你需要的交叉表结构,行维度为员工编号、姓名,列维度为所有查询范围内的月份。
注意事项
- 你原查询中的
'l$lastdate'存在笔误,多了多余的字母l,需修正 - 直接在SQL中拼接变量存在SQL注入风险,建议统一使用
oci_bind_by_name做参数绑定
内容的提问来源于stack exchange,提问作者shujaazher
相关产品推荐
相关产品推荐

