SQL GROUP_CONCAT没有GROUP BY?

huangapple go评论66阅读模式
英文:

SQL GROUP_CONCAT without GROUP BY?

问题

我有4个表格

主表格存放许可数据叫做 `licence`,为了举例,我们关心两列 `licence_id`  `owner_id`

+------------+----------------+
| licence_id | owner_id |
+------------+----------------+
| 1 | 124 |


第二个表格连接许可与国家的关系 `licence_countries`

+------------+----------------+
| licence_id | country_id |
+------------+----------------+
| 1 | 45 |


第三个表格存放国家属于哪个地区的关系 `region_countries`

+------------+----------------+
| region_id | country_id |
+------------+----------------+
| 45 | 10 |
| 45 | 12 |


第四个表格存放许可在不同语言下的 `title` 和 `description`

+------------+----------------+----------+---------------+
| licence_id | language_id | title | description |
+------------+----------------+----------+---------------+
| 10 | 18 | Licence | Licence for.. |
| 10 | 13 | Licenz | Licenz fur.. |


我试图生成查询,使得地区和国家以逗号分隔,按照 `licence id` 汇总在一行中。因此,一行将包括 `licence id` 以及一个以 `;` 分隔的地区列表和另一个以相同方式分隔的国家列表。我通过使用 GROUP_CONCAT() 来实现这一点

SELECT
l.id,
GROUP_CONCAT(rc.id_country SEPARATOR ';') AS countries,
GROUP_CONCAT(rc.id_region SEPARATOR ';') AS regions
FROM license l
LEFT JOIN licence_country lc ON l.id = lc.id_licence
LEFT JOIN region_country rc ON lc.id_country = rc.id_country
GROUP BY l.id


这个方法很好用,但我的问题是如何连接语言。我们关心的标题和描述不应该在一行中连接,所以我们希望它们像通常的 `LEFT JOIN` 一样,如果我们有一个 `licence_id` 并且与其连接的有10种语言,那么我们将会得到10行,其中包含了重复的语言、国家、地区等值。为此,我添加了常规的 `LEFT JOIN`

LEFT JOIN license_language ll ON l.id = ll.id_licence


但它失败了,因为它要求 `title` 和 `id` 在 GROUP BY 中,但这会导致重复条目被移除。

我对于每个 `licenceId` 和 `languageId` 都有重复的条目,因为有许多组合。

最终结果应该看起来像这样

+------------+----------------+----------+---------------+--------------+----------+
| licence_id | language_id | title | description | countries | regions |
+------------+----------------+----------+---------------+--------------+----------+
| 10 | 18 | Licence | Licence for.. |France, Bel.. | Europe.. |
| 10 | 13 | Licenz | Licenz fur.. |France, Bel.. | Europe.. |
| 13 | 10 | Licence | Licence for.. |Brazil, Arg.. | South .. |
| 15 | 5 | Lice | Lice f. ir.. |USA, Canada | North .. |


我需要从 `licence` 中获取其他列,而不仅仅是 `ID`,但基本上我想要将来自两个表格的两列连接起来,而其他数据则像正常的 `LEFT JOIN` 一样。
英文:

I have 4 tables

Main table holding the licence data called licence, for sake of example we care for 2 columns licence_id and owner_id

+------------+----------------+ 
| licence_id | owner_id       |
+------------+----------------+ 
| 1          |            124 |

Second table connecting the licence to countries licence_countries

+------------+----------------+ 
| licence_id | country_id     |
+------------+----------------+ 
| 1          |            45  |

Third table holding which countries belong to what region region_countries

+------------+----------------+ 
| region_id  |   country_id   |
+------------+----------------+ 
| 45         |            10  |
| 45         |            12  |

Fourth table holds title and description in different languages for the licence

+------------+----------------+----------+---------------+
| licence_id  |   language_id |   title  | description   |
+------------+----------------+----------+---------------+
| 10         |            18  | Licence  | Licence for.. |
| 10         |            13  | Licenz   | Licenz fur..  |

I am trying to generate the queries as such that the region and countries are comma separated per licence id. So 1 row would have licence id and ; separated list of regions in one column and the same in another column for countries. I am doing this with GROUP_CONCAT()

SELECT
    l.id,
    GROUP_CONCAT(rc.id_country SEPARATOR ';') AS countries,
    GROUP_CONCAT(rc.id_region SEPARATOR  ';') AS regions
FROM license l
LEFT JOIN licence_country lc ON l.id = lc.id_licence
LEFT JOIN region_country rc ON lc.id_country = rc.id_country
GROUP BY l.id

This works fine, but my problem is connecting the languages. The titles and descriptions we care about to not be joined in one row so for them we want the normal LEFT JOIN action where if we have 1 licence_id and 10 languages connected to it then we have 10 rows with duplicated values for language, countries, regions etc. For this I added the normal LEFT JOIN

