ORDER BY IN值列表

我在PostgreSQL 8.3中有一个简单的SQL查询来抓取一堆评论。 我在WHERE子句中为IN构造提供了一个sorting的值列表:

 SELECT * FROM comments WHERE (comments.id IN (1,3,2,4)); 

这个以任意顺序返回的评论,在我碰巧是1,2,3,4

我想要结果行像IN结构中的列表一样sorting: (1,3,2,4)
如何实现?

你可以很容易地使用(在PostgreSQL 8.2中引入)VALUES(),()。

语法将如下所示:

 select c.* from comments c join ( values (1,1), (3,2), (2,3), (4,4) ) as x (id, ordering) on c.id = x.id order by x.ordering 

只是因为它很难find,它必须传播: 在MySQL中,这可以做得更简单 ,但我不知道它是否适用于其他SQL。

 SELECT * FROM `comments` WHERE `comments`.`id` IN ('12','5','3','17') ORDER BY FIELD(`comments`.`id`,'12','5','3','17') 

我觉得这样比较好:

 SELECT * FROM "comments" WHERE ("comments"."id" IN (1,3,2,4)) ORDER BY id=1 DESC, id=3 DESC, id=2 DESC, id=4 DESC 

在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 , 已经提到了@a_horse 。

  • 我们不需要子查询,我们可以使用像表一样的返回函数。

  • 交给数组而不是ARRAY构造函数的string文字可能更容易与一些客户端实现。

详细说明:

  • PostgreSQL unnest()与元素编号

在Postgres中做的另一种方法是使用idx函数。

 SELECT * FROM comments ORDER BY idx(array[1,3,2,4], comments.id) 

不要忘了先创buildidx函数,如下所述: http : //wiki.postgresql.org/wiki/Array_Index

使用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 

删除需要手动分配/维护每个值的位置。

使用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); 

在Postgresql中:

 select * from comments where id in (1,3,2,4) order by position(id::text in '1,3,2,4') 

在研究这一些,我发现这个解决scheme:

 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 

但是,这看起来相当冗长,并可能有大型数据集的性能问题。 任何人都可以评论这些问题?

要做到这一点,我想你应该有一个额外的“ORDER”表,它定义了ID的映射顺序(有效地做你对自己的问题的回应说),然后你可以使用作为一个额外的列在你的select你可以sorting。

这样,您就明确地描述了数据库中您希望的顺序。

sans SEQUENCE,仅适用于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,') 

我同意所有其他宣称“不这样做”或“SQL不擅长”的海报。 如果你想按照某些方面的评论sorting,然后添加另一个整数列到您的表之一来保存您的sorting标准和sorting的价值。 例如“ORDER BY comments.sort DESC”如果你想每次都按不同的顺序sorting,那么… SQL在这种情况下不适合你。

这是另一个解决scheme,使用常量表( http://www.postgresql.org/docs/8.3/interactive/sql-values.html ):

 SELECT * FROM comments AS c, (VALUES (1,1),(3,2),(2,3),(4,4) ) AS t (ord_id,ord) WHERE (c.id IN (1,3,2,4)) AND (c.id = t.ord_id) ORDER BY ord 

但是我不能肯定这是高性能的。

我现在有一堆答案。 我可以得到一些投票和评论,所以我知道哪个是赢家!

谢谢大家:-)

 create sequence serial start 1; select * from comments c join (select unnest(ARRAY[1,3,2,4]) as id, nextval('serial') as id_sorter) x on x.id = c.id order by x.id_sorter; drop sequence serial; 

[编辑]

unnest在8.3里还没有内置,但是你可以自己创build一个(任何*的美):

 create function unnest(anyarray) returns setof anyelement language sql as $$ select $1[i] from generate_series(array_lower($1,1),array_upper($1,1)) i; $$; 

该function可以在任何types的工作:

 select unnest(array['John','Paul','George','Ringo']) as beatle select unnest(array[1,3,2,4]) as id 

对使用序列的版本稍作改进我认为:

 CREATE OR REPLACE FUNCTION in_sort(anyarray, out id anyelement, out ordinal int) LANGUAGE SQL AS $$ SELECT $1[i], i FROM generate_series(array_lower($1,1),array_upper($1,1)) i; $$; SELECT * FROM comments c INNER JOIN (SELECT * FROM in_sort(ARRAY[1,3,2,4])) AS in_sort USING (id) ORDER BY in_sort.ordinal; 
 select * from comments where comments.id in (select unnest(ids) from bbs where id=19795) order by array_position((select ids from bbs where id=19795),comments.id) 

在这里,[bbs]是有一个叫做id的字段的主表,而id是存储comments.id的数组。

通过postgresql 9.6