【问题标题】:Check if set of items occurrs in row MySQL检查是否在行 MySQL 中出现一组项目
【发布时间】:2018-03-21 16:19:27
【问题描述】:

我正在使用 MySQL(结合 Java)中的大型数据集并尝试实现频繁项集算法。 该算法的一个反复出现的方面是计算一组项目(一个项目是一个随机整数)在数据集中出现的次数。

以这个小数据集为例T

ID | COL1 | COL2 | COL3 | COL4 | COL5 |
---------------------------------------
1  |   8  |  35  |  42  |  12  |  27  |
2  |  22  |  42  |  35  |  8   | NULL |
3  |  18  |  22  |   8  | NULL | NULL |
4  |  42  |  12  |  27  |  35  |  8   |
5  |  18  |  27  |  12  |  22  | NULL |

还有这张表T2

COL1 | COL2 |
-------------
35   | 27   |
22   | 8    |
42   | 8    |
18   | 35   |
35   | 42   |

我想要的结果是下表(它也可以是查询的答案):

COL1 | COL2 | COUNT |
---------------------
35   | 27   | 2     |
22   | 8    | 2     |
42   | 8    | 3     |
18   | 35   | 0     |
35   | 42   | 3     |

所以我想计算表 T 中表 T2 每一行的每次出现次数。基本上一行T2T

行子集的次数

这必须在每一代算法中完成。这是一个非常小的例子,最终必须对 T3(3 个项目的行)、T4(4 个项目的行)等进行同样的操作。表 T 保持不变。 我还必须考虑到顺序无关紧要 (|35, 27| = |27, 35|) 并且它们可能不会在 T

是否可以在不遍历数据集太多次的情况下执行此操作(而 太多 = 超过 T2 中的行数)? 将一行表示为一个元组(例如 (35, 27))会更好吗?

【问题讨论】:

  • “而太多 = 超过 T2 的行数”看起来不像我能想到的是生成一个 cvs 并使用 FIND_IN_SET 找到它们,但你不能使用索引如果 anny 所以这不会在大型数据集上扩展或在 T 表上使用 UNION ALL 将列转换为记录并与 T2 表外的列连接,但如果列 col1 和 col2 都被索引,则只会在大型数据集上扩展这种方法的问题是 UNION ALL 将使用内存表来保存结果。
  • 将行表示为元组只会使您的问题更加复杂;问题是 T 应该是两个表 T(带有 set_id)和 T values(带有 set_id、值,如果重要的话,可能还有“序列”。)... T2-T4 应该进行类似的重组。跨度>

标签: mysql subset find-occurrences


【解决方案1】:

如果您可以将数据重组为每行一个值,对于 T 和 TN,这样的方法应该同时适用于所有 TN。

SELECT n_id, COUNT(CASE WHEN matches = n_count THEN v_id ELSE NULL) AS occurences
FROM (
  SELECT n.n_id, v.set_id AS v_id, n.n_count, COUNT(*) AS matches
  FROM (SELECT n_id, COUNT(*) AS n_count FROM tN GROUP BY id) AS n
  INNER JOIN tN AS nv ON n.n_id = nv.n_id
  LEFT JOIN T_VALUES AS v ON nv.value = v.value
  GROUP BY n.n_id, v.set_id, n.n_count
) AS subQ;

如果您在最终结果中需要 TN 值,类似这样的方法会很接近。

SELECT n_id, n_values, COUNT(CASE WHEN matches = n_count THEN v_id ELSE NULL) AS occurences
FROM (
  SELECT n.n_id, n.n_count, n.n_values, v.set_id AS v_id, COUNT(*) AS matches
  FROM (
       SELECT n_id, COUNT(*) AS n_count 
          , GROUP_CONCAT(n.value) AS n_values
       FROM tN 
       GROUP BY id
  ) AS n
  INNER JOIN tN AS nv ON n.n_id = nv.n_id
  LEFT JOIN T_VALUES AS v ON nv.value = v.value
  GROUP BY n.n_id, n.n_count, n.n_values, v.set_id
) AS subQ;

注意:您可能无需子查询就可以逃脱,但最终可能会让数据库为 T 的每一行重复计算相同的 n_count 和 n_values。

【讨论】:

  • 谢谢,我实际上并没有使用过这个特殊的解决方案,但它表明我必须重组我的数据集。下面有一个解释。
【解决方案2】:

由于 Uueerdo 的回答,我意识到我必须使用不同的结构,所以不要使用表格 T

ID | COL1 | COL2 | COL3 | COL4 | COL5 |
---------------------------------------
1  |   8  |  35  |  42  |  12  |  27  |
2  |  22  |  42  |  35  |  8   | NULL |
3  |  18  |  22  |   8  | NULL | NULL |
4  |  42  |  12  |  27  |  35  |  8   |
5  |  18  |  27  |  12  |  22  | NULL |

我现在使用 Tnew

ID | Item|
1  | 8   |
1  | 35  |
1  | 42  |
.  |  .  |
.  |  .  |
.  |  .  |

这在 SQL 中更容易工作,您可以使用 Group By 和 Join 来获得所需的结果。该查询适用于具有相同 ID 的任意数量的项目。此外,您不必使用值 NULL 并且数据集更容易创建

如果有人想知道我最终使用的查询,请告诉我(想出好表名并使其清晰易懂的一些工作)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-17
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    • 2012-06-30
    • 2017-04-10
    • 1970-01-01
    • 2011-06-09
    相关资源
    最近更新 更多