识别表中的排序顺序

时间:2013-10-08 07:08:46

标签: mysql sql

我有一张桌子,其中的项目是按照特定顺序一起预订的。这会产生一个包含这样数据集的表。

id item_id group_id 
 1     1        1
 2     2        1
 3     3        1
 4     1        2
 5     2        2
 6     3        2
 7     2        3
 8     1        3
 9     3        3
10     3        4
11     2        4
12     1        4
13     1        5
14     2        5
15     3        5
16     4        5
 .
 .
 .

现在,我正在寻找一个查询(或多个)查找组内的不同排序顺序,这可以指示主导顺序。在这种情况下,答案应该是:

group_id order_used_nr_times
     1        3
     2        3
     3        1
     4        1
     5        3
     .             
     .             
     .             

注意,正如第5组所示,很可能组内存在更多项目,并且搜索到的项目是一个子集(例如,查找项目4,5,6的顺序,并在1,2,3中找到,4,5,6,7,8,9是一个选项。

我一直在考虑与群组进行查询以及使用mysql transpose进行查询,但我无法理解它。

其他信息:

我需要查询为我提供显性排序顺序(此案例为1,2,3),因此可用于插入由1,2,3订购的1,2,3项和此示例中不是2,1,33,2,1,

从业务角度来看:有两个“人群”使用系统,A组和B组.A组知道如何订购商品,因此手动设置订单,系统只是在给定的数据中插入数据订购。然而,B组不知道订单。因此,系统(查询)需要查看组A是否已经预订了这些项目,如果是,那么它们最常出现的顺序(顺序可能与示例所示不同)。然后,来自A组的订单将用于插入来自B组的数据,假设这是最合乎逻辑的。

我希望这个解释有所帮助。

1 个答案:

答案 0 :(得分:1)

可以找到相同组的计数。您可以先按group_id和GROUP_CONCAT对行item_id值进行分组:

SELECT
  group_id,
  GROUP_CONCAT(item_id ORDER BY id) AS item_list
FROM atable
GROUP BY
  group_id
;

那会给你一个像这样的结果集:

group_id  item_list
--------  ---------
1         1,2,3
2         1,2,3
3         2,1,3
4         3,2,1
5         1,2,3,4

现在很容易获得每个不同项目列表的条目数:

SELECT
  item_list,
  COUNT(*) AS nr_times
FROM (
  SELECT
    group_id,
    GROUP_CONCAT(item_id ORDER BY id) AS item_list
  FROM atable
  GROUP BY
    group_id
) AS s
GROUP BY
  item_list
;

然后查询返回:

item_list  nr_times
---------  --------
1,2,3      2
1,2,3,4    1
2,1,3      1
3,2,1      1

这不是您所需的输出,因为您需要组ID旁边的计数。因此,最后一行需要连接到上一行集:

SELECT
  groups.group_id,
  counts.nr_times
FROM (
  SELECT
    group_id,
    GROUP_CONCAT(item_id ORDER BY id) AS item_list
  FROM atable
  GROUP BY group_id
) AS groups
INNER JOIN (
  SELECT
    item_list,
    COUNT(*) AS nr_times
  FROM (
    SELECT GROUP_CONCAT(item_id ORDER BY id) AS item_list
    FROM atable
    GROUP BY group_id
  ) AS s
  GROUP BY item_list
) AS counts
ON groups.item_list = counts.item_list
;

输出:

group_id  nr_times
--------  --------
1         2
2         2
3         1
4         1
5         1

此时,很明显,将同一组分组两次可能不是一个好主意。也许最好将第一个分组的结果存储到临时表中,然后使用它来获得最终结果:

CREATE TEMPORARY TABLE temp_results
AS
SELECT
  group_id,
  GROUP_CONCAT(item_id ORDER BY id) AS item_list
FROM atable
GROUP BY
  group_id
;

SELECT
  groups.group_id,
  counts.nr_times
FROM temp_results AS groups
INNER JOIN (
  SELECT
    item_list,
    COUNT(*) AS nr_times
  FROM temp_results
  GROUP BY item_list
) AS counts
ON groups.item_list = counts.item_list
;

现在要获得所需输出中的数字,您可以尝试使用LIKE匹配两组,如下所示:

SELECT
  groups.group_id,
  counts.nr_times
FROM temp_results AS groups
INNER JOIN (
  SELECT
    item_list,
    COUNT(*) AS nr_times
  FROM temp_results
  GROUP BY item_list
) AS counts
ON CONCAT(',', groups.item_list, ',') LIKE CONCAT('%,', counts.item_list, ',%')
OR CONCAT(',', counts.item_list, ',') LIKE CONCAT('%,', groups.item_list, ',%')
;

以上内容将为您提供以下内容:

group_id  nr_times
--------  --------
1         2
1         1
2         2
2         1
3         1
4         1
5         2
5         1

显然,你现在只需要坚持

GROUP BY groups.group_id

在最后一个查询的末尾,并用

替换其SELECT子句中的counts.nr_times
SUM(counts.nr_times) AS order_used_nr_times

获得与您的问题相同的输出:

group_id  order_used_nr_times
--------  -------------------
1         3
2         3
3         1
4         1
5         3

但请注意,如果您的群组包含项1,2,33,4,51,2,3,4,5,6,则上次查询中使用的LIKE加入条件将与前两个群组中的任何一个匹配只有第三组而不是彼此,而第三组将与前两组相匹配。

我不确定这是否符合您的要求,因为我仍然无法对该特定点做出解释(抱歉)。我希望这篇文章至少可以为你提供一些如何最终得出正确结果的想法。