
本文介绍如何将数据库中多个字段(如 technician_1 和 technician_2)的值统一统计,生成去重后的技术人员频次数据,并渲染为 chart.js 柱状图,避免重复查询、提升性能与可维护性。
本文介绍如何将数据库中多个字段(如 technician_1 和 technician_2)的值统一统计,生成去重后的技术人员频次数据,并渲染为 chart.js 柱状图,避免重复查询、提升性能与可维护性。
在使用 Chart.js 展示人员分布类数据时,常见需求是:将同一逻辑实体(如“处理人”)分散在多个字段中的记录进行合并统计。例如,tb_ticket 表中 technician_1 和 technician_2 均可能填写技术人员姓名,需将其合并计数(如 "Ema" 出现在任一列即计 1 次),最终得到类似 Ema=3, Tom=4, Ana=1, Lisa=2 的聚合结果。
⚠️ 原代码存在严重问题:
- 使用了错误的 SQL 语法 WHERE (technician_1','technician_2)='Ema' —— 这在 MySQL 中非法且无法执行;
- 对每位技术人员单独发起 4 次查询,效率低下,且硬编码标签与数据顺序易错;
- 大小写敏感(如 'lisa' ≠ 'Lisa'),未做标准化处理;
- 缺乏动态扩展能力:新增技术人员需手动修改 PHP 和 JS 两处代码。
✅ 推荐解决方案:单次 SQL 聚合查询 + PHP 数组归并
-- 统一提取所有技术人员(含去重与大小写归一化) SELECT UPPER(TRIM(technician)) AS tech_name, COUNT(*) AS count FROM ( SELECT technician_1 AS technician FROM tb_ticket UNION ALL SELECT technician_2 AS technician FROM tb_ticket ) AS all_techs WHERE technician IS NOT NULL AND TRIM(technician) != '' GROUP BY UPPER(TRIM(technician)) ORDER BY count DESC;
该查询将两列数据垂直堆叠(UNION ALL),清洗空值与空格,并统一转为大写(避免 Ema/ema 被视为不同项),最后按姓名分组计数。
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
对应 PHP + Chart.js 完整实现如下:
<?php // 执行聚合查询
$sql = "SELECT UPPER(TRIM(technician)) AS tech_name, COUNT(*) AS count
FROM (SELECT technician_1 AS technician FROM tb_ticket
UNION ALL
SELECT technician_2 AS technician FROM tb_ticket) AS all_techs
WHERE technician IS NOT NULL AND TRIM(technician) != ''
GROUP BY UPPER(TRIM(technician))
ORDER BY count DESC";
$result = mysqli_query($koneksi, $sql);
$labels = [];
$data = [];
while ($row = mysqli_fetch_assoc($result)) {
$labels[] = $row['tech_name'];
$data[] = (int)$row['count'];
}
?><script>
const ctx = document.getElementById("myChart").getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: <?php echo json_encode($labels); ?>,
datasets: [{
label: 'Request Count by Technician',
data: <?php echo json_encode($data); ?>,
backgroundColor: [
'#1B4F72', '#21618C', '#2874A6', '#2E86C1', '#3498DB'
].slice(0, <?php echo count($labels); ?>),
borderWidth: 0
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
ticks: {
precision: 0 // 确保显示整数
}
},
x: {
ticks: {
autoSkip: false
}
}
}
}
});
</script>
? 关键优势说明:
- ✅ 一次查询完成全部统计,性能更优,逻辑更清晰;
- ✅ 使用 json_encode() 安全输出 PHP 数组到 JS,避免 XSS 风险与引号嵌套问题;
- ✅ UPPER(TRIM()) 保障名称标准化,消除大小写与空格干扰;
- ✅ 标签与数据严格一一对应,支持任意数量技术人员动态渲染;
- ✅ 图表配置启用 responsive: true 和 beginAtZero: true,确保专业可视化效果。
? 进阶建议:
- 若需区分主/辅技术员权重(如 technician_1 计 1.0 分,technician_2 计 0.5 分),可改用 UNION ALL 后加 CASE WHEN 加权求和;
- 生产环境务必对 $koneksi 连接做异常检测,并使用 PDO 或 MySQLi 面向对象方式增强可读性;
- 前端可结合 Chart.js 插件(如 chartjs-plugin-datalabels)直接在柱上显示数值,提升可读性。
通过此方案,你不仅能正确呈现多列合并统计图表,更构建了可复用、易维护的数据可视化基础结构。










