我有一个 mysql 表,其中包含一些随机数字组合。为简单起见,以下表为例:
index|n1|n2|n3
1 1 2 3
2 4 10 32
3 3 10 4
4 35 1 2
5 27 1 3
etc
我想知道的是表中组合出现的次数。例如,4 10 或 1 2 或 1 2 3 或 3 10 4 等的组合出现了多少次。
我是否必须创建另一个包含所有可能组合的表并从那里进行比较,还是有其他方法可以做到这一点?
我有一个 mysql 表,其中包含一些随机数字组合。为简单起见,以下表为例:
index|n1|n2|n3
1 1 2 3
2 4 10 32
3 3 10 4
4 35 1 2
5 27 1 3
etc
我想知道的是表中组合出现的次数。例如,4 10 或 1 2 或 1 2 3 或 3 10 4 等的组合出现了多少次。
我是否必须创建另一个包含所有可能组合的表并从那里进行比较,还是有其他方法可以做到这一点?
表中只有三列,因此您正在寻找 1、2 和 3 个元素的组合。
为简单起见,我将从下表开始:
select index, n1 as n from t union all
select index, n2 from t union all
select index, n3 from t union all
select distinct index, -1 from t union all
select distinct index, -2 from t
我们称之为“价值观”。现在,我们想从这个表中获取给定索引的所有三元组。在这种情况下,-1 和 -2 表示 NULL。
select (case when v1.n < 0 then NULL else v1.n end) as n1,
(case when v2.n < 0 then NULL else v2.n end) as n2,
(case when v3.n < 0 then NULL else v3.n end) as n3,
count(*) as NumOccurrences
from values v1 join
values v2
on v1.n < v2.n and v1.index = v2.index join
values v3
on v2.n < v3.n and v2.index = v3.index
这是使用连接机制来生成组合。
此方法查找所有组合而不考虑排序(因此 1、2、3 与 2、3、1 相同)。此外,这会忽略重复项,因此如果 2 重复两次,则无法找到 (1, 2, 2) 。
对于单个组合,这很容易:
SELECT COUNT(*)
FROM my_table
WHERE n1 = 3 AND n2 = 10 AND n3 = 4
如果您想使用多种组合来执行此操作,您可以创建它们的(临时)表并将该表与您的数据连接起来,如下所示:
CREATE TEMPORARY TABLE combinations (
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
n1 INTEGER, n2 INTEGER, n3 INTEGER
);
INSERT INTO combinations (n1, n2, n3) VALUES
(1, 2, NULL), (4, 10, NULL), (1, 2, 3), (3, 10, 4);
SELECT c.n1, c.n2, c.n3, COUNT(t.id) AS num
FROM combinations AS c
LEFT JOIN my_table AS t
ON (c.n1 = t.n1 OR c.n1 IS NULL)
AND (c.n2 = t.n2 OR c.n2 IS NULL)
AND (c.n3 = t.n3 OR c.n3 IS NULL)
GROUP BY c.id;
请注意,由于OR c.n? IS NULL
子句的原因,编写的这个查询效率不高,MySQL 不够聪明,无法优化。如果您的所有组合都包含相同数量的术语,则可以将其省略,这将允许查询利用数据表上的索引。
附言。使用上面的查询,组合(1, 2, NULL)
将不匹配(35, 1, 2)
。但是,(NULL, 1, 2)
如果你想要两者,一个简单的解决方法是在你的组合表中包含这两种模式。
如果您实际上有比示例中显示的多得多的列,并且您想要匹配任何一组连续列中出现的模式,那么您真的应该将您的列打包成一个字符串并使用LIKE
orREGEXP
查询。例如,如果您将所有数据列连接到名为 的列中的逗号分隔字符串中data
,您可以像这样搜索它:
INSERT INTO combinations (pattern) VALUES
('1,2'), ('4,10'), ('1,2,3'), ('3,10,4'), ('7,8,9');
SELECT c.pattern, COUNT(t.id) AS num
FROM combinations AS c
LEFT JOIN my_table AS t
ON CONCAT(',', t.data, ',') LIKE CONCAT('%,', c.pattern, ',%')
GROUP BY c.id;
您可以通过在表中添加前缀和后缀以及部分实际数据来使此查询更快一些CONCAT()
,但是如果您要搜索大量数据,这仍然是一个相当低效的查询,因为它无法使用的索引。如果您需要在大型数据集上有效地执行这种子字符串搜索,您可能希望使用比 MySQL 更适合特定目的的东西。
SELECT
CONCAT(CAST(n1 AS VARCHAR(10)),'|',CAST(n2 AS VARCHAR(10)),'|',CAST(n3 AS VARCHAR(10))) AS Combination,
COUNT(CONCAT(CAST(n1 AS VARCHAR(10)),'|',CAST(n2 AS VARCHAR(10)),'|',CAST(n3 AS VARCHAR(10)))) AS Occurrences
FROM
MyTable
GROUP BY
CONCAT(CAST(n1 AS VARCHAR(10)),'|',CAST(n2 AS VARCHAR(10)),'|',CAST(n3 AS VARCHAR(10)))
这将创建一个单列,通过连接值来表示 3 列中的值的组合。它将计算每个的出现次数。