【问题标题】:MySQL - ORDER BY with part of UNIONMySQL - ORDER BY 与 UNION 的一部分
【发布时间】:2018-06-15 12:00:10
【问题描述】:

长期以来,我一直使用这种方法来订购我的列表(用于 html 选择):

SELECT '' AS ID, '' AS Name UNION 
SELECT ID, Name FROM (SELECT ID, Name FROM myTable ORDER BY Name) AS myTableTmp

但在更新到新的 MySQL(MariaDB) 版本后,我发现这种排序不再起作用。就像这里解释的那样,它与 SQL 标准冲突:mysql - order by inside subquery

获得所需订单的最佳做法是什么? 或者我应该使用简单的方法,并将LIMIT 65000 添加到嵌套查询中?

编辑:

嗯,我原来的例子不够精确,所以人们可能会误解我。 这是更正的示例:

CREATE TABLE IF NOT EXISTS `myTable` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` varchar(120) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=4 ;


INSERT INTO `myTable` (`ID`, `Name`) VALUES
(1, 'Banana'),
(2, 'Apple'),
(3, NULL);

如果我选择旧版本:

SELECT '0' AS ID, '-' AS Name UNION 
SELECT ID, Name FROM (SELECT ID, Name FROM myTable ORDER BY Name) AS myTableTmp

我明白了:

0   -
3   NULL
2   Apple
1   Banana

我如何在新的 MySQL 版本中获得相同的结果?

【问题讨论】:

  • 外部查询中的 order by 将是最简单的。
  • 但无论如何我都希望工会的第一部分保持领先。 SELECT '' AS ID, '' AS Name UNION SELECT ID, Name FROM myTable ORDER BY Name 会为所有行排序,甚至给出错误吗?我记得至少在大约 8 年前就存在这个问题......
  • ORDER BY 最后是下订单 (3, 0, 2, 1),我需要订单 (0, 3, 2, 1) ...

标签: mysql sql-order-by mariadb union


【解决方案1】:

否则您可以将订单移到外面:

SELECT 
    ID, Name
FROM
    (SELECT '' AS ID, '' AS Name UNION SELECT 
        ID, Name
    FROM
        yourTable) AS yourTableTmp
ORDER BY Name;

【讨论】:

  • 这正是我想要避免的——我希望SELECT '' AS ID, '' AS Name 不在ORDER BY 之外,并且永远是第一行。
  • 对不起,如果我理解错了:您希望 "", "" 位于 HTML 选择的顶部,但您没有不想将 ORDER BY 应用于具有选定行的 ""、""?你能补充更多细节吗?
【解决方案2】:

您可以使用ORDER BY CASE ... END 更改默认排序行为以获得预期结果。

它是如何工作的

所有“-”值在 ORDER BY 中的位置为“1”
所有 NULL 值在 ORDER BY 中的位置为“2”
所有名称都获得位置“3+”并按字母排序。

查询

SELECT '0' AS ID, '-' AS Name UNION 
SELECT ID, Name FROM (
  SELECT
     ID
   , Name
  FROM
   myTable
) AS myTableTmp
ORDER BY
 CASE 
  WHEN 
   Name = '-'
  THEN
   1
  WHEN 
   Name IS NULL
  THEN
   2
  ELSE 
   Name
 END

查看演示https://www.db-fiddle.com/f/xcy45sUEDKN9gJhNpVqoHd/2

但是如果有人把名字'-'放在表中怎么办?我可能会得到错误的 id 那个案子……

查询

SELECT
   '0' AS ID
 , '-' AS Name
 , 0 AS position

UNION

SELECT
   ID
 , Name
 , CASE
     WHEN 
      Name IS NULL
     THEN 
      2
     ELSE
      3
   END AS position
FROM (
   SELECT
       ID
     , Name
   FROM
    myTable 
) AS myTableTmp

ORDER BY 
   position
 , name ASC

见演示https://www.db-fiddle.com/f/xcy45sUEDKN9gJhNpVqoHd/7

【讨论】:

  • 但是如果有人把名字'-'放在表中怎么办?在那种情况下,我可能会得到错误的 ID...
  • “但是如果有人把名字'-'放在表中怎么办?在这种情况下我可能会得到错误的ID......”我已经更新了@Andrei,我认为更新做得更好处理那个案子。
  • 添加专用列进行排序可能是正确的方向之一......问题是 - 我的查询通常又大又丑,如果我也开始向它们添加 CASE、CROSS JOIN 和用户变量,我会自己无法阅读它们:)
  • 看不起它,你甚至不需要使用 MySQL 用户变量来工作。 @Andrei .. CASE 是必需的,或者您需要将其分解为其他 UNION.something like this db-fiddle.com/f/xcy45sUEDKN9gJhNpVqoHd/8
【解决方案3】:

我猜,目前最干净的 SQL 唯一解决方案是这里 Using union and order by clause in mysql

SELECT ID, Name FROM (
SELECT '0' AS ID, '-' AS Name, 1 AS Rank UNION 
SELECT ID, Name, 2 AS Rank FROM myTable
) AS myTableTmp ORDER BY Rank, Name

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 2011-12-20
    • 2014-05-30
    • 2016-11-22
    • 1970-01-01
    • 2018-02-15
    • 2015-04-30
    相关资源
    最近更新 更多