将 group_concat 的结果集限制为实际结果

Posted

技术标签:

【中文标题】将 group_concat 的结果集限制为实际结果【英文标题】:limit group_concat's resultset to actual results 【发布时间】:2016-03-22 15:15:59 【问题描述】:

我有以下查询,它大部分都在工作,但是当一个连接表返回的结果数量不同时,group_concat() 中返回的结果太多:

select 
    a.sku, a.ek, a.mwst, 
    concat('[[', group_concat('"offer": ', b.offer, ', "minQuantity": ', b.minQuantity, '') , ']]') offersA,
    concat('[[', group_concat('"offer": ', c.offer, ', "minQuantity": ', c.minQuantity, '') , ']]') offersB,
    concat('[[', group_concat('"offer": ', d.offer, ', "minQuantity": ', d.minQuantity, '') , ']]') offersC
from all_prices a 
    left join all_prices_a b on a.sku = b.sku 
    left join all_prices_b c on a.sku = c.sku 
    left join all_prices_c d on a.sku = d.sku
where a.sku in (123,456) 
group by a.sku

我得到的结果是(请运行sn-p查看表格)或查看fiddle

<table border=1>
<tr>
<td bgcolor=silver class='medium'>sku</td>
<td bgcolor=silver class='medium'>ek</td>
<td bgcolor=silver class='medium'>mwst</td>
<td bgcolor=silver class='medium'>offersA</td>
<td bgcolor=silver class='medium'>offersB</td>
<td bgcolor=silver class='medium'>offersC</td>
</tr>

<tr>
<td class='normal' valign='top'>123</td>
<td class='normal' valign='top'>154.32</td>
<td class='normal' valign='top'>19</td>
<td class='normal' valign='top'>[[&quot;offer&quot;: 9.65, &quot;minQuantity&quot;: 3,&quot;offer&quot;: 9.86, &quot;minQuantity&quot;: 1]]</td>
<td class='normal' valign='top'>[[&quot;offer&quot;: 9.66, &quot;minQuantity&quot;: 1,&quot;offer&quot;: 9.66, &quot;minQuantity&quot;: 1]]</td>
<td class='normal' valign='top'>[[&quot;offer&quot;: 9.65, &quot;minQuantity&quot;: 1,&quot;offer&quot;: 9.65, &quot;minQuantity&quot;: 1]]</td>
</tr>

<tr>
<td class='normal' valign='top'>456</td>
<td class='normal' valign='top'>48.48</td>
<td class='normal' valign='top'>19</td>
<td class='normal' valign='top'>[[&quot;offer&quot;: 13.30, &quot;minQuantity&quot;: 1,&quot;offer&quot;: 13.30, &quot;minQuantity&quot;: 1]]</td>
<td class='normal' valign='top'>[[&quot;offer&quot;: 13.30, &quot;minQuantity&quot;: 1,&quot;offer&quot;: 122.00, &quot;minQuantity&quot;: 3]]</td>
<td class='normal' valign='top'>NULL</td>
</tr>
</table>

如您所见,例如 offerB 包含两个结果

[["offer": 9.66, "minQuantity": 1,"offer": 9.66, "minQuantity": 1]]

两者相同,数据库中只有一个条目对应给定的 sku 123,但 offerA 针对这个 sku 的不同数量有两个不同的报价:

[["offer": 9.65, "minQuantity": 3,"offer": 9.86, "minQuantity": 1]] 

我稍后会使用 javascript 来处理结果,所以我可以删除重复的结果 - 但我想知道是否有

a) 一种更聪明的数据查询方式

b) 一种在查询本身中删除这些重复项的方法

【问题讨论】:

【参考方案1】:

试试这个:

SELECT a.sku, a.ek, a.mwst, 
      CONCAT('[[', b.offersA , ']]') offersA,
      CONCAT('[[', c.offersB , ']]') offersB,
      CONCAT('[[', d.offersC , ']]') offersC
FROM all_prices a 
LEFT JOIN ( SELECT b.sku, GROUP_CONCAT('"offer": ', b.offer, ', "minQuantity": ', b.minQuantity, '') AS offersA
            FROM all_prices_a b 
            GROUP BY b.sku
          ) AS b ON a.sku = b.sku 
LEFT JOIN ( SELECT c.sku, GROUP_CONCAT('"offer": ', c.offer, ', "minQuantity": ', c.minQuantity, '') AS offersB
            FROM all_prices_b c 
            GROUP BY c.sku
          ) AS c ON a.sku = c.sku 
LEFT JOIN ( SELECT d.sku, GROUP_CONCAT('"offer": ', d.offer, ', "minQuantity": ', d.minQuantity, '') AS offersC
            FROM all_prices_c d 
            GROUP BY d.sku
          ) AS d ON a.sku = d.sku 
WHERE a.sku IN (123, 456);

查看SQL FIDDLE DEMO

::OUTPUT::

| sku |    ek | mwst |                                                                   offersA |                                offersB |                                offersC |
|-----|-------|------|---------------------------------------------------------------------------|----------------------------------------|----------------------------------------|
| 123 | 12.48 |   19 | [["offer": 12.28, "minQuantity": 1,"offer": 11.24, "minQuantity": 3]] | [["offer": 12.28, "minQuantity": 1]] | [["offer": 12.28, "minQuantity": 1]] |
| 456 | 13.24 |   19 |  [["offer": 10.00, "minQuantity": 1,"offer": 9.00, "minQuantity": 3]] |  [["offer": 9.00, "minQuantity": 3]] |  [["offer": 9.00, "minQuantity": 3]] |

【讨论】:

没错。如果你对 JOINed 表进行聚合 (GROUP_CONCAT ... GROUP BY) 操作,你会得到 dups。【参考方案2】:

这是一种稍微低俗的方式来满足您的需求。使用GROUP_CONCAT(DISTINCT...)

select 
  a.sku, a.ek, a.mwst, 
  concat('[[', group_concat(DISTINCT '"offer": ', b.offer, ', "minQuantity": ', b.minQuantity, '') , ']]') offersA,
...

我称之为低俗,因为它会错误地消除数据中真正存在的重复项。 http://sqlfiddle.com/#!9/2481e/6/0

【讨论】:

以上是关于将 group_concat 的结果集限制为实际结果的主要内容,如果未能解决你的问题,请参考以下文章

有没有人发现限制 group_concat 行的(简单)方法?

限制 GROUP_CONCAT() 或 INNER JOIN 的结果

解决Mysql group_concat长度限制

MySQL 和 GROUP_CONCAT() 最大长度

如何将结果集限制为仅 JOIN 中的最新实例

MySQL GROUP_CONCAT长度限制引发的一场灾难