LEFT JOIN license_language ll ON l.id = ll.id_licence

And it fails, because it wants the title and the id in the GROUP BY, but then it removes the duplicate entries.

I have duplicates for every licenceId and languageId since there are many combinations.

The end result should look like something like this

+------------+----------------+----------+---------------+--------------+----------+
| licence_id |   language_id  |   title  | description   | countries    | regions  |
+------------+----------------+----------+---------------+--------------+----------+
| 10         |            18  | Licence  | Licence for.. |France, Bel.. | Europe.. |
| 10         |            13  | Licenz   | Licenz fur..  |France, Bel.. | Europe.. |
| 13         |            10  | Licence  | Licence for.. |Brazil, Arg.. | South .. |
| 15         |            5   | Lice     | Lice f. ir..  |USA, Canada   | North .. |

I have other columns I need from licence not only the ID, but in essence I want to Concat 2 columns from 2 tables while the other data acs as a normal LEFT JOIN

答案1

得分: 2

也许有更优化的解决方案,但我能想到的最简单的方法是将分组的查询放入另一个查询中,然后将结果与您的语言表连接,类似于以下方式:

SELECT * FROM (
    SELECT
        l.id,
        GROUP_CONCAT(rc.id_country SEPARATOR ';') AS countries,
        GROUP_CONCAT(rc.id_region SEPARATOR ';') AS regions
    FROM license l
    LEFT JOIN licence_country lc ON l.id = lc.id_licence
    LEFT JOIN region_country rc ON lc.id_country = rc.id_country
    GROUP BY l.id
) mq
LEFT JOIN license_language ll ON mq.id = ll.id_licence

编辑:这里是SQL Fiddle中的工作示例,请注意,我不得不从提供的查询中进行了许多更改,因为您提供的数据示例与查询具有不同的字段名称(当我注意到时,我已经编写了表结构,所以我坚持使用它们)。请特别注意licence(c)和license(s)的错误,如果您尚未选择,请选择一个,并在所有表格中坚持使用它(我更喜欢使用s,因为它是标准英语)。

还有另一种解决方案,但它要求您的语言表具有唯一标识符:您可以使用多个字段进行分组,以确保(许可证,语言)的组合是唯一的:

SELECT
    l.licence_id,
    GROUP_CONCAT(rc.country_id SEPARATOR ';') AS countries,
    GROUP_CONCAT(rc.region_id SEPARATOR ';') AS regions,
    ll.title, ll.description
FROM licence l
LEFT JOIN licence_countries lc ON l.licence_id = lc.licence_id
LEFT JOIN region_countries rc ON lc.country_id = rc.country_id
LEFT JOIN license_language ll ON l.licence_id = ll.licence_id
GROUP BY l.licence_id, ll.id

SQL Fiddle中有示例,语言表中添加了字段id

英文:

Maybe there is a more optimized solution, but the simplest that comes to mind would be to enclose the grouped query in another query, then join the result with your languages, something like this:

SELECT * FROM (
    SELECT
        l.id,
        GROUP_CONCAT(rc.id_country SEPARATOR ';') AS countries,
        GROUP_CONCAT(rc.id_region SEPARATOR  ';') AS regions
    FROM license l
    LEFT JOIN licence_country lc ON l.id = lc.id_licence
    LEFT JOIN region_country rc ON lc.id_country = rc.id_country
    GROUP BY l.id
) mq
LEFT JOIN license_language ll ON mq.id = ll.id_licence

EDIT: here is a working example in SQL Fiddle, note that I was obliged to correct many thing from the provided query, as the examples of data you provided had different field names than the query (I had already written the tables structure when I noticed, so I stuck to them). Be particularly cautious about mistakes with licence (c) and license (s), if you haven't already, pick one and stick to it for all your tables (I would prefer with a "s" as it is standard english)

There is another solution, but it requires that your language table has a unique identifier: you can GROUP BY using multiple fields, assuring you that the combination of (license,language) is unique:

SELECT
    l.licence_id,
    GROUP_CONCAT(rc.country_id SEPARATOR ';') AS countries,
    GROUP_CONCAT(rc.region_id SEPARATOR  ';') AS regions,
    ll.title, ll.description
FROM licence l
LEFT JOIN licence_countries lc ON l.licence_id = lc.licence_id
LEFT JOIN region_countries rc ON lc.country_id = rc.country_id
LEFT JOIN license_language ll ON l.licence_id = ll.licence_id
GROUP BY l.licence_id,ll.id

example in SQL Fiddle with field id added to the language table

huangapple
  • 本文由 发表于 2023年6月22日 20:40:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76532024.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定