繁体   English   中英

如何在分组之前对分组排序(mysql,mariadb)

[英]How Can I Sort BEFORE Group By (mysql, mariadb)

我已经花了很多时间来寻找答案。 看起来应该很简单,但我不确定是不是...

设定:

数据库具有两个表:my_contacts和my_sales。

每个联系人可以有一个或多个销售。 每个销售都有创建日期,可以打开或关闭。

挑战:

我想生成一个查询以返回加入的结果集,该结果集的每个联系人只有一条记录,如下所示:

  • 如果该联系人有任何未完成的销售,请返回最近创建的销售。
  • 如果没有未完成的销售,则返回最近创建的销售。

我尝试过按is_open,create_date_time进行排序,然后按contact_id进行分组-但是Group By指出在进行任何排序之前它会选择其记录,因此它不起作用。

数据库详细信息:

CREATE TABLE `my_contacts` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`id`));

CREATE TABLE `my_sales` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `contact_id` INT(11) NOT NULL,
  `description` VARCHAR(45) NOT NULL,
  `is_open` INT(1) NOT NULL,
  `create_date_time` DATETIME NOT NULL,
  PRIMARY KEY (`id`));

INSERT INTO `my_contacts` (`name`) VALUES ('Jim');
INSERT INTO `my_contacts` (`name`) VALUES ('Jane');
INSERT INTO `my_contacts` (`name`) VALUES ('Roger');
INSERT INTO `my_contacts` (`name`) VALUES ('Alice');

INSERT INTO `my_sales` VALUES (NULL, '2', 'Books', '0', '2017-09-06');
INSERT INTO `my_sales` VALUES (NULL, '3', 'Toys', '0', '2017-06-21');
INSERT INTO `my_sales` VALUES (NULL, '2', 'Groceries', '1', '2017-05-06');
INSERT INTO `my_sales` VALUES (NULL, '1', 'Water', '0', '2016-09-21');
INSERT INTO `my_sales` VALUES (NULL, '4', 'Toys', '1', '2017-04-04');
INSERT INTO `my_sales` VALUES (NULL, '3', 'Food', '1', '2017-05-06');
INSERT INTO `my_sales` VALUES (NULL, '2', 'Water', '1', '2017-04-07');
INSERT INTO `my_sales` VALUES (NULL, '4', 'Food', '1', '2017-01-02');
INSERT INTO `my_sales` VALUES (NULL, '1', 'Food', '0', '2017-07-09');

结果:

该查询将连接两个表并产生以下结果:

id  contact_id  description is_open create_date_time    id  name
9   1           Food        0       7/9/2017 0:00       1   Jim
3   2           Groceries   1       5/6/2017 0:00       2   Jane
6   3           Food        1       5/6/2017 0:00       3   Roger
5   4           Toys        1       4/4/2017 0:00       4   Alice

在支持“窗口函数”的数据库版本中,可以通过使用ROW_NUMBER() OVER()来解决此样式的问题,并在OVER子句中应用所需的顺序,如下所示(使用Mariadb 10.2):

 select * from ( select s.*, c.name , row_number() over(partition by c.id order by s.is_open DESC, create_date_time DESC) as rn from my_contacts c left join my_sales s on c.id = s.contact_id ) d where rn = 1 order by d.contact_id 

请注意,您必须通过row_number()的别名进行过滤,因此需要一个如上所示的子查询构造。

结果

\n id |  contact_id |  描述|  is_open |  create_date_time |  名称|  RN\n -:|  ---------:|  :---------- |  ------:|  :------------------ |  :---- |   - :\n  9 |  1 |  食物|  0 |  2017-07-09 00:00:00 |  吉姆|  1\n  3 |  2 |  杂货|  1 |  2017-05-06 00:00:00 |  简|  1\n  6 |  3 |  食物|  1 |  2017-05-06 00:00:00 |  罗杰|  1\n  5 |  4 |  玩具|  1 |  2017-04-04 00:00:00 |  爱丽丝|  1\n

dbfiddle 在这里


对于不支持ROW_NUMBER()的MySQL或Mariadb版本,请尝试以下方法通过使用变量模仿row_number()的效果(并获得相同的结果):

select
        d.contact_id
      , d.description
      , d.is_open
      , d.create_date_time
      , c.name
from (
        SELECT
                @row_num :=IF(@prev_value=s.contact_id,@row_num+1,1) AS RN
              , s.contact_id
              , s.description
              , s.is_open
              , s.create_date_time
              , @prev_value := s.contact_id
        FROM my_sales s
        CROSS JOIN (
                    SELECT @row_num :=1 x,  @prev_value :=0 y
                   ) vars
        ORDER BY
                s.contact_id
              , s.is_open DESC
              , s.create_date_time DESC
    ) d
inner join my_contacts c on c.id = d.contact_id
where d.rn = 1
order by d.contact_id

;

对于这种方法,请参见: http : //sqlfiddle.com/#!9/bfa9809/1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM