PostgreSQL:如何对未包含列的联合查询进行排序?

PostgreSQL: How to sort union query on not included column?

我尝试 ORDER 2 UNION 次查询。 运行 这个:

SELECT b.id
  FROM book.book b 
    WHERE title ILIKE '%something%' 
UNION
SELECT b.id
  FROM book.book b
    JOIN book.book_person bp
      ON bp.bookID = b.id 
    JOIN person p 
      ON p.id = bp.personID 
    WHERE lastname ILIKE '%something%' 
    ORDER BY b.title ASC, b.year DESC, b.volume ASC

给我错误:

ERROR:  42P01: missing FROM-clause entry for table "b"
LINE 12:         ORDER BY b.title ASC, b.year DESC, b.volume ASC
                          ^
LOCATION:  errorMissingRTE, parse_relation.c:3140

没有 ORDER-子句它工作正常。当我包含我想要订购的 cols 时它工作正常:

SELECT b.id, b.title, b.year, b.volume 
  FROM book.book b 
    WHERE title ILIKE '%something%' 
UNION
SELECT b.id, b.title, b.year, b.volume 
  FROM book.book b
    JOIN book.book_person bp
      ON bp.bookID = b.id 
    JOIN person p 
      ON p.id = bp.personID 
    WHERE lastname ILIKE '%something%' 
    ORDER BY "title" ASC, "year" DESC, "volume" ASC

有没有比包含更多列更好的方式来订购 UNIONed queris?

那是因为首先创建 UNION 结果,然后执行 ORDER BYtitle 等不再可用于 UNION 结果的引用。 (基本上 UNION 比 ORDER BY 绑定更紧密。)

因此,为了解决这个问题,只需将第二个查询和 ORDER BY 语句括起来,假设您只想订购该部分:

SELECT id
...
UNION
(SELECT id
...
ORDER BY title, etc)

如果您希望对完整查询进行排序,您的 UNION 查询将必须 return 所有排序列,然后您将对其执行 select:

SELECT id
FROM (
    SELECT id, title, etc
    ...
    UNION
    SELECT id, title, etc
) x
ORDER BY title, etc

这才是正确的做法;如果您只需要 id 输出,只需用 select id from (...)_.

包装您现有的查询

根据 the docs:

,您需要在联合选择中包含要排序的列的原因是

select_statement is any SELECT statement without an ORDER BY, LIMIT, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE, or FOR KEY SHARE clause. (ORDER BY and LIMIT can be attached to a subexpression if it is enclosed in parentheses. Without parentheses, these clauses will be taken to apply to the result of the UNION, not to its right-hand input expression.)

因此 ORDER BY 仅适用于并集的结果,当仅输出图书 ID 时,只有该列可用。所以是的,要让两个结果集都按其他列排序,它们必须位于 UNION.

两侧的 SELECT 列列表中

完全摆脱 union 怎么样?

SELECT b.id
FROM book.book b LEFT JOIN
     book.book_person bp
     ON bp.bookID = b.id LEFT JOIN
     person p 
     ON p.id = bp.personID 
WHERE b.title ILIKE '%something%' OR p.lastname ILIKE '%something%' 
ORDER BY "title" ASC, "year" DESC, "volume" ASC