mysql组合/值的分布

mysql组合/值的分布,mysql,sql,combinatorics,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等组合出现了多少次 我是否必须创建另一个包含所有可能组合的表并从中进行比较,或者是否有其他方法进行比较 SELECT CONCAT(CAST(n1 AS

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

我是否必须创建另一个包含所有可能组合的表并从中进行比较,或者是否有其他方法进行比较

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列中的值的组合。它将统计每种情况的发生次数。

对于单个组合,这很简单:

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;
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;
()

注意,由于
或c.n?是NULL
子句,MySQL没有足够的智能来优化它。如果所有组合都包含相同数量的术语,则可以省略这些术语,这将允许查询使用数据表上的索引

注:对于上面的查询,组合
(1,2,NULL)
将与
(35,1,2)
不匹配。但是,
(NULL,1,2)
会,因此,如果您想要两者,一个简单的解决方法是在组合表中只包含这两种模式

如果您实际拥有的列比示例中显示的多,并且您希望匹配任何一组连续列中出现的模式,那么您真的应该将列打包成一个字符串,并使用
之类的
REGEXP
查询。例如,如果将所有数据列连接到名为
data
的列中以逗号分隔的字符串中,则可以按如下方式进行搜索:

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;
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更适合特定用途的工具。

表中只有三列,因此您正在寻找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
选择(当v1.n<0时为空,否则为v1.n结束)作为n1,
(当v2.n<0时为空,否则v2.n结束)为n2,
(当v3.n<0时为空,否则v3.n结束)作为n3,
将(*)计为货币
从值v1连接
值v2
在v1.n
这是使用连接机制来生成组合


此方法查找所有组合,而不考虑顺序(因此1、2、3与2、3、1相同)。此外,这会忽略重复项,因此如果2重复两次,则无法找到(1、2、2)。

现在我认为一个解决方案是为所有可能的3-combo生成一个表,为所有可能的4-combo生成一个表等。然后对每个表执行select*操作,在java中执行一个交集并保持计数。但这似乎很难做到。因此,我想知道是否有更简单的方法可以做到这一点。谢谢你的代码,你能解释一下它和它是如何工作的吗?mysql告诉我你的代码错误。我将试着玩玩它,看看我是否能让它工作..你可以使用
CONCAT\WS()
来简化那些长的
CONCAT()
表达式。是的,单次很容易,但我必须多次进行。我正在编写一个java应用程序来实现这一点。因此,我的方法是创建另一个表,其中包含所有可能的组合,并在java中执行联接或交集,尽管这似乎是一个昂贵的操作。我退出了更多的列,而简化的列会使它变得更复杂。组合的总数约为200万。在这种情况下,将数据存储为字符串可能确实更好;请看上面的编辑。戈登,谢谢。我稍后会试试这个,看看它是如何工作的。我想你也可以根据需要将其扩展到7列?@SoucianceEqdamRashti。对在中间表中,您需要六行
selectdistinct
行,以便处理少于7项的组合。