繁体   English   中英

计算非规范化数据库中按 id 和月份分组的条目

[英]Count entries grouped by id and month from denormalized database

我有一个表 (tbl_operations),其中 id 列值可能是逗号分隔的行。 我想获取每个月每个OpId的计数。 我试图通过纯 sql 来实现这一点,但没有成功。

从这个角度来看

OpId 手术日期
3个 2022-01-03
5,3 2022-01-15
4个 2022-01-27
5个 2022-02-01
7 2022-02-09
3,2 2022-01-16

对此

OpId 数数
2个 1个 01
3个 3个 01
4个 1个 01
5个 1个 01
5个 1个 02
7 1个 02

我被困在这里。 有人可以告诉我如何使用 sql 执行此操作吗? 如果不是,也许使用 php 来显示结果?

SELECT tbl_operations.OpId,
    tbl_operations.OpDate ,
    COUNT(tbl_operations.OpId) AS `count`
FROM tbl_operations
WHERE MONTH(OpDate)=1
GROUP BY  tbl_operations.OpId

这是一个简单的例子。 第一部分只是创建一个 arrays 数组,它模拟您从数据库中获得的内容。

要点是$counts是一个数组,其中的键具有唯一的 OpID。 那些 arrays 的值是带有月份键和它们被找到次数的值的子数组。

显示应该再次只是一个简单的循环,但是您可能想要对其进行排序。

$rows = [
['3',   '2022-01-03'],
['5,3', '2022-01-15'],
['4',   '2022-01-27'],
['5',   '2022-02-01'],
['7',   '2022-02-09'],
['3,2', '2022-01-16'],
];

$counts = [];
foreach($rows as $row){
    $ids = explode(',', $row[0]);
    $month = date('m', strtotime($row[1]));
    foreach($ids as $id){
        if(!array_key_exists($id, $counts)){
            $counts[$id] = [];
        }
        if(!array_key_exists($month, $counts[$id])){
            $counts[$id][$month] = 0;
        }
        
        $counts[$id][$month]++;
    }
}

演示在这里: https://3v4l.org/mVaBB

编辑

来自@mickmackusa,您可以使用isset缩短内部循环:

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

查看他们的评论以获取演示链接

如果你要查询 PHP 中的数据,你还不如先返回一个更好的结果来处理:

SQL

SELECT GROUP_CONCAT(OpId), MONTH(OpDate)
FROM tbl_operations
GROUP BY MONTH(OpDate)

PHP

// Result from MySQL query
$rows = [
    ['3,5,3,4,3,2', 1],
    ['5,7', 2]
];

您可以像这样对这些分组结果进行计数:

$results = [];
foreach ($rows as $row) {
    $counts = array_count_values(explode(',', $row[0]));
    $results[$row[1]] = $counts;
}

结果

Array
(
    [1] => Array
        (
            [3] => 3
            [5] => 1
            [4] => 1
            [2] => 1
        )

    [2] => Array
        (
            [5] => 1
            [7] => 1
        )

)


你真正想做的是标准化你的数据,然后你可以单独在 SQL 中轻松地做到这一点。

如果您至少使用 MYSQL8,并且您不打算规范化您的表设计,那么您实际上可以使用以下CTE查询来拆分、分组、格式化和排序您的结果集(没有 PHP 处理)。

这种方法对非规范化表进行递归调用,并逐步将最右边的 id 从逗号分隔值中分离出来,并为各个 id 值生成新行。 递归继续,直到没有逗号为止。

该解决方案建立在此处演示的基本技术之上。

SQL:( 演示

WITH RECURSIVE norm AS (
    SELECT OpId,
           OpDate
    FROM tbl_operations
    UNION ALL
    SELECT REGEXP_REPLACE(OpId, '^[^,]*,', '') AS OpId,
           OpDate
    FROM norm
    WHERE OpId LIKE '%,%'
)
SELECT Id,
       Mo,
       COUNT(*) AS Cnt
FROM (
    SELECT REGEXP_REPLACE(norm.OpId, ',.*', '') AS Id,
           MONTH(norm.OpDate) AS Mo
    FROM norm
) formatted
GROUP BY formatted.Id, 
         formatted.Mo

结果集:

ID 计数
2个 1个 1个
3个 1个 3个
4个 1个 1个
5个 1个 1个
5个 2个 1个
7 2个 1个

就是说,对于一项非常容易的任务来说,这是很多不必要的巫术胡言乱语,一旦您对表格进行了规范化 --- 尽快对其进行规范化

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM