mysql分配组合/值

时间:2013-01-04 00:51:40

标签: mysql sql combinatorics

我有一个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等的组合出现了多少次。

我是否必须创建另一个包含所有可能组合的表并从那里进行比较,还是有其他方法可以做到这一点?

3 个答案:

答案 0 :(得分:1)

对于单一组合,这很容易:

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;

demo on SQLize

请注意,由于OR c.n? IS NULL子句,所写的查询效率不高,MySQL不够智能,无法优化。如果所有组合包含相同数量的术语,则可以将其保留,这将允许查询使用数据表上的索引。

聚苯乙烯。根据上述查询,(1, 2, NULL)组合将与(35, 1, 2)不匹配。但是,(NULL, 1, 2),如果你想要两者,一个简单的解决方法就是在你的组合表中包含这两种模式。

如果您实际拥有的列数多于示例中显示的列数,并且您希望匹配任何连续列集中出现的模式,那么您真的应该将列打包成字符串并使用LIKEREGEXP查询。例如,如果将所有数据列连接到名为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;

demo on SQLize

通过在表中添加CONCAT()部分实际数据的前缀和后缀,可以使这个查询更快一些,但如果您有大量数据,这仍然是一个相当低效的查询搜索,因为它无法使用索引。如果你需要有效地对大型数据集进行这种子串搜索,你可能想要使用比MySQL特定目的更适合的东西。

答案 1 :(得分:1)

表格中只有三列,因此您正在寻找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)。

答案 2 :(得分:0)

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列中值的组合。它将计算每个事件的发生次数。