我在PostgreSQL 8.3中有一个简单的SQL查询,它抓取了一堆注释。我在WHERE子句中为IN构造提供了一个排序的值列表:
SELECT * FROM comments WHERE (comments.id IN (1,3,2,4));
这将以任意顺序返回注释,在my中恰好是id,如1,2,3,4。
我希望结果行像in结构中的列表一样排序:(1,3,2,4)。 如何实现这一目标?
我在PostgreSQL 8.3中有一个简单的SQL查询,它抓取了一堆注释。我在WHERE子句中为IN构造提供了一个排序的值列表:
SELECT * FROM comments WHERE (comments.id IN (1,3,2,4));
这将以任意顺序返回注释,在my中恰好是id,如1,2,3,4。
我希望结果行像in结构中的列表一样排序:(1,3,2,4)。 如何实现这一目标?
当前回答
要做到这一点,我认为您可能应该有一个额外的“ORDER”表,它定义了id到ORDER的映射(有效地执行您对自己的问题的回答),然后您可以将其用作选择上的附加列,然后对其进行排序。
通过这种方式,您可以显式地描述您希望在数据库中的顺序,以及它应该在哪里。
其他回答
无序列,只适用于8.4:
select * from comments c
join
(
select id, row_number() over() as id_sorter
from (select unnest(ARRAY[1,3,2,4]) as id) as y
) x on x.id = c.id
order by x.id_sorter
SELECT * FROM "comments" JOIN (
SELECT 1 as "id",1 as "order" UNION ALL
SELECT 3,2 UNION ALL SELECT 2,3 UNION ALL SELECT 4,4
) j ON "comments"."id" = j."id" ORDER BY j.ORDER
或者如果你喜欢恶而不是善:
SELECT * FROM "comments" WHERE ("comments"."id" IN (1,3,2,4))
ORDER BY POSITION(','+"comments"."id"+',' IN ',1,3,2,4,')
在Postgres 9.4中,这可以做得更短一些:
select c.*
from comments c
join (
select *
from unnest(array[43,47,42]) with ordinality
) as x (id, ordering) on c.id = x.id
order by x.ordering;
或者在没有派生表的情况下更加紧凑:
select c.*
from comments c
join unnest(array[43,47,42]) with ordinality as x (id, ordering)
on c.id = x.id
order by x.ordering
无需手动为每个值分配/维护位置。
在Postgres 9.6中,可以使用array_position():
with x (id_list) as (
values (array[42,48,43])
)
select c.*
from comments c, x
where id = any (x.id_list)
order by array_position(x.id_list, c.id);
使用CTE时,值列表只需要指定一次。如果这并不重要,也可以写成:
select c.*
from comments c
where id in (42,48,43)
order by array_position(array[42,48,43], c.id);
通过进一步研究,我发现了这个解决方案:
SELECT * FROM "comments" WHERE ("comments"."id" IN (1,3,2,4))
ORDER BY CASE "comments"."id"
WHEN 1 THEN 1
WHEN 3 THEN 2
WHEN 2 THEN 3
WHEN 4 THEN 4
END
然而,这似乎相当冗长,并且对于大型数据集可能会有性能问题。 有人能就这些问题发表评论吗?
在Postgres 9.4或更高版本中,这是最简单和最快的:
SELECT c.*
FROM comments c
JOIN unnest('{1,3,2,4}'::int[]) WITH ORDINALITY t(id, ord) USING (id)
ORDER BY t.ord;
WITH ORDINALITY was introduced with in Postgres 9.4. No need for a subquery, we can use the set-returning function like a table directly. (A.k.a. "table-function".) A string literal to hand in the array instead of an ARRAY constructor may be easier to implement with some clients. For convenience (optionally), copy the column name we are joining to ("id" in the example), so we can join with a short USING clause to only get a single instance of the join column in the result. Works with any input type. If your key column is of type text, provide something like '{foo,bar,baz}'::text[].
详细解释:
PostgreSQL unnest()与元素号