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
것을 사용하여 이미 언급했다 .
하위 쿼리가 필요하지 않으며 테이블처럼 set-returning 함수를 사용할 수 있습니다.
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
각 값에 위치를 수동으로 할당 / 유지할 필요가 없습니다.
로 포스트 그레스 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);
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
을 사용하면 앱 사용자가 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
절에 수천 개의 값이 있으면 어떻게 됩니까? 수천 개의 레코드를 처리해야하기 때문입니다.
이렇게하려면 주문할 ID 매핑을 정의하는 추가 "ORDER"테이블이 있어야한다고 생각합니다 (실제로 자신의 질문에 대한 응답이 수행 한 작업 수행). 그런 다음 정렬 할 수 있습니다.
그런 식으로 데이터베이스에서 원하는 순서를 명시해야합니다.
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)
비결은 각 상태 값에 interger를 부여하고 목록을 숫자로 정렬하는 것입니다.
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