MySQL 使用查找将 2 个逗号分隔的列拆分为多行
MySQL Split 2 comma separated columns into multiple rows with lookup
我有一个 table,其中 两个 列的值由逗号分隔,另一个 table类别。 group_1 最多可以有 30 个分隔值,group_2 最多可以有 5 个分隔值
myProducts
alias
group_1
group_2
product_a
1,2,3,[...]
uk, us [...]
product_b
2,4,[...]
uk, us, [...]
product_c
1,4,[...]
spain, germany, [...]
myCategories
id
category
1
category_a
2
category_b
3
category_c
4
category_d
是否可以使用 MySQL 将逗号分隔的字段拆分为多行和 return 从类别 table 中查找值后的结果。所以在上面的示例中,原始 table 的第一行将 return:
alias
group_1
group_2
product_a
category_a
uk
product_a
category_a
us
product_a
category_b
uk
product_a
category_b
us
product_a
category_c
uk
product_a
category_c
us
...
...
...
查找部分是我想要的,但如果它被证明太复杂,我可以没有那个部分。
是的,但您不会对性能满意。
您可以使用 MySQL 的 FIND_IN_SET() 函数将逗号分隔的列表与单个值进行匹配。
select p.alias, a.category as group_1, c.country as group_2
from myProducts p join myCategories a on find_in_set(a.id, p.group_1)
join countries c on find_in_set(c.country, p.group_2);
+-----------+------------+---------+
| alias | group_1 | group_2 |
+-----------+------------+---------+
| product_c | category_a | spain |
| product_c | category_d | spain |
| product_a | category_a | uk |
| product_a | category_b | uk |
| product_b | category_b | uk |
| product_a | category_c | uk |
| product_b | category_d | uk |
+-----------+------------+---------+
我确实创建了另一个查找 table countries
:
create table countries (country varchar(20) primary key);
insert into countries values ('uk'),('us'),('spain'),('germany');
注意:如果以逗号分隔的列表有空格,它们将被视为列表中每个字符串的一部分,因此您要删除空格。
select p.alias, a.category as group_1, c.country as group_2
from myProducts p join myCategories a on find_in_set(a.id, p.group_1)
join countries c on find_in_set(c.country, replace(p.group_2,' ',''));
+-----------+------------+---------+
| alias | group_1 | group_2 |
+-----------+------------+---------+
| product_c | category_a | germany |
| product_c | category_d | germany |
| product_c | category_a | spain |
| product_c | category_d | spain |
| product_a | category_a | uk |
| product_a | category_b | uk |
| product_b | category_b | uk |
| product_a | category_c | uk |
| product_b | category_d | uk |
| product_b | category_b | us |
| product_b | category_d | us |
+-----------+------------+---------+
但是如果你这样做,就没有办法优化索引查找。所以每个连接都将是一个 table 扫描。随着 table 变大,您会发现性能下降到无法使用的程度。
对此进行优化的方法是避免使用逗号分隔的列表。将多对多关系规范化为新的 table。然后查找可以使用索引,除了 all the other problems with using comma-separated lists.
之外,您将避免性能下降
回复您的评论:
您可以通过明确列出国家/地区来创建派生 table:
FROM ...
JOIN (
SELECT 'us' AS country UNION SELECT 'uk' UNION SELECT 'spain' UNION SELECT 'germany'
) AS c
但这越来越荒谬了。您没有使用 SQL 来获得任何优势。您不妨将整个数据集取回您的客户端应用程序,并将其分类为内存中的某些数据结构。
我有一个 table,其中 两个 列的值由逗号分隔,另一个 table类别。 group_1 最多可以有 30 个分隔值,group_2 最多可以有 5 个分隔值
myProducts
alias | group_1 | group_2 |
---|---|---|
product_a | 1,2,3,[...] | uk, us [...] |
product_b | 2,4,[...] | uk, us, [...] |
product_c | 1,4,[...] | spain, germany, [...] |
myCategories
id | category |
---|---|
1 | category_a |
2 | category_b |
3 | category_c |
4 | category_d |
是否可以使用 MySQL 将逗号分隔的字段拆分为多行和 return 从类别 table 中查找值后的结果。所以在上面的示例中,原始 table 的第一行将 return:
alias | group_1 | group_2 |
---|---|---|
product_a | category_a | uk |
product_a | category_a | us |
product_a | category_b | uk |
product_a | category_b | us |
product_a | category_c | uk |
product_a | category_c | us |
... | ... | ... |
查找部分是我想要的,但如果它被证明太复杂,我可以没有那个部分。
是的,但您不会对性能满意。
您可以使用 MySQL 的 FIND_IN_SET() 函数将逗号分隔的列表与单个值进行匹配。
select p.alias, a.category as group_1, c.country as group_2
from myProducts p join myCategories a on find_in_set(a.id, p.group_1)
join countries c on find_in_set(c.country, p.group_2);
+-----------+------------+---------+
| alias | group_1 | group_2 |
+-----------+------------+---------+
| product_c | category_a | spain |
| product_c | category_d | spain |
| product_a | category_a | uk |
| product_a | category_b | uk |
| product_b | category_b | uk |
| product_a | category_c | uk |
| product_b | category_d | uk |
+-----------+------------+---------+
我确实创建了另一个查找 table countries
:
create table countries (country varchar(20) primary key);
insert into countries values ('uk'),('us'),('spain'),('germany');
注意:如果以逗号分隔的列表有空格,它们将被视为列表中每个字符串的一部分,因此您要删除空格。
select p.alias, a.category as group_1, c.country as group_2
from myProducts p join myCategories a on find_in_set(a.id, p.group_1)
join countries c on find_in_set(c.country, replace(p.group_2,' ',''));
+-----------+------------+---------+
| alias | group_1 | group_2 |
+-----------+------------+---------+
| product_c | category_a | germany |
| product_c | category_d | germany |
| product_c | category_a | spain |
| product_c | category_d | spain |
| product_a | category_a | uk |
| product_a | category_b | uk |
| product_b | category_b | uk |
| product_a | category_c | uk |
| product_b | category_d | uk |
| product_b | category_b | us |
| product_b | category_d | us |
+-----------+------------+---------+
但是如果你这样做,就没有办法优化索引查找。所以每个连接都将是一个 table 扫描。随着 table 变大,您会发现性能下降到无法使用的程度。
对此进行优化的方法是避免使用逗号分隔的列表。将多对多关系规范化为新的 table。然后查找可以使用索引,除了 all the other problems with using comma-separated lists.
之外,您将避免性能下降回复您的评论:
您可以通过明确列出国家/地区来创建派生 table:
FROM ...
JOIN (
SELECT 'us' AS country UNION SELECT 'uk' UNION SELECT 'spain' UNION SELECT 'germany'
) AS c
但这越来越荒谬了。您没有使用 SQL 来获得任何优势。您不妨将整个数据集取回您的客户端应用程序,并将其分类为内存中的某些数据结构。