在多次使用CONCAT()后,我有这种来自我的数据库的字符串。
1, AA, 6, 10; 1, Z, 1, 5; 2, AE, 1, 5; 2, AF, 6, 10; 3, X, 1, 5; 3, Y, 5, 10
为了清楚地说明一点,让我们这样说:
;
Group
Section
From
To
使用此代码
$data = "1, AA, 6, 10; 1, Z, 1, 5; 2, AE, 1, 5; 2, AF, 6, 10; 3, X, 1, 5; 3, Y, 5, 10";
echo $data;
$ret = array_map (
function ($_) {return explode (', ', $_);},
explode (';', $data)
);
我得到以下多维数组
Array
(
[0] => Array
(
[0] => 1
[1] => AA
[2] => 6
[3] => 10
)
[1] => Array
(
[0] => 1
[1] => Z
[2] => 1
[3] => 5
)
[2] => Array
(
[0] => 2
[1] => AE
[2] => 1
[3] => 5
)
[3] => Array
(
[0] => 2
[1] => AF
[2] => 6
[3] => 10
)
[4] => Array
(
[0] => 3
[1] => X
[2] => 1
[3] => 5
)
[5] => Array
(
[0] => 3
[1] => Y
[2] => 5
[3] => 10
)
)
我希望以一个看起来像这样的多维数组结束:
Array
(
[0] => Array
(
[0] => 1
[1] => Array
(
[0] => Z
[1] => 1
[2] => 5
)
[2] => Array
(
[0] => AA
[1] => 6
[2] => 10
)
)
[1] => Array
(
[0] => 2
[1] => Array
(
[1] => AE
[2] => 1
[3] => 5
)
[2] => Array
(
[1] => AF
[2] => 6
[3] => 10
)
)
[2] => Array
(
[0] => 3
[1] => Array
(
[1] => X
[2] => 1
[3] => 5
)
[2] => Array
(
[1] => Y
[2] => 6
[3] => 10
)
)
)
我不知道最好的方法是什么才能获得这个结果,也不知道如果没有太复杂的操作就可以做到这一点。 获得最终结果的最佳方法是什么?我应该处理“原始”多维数组还是应该从一开始就使用字符串?
合并具有相同Group
首先,我想合并以相同Group
值开头的子字符串。然后每个字符串的其余部分成为新创建的数组中的另一个数组。
我想我可以通过解析初始数组(或者字符串本身?)并将结果推送到新数组,同时合并数据来实现。
在我的例子中,它已经完成了六个起始数组,现在分成三个数组。
使用From
和To
值进行排序
将具有相同Group
值的子字符串组合成数组后,我想对这些数组进行排序,以使子数组的To
值始终小于From
值下一个。
始终使用以下规则生成初始字符串:
From
和To
重叠的值:1,5 - 4,7
。它可以是1,4 - 5,7
或1,5 - 6,7
1,3 - 5,7
From
和To
值可以相同。所以你可以得到:1,4 - 5,5 - 6,7
这就是为什么1, AA, 6, 10; 1, Z, 1, 5;
已排在Z, 1, 5
之后AA, 6, 10
。是否有可以进行这种排序的PHP函数(通过比较不同键的值)或者我应该自己创建吗?
另外,如果您认为我应该完全改变我想要这样做的方式(使用多维数组......)并且您有一些想法,请继续并分享它们。我也在这里学习新的做事方式。
有关数据库结构的版本
如@deceze所述,在SQL查询期间构造初始字符串可能更容易。我试过了,但我可能不够熟练,无法得到我想要的东西。我的数据库看起来像这样: Database Structure 如您所见,所有行都由MasterID链接。这是因为我在多个表上进行1到n查询。 到目前为止,我的查询看起来像那样(我从中删除了所有不必要的东西):
SELECT s.MasterID,
GROUP_CONCAT(CONCAT( CONCAT( CONCAT( CONCAT( CONCAT(
s2d.Group, ', '),
s2d.Section, ', '),
s2d.From),', '),
s2d.To) SEPARATOR '; ') AS Concatstuff,
FROM table1 AS s
JOIN table2 AS s2d
ON s2d.MasterID = s.MasterID
WHERE MasterID = $MasterID (A PHP variable)
由于1到N的关系,我不知道如何以不同的方式做到这一点。也许我可以保持简单并执行两个查询而不是一个。在第一个查询中,我从table1获取信息,在第二个查询中获取table2中的信息。 但是如果你知道一种方法只在一个查询中完成所有这些,我很想知道如何做到这一点!
答案 0 :(得分:2)
我建议在进行许多PHP更改之前修改MySQL查询。
大量的会话将会变得非常大,最终你甚至可能需要调整GROUP_CONCAT()
的MySQL配置设置,因为它会在一定长度后截断。
相反,我们可以将GROUP_CONCAT()
和群组专门保留在具有GROUP BY
的各个masterid / group组合上。此外,GROUP_CONCAT()
具有ORDER BY
属性,可解决排序问题:
SELECT
s.MasterID,
s2d.`group`,
GROUP_CONCAT(
s2d.`section`, ',', s2d.`from`, ',', s2d.`to`
ORDER BY `from`, `to`
SEPARATOR ';'
) AS Concatstuff
FROM
table1 AS s
JOIN table2 AS s2d
ON s2d.MasterID = s.MasterID
GROUP BY
s.MasterID, s2d.`group`
WHERE
s.MasterID = $MasterID;
这应该给我们类似的数据:
MasterID group Concatstuff
2 1 z,1,5;aa,6,10
2 2 ae,1,5;af,6,10
2 3 x,1,5;y,6,10
假设您已从数据库中检索到此内容并将其存储在名为$results
的数组中,我们可以迭代它:
$final_groups = array();
foreach ($results as $group) {
// your original `array_map()` logic:
$split_group = array_map(function($_) {
return explode(',', $_);
},
explode(';', $group['Concatstuff'])
);
// ... any other processing you want to do
// store the results:
$final_groups[$group['group']] = $split_group;
}
注意:明确回答您的问题
是否有可以进行此类排序的PHP函数
是的,usort()
:
function sort_group($a, $b) {
// [1] = 'from'
// [2] = 'to'
if ($a[1] == $b[1]) {
if ($a[2] == $b[2]) {
return 0;
}
return ($a[2] < $b[2]) ? -1 : 1;
}
return ($a[1] < $b[1]) ? -1 : 1;
}
usort($split_group, 'sort_group');
您可以在sort_group()
中自定义比较逻辑,以匹配您想要的任何内容。上面,我按 from
和to
=]
答案 1 :(得分:0)
尝试在不为您编写代码的情况下给出一般答案:
对于每个组,您可以使用组号作为所包含数据的索引。
对于每个组,您将其组索引写入具有索引字符串前缀加数字零的元素:$ret1[$group_number]['d0'] = $group_number;
。每次向群组添加内容时都会被覆盖。
然后使用适合排序的字符串索引添加组内容。我建议使用sprintf()生成索引,如$idx = sprintf('d%05.1f%05.1f', $from, $to);
,因此组编号将始终排在前面。再次这里是前缀。添加$ret1[$group_number][$idx] = $group_array;
。
为所有输入数据完成此操作后,运行它以进行排序和完成:
$ret1
中的所有群组进行迭代,按键对其进行排序,然后使用array_values()
删除密钥。使用$ret[] = ...
将其添加到新阵列。