【问题标题】:How Can I Sort BEFORE Group By (mysql, mariadb)如何在分组前排序(mysql,mariadb)
【发布时间】:2018-03-02 11:15:40
【问题描述】:

我已经寻找了很长一段时间的答案。看起来应该很简单,但我不确定它是否......

设置:

一个数据库有两个表: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

【问题讨论】:

  • 你看过thisthis的问题吗?他们似乎问你同样的事情,所以也许那里的答案可以帮助你解决你的问题?
  • 肯定是类似的。第一个链接不好,但我可能可以从stackoverflow.com/questions/14770671/…中弄清楚——我现在试试……
  • 这对我不起作用。我试图保持简单,只处理内部查询 SELECT id, max(is_open), max(create_date_time), contact_id, description FROM my_sales GROUP BY contact_id 结果是错误的 - 来自不同记录的数据被组合成一个记录,最重要的是,记录 ID 不正确。据我所知,这是一个不平凡的问题。
  • 在 group by 之前对子表进行排序是无用的。因为你得不到。你应该使用 where 条件来过滤而不是排序
  • 第一部分的分组最大值。然后为第二个做一个 UNION。

标签: mysql group-by sql-order-by mariadb groupwise-maximum


【解决方案1】:

在支持“窗口函数”的数据库版本中,这种类型的问题可以通过使用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() 的别名进行过滤,因此您需要一个子查询结构,如上所示。

结果

编号 |联系方式 |描述 | is_open |创建日期时间 |姓名 | rn -: | ---------: | :------------ | ------: | :----------------- | :---- | -: 9 | 1 |食品 | 0 | 2017-07-09 00:00:00 |吉姆 | 1 3 | 2 |杂货 | 1 | 2017-05-06 00:00:00 |简 | 1 6 | 3 |食品 | 1 | 2017-05-06 00:00:00 |罗杰 | 1 5 | 4 |玩具 | 1 | 2017-04-04 00:00:00 |爱丽丝 | 1

dbfiddle here


对于不支持 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

【讨论】:

  • MySQL 8.0 终于支持窗口函数了!
  • 让我们把兴奋推迟到 MySQL v8.x 可用于生产使用。在此之前,一些杂乱无章仍然是必要的
  • 做得很好,谢谢!干净简单易懂!!​​span>
猜你喜欢
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多