Mysql 按条件按多列排序
Mysql order by multiple columns with conditions
我有一个应用程序使用 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'
我需要实现的是选择所有广告,但先订购 none 过期包 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'
我已在 fiddle
上添加架构
您在 (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
使用两个单独的查询,然后 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
我有一个应用程序使用 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'
我需要实现的是选择所有广告,但先订购 none 过期包 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'
我已在 fiddle
上添加架构您在 (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
使用两个单独的查询,然后 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