mysql 如何使用group_concat连接3个表

9nvpjoqh  于 2023-06-04  发布在  Mysql
关注(0)|答案(3)|浏览(269)

bounty还有16小时到期。此问题的答案有资格获得+50声望奖励。Dan正在寻找此问题的最新答案。

我正在为客户网站使用Cubecart,他们使用逗号分隔值将某些选项ID与产品相关联。我需要创建一个自定义表,它可以将所有这些信息转换为一种格式,以便我可以为不同的产品选项组合分配不同的产品代码。
产品列表
| 产品编号|产品型号|指定密钥|
| - -----|- -----|- -----|
| 1| ABC| 23,45|
| 1| HIJ|二十三|
| 1|荷航|四十五|
| 2| DEF| 10,28|
| 2| GHI|十个|
| 2| NOP|二十八|
分配表
| 产品编号|分配ID|值ID|
| - -----|- -----|- -----|
| 1|二十三|1|
| 1|四十五|2|
| 2|十个|3|
| 2|二十八|4|
数值表
| 值ID|价值|
| - -----|- -----|
| 1|红色|
| 2|大|
| 3|蓝色|
| 4|小型|
如果赋值键实际上是值ID,我可以计算出如何将products表直接连接到values表,但我无法计算出如何将assign表连接到中间。我需要连接要分配的产品并分配给值。

SELECT 
        t1.product_code, 
        t1.product_id,
        t1.assign_key,
        GROUP_CONCAT(t2.value_name)
    FROM products t1 
    LEFT JOIN values t2 ON FIND_IN_SET(t2.value_id, t1.assign_key)    
    GROUP BY t1.assign_key

预期输出:
| 产品编号|产品型号|分配ID|值ID|价值观|
| - -----|- -----|- -----|- -----|- -----|
| 1| ABC| 23,45|一二|红色,大号|
| 1| HIJ|二十三|1|红色|
| 1|荷航|四十五|2|大|
| 2| DEF| 10,28|三四|蓝色,小号|
| 2| GHI|十个|3|蓝色|
| 2| NOP|二十八|4|小型|
我尝试在中间添加另一个连接,但无法解决如何将concat分组两次。
我不能只分离赋值键,这样每行只有一个值,因为关键是产品代码只与两个赋值键的组合相关。

pprl5pva

pprl5pva1#

此查询产生了所需的结果:

SELECT 
  p.product_id,
  p.product_code,
  GROUP_CONCAT( SUBSTRING_INDEX(SUBSTRING_INDEX(assign_key,',',FIND_IN_SET(a.assign_id,p.assign_key)),',',-1)
          ORDER BY SUBSTRING_INDEX(SUBSTRING_INDEX(assign_key,',',FIND_IN_SET(a.assign_id,p.assign_key)),',',-1)) as AssignIDs,
  GROUP_CONCAT( a.value_id ORDER BY a.value_id) as ValueIDs,
  GROUP_CONCAT( v.value_name ORDER BY a.value_id) as "Values"
FROM products p
INNER JOIN assign a ON a.product_id = p.product_id
INNER JOIN value v ON v.value_id = a.value_id
WHERE FIND_IN_SET(a.assign_id,p.assign_key) > 0
GROUP BY p.product_id, p.product_code;

输出:
| 产品ID|乘积码|分配ID| ValueID|价值观|
| - -----|- -----|- -----|- -----|- -----|
| 1| ABC| 23,45|一二|红色,大号|
| 1| HIJ|二十三|1|红色|
| 1|荷航|四十五|2|大|
| 2| DEF| 10,28|三四|蓝色,小号|
| 2| GHI|十个|3|蓝色|
| 2| NOP|二十八|4|小型|
DBFIDDLE中完成了一个(简短的)分步计划,但它基本上是“不断向这个查询添加内容,直到我们获得所有需要的值”,然后应用GROUP_CONCAT,以及一个适当的GROUP BY
(An关于错误“ONLY_FULL_GROUP_BY”的解释,以及如何在查询中解决它,也在DBFIDLE中。)
一些注意事项:

  • SUBSTRING_INDEX(SUBSTRING_INDEX(assign_key,',',FIND_IN_SET(a.assign_id,p.assign_key)),',',-1)的目的是在逗号分隔的字符串中查找第n个元素。

一个简短的例子:这将返回d
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a,b,c,d,e',',',4),',',-1)

  • “Values”中的排序是在ValueID上完成的,以将描述与ID相匹配,因此我们有“Red,Large”(而不是这些值的字母顺序),因为我们有“1,2”,而Red的值为“1”。
6ss1mwsb

6ss1mwsb2#

作为find_in_set的替代方案,我们可以使用JSON。一个逗号分隔的整数列表可以很容易地转换成一个JSON数组,方法是用方括号将其括起来;然后,我们可以使用handy JSON function json_table将数组解嵌套到行,同时使用选项with ordinality跟踪每个元素的原始位置。
有了非嵌套的键列表,现在很容易将表assignvaluejoin s合并;由于我们有原始索引可用,因此生成CSV值列表是安全和简单的。
我们可以用一个横向连接来表示:

select p.*, x.*
from products p
cross join lateral (
    select 
        group_concat(a.value_id   order by j.idx) value_ids,
        group_concat(v.value_name order by j.idx) value_names
    from json_table(
        concat('[', p.assign_key, ']'),
        '$[*]' columns ( idx for ordinality, assign_id int path '$')
    ) j
    inner join assign a on a.assign_id = j.assign_id
    inner join value v on v.value_id  = a.value_id
) x

或者我们可以直接在外部查询中进行解嵌套和聚合:

select p.product_id, p.product_code, p.assign_key,
  group_concat(a.value_id   order by j.idx) value_ids,
  group_concat(v.value_name order by j.idx) value_names
from products p
cross join json_table(
    concat('[', p.assign_key, ']'),
    '$[*]' columns ( idx for ordinality, assign_id int path '$')
) j
inner join assign a on a.assign_id = j.assign_id
inner join value v on v.value_id  = a.value_id
group by p.product_id, p.product_code, p.assign_key

这种方法的一个结果是,它将正确处理CSV列表中的重复项(如果有)(而基于find_in_set的解决方案通常会删除其中一个重复项)-我将这种情况添加到示例数据中的产品1中。
此外,它避免了对find_in_set的重复调用-但当然json_table也有代价,因此这是否会提高性能在很大程度上取决于您的数据和设置。

Demo on DBFiddle

| 产品编号|产品编号|分配密钥(_K)|值ID|值名称|
| - -----|- -----|- -----|- -----|- -----|
| 1| ABC|二十三,四十五,二十三|一,二,一|红色,大号,红色|
| 1| HIJ|二十三|1|红色|
| 1|荷航|四十五|2|大|
| 2| DEF| 10,28|三四|蓝色,小号|
| 2| GHI|十个|3|蓝色|
| 2| NOP|二十八|4|小型|

ie3xauqp

ie3xauqp3#

你可以使用find_in_set ... 2345将分别在位置1和2的23,45中找到。这将是join和order by的基础。

select products.ProductID
     , products.ProductCode
     , products.AssignKey
     , group_concat(valuess.ValueID order by find_in_set(assign.AssignID, products.AssignKey) separator ',') as ValueIDs
     , group_concat(valuess.Value order by find_in_set(assign.AssignID, products.AssignKey) separator ',') as ValueNames
from products
join assign on products.ProductID = assign.ProductID and find_in_set(assign.AssignID, products.AssignKey) > 0
join valuess on assign.ValueID = valuess.ValueID
group by products.ProductID, products.ProductCode

SQLFiddle

相关问题