【问题标题】:MySQL: Order by 2nd column--if not null--while maintaining 1st column orderMySQL:按第二列排序——如果不为空——同时保持第一列顺序
【发布时间】:2021-10-26 04:46:36
【问题描述】:

基本上我想按“标题”排序,同时在该顺序中将具有相同、非空“series_id”的电影分组在一起。 series_id 为 NULL 的标题应仅按标题排序,而非 NULL series_ids 应按“series_order”排序,并根据原始列中的“series”.“title”排序。我宁愿在查询中实现这一点,而不是加载整个数据库并从那里进行排序。

我尝试过的(MySQL 5.7.17):

按标题排序,series_id

    SELECT * FROM media
        ORDER BY title, series_id, series_order
    LIMIT 0, 30

不考虑字母顺序不同的系列中的标题(参见下面的示例)。

ORDER BY CASE 使用 CONCAT 按 'series'.'title' + 'media'.'series_order' 排序

    SELECT * FROM media
        ORDER BY CASE
            WHEN series_id IS NULL THEN title
            ELSE CONCAT((SELECT title FROM series WHERE id = media.series_id), series_order)
        END
    LIMIT 0, 30

结果在 SQL Fiddle 中正确排序,但在开发服务器上没有。公平地说,这仍然不是预期的结果,因为“系列”。“标题”可能与原始电影标题不同。

LEFT JOIN 包含“系列”表以使用相同的想法进行排序

    SELECT media.*, series.title, series.id FROM media
        LEFT JOIN series ON media.series_id = series.id
    LIMIT 0, 30

这也不能正确地对数据进行排序。

样本数据

title series_id series_order
88 Minutes NULL NULL
Live Free or Die Hard 100094 4
3rd Rock from the Sun 100000 2
2 Guns NULL NULL
Die Hard 100094 1
Evil Dead NULL NULL
A Good Day to Die Hard 100094 5
3rd Rock from the Sun 100000 1
Desired Result Order
2 Guns NULL
3rd Rock from the Sun 1
3rd Rock from the Sun 2
88 Minutes NULL
Die Hard 1
Live Free or Die Hard 4
A Good Day to Die Hard 5
Evil Dead NULL

主表:媒体 相关列title、series_id、series_order

系列表:系列 相关列id、title

小提琴http://sqlfiddle.com/#!9/efca7c/3

在小提琴上,选项 2 似乎有效。在开发版本中,它只对部分内容进行排序。

编辑:事实证明,在将数据转换为 JSON 之前,我用来存储数据的 PHP 代码不可避免地会按主 ID 重新排序结果。

【问题讨论】:

  • 您的media 表缺少id 列。是主键吗?
  • 所以您实际上是在查看 Web 界面排序而不是查询结果?如果我没记错的话,您在查询中的顺序不一定会在 Web 界面上复制……这是两种不同的顺序。后面运行的查询应该已经 limit 基于放置的过滤器的结果,我很确定它不会加载整个数据库。那你应该试着从网络界面弄清楚排序,对吧?
  • @FaNo_FN Web 界面正在执行 AJAX 请求,然后以 JSON 格式返回。订单没有被界面修改,因为我还没有在界面中写入任何订单。
  • 所以,假设我们像以前一样使用一小组数据,那么您已经设法在查询中正确获取订单,但是当它转换到 Web 界面时,订单发生了变化。我假设最终的 JSON 值被检索到网络中是根据 JSON 中的排序,对吗?我想您将能够看到从 MySQL 查询到 JSON 的转换是否保留相同的顺序。抱歉,我真的不熟悉 AJAX 或 JSON,但这似乎不是 MySQL 查询问题。
  • @FaNo_FN 顺便说一句,你在标记上。虽然问题不是 AJAX 或 JSON,但我将信息存储在 PHP 变量中的方式是按主 ID 自动对其进行排序。仅当根据我的搜索参数删除结果时,结果才会波动。我点赞了您的 cmets,因为它们与寻找解决方案有关。谢谢!

标签: php mysql database


【解决方案1】:

根据实现所需排序所需的卷积,如果这是我的应用程序,我可能会创建一个新列,其中包含该系列的“基本标题”并在插入期间填充该值,然后您可以排序没有任何巫术或眼睛疲劳。

在没有修改您的表结构的情况下,我设法将使用ROW_NUMBER()PARTITION (MySQL8.0 Demo) 的解决方案降级为几个嵌套子查询——这不是我认为的漂亮。

SQL (Demo)

SELECT m2.title grouping_title, m1.title, COALESCE(m2.title, m1.title), m1.series_order
FROM media m1
LEFT JOIN (
    SELECT series_id, title
    FROM media m3
    WHERE series_order = (SELECT MIN(series_order) FROM media WHERE series_id = m3.series_id)
) m2 ON m1.series_id = m2.series_id
ORDER BY COALESCE(m2.title, m1.title), m1.series_order

您可以根据需要修改外部SELECT,但我只是想展示COALESCE() 函数生成的内容。实际上,我将媒体表连接到自身,以便我可以获得给定series_id 的最低series_order 值。 THAT 行中的title 表示要在排序算法的第一条规则中使用的“基本标题”——除非它是NULL,在这种情况下,我们只使用父查询中的title

对于您的应用程序输出,您需要使用m1.titlem1.series_order

【讨论】:

  • 我的坏人。这是我承认自己是个彻头彻尾的白痴的地方。一直以来,我一直没有注意到我将所有内容都存储到 $Movies[$ID] 中的事实,这将...当转换为 JSON 时按 primary_id 排序。我应该根据sql的原始顺序存储它。啊!很抱歉浪费了你的时间。不过,会将您的答案标记为最佳答案。您肯定花时间想出了一个可行的解决方案! (公平地说,至少在我发布这个问题之前,sql 没有工作)。 排队面掌
【解决方案2】:

使用CASE表达式检查seris_order值是否为null,如果为null则只取titlw,否则将title与series_order连接。

查询

Select case when series_order is null then title else concat(title, ' : Season ', series_order) end as title
From table_name
Order by 1;

【讨论】:

  • 好的,这让我更接近于我正在寻找的东西,但我仍然没有得到想要的结果。您的建议导致所有非空 series_order 被放置在结果的末尾。我使用了 CASE 的想法并来到了这里:SELECT * FROM media ORDER BY CASE WHEN series_id IS NULL THEN title ELSE CONCAT((SELECT title FROM series WHERE id = media.series_id), series_order) END 结果与我最初得到的结果几乎相同,但我觉得它快到了。我也尝试了左连接以使用“系列”。“标题”列进行排序,但它把所有 series_id 放在前面。
  • @TibTibs ,你应该更新你关于“非空被放在最后”的问题。据我所知,此查询建议返回您在问题中发布的exactly as the desired result。你能提供更多细节吗?我的意思是,在您测试了这个查询之后,您是否有不同的期望结果?
  • 由于@FaN 所述的原因,此页面应作为需要澄清关闭。
猜你喜欢
  • 2023-01-09
  • 2016-07-19
  • 2012-02-18
  • 2018-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
相关资源
最近更新 更多