분리 된 값이있는 열이 있으면 다음 unnest()
함수를 사용할 수 있습니다 .
myTable
id | elements
---+------------
1 |ab,cd,efg,hi
2 |jk,lm,no,pq
3 |rstuv,wxyz
select id, unnest(string_to_array(elements, ',')) AS elem
from myTable
id | elem
---+-----
1 | ab
1 | cd
1 | efg
1 | hi
2 | jk
...
요소 번호를 어떻게 포함시킬 수 있습니까? 즉 :
id | elem | nr
---+------+---
1 | ab | 1
1 | cd | 2
1 | efg | 3
1 | hi | 4
2 | jk | 1
...
소스 문자열에서 각 요소 의 원래 위치 를 원합니다 . 나는 윈도우 함수 (함께 시도했다 row_number()
, rank()
등)하지만 난 항상 얻을 1
. 소스 테이블의 동일한 행에 있기 때문일까요?
나는 그것이 나쁜 테이블 디자인이라는 것을 알고 있습니다. 내 것이 아니에요. 그냥 고치려고하는 거에요.
답변
Postgres 9.4 이상
사용 WITH ORDINALITY
설정을 반환하는 기능 :
FROM
절의 함수에 접미사가 붙으면 1부터 시작하여 함수 출력의 각 행에 대해 1 씩 증가WITH ORDINALITY
하는
bigint
열이 출력에 추가됩니다. 이것은unnest()
.
LATERAL
pg 9.3+ 의 기능 과 결합하고 pgsql-hackers 의이 스레드에 따르면 위의 쿼리는 이제 다음과 같이 작성할 수 있습니다.
SELECT t.id, a.elem, a.nr
FROM tbl AS t
LEFT JOIN LATERAL unnest(string_to_array(t.elements, ','))
WITH ORDINALITY AS a(elem, nr) ON TRUE;
LEFT JOIN ... ON TRUE
오른쪽에있는 테이블 표현식이 행을 반환하지 않더라도 왼쪽 테이블의 모든 행을 유지합니다. 그것이 문제가되지 않는다면이 동등하고 덜 장황한 형태를 암시 적으로 사용할 수 있습니다 CROSS JOIN LATERAL
.
SELECT t.id, a.elem, a.nr
FROM tbl t, unnest(string_to_array(t.elements, ',')) WITH ORDINALITY a(elem, nr);
또는 실제 배열 ( arr
배열 열)을 기반으로하는 경우 더 간단합니다 .
SELECT t.id, a.elem, a.nr
FROM tbl t, unnest(t.arr) WITH ORDINALITY a(elem, nr);
또는 최소한의 구문으로 :
SELECT id, a, ordinality
FROM tbl, unnest(arr) WITH ORDINALITY a;
a
자동으로 테이블 및 열 별칭입니다. 추가 된 순서 열의 기본 이름은입니다 ordinality
. 그러나 명시 적 열 별칭 및 테이블 한정 열을 추가하는 것이 더 좋습니다 (안전하고 깔끔함).
Postgres 8.4-9.3
함께 row_number() OVER (PARTITION BY id ORDER BY elem)
사용하면 정렬 순서가 아닌의 서수에 따라 번호를 얻을 원래 순서 위 문자열이다.
간단히 생략 할 수 있습니다 ORDER BY
.
SELECT *, row_number() OVER (PARTITION by id) AS nr
FROM (SELECT id, regexp_split_to_table(elements, ',') AS elem FROM tbl) t;
이것이 정상적으로 작동하고 간단한 쿼리에서 실패하는 것을 본 적이 없지만 PostgreSQL은 ORDER BY
. 구현 세부 사항으로 인해 작동합니다.
공백으로 구분 된 문자열 에서 요소의 서수 를 보장 하려면 다음을 수행하십시오.
SELECT id, arr[nr] AS elem, nr
FROM (
SELECT *, generate_subscripts(arr, 1) AS nr
FROM (SELECT id, string_to_array(elements, ' ') AS arr FROM tbl) t
) sub;
또는 실제 배열을 기반으로하는 경우 더 간단합니다 .
SELECT id, arr[nr] AS elem, nr
FROM (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t;
dba.SE 관련 답변 :
Postgres 8.1-8.4
이러한 기능 중에 아직 사용할 수 없습니다 : RETURNS TABLE
, generate_subscripts()
, unnest()
, array_length()
. 그러나 이것은 작동합니다.
CREATE FUNCTION f_unnest_ord(anyarray, OUT val anyelement, OUT ordinality integer)
RETURNS SETOF record
LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1
FROM generate_series(array_lower($1,1), array_upper($1,1)) i';
특히 배열 인덱스는 요소의 서수 위치와 다를 수 있습니다. 확장 된 기능 이있는이 데모를 고려하십시오 .
CREATE FUNCTION f_unnest_ord_idx(anyarray, OUT val anyelement, OUT ordinality int, OUT idx int)
RETURNS SETOF record
LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1, i
FROM generate_series(array_lower($1,1), array_upper($1,1)) i';
SELECT id, arr, (rec).*
FROM (
SELECT *, f_unnest_ord_idx(arr) AS rec
FROM (VALUES (1, '{a,b,c}'::text[]) -- short for: '[1:3]={a,b,c}'
, (2, '[5:7]={a,b,c}')
, (3, '[-9:-7]={a,b,c}')
) t(id, arr)
) sub;
id | arr | val | ordinality | idx
----+-----------------+-----+------------+-----
1 | {a,b,c} | a | 1 | 1
1 | {a,b,c} | b | 2 | 2
1 | {a,b,c} | c | 3 | 3
2 | [5:7]={a,b,c} | a | 1 | 5
2 | [5:7]={a,b,c} | b | 2 | 6
2 | [5:7]={a,b,c} | c | 3 | 7
3 | [-9:-7]={a,b,c} | a | 1 | -9
3 | [-9:-7]={a,b,c} | b | 2 | -8
3 | [-9:-7]={a,b,c} | c | 3 | -7
비교:
답변
시험:
select v.*, row_number() over (partition by id order by elem) rn from
(select
id,
unnest(string_to_array(elements, ',')) AS elem
from myTable) v
답변
첨자 생성 함수를 사용합니다 .
http://www.postgresql.org/docs/current/static/functions-srf.html#FUNCTIONS-SRF-SUBSCRIPTS
예를 들면 :
SELECT
id
, elements[i] AS elem
, i AS nr
FROM
( SELECT
id
, elements
, generate_subscripts(elements, 1) AS i
FROM
( SELECT
id
, string_to_array(elements, ',') AS elements
FROM
myTable
) AS foo
) bar
;
더 간단하게 :
SELECT
id
, unnest(elements) AS elem
, generate_subscripts(elements, 1) AS nr
FROM
( SELECT
id
, string_to_array(elements, ',') AS elements
FROM
myTable
) AS foo
;
답변
요소의 순서가 중요하지 않은 경우
select
id, elem, row_number() over (partition by id) as nr
from (
select
id,
unnest(string_to_array(elements, ',')) AS elem
from myTable
) a
답변
unnest2()
운동으로
pg v8.4 이전 버전은 사용자 정의 unnest()
. 인덱스가있는 요소를 반환하도록이 이전 함수를 조정할 수 있습니다.
CREATE FUNCTION unnest2(anyarray)
RETURNS setof record AS
$BODY$
SELECT $1[i], i
FROM generate_series(array_lower($1,1),
array_upper($1,1)) i;
$BODY$ LANGUAGE sql IMMUTABLE;