Search code examples
mysqlsqlselectjoingroup-concat

limit group_concat's resultset to actual results


I have the following query which is mostly working, but returns too many results within the group_concat() when one of the joined tables has a different number of results returned:

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

The result I get is (please run the snippet to see the table) or see the 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>

As you can see, for example offersB holds two results

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

that are both equal, there is only one entry in the database for the given sku 123, but offersA has two different offers for different quantities for this sku:

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

I'm using JavaScript to handle the results later, so I could just remove the duplicated results - but am wondering if there's

a) a more clever way to query for the data

b) a way to remove those duplicates in the query itself


Solution

  • Try this:

    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);
    

    Check this 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}]] |