【问题标题】:Order rows by column whilst keeping rows with a common column together按列对行进行排序,同时将具有公共列的行保持在一起
【发布时间】:2019-07-26 10:33:00
【问题描述】:

我正在运行相当于 MySQL 5.5 的 MariaDB 5.5。

我有以下测试数据。

CREATE TABLE `dev_test` (
    `id` INT NOT NULL AUTO_INCREMENT , 
    `date` DATE NOT NULL , 
    `venue` INT NOT NULL , 
    PRIMARY KEY (`id`)
) ENGINE = InnoDB;

INSERT INTO `dev_test` (`id`, `date`, `venue`) VALUES (NULL, '2019-08-01', '2'),
                           (NULL, '2019-09-01', '1'), (NULL, '2019-10-01', '2');
INSERT INTO `dev_test` (`id`, `date`, `venue`) VALUES (NULL, '2019-11-01', '3');

我希望对场地和活动进行排序,以便首先安排下一个活动的场地,然后是该场地的所有其他活动。然后是下一个尚未全部就绪的事件。

所以我想要这些数据:

Event ID 1 - 2019-08-01 Venue 2
Event ID 3 - 2019-10-01 Venue 2
Event ID 2 - 2019-09-01 Venue 1
Event ID 4 - 2019-11-01 Venue 3

我可以按任意顺序抓取所有事件,然后使用 PHP 对其进行排序。

或者我可以选择

SELECT venue FROM `dev_test` GROUP BY venue ORDER BY date;

然后使用 PHP 获取一个按日期排序的场地

SELECT * FROM `dev_test` WHERE venue = 2 ORDER BY date;
SELECT * FROM `dev_test` WHERE venue = 1 ORDER BY date;

但是在纯 MySQL (MariaDB) 中是否有一个很好的方法来做到这一点?
也许某种方式可以为所有场地提供与该场地最早日期相同的临时日期列?
还是我应该只用 PHP 来做?

对不起标题戈尔。我试图使“按日期排序事件,同时将事件保持在同一位置”更通用。

【问题讨论】:

  • @Strawberry 你能扩展一下吗?
  • 日期是唯一的吗?
  • @strawberry 不能保证唯一的日期。但返回哪个订单重复日期并不重要。

标签: php mysql mariadb innodb


【解决方案1】:

试试这个查询,我想这对你有帮助

SELECT t2.* FROM 
(SELECT venue FROM dev_test GROUP BY venue ORDER BY date) AS t1
LEFT JOIN (SELECT * FROM dev_test ORDER BY date) AS t2 ON t1.venue=t2.venue

这里的结果

【讨论】:

  • 这只是按日期顺序给了我事件。我尝试删除 select as t2 中的“ORDER BY date”,但这并没有改变任何东西。不过谢谢!
  • 抱歉,它确实有效。它不适用于我的数据库,所以我会看看它是否是不同的版本。
  • 没关系。也许您本地数据库中的数据与此处略有不同?
  • 我正在运行相当于 MySQL 5.5 的 MariaDB 5.5。因此,MySQL 5.5 和 5.6 之间的差异可能是问题所在。
  • 这适用于 MySQL 5.5+。不适用于服务器版本:5.5.60-MariaDB - MariaDB 服务器。如果我找到解决方案会更新。
【解决方案2】:

您可以使用带有 CTE 的窗口函数来实现这一点(注意:需要 MySQL 8+:

WITH added_initial_date 
 AS (SELECT id, 
            date, 
            venue, 
            FIRST_VALUE(date) 
              OVER( 
                PARTITION BY venue 
                ORDER BY date) AS 'initial_date' 
     FROM   dev_test), 
 ranked 
 AS (SELECT id, 
            date, 
            venue, 
            initial_date, 
            RANK() 
              OVER( 
                ORDER BY initial_date ASC) AS position 
     FROM   added_initial_date) 
SELECT id, 
   date, 
   venue 
FROM   ranked 
ORDER  BY position ASC, date ASC; 

也许它不是最有效的,但它确实有效。

更新:添加了按日期排序以首先获得最接近的记录。这是 db-fiddle:https://www.db-fiddle.com/f/puYqhDF53ocRiRys61XH53/0

【讨论】:

  • 感谢您的回答。必须相信这适用于运行 MySQL 8+ 的人。抱歉,我最初没有在问题中包含我的数据库版本。
【解决方案3】:

您可以在下面尝试 - 使用 order by venue desc, date asc

SELECT * FROM `dev_test` 
order by venue desc, date asc

【讨论】:

  • 像他说的那样使用多个订单
  • 这适用于测试数据。但是如果你切换所有的场地,那么它就会失败,因为它总是首先返回最高的场地。
  • 我在测试数据中添加了另一行来说明为什么这不起作用。
【解决方案4】:

例如:

SELECT a.*
  FROM dev_test a 
  LEFT 
  JOIN (SELECT * FROM dev_test ORDER BY date DESC LIMIT 1) b 
    ON b.venue = a.venue 
 ORDER 
    BY b.id IS NULL, date DESC;

根据示例数据,假设日期是唯一的

【讨论】:

  • 这需要哪个版本的 MySQL?它似乎不适用于 MySQL 5.5 或 5.6 sqlfiddle.com/#!9/dd0578/2
  • @SamDean 在我看来不错。也许规范需要澄清。扩展的数据集和相应的结果可能会有所帮助。
  • db-fiddle.com/f/puYqhDF53ocRiRys61XH53/1 它只返回日期为 DESC 的行
  • 那是因为3号场地只有一场活动
猜你喜欢
  • 2017-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-17
  • 2016-11-08
  • 1970-01-01
  • 2022-08-11
相关资源
最近更新 更多