• mysql GROUP_CONCAT+ GROUP BY + substring_index获取分组的前几名


    mysql方法来源于:http://www.cnblogs.com/jjcc/p/5896588.html

    ###在网上看到一篇,非常赞的方法###

    比如说要获取班级的前3名,mysql就可以用GROUP_CONCAT  + GROUP BY + substring_index实现。

    考试表

    DROP TABLE IF EXISTS `test`;
    CREATE TABLE `test` (
    `id` int(11) DEFAULT NULL,
    `name` varchar(20) DEFAULT NULL,
    `score` int(11) DEFAULT NULL,
    `class` char(12) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

    插入数据

    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('1', 'Bobdd', '25', '1');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('2', 'xx', '20', '2');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('3', 'Jack', '30', '2');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('4', 'Bill', '32', '4');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('5', 'Nick', '22', '3');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('6', 'Kathy', '18', '3');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('7', 'Steve', '36', '3');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('8', 'Anne', '25', '2');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('9', 'Kathy', '18', '2');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('11', 'Bob1', '25', '3');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('12', 'Jane1', '20', '1');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('13', 'Jack1', '30', '1');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('14', 'Bill1', '32', '1');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('15', 'Nick1', '22', '4');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('16', 'Kathy1', '18', '4');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('17', 'Steve1', '36', '4');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('18', 'Anne1', '25', '1');
    INSERT INTO `test` (`id`, `name`, `score`, `class`) VALUES ('19', 'Kathy1', '18', '2');

    运用group_concat + GROUP BY 分组 获取前3名

    select GROUP_CONCAT(t1.id) as ids from (
    SELECT t.class, substring_index(GROUP_CONCAT(t.id ORDER BY t.score desc),',',3) as id from
    test t GROUP BY t.class 
    )t1

    得到

    注意 是t.id ORDER BY t.score desc 分数从高到低。

    上面的语句只是获取到总的id。但是转换为列不太好弄。可以拆分用union all 来搞。

    获取第一名

    SELECT t.class, substring_index(GROUP_CONCAT(t.id ORDER BY t.score desc),',',1) as id from
    test t GROUP BY t.class 

    union all

    -- 第二名
    SELECT t.class, substring_index(substring_index(GROUP_CONCAT(t.id ORDER BY t.score desc),',',2),',',-1) as id from
    test t GROUP BY t.class

    union all

    -- 第三名
    SELECT t.class, substring_index(substring_index(GROUP_CONCAT(t.id ORDER BY t.score desc),',',3),',',-1) as id from
    test t GROUP BY t.class

    好了到现在 已经获取到了一个list

    用 in 来完成最后的步骤 

    SELECT class,score,name FROM test where id in(
    SELECT id from 
    (SELECT t.class, substring_index(GROUP_CONCAT(t.id ORDER BY t.score desc),',',1) as id from
    test t GROUP BY t.class 
    union all  
    SELECT t.class, substring_index(substring_index(GROUP_CONCAT(t.id ORDER BY t.score desc),',',2),',',-1) as id from
    test t GROUP BY t.class 
    union all 
    SELECT t.class, substring_index(substring_index(GROUP_CONCAT(t.id ORDER BY t.score desc),',',3),',',-1) as id from
    test t GROUP BY t.class) t2
    ) ORDER BY class asc,score desc

     最终结果

    关于mysql函数GROUP_CONCAT

    GROUP_CONCAT([DISTINCT] expr [,expr ...] [ORDER BY {unsigned_integer | col_name | expr} [ASC | DESC] [,col_name ...]] [SEPARATOR str_val])

    1.例如:
    SELECT student_id, GROUP_CONCAT(courses_id) AS courses FROM student_courses WHERE student_id=2 GROUP BY student_id;
    +------------+---------+
    | student_id | courses |
    +------------+---------+
    | 2 | 3,4,5 |
    +------------+---------+

    2.当然分隔符还可以自定义,默认是以“,”作为分隔符,若要改为“|||”,则使用SEPARATOR来指定,例如:
    SELECT student_id, GROUP_CONCAT(courses_id SEPARATOR '|||') AS courses FROM student_courses WHERE student_id=2 GROUP BY student_id;
    +------------+---------+
    | student_id | courses |
    +------------+---------+
    | 2 | 3|||4|||5 |
    +------------+---------+
    3.除此之外,还可以对这个组的值来进行排序再连接成字符串,例如按courses_id降序来排:
    SELECT student_id, GROUP_CONCAT(courses_id ORDER BY courses_id DESC) AS courses FROM student_courses WHERE student_id=2 GROUP BY student_id;
    +------------+---------+
    | student_id | courses |
    +------------+---------+
    | 2 | 5,4,3 |
    +------------+---------+

    4.需要注意的:

    a.int字段的连接陷阱
    当你用group_concat的时候请注意,连接起来的字段如果是int型,一定要转换成char再拼起来
    否则在你执行后(ExecuteScalar或者其它任何执行SQL返回结果的方法)返回的将不是一个逗号隔开的串,
    而是byte[]。
    该问题当你在SQLyog等一些工具中是体现不出来的,所以很难发现。
    select group_concat(ipaddress) from t_ip 返回逗号隔开的串
    select group_concat(id) from t_ip 返回byte[]
    select group_concat(CAST(id as char)) from t_dep 返回逗号隔开的串
    select group_concat(Convert(id , char)) from t_dep 返回逗号隔开的串
    附Cast,convert的用法:
    CAST(expr AS type), CONVERT(expr,type) , CONVERT(expr USING transcoding_name)
    CAST() 和CONVERT() 函数可用来获取一个类型的值,并产生另一个类型的值。
    这个类型 可以是以下值其中的 一个:
    BINARY[(N)]
    CHAR[(N)]
    DATE
    DATETIME
    DECIMAL
    SIGNED [INTEGER]
    TIME
    UNSIGNED [INTEGER]
    b.长度陷阱
    用了group_concat后,select里如果使用了limit是不起作用的.
    用group_concat连接字段的时候是有长度限制的,并不是有多少连多少。但你可以设置一下。
    使用group_concat_max_len系统变量,你可以设置允许的最大长度。
    程序中进行这项操作的语法如下,其中 val 是一个无符号整数:
    SET [SESSION | GLOBAL] group_concat_max_len = val;
    若已经设置了最大长度,则结果被截至这个最大长度。
    在SQLyog中执行 SET GLOBAL group_concat_max_len = 10 后,重新打开SQLyog,设置就会生效。

    SELECT SUBSTRING(str,pos,len)函数用法
    SELECT SUBSTRING(str,pos,len) 返回字符串 str 中以 pos 作为起始位置,长度为 len 的子字符串。

    SELECT SUBSTRING(str FROM pos FOR len) -- 返回字符串 str 中以 pos 作为起始位置,长度为 len 的子字符串。
    SELECT SUBSTRING(str FROM pos) -- 返回字符串 str 中以 pos 作为起始位置,到结束的子字符串。
    SELECT SUBSTRING(str,pos) -- 返回字符串 str 中以 pos 作为起始位置,到结束的子字符串。
    SELECT SUBSTRING(str,pos,len) -- 返回字符串 str 中以 pos 作为起始位置,长度为 len 的子字符串。

    应用实例:
    SELECT SUBSTRING('123456' FROM 2 FOR 3)
    ------------------------------------------
    234

    SELECT SUBSTRING('123456',2,3)
    --------------------------------------
    234

    SELECT SUBSTRING('123456' FROM 2)
    -----------------------------------
    23456

    SELECT SUBSTRING('123456',2)
    -----------------------------------
    23456

  • 相关阅读:
    缓存
    json集合取值
    四个div块点击某个突出显示
    table获取某一列的td
    鼠标悬浮tr追加背景颜色
    jquery弹出层
    面试题
    表单校验及正则表达式
    jquery操作DOM
    jquery的事件与动画
  • 原文地址:https://www.cnblogs.com/nxld/p/6067970.html
Copyright © 2020-2023  润新知