在 MySQL 中使用 UNION 的 ORDER BY 子句出错

Error with ORDER BY clause using UNION in MySQL

我在 MySQL 中有以下查询:

(SELECT ue.id, ue.userid, ue.status, ue.timestart, ue.timeend, e.courseid,
        e.id AS enrolid, ra.roleid
 FROM user_enrolments ue
 JOIN enrol e ON e.id = ue.enrolid
 JOIN course c ON c.id = e.courseid
 JOIN user u ON u.id = ue.userid
 JOIN context ct ON ct.instanceid = c.id
 LEFT JOIN role_assignments ra ON ra.userid = u.id AND 
                               ra.contextid = ct.id AND
                               ra.itemid = e.id
 WHERE e.customint1 = 1 AND u.deleted = 0 AND 
       ct.contextlevel = 50 AND (ue.status = 0 OR ue.status = 1)) 

UNION

(SELECT de.enrolid AS id, de.userid, de.status, de.date_ini, de.date_fin, 
        de.courseid, de.enrolid, de.roleid
 FROM deleted_enrols de
 JOIN user u ON u.id = de.userid
 WHERE userid = ANY (SELECT userid FROM local_users WHERE clientid = 1))

ORDER BY u.firstname, u.lastname, c.fullname LIMIT 0, 100

如果我删除 ORBER BY 和 LIMIT,此查询工作正常...但 ORDER BY 子句给出错误:

Table 'u' from one of the SELECTs cannot be used in global ORDER clause

如果我删除两个 SELECT 查询的括号,错误是不同的:

Table 'u' from one of the SELECTs cannot be used in field list

我也尝试过使用 UNION ALL,但它也不起作用。

有什么建议或线索吗?预先感谢您的时间...

您需要在联合查询的选择中包含要排序的数据; UNION 之后的 ORDER BY 被处理 就好像 它是 SELECT * FROM (unions) ORDER BY ... 所以任何不是来自 union 的东西都不能用于排序。

具有讽刺意味的是,与此类似的查询是获得所需内容的关键,例如

SELECT x, y, z
FROM (
SELECT x, y, z, somethingIdontactuallywant
FROM blah
UNION
SELECT a, b, c, somethingIdontactuallywant
FROM blah2
) AS u
ORDER BY u.somethingIdontactuallywant

假设您要对全部进行排序,请尝试用括号括起整个查询,然后执行 ORDER BY:

select id, userid, status, timestart, timeend, courseid, enrolid, roleid from
((SELECT ue.id, ue.userid, ue.status, ue.timestart, ue.timeend, e.courseid,
        e.id AS enrolid, ra.roleid, u.firstname, u.lastname, c.fullname
 FROM user_enrolments ue
 JOIN enrol e ON e.id = ue.enrolid
 JOIN course c ON c.id = e.courseid
 JOIN user u ON u.id = ue.userid
 JOIN context ct ON ct.instanceid = c.id
 LEFT JOIN role_assignments ra ON ra.userid = u.id AND 
                               ra.contextid = ct.id AND
                               ra.itemid = e.id
 WHERE e.customint1 = 1 AND u.deleted = 0 AND 
       ct.contextlevel = 50 AND (ue.status = 0 OR ue.status = 1)) 

UNION

(SELECT de.enrolid AS id, de.userid, de.status, de.date_ini, de.date_fin, 
        de.courseid, de.enrolid, de.roleid, u.firstname, u.lastname, ' ' as fullname
 FROM deleted_enrols de
 JOIN user u ON u.id = de.userid
 WHERE userid = ANY (SELECT userid FROM local_users WHERE clientid = 1))) s1

ORDER BY firstname, lastname, fullname LIMIT 0, 100

(显然第二个 SELECT 语句中的全名会被填充,但看起来很合理)

您的 UNION 结果不包含 table 'u' 的任何字段,因此这些结果无法按 table 'u' 字段排序。

您或许可以执行 UNION,然后将结果重新连接到 table 'u',然后使用它按 table 'u' 字段对结果进行排序.排序存在类似问题 course.fullname,因此也需要重新加入。

SELECT x.id, x.userid, x.status, x.timestart, x.timeend, x.courseid, x.enrolid, x.roleid
FROM ((SELECT ue.id, ue.userid, ue.status, ue.timestart, ue.timeend, e.courseid,
        e.id AS enrolid, ra.roleid
       FROM user_enrolments ue
         JOIN enrol e ON e.id = ue.enrolid
         JOIN course c ON c.id = e.courseid
         JOIN user u ON u.id = ue.userid
         JOIN context ct ON ct.instanceid = c.id
         LEFT JOIN role_assignments ra ON ra.userid = u.id 
           AND ra.contextid = ct.id 
           AND ra.itemid = e.id
       WHERE e.customint1 = 1 AND u.deleted = 0 
           AND ct.contextlevel = 50 AND (ue.status = 0 OR ue.status = 1)) 
       UNION
       (SELECT de.enrolid AS id, de.userid, de.status, de.date_ini, de.date_fin, 
        de.courseid, de.enrolid, de.roleid
        FROM deleted_enrols de
          JOIN user u ON u.id = de.userid
         WHERE userid = ANY (SELECT userid FROM local_users WHERE clientid = 1))
) x
  JOIN user z ON z.id = x.userid
  JOIN course d ON d.id = x.courseid
ORDER BY z.firstname, z.lastname, d.fullname LIMIT 0, 100

正如 mysql 关于 union 的文档所说:

This kind of ORDER BY cannot use column references that include a table name (that is, names in tbl_name.col_name format). Instead, provide a column alias in the first SELECT statement and refer to the alias in the ORDER BY. (Alternatively, refer to the column in the ORDER BY using its column position. However, use of column positions is deprecated.)

Also, if a column to be sorted is aliased, the ORDER BY clause must refer to the alias, not the column name.

因此,不要引用任何 table 名称并使用实际上在联合结果集中的列。