PostgreSQL 8.3 には、多数のコメントを取得する単純な SQL クエリがあります。句の構造に値の並べ替えられたリストを提供します。IN
WHERE
SELECT * FROM comments WHERE (comments.id IN (1,3,2,4));
これは、たまたま のような ID である任意の順序でコメントを返します1,2,3,4
。
結果の行をコンストラクトのリストのように並べ替えたいIN
: (1,3,2,4)
.
それを達成する方法は?
PostgreSQL 8.3 には、多数のコメントを取得する単純な SQL クエリがあります。句の構造に値の並べ替えられたリストを提供します。IN
WHERE
SELECT * FROM comments WHERE (comments.id IN (1,3,2,4));
これは、たまたま のような ID である任意の順序でコメントを返します1,2,3,4
。
結果の行をコンストラクトのリストのように並べ替えたいIN
: (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
見つけるのが非常に難しく、広める必要があるという理由だけで: 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 でそれを行う別の方法は、idx
関数を使用することです。
SELECT *
FROM comments
ORDER BY idx(array[1,3,2,4], comments.id)
idx
ここで説明されているように、最初に関数を作成することを忘れないでください: http://wiki.postgresql.org/wiki/Array_Index
Postgresql では:
select *
from comments
where id in (1,3,2,4)
order by position(id::text in '1,3,2,4')
これをさらに調査すると、この解決策が見つかりました:
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
ただし、これはかなり冗長に見え、大規模なデータセットではパフォーマンスの問題が発生する可能性があります。誰でもこれらの問題についてコメントできますか?
これを行うには、注文するIDのマッピングを定義する追加の「ORDER」テーブルがおそらく必要だと思います(あなた自身の質問に対する回答が言ったことを効果的に実行します)。これは、選択した追加の列として使用できますその後、並べ替えることができます。
このようにして、データベース内の必要な順序を明示的に記述します。
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,')
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;
[EDIT]
unnest is not yet built-in in 8.3, but you can create one yourself(the beauty of any*):
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;
$$;
that function can work in any type:
select unnest(array['John','Paul','George','Ringo']) as beatle
select unnest(array[1,3,2,4]) as id
And here's another solution that works and uses a constant table (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
But again I'm not sure that this is performant.
I've got a bunch of answers now. Can I get some voting and comments so I know which is the winner!
Thanks All :-)
私が思うシーケンスを使用するバージョンよりもわずかな改善:
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 a.id,a.status,a.description FROM minicloud_tasks as a ORDER BY random();
id | status | description
----+------------+------------------
4 | processing | work on postgres
6 | deleted | need some rest
3 | pending | garden party
5 | completed | work on html
また、タスクのリストをステータス順に並べたいとします。ステータスは文字列値のリストです:
(processing, pending, completed, deleted)
秘訣は、各ステータス値に整数を与え、リストを数値で並べることです。
SELECT a.id,a.status,a.description FROM minicloud_tasks AS a
JOIN (
VALUES ('processing', 1), ('pending', 2), ('completed', 3), ('deleted', 4)
) AS b (status, id) ON (a.status = b.status)
ORDER BY b.id ASC;
これは次のことにつながります。
id | status | description
----+------------+------------------
4 | processing | work on postgres
3 | pending | garden party
5 | completed | work on html
6 | deleted | need some rest
クレジット @ user80168
「そんなことはしないでください」または「SQL はそれが得意ではありません」と言っている他のすべての投稿者に同意します。コメントのいくつかの面で並べ替えたい場合は、テーブルの 1 つに別の整数列を追加して、並べ替え基準を保持し、その値で並べ替えます。例: "ORDER BY comments.sort DESC " 毎回異なる順序で並べ替えたい場合... この場合、SQL は役に立ちません。