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
with ordered_products as (select row_number() OVER (ORDER BY whatever) as reportingorder, id from comments) ... ORDER BY reportingorder
。
それを見つけるのが非常に難しく、それを広めなければならないからといって、mySQLではこれをはるかに簡単に行うことができますが、他のSQLで機能するかどうかはわかりません。
SELECT * FROM `comments`
WHERE `comments`.`id` IN ('12','5','3','17')
ORDER BY FIELD(`comments`.`id`,'12','5','3','17')
ERROR: cannot pass more than 100 arguments to a function
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;
新しい@a_horseをすでに使用してWITH ORDINALITY
いることを使用します。
サブクエリは必要ありません。テーブルのようにセットを返す関数を使用できます。
一部のクライアントでは、ARRAYコンストラクタの代わりに配列を渡す文字列リテラルを実装する方が簡単な場合があります。
詳細な説明:
私はこの方法が良いと思います:
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
... order by id=? desc, id=? desc, id=? desc
、それは
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が使用されるため、値のリストを指定する必要があるのは1回だけです。それが重要でない場合は、次のように書くこともできます。
select c.*
from comments c
where id in (42,48,43)
order by array_position(array[42,48,43], c.id);
IN
、WHERE
節内のORDER BY
節のリスト全体を再び繰り返すわけではないため、これが最良の答えであると言えます...これで、MySQLに似たものを見つけるだけです...
order by array_position(array[42,48,43], c.id::int);
。場合によっては、バグにつながる可能性があります。
array_position(array[42, 48, 43]::bigint[], c.id::bigint)
、不要切り捨てるようbigint
にint
。
Postgresでこれを行う別の方法は、idx
関数を使用することです。
SELECT *
FROM comments
ORDER BY idx(array[1,3,2,4], comments.id)
idx
ここで説明されているように、最初に関数を作成することを忘れないでください:http : //wiki.postgresql.org/wiki/Array_Index
CREATE EXTENSION intarray;
ます。
enable_extension
重ねると、Amazon RDSユーザーの場合、ROR移行機能を使用すると、アプリユーザーがrds_superuser
グループのメンバーである限り、これをアクティブ化できます。
Postgresqlの場合:
select *
from comments
where id in (1,3,2,4)
order by position(id::text in '1,3,2,4')
position(id::text in '123,345,3,678')
。ID 3
はIDの前に一致345
しますが、いけませんか?
これをさらに調査すると、私はこの解決策を見つけました:
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
ただし、これはかなり冗長に見え、大規模なデータセットでパフォーマンスの問題が発生する可能性があります。誰でもこれらの問題についてコメントできますか?
IN
句に何千もの値がある場合はどうなりますか?何千ものレコードに対してそれをしなければならないからです。
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,')
そして、定数テーブル(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にはまだ組み込まれていませんが、自分で作成できます(任意の美しさ*)。
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;
$$;
その関数はどのタイプでも機能します。
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]はidsというフィールドを持つメインテーブルであり、idsはcomments.idを格納する配列です。
postgresql 9.6で渡されました
すでに言われたことについて視覚的な印象を与えましょう。たとえば、いくつかのタスクを含むテーブルがあるとします。
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