【问题标题】:Mysql order by multiple columns with conditionsMysql按条件按多列排序
【发布时间】:2021-12-29 09:57:22
【问题描述】:

例如,我有应用程序使用带有此架构的 Mysql 数据库。

packages
id, name,       order
1, 'Free',      3
2, 'Basic',     2
3, 'Extensive', 1

ads
id,    date,                    package_id,   package_expires_at
1,     '2021-12-10 00:00:00',   1,            '2022-01-10'
2,     '2021-12-15 00:00:00',   3,            '2021-12-28'
3,     '2021-12-15 00:00:00',   3,            '2022-01-10'
4,     '2021-12-20 00:00:00',   2,            '2022-01-10'
5,     '2021-12-21 00:00:00',   1,            '2021-12-28'
6,     '2021-12-25 00:00:00',   1,            '2021-12-28'

我需要实现的是选择所有广告,但首先订购无过期包by packages.order asc, package_expire_at desc,然后订购过期的date desc

例如假设我们在 '2021-12-29' 那么结果应该是

id,    date,                    package_id,   package_expires_at
3,     '2021-12-15 00:00:00',   3,            '2022-01-10'
4,     '2021-12-20 00:00:00',   2,            '2022-01-10'
1,     '2021-12-10 00:00:00',   1,            '2022-01-10'
6,     '2021-12-25 00:00:00',   1,            '2021-12-28'
5,     '2021-12-21 00:00:00',   1,            '2021-12-28'
2,     '2021-12-15 00:00:00',   3,            '2021-12-28'

我已经在小提琴上添加了架构

http://sqlfiddle.com/#!9/cedb45/9

【问题讨论】:

  • 日期是存储为 DATE 还是 DATETIME 字段?
  • date 是日期时间字段,但 package_expires_at 是 date 字段

标签: php mysql sql-order-by


【解决方案1】:

您在 (My)SQL 中执行此操作的方式是,您提供一个虚拟字段作为ORDER BY 条件。 像这样的东西应该可以解决问题:

      SELECT a.id
           , a.date
           , a.package_id
           , a.package_expires_at
           , IF( a.package_expires_at < CURRENT_DATE,  1,         0                      ) AS is_expired
           , IF( a.package_expires_at < CURRENT_DATE,  a.`date`,  a.`package_expires_at` ) AS sort_date
           , p.`order`                                                                     AS sort_package_order
        FROM ads       AS  a
  INNER JOIN packages  AS  p 
          ON p.id = a.package_id
    ORDER BY IF( a.package_expires_at < CURRENT_DATE,  1,         0                      ) ASC
           , IF( a.package_expires_at < CURRENT_DATE,  1,         p.`order`              ) ASC
           , IF( a.package_expires_at < CURRENT_DATE,  a.`date`,  a.`package_expires_at` ) DESC

【讨论】:

  • 我添加了一个小提琴链接,您可以对其进行测试
  • 干得好;但它应该已经可以正常工作了吗?
  • 很遗憾不是预期的结果
  • 有什么不同?它遵循order asc, then package_expire_at desc 的活动项目订单,然后是您要求的过期项目的date desc 订单。
  • 看看我的预期结果它应该返回 3, 4, 1, 6, 5, 2 但结果小提琴返回 3, 4, 6, 5, 1, 2
【解决方案2】:

使用两个单独的查询,然后 union 他们(您的包裹订单现在与其 ID 倒置)

select * from (SELECT * from ads WHERE package_expires_at >= '2021-12-29' order by package_id asc, package_expires_at desc ) as a
union
select * from (SELECT * from ads WHERE package_expires_at < '2021-12-29' order by date desc) as b

如果他们是动态的并且没有顺序,加入他们然后做上面的事情。

select * from (SELECT ads.id,date,package_id,package_expires_at from ads left outer join packages on package_id = ads.id WHERE package_expires_at >= '2021-12-29' order by packages.order asc, package_expires_at desc ) as a
union
select * from ( SELECT ads.id,date,package_id,package_expires_at from ads left outer join packages on package_id = ads.id WHERE package_expires_at < '2021-12-29' order by date desc ) as b

【讨论】:

  • 这行不通,因为我在 Laravel 中使用了分页,这会导致一些问题。
猜你喜欢
  • 1970-01-01
  • 2018-03-12
  • 2023-04-11
  • 1970-01-01
  • 2013-09-13
  • 2018-03-14
  • 1970-01-01
  • 2012-09-13
  • 2020-01-18
相关资源
最近更新 更多