MySQL按排序的列值选择多列组

时间:2018-10-09 14:59:08

标签: mysql sorting field

我有此表的列结构:

id - n1 - n2 - n3

这里是一些伪数据:

id - n1 - n2 - n3
1 - 3 - 2 - 1
2 - 6 - 5 - 7
3 - 2 - 3 - 1
4 - 1 - 6 - 5
5 - 5 - 6 - 7
6 - 3 - 5 - 6

我们的想法是依次选择和计数n1,n2和n3的每个唯一不同的组。

例如,我们可以得到以下结果:

total - n1s - n2s - n3s
2 - 1 - 2 - 3
2 - 5 - 6 - 7
1 - 1 - 5 - 6
1 - 3 - 5 - 6

您能帮我设置实现该目标的状态吗?

我正在尝试不进行多重选择和PHP数组排序...

谢谢。

3 个答案:

答案 0 :(得分:0)

请考虑以下内容-标准化数据集...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(id INT NOT NULL
,n INT NOT NULL
,val INT NOT NULL
,PRIMARY KEY(id,n)
);

INSERT INTO my_table VALUES
(1, 1, 3),
(1, 2, 2),
(1, 3, 1),
(2, 1, 6),
(2, 2, 5),
(2, 3, 7),
(3, 1, 2),
(3, 2, 3),
(3, 3, 1),
(4, 1, 1),
(4, 2, 6),
(4, 3, 5),
(5, 1, 5),
(5, 2, 6),
(5, 3, 7),
(6, 1, 3),
(6, 2, 5),
(6, 3, 6);

这是一个快速的(写的)肮脏的解决方案。可以提供更快/更优雅的解决方案...

SELECT vals
     , COUNT(*) total
  FROM 
     ( SELECT id
            , GROUP_CONCAT(val ORDER BY val) vals 
         FROM my_table 
        GROUP 
           BY id
     ) x 
 GROUP 
    BY vals;
+-------+-------+
| vals  | total |
+-------+-------+
| 1,2,3 |     2 |
| 1,5,6 |     1 |
| 3,5,6 |     1 |
| 5,6,7 |     2 |
+-------+-------+

答案 1 :(得分:0)

我们只需要表达式即可对n1,n2和n3列中的值进行“排序”。如果有,那么我们可以做一个简单的GROUP BYCOUNT

SELECT COUNT(1) AS total
     , IF(t.n1<=t.n2,IF(t.n1<=t.n3,t.n1,t.n3),IF(t.n2<=t.n3,t.n2,t.n3)) AS n1s
     , IF(t.n1<=t.n2,IF(t.n2<=t.n3,t.n2,IF(t.n1<=t.n3,t.n3,t.n1)),IF(t.n1<=t.n3,t.n1,IF(t.n2<=t.n3,t.n3,t.n2 ))) AS n2s
     , IF(t.n1<=t.n2,IF(t.n2<=t.n3,t.n3,t.n2),IF(t.n1<=t.n3,t.n3,t.n1)) AS n3s
  FROM this_table_column_structure t
 GROUP BY n1s,n2s,n3s
 ORDER BY total DESC, n1s, n2s, n3s

将返回

total   n1s   n2s   n3s
-----  ----  ----  ----
    2     1     2     3
    2     5     6     7
    1     1     5     6
    1     3     5     6

答案 2 :(得分:0)

作为第一种方法(如果时间允许),您应该按照@Strawberry的normalizing

的建议,考虑answer您的表

但是,第二种方法可以利用User Defined Functions来允许任意数量的列(尽管由于字符串操作和冒泡排序而效率低下)。

我们基本上需要创建一个函数,该函数可以对逗号分隔的字符串中的值进行排序。我找到了一个可以进行排序的工作功能。从here复制代码:

-- sort comma separated substrings with unoptimized bubble sort
DROP FUNCTION IF EXISTS sortString;
DELIMITER |
CREATE FUNCTION sortString(inString TEXT) RETURNS TEXT
BEGIN
  DECLARE delim CHAR(1) DEFAULT ','; -- delimiter 
  DECLARE strings INT DEFAULT 0;     -- number of substrings
  DECLARE forward INT DEFAULT 1;     -- index for traverse forward thru substrings
  DECLARE backward INT;   -- index for traverse backward thru substrings, position in calc. substrings
  DECLARE remain TEXT;               -- work area for calc. no of substrings
-- swap areas TEXT for string compare, INT for numeric compare
  DECLARE swap1 TEXT;                 -- left substring to swap
  DECLARE swap2 TEXT;                 -- right substring to swap
  SET remain = inString;
  SET backward = LOCATE(delim, remain);
  WHILE backward != 0 DO
    SET strings = strings + 1;
    SET backward = LOCATE(delim, remain);
    SET remain = SUBSTRING(remain, backward+1);
  END WHILE;
  IF strings < 2 THEN RETURN inString; END IF;
  REPEAT
    SET backward = strings;
    REPEAT
      SET swap1 = SUBSTRING_INDEX(SUBSTRING_INDEX(inString,delim,backward-1),delim,-1);
      SET swap2 = SUBSTRING_INDEX(SUBSTRING_INDEX(inString,delim,backward),delim,-1);
      IF  swap1 > swap2 THEN
        SET inString = TRIM(BOTH delim FROM CONCAT_WS(delim
        ,SUBSTRING_INDEX(inString,delim,backward-2)
        ,swap2,swap1
        ,SUBSTRING_INDEX(inString,delim,(backward-strings))));
      END IF;
      SET backward = backward - 1;
    UNTIL backward < 2 END REPEAT;
    SET forward = forward +1;
  UNTIL forward + 1 > strings
  END REPEAT;
RETURN inString;
END |
DELIMITER ;

您将需要在MySQL服务器上运行此代码,以便该函数在查询中可用,就像本机内置的MySQL函数一样。现在,查询部分变得简单。您需要做的就是用逗号Concat_ws()的所有数字列。然后,对串联的字符串应用sortString()函数。最终,使用Group By子句中的“有序”字符串来获得所需的结果。

尝试:

SELECT sortString(CONCAT_WS(',', n1, n2, n3)) AS n_sequence -- add more columns here
       COUNT(id) AS total 
FROM your_table 
GROUP BY n_sequence 
ORDER BY total DESC 

现在,我建议您可以使用应用程序代码将以逗号分隔的n_sequence更改回表格列显示。