我刚刚发现了这个非常有用的MySQL函数GROUP_CONCAT
。对我来说它看起来非常有用且过于简单,我实际上害怕使用它。主要是因为自从我开始进行网络编程以来已经有一段时间了,我从未在任何地方看过它。一个令人敬畏的用法示例如下
表clients
为每个拥有唯一ID的客户端拥有一行客户(您不会说......)
表格currencies
有3列client_id
,currency
和amount
。
现在,如果我想从name
表中获取用户15 clients
及其余额,使用“旧”数组覆盖方法,我将不得不使用以下SQL
SELECT id, name, currency, amount
FROM clients LEFT JOIN currencies ON clients.id = client_id
WHERE clients.id = 15
然后在php中我必须循环遍历结果集并进行数组覆盖(我真的不喜欢,特别是在大量结果集中),如
$result = array();
foreach($stmt->fetchAll() as $row){
$result[$row['id']]['name'] = $row['name'];
$result[$row['id']]['currencies'][$row['currency']] = $row['amount'];
}
然而,对于新发现的功能,我可以使用此
SELECT id, name, GROUP_CONCAT(currency) as currencies GROUP_CONCAT(amount) as amounts
FROM clients LEFT JOIN currencies ON clients.id = client_id
WHERE clients.id = 15
GROUP BY clients.id
然后在应用程序级别,事情是如此可怕和漂亮
$results = $stmt->fetchAll();
foreach($results as $k => $v){
$results[$k]['currencies'] = array_combine(explode(',', $v['currencies']), explode(',', $v['amounts']));
}
我想问的问题是在演奏中使用此功能还是有任何缺点,因为对我而言,它看起来就像是非常棒的,这让我觉得必须有一个原因让人们不要经常使用它。
我想最后问一下,除了数组覆盖之外还有哪些其他选项最终得到MySQL结果集中的多维数组,因为如果我选择了15列,那么写一下就会非常痛苦。兽..
答案 0 :(得分:6)
使用GROUP_CONCAT()通常会调用分组逻辑并创建临时表,这通常会对性能产生很大的负面影响。有时您可以添加正确的索引以避免分组查询中的临时表,但不是在每种情况下都是如此。
正如@MarcB指出的那样,组连接字符串的默认长度限制非常短,很多人都被截断列表搞糊涂了。您可以使用group_concat_max_len增加限制。
在PHP中将字符串爆炸成数组并不是免费的。仅仅因为你可以在PHP中的一个函数调用中执行它并不意味着它对性能最好。我没有对差异进行基准测试,但我怀疑你有不同。
GROUP_CONCAT()是一种MySQL主义。其他SQL产品不支持它。在某些情况下(例如SQLite),它们具有GROUP_CONCAT()函数,但它与MySQL中的工作方式不完全相同,因此如果必须支持多个RDBMS后端,这可能会导致混乱的错误。当然,如果您不需要担心移植,这不是问题。
如果要从currencies
表中获取多个列,则需要多个GROUP_CONCAT()表达式。这些清单是否保证是相同的顺序?也就是说,一个列表中的第三个字段是否与下一个列表中的第三个字段相对应?答案是否定的 - 除非您在GROUP_CONCAT()中指定带有ORDER BY
子句的订单。
我通常喜欢你的第一个代码格式,使用传统的结果集,并循环结果,保存到由客户端ID索引的新数组,将货币附加到数组。这是一个简单的解决方案,使SQL更简单,更容易优化,并且如果您有多个要提取的列,则效果会更好。
我不是说GROUP_CONCAT()不好!在许多情况下它确实很有用。但是,试图制定任何一个通用的规则来使用(或避免)任何功能或语言功能都是过于简单化。
答案 1 :(得分:2)
我在GROUP_CONCAT
看到的最大问题是它对MySql非常具体:如果要将代码移植到任何其他平台上,则必须重写所有使用{{1}的查询}}。例如,您的第一个查询更具可移植性 - 您可以针对任何主要的RDBMS引擎运行它而不更改其中的单个字符。
如果您只使用MySql(例如,因为您正在编写一个特定于MySql的工具),那么GROUP_CONCAT
的查询可能会更快,因为RDBMS会做更多的工作为您节省数据传输的大小。