如何在非规范化数据库中按 ID 和月份统计条目数量

发布时间 - 2026-01-20 00:00:00    点击率:

本文介绍如何处理 `opid` 字段包含逗号分隔值的非规范化表,通过 php 预处理实现按单个操作 id(而非整条字符串)和月份精准计数,并生成结构化统计结果。

在实际开发中,我们偶尔会遇到设计不规范的数据库表——例如 tbl_operations 表中 OpId 字段并非原子值,而是以逗号分隔的字符串(如 '5,3' 或 '3,2')。这种非规范化结构使得纯 SQL 聚合统计变得异常困难:标准 GROUP BY 无法直接拆分字符串,而 MySQL 8.0+ 的 REGEXP_SUBSTR 或递归 CTE 虽可行,但兼容性差、可读性低,且在高并发或大数据量下性能堪忧。

因此,推荐采用“SQL + PHP 协同处理”的稳健方案:先用简单 SQL 获取原始数据,再由 PHP 完成字符串解析、月份提取与多维计数。该方法逻辑清晰、易于调试、完全兼容所有 PHP 环境(>=7.4),并便于后续扩展(如去重、过滤、导出等)。

以下是核心实现代码:

// 假设 $pdo 是已建立的 PDO 连接
$stmt = $pdo->query("SELECT OpId, OpDate FROM tbl_operations");
$rows = $stmt->fetchAll(PDO::FETCH_NUM);

$counts = [];
foreach ($rows as $row) {
    [$opIdStr, $opDate] = $row;
    $ids = array_map('trim', explode(',', $opIdStr)); // 自动去除空格(如 '5, 3')
    $month = date('m', strtotime($opDate)); // 提取两位月份(如 '01')

    foreach ($ids as $id) {
        if (!isset($counts[$id][$month])) {
            $counts[$id][$month] = 0;
        }
        $counts[$id][$month]++;
    }
}

// 转换为题设要求的扁平化结果数组(便于渲染表格或 JSON 输出)
$result = [];
foreach ($counts as $opId => $months) {
    foreach ($months as $month => $count) {
        $result[] = ['OpId' => $opId, 'count' => $count, 'Month' => $month];
}

// 可选:按 OpId 升序、Month 升序排序,确保输出稳定
usort($result, function($a, $b) {
    return $a['OpId'] <=> $b['OpId'] ?: $a['Month'] <=> $b['Month'];
});

关键优势说明

  • array_map('trim', ...) 防止因空格导致 ' 3' 与 '3' 被视为不同 ID;
  • isset() 检查比 array_key_exists() 更高效,且能同时判断嵌套键是否存在;
  • usort() 确保结果顺序可控,避免因数组遍历不确定性影响测试或展示;
  • 整体时间复杂度为 O(n×m),其中 n 为行数、m 为平均每行 ID 数量,性能线

    性可预期。

⚠️ 注意事项

  • 若数据量极大(如超 10 万行),建议在 PHP 层分批次处理,或改用数据库端 JSON 函数(MySQL 5.7+/PostgreSQL)预处理;
  • 长期来看,强烈建议重构表结构:新建关联表 operation_ids(op_id, operation_id) 实现一对多关系,从根本上消除字符串解析需求;
  • 生产环境务必对 strtotime($opDate) 做容错处理(如检查返回 false 并跳过非法日期)。

通过此方案,你不仅能准确复现题设中的统计表格,还能灵活支持分页、筛选、导出 CSV 等衍生需求,真正兼顾正确性、可维护性与扩展性。


# mysql  # php  # js  # json  # 大数据  # csv  # 字符串解析  # sql  # 字符串  # 递归  # 并发  # postgresql  # 数据库  # 重构  # 升序  # 多维  # 还能  # 遍历  # 两位  # 你不  # 分页  # 可选  # 而非 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】  齐河建站公司:营销型网站建设与SEO优化双核驱动策略  JavaScript如何实现音频处理_Web Audio API如何工作?  Laravel如何生成API文档?(Swagger/OpenAPI教程)  如何在阿里云虚拟服务器快速搭建网站?  深入理解Android中的xmlns:tools属性  Laravel辅助函数有哪些_Laravel Helpers常用助手函数大全  长沙企业网站制作哪家好,长沙水业集团官方网站?  如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  湖南网站制作公司,湖南上善若水科技有限公司做什么的?  5种Android数据存储方式汇总  Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程  如何快速打造个性化非模板自助建站?  网页制作模板网站推荐,网页设计海报之类的素材哪里好?  装修招标网站设计制作流程,装修招标流程?  Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置  百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭  Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】  EditPlus 正则表达式 实战(3)  宙斯浏览器怎么屏蔽图片浏览 节省手机流量使用设置方法  详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点  Laravel如何使用Scope本地作用域_Laravel模型常用查询逻辑封装技巧【手册】  如何用VPS主机快速搭建个人网站?  想要更高端的建设网站,这些原则一定要坚持!  浅谈Javascript中的Label语句  如何用5美元大硬盘VPS安全高效搭建个人网站?  INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】  Laravel请求验证怎么写_Laravel Validator自定义表单验证规则教程  Laravel怎么配置自定义表前缀_Laravel数据库迁移与Eloquent表名映射【步骤】  Win11怎样安装网易有道词典_Win11安装词典教程【步骤】  Bootstrap整体框架之JavaScript插件架构  如何在VPS电脑上快速搭建网站?  html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  Python数据仓库与ETL构建实战_Airflow调度流程详解  电商网站制作价格怎么算,网上拍卖流程以及规则?  ChatGPT怎么生成Excel公式_ChatGPT公式生成方法【指南】  Laravel如何使用withoutEvents方法临时禁用模型事件  如何快速选择适合个人网站的云服务器配置?  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  阿里云网站搭建费用解析:服务器价格与建站成本优化指南  广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?  Linux安全能力提升路径_长期防护思维说明【指导】  Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践  悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】  HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】  Laravel全局作用域是什么_Laravel Eloquent Global Scopes应用指南