PostgreSQL获取记录按顺序传递给IN条件

时间:2013-10-31 13:01:50

标签: sql postgresql

希望结果与传递给IN条件的顺序相同:

SELECT "id", 
       "field_a", 
       "field_b", 
       To_timestamp("on_dated") 
FROM   "test" 
WHERE  "id" IN ( 3, 1, 6, 2, 4 );

获得:

id    | field_a | field_b | on_dated
-------------------------------------
1     | Vinay   | M       | 1383224064
2     | Asha    | F       | 1383224064
3     | Shashi  | F       | 1383224064
4     | Vinita  | F       | 1383224064
5     | Arnav   | M       | 1383224064
6     | Jayant  | M       | 1383224064

期待:

id    | field_a | field_b | on_dated
-------------------------------------
3     | Shashi  | F       | 1383224064
1     | Vinay   | M       | 1383224064
6     | Jayant  | M       | 1383224064
2     | Asha    | F       | 1383224064
4     | Vinita  | F       | 1383224064

尝试:

SELECT "id", 
       "field_a", 
       "field_b", 
       To_timestamp("on_dated") 
FROM   "test" 
WHERE  "id" IN ( 3, 1, 6, 2, 4 ) 
ORDER  BY Field("id", '3', '1', '6', '2', '4');

但抛出错误:(


找到了更好的答案:

我也找到了一个更紧凑的答案:

SELECT * FROM "test"
WHERE "id" IN (3,1,6,2,4)
ORDER BY (id=3, id=1, id=6, id=2, id=4) DESC;

2 个答案:

答案 0 :(得分:1)

我能想到的唯一方法就是这样:

with numbers (id, sort_order) as (
  values 
     (3,1), 
     (1,2),
     (6,3),
     (2,4), 
     (4,5)
)
SELECT t.id, 
       t.field_a, 
       t.field_b, 
       to_timestamp(t.on_dated) 
FROM test
  JOIN numbers n on t.id = n.id
ORDER BY n.sort_order;

另一个稍微紧凑的版本:

with numbers (id, sort_order) as (
  select i, 
         row_number() over () 
  from unnest(ARRAY[3,1,6,2,4]) i
)
SELECT t.id, 
       t.field_a, 
       t.field_b, 
       to_timestamp(t.on_dated) 
FROM test
  JOIN numbers n on t.id = n.id
ORDER BY n.sort_order;

但是 :这依赖于这样一个事实:不再总是以相同的顺序生成行。我并不完全确定情况总是这样。

如果您经常需要此功能,可以创建一个功能来执行此操作:

create or replace function get_index(to_find integer, elements int[])
  returns integer
as
$$
declare
  idx integer;
  x integer;
begin
  idx := 1;
  foreach x in array elements
  loop
    if to_find = x then
      return idx;
    end if;
    idx := idx + 1;
  end loop;
  return -1;
end;
$$
language plpgsql;

然后你可以写:

SELECT id, 
       field_a, 
       field_b, 
       to_timestamp(on_dated) 
FROM test
WHERE id = any (array[2,7,3,1])
ORDER BY get_index(id, array[2,7,3,1]);

答案 1 :(得分:1)

根据定义,没有订单。因此,您的原始问题无法得到解答。它只能通过提供附加信息(就像您在添加的解决方案中所做的那样)来工作。

您可以将数组作为provided by @a_horse传递。我建议在这种情况下使用generate_subscripts(),如下所示: PostgreSQL unnest() with element number

即将发布的Postgres 9.4 (现在正在开发中)中有一个新功能,可以让更多更简单: WITH ORDINALITY Details in the same answer.

目前,您可以使用一组复合类型,包括行号:

SELECT t.*
FROM   test t
JOIN  (
    VALUES 
     (1, 3)
    ,(2, 1)
    ,(3, 6)
    ,(4, 2)
    ,(5, 5)
    ) val(rnk, test_id) USING (test_id)
ORDER  BY val.rnk;

->SQLfiddle demo.