分组MySql数组行

时间:2015-09-15 07:32:46

标签: mysql sql arrays count

我有这样的表(值列值分隔为' @#@')

Id | Values
1 | abc@#@def@#@ghi@#@
2 | def@#@ghi@#@xyz@#@
3 | abc@#@def@#@xyz@#@

现在我希望结果计数为

abc = 2
def = 3
xyz = 2

我该怎么做?

2 个答案:

答案 0 :(得分:0)

如果你知道要查找的子字符串值,那就很容易了。

select string,  
(
length(group_concat(values)) -- length of whole thing
-length(group_concat(replace(values, string, '')) -- length of whole thing without searched string
)-- substraction equals length of string*count of strings
/length(string) -- length of string
as string_count
from values 
cross join 
(select abc as string
union all select def ...)
group by 1

您可能还需要使用

扩展max group concat
SET SESSION group_concat_max_len = 1000000;

如果您没有这些值,我建议您查看'mysql explode',Can you split/explode a field in a MySQL query? 并预先创建一个包含这些值(不同)的表

答案 1 :(得分:0)

可以做但有点乱。

首先,生成一个大于分隔字段中可能值数的数字范围。然后将其与您的桌子交叉加入。

将其拆分的基础知识如下(假设在这种情况下最多有100个分隔值): -

SELECT Id, SUBSTRING_INDEX(SUBSTRING_INDEX(sometable.`values`, '@#@', sub0.aNum), '@#@', -1)
FROM sometable
INNER JOIN
(
    SELECT 1 + units.i + tens.i * 10 AS aNum
    FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
    CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
) sub0
ON ((LENGTH(sometable.`values`) - LENGTH(REPLACE(sometable.`values`, '@#@', ''))) / 3) >= sub0.aNum;

然后可以扩展它以获得计数: -

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(sometable.`values`, '@#@', sub0.aNum), '@#@', -1) AS the_value, COUNT(sometable.id)
FROM sometable
INNER JOIN
(
    SELECT 1 + units.i + tens.i * 10 AS aNum
    FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
    CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
) sub0
ON ((LENGTH(sometable.`values`) - LENGTH(REPLACE(sometable.`values`, '@#@', ''))) / 3) >= sub0.aNum
GROUP BY the_value;

如果分隔值只能在任何行中出现一次,您可以简化此操作: -

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(sometable.`values`, '@#@', sub0.aNum), '@#@', -1) AS the_value, COUNT(DISTINCT sometable.id)
FROM sometable
CROSS JOIN
(
    SELECT 1 + units.i + tens.i * 10 AS aNum
    FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
    CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
) sub0
GROUP BY the_value;

另一种可能性是,如果您有一个包含值列表的表: -

SELECT possible_values.avalue AS the_value, COUNT(DISTINCT sometable.id)
FROM sometable
INNER JOIN possible_values
ON FIND_IN_SET(possible_values.avalue, REPLACE(sometable.`values`, '@#@', ','))
GROUP BY the_value;

但是,一般情况下,最好的情况是避免使用包含分隔值的字段。它们是数据库规范化程度不高的标志。