[英]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.