PostgreSQL에서 크로스 탭 쿼리를 만드는 방법을 아는 사람이 있습니까?
예를 들어 다음 표가 있습니다.
Section Status Count
A Active 1
A Inactive 2
B Active 4
B Inactive 5
쿼리에서 다음 크로스 탭을 반환하고 싶습니다.
Section Active Inactive
A 1 2
B 4 5
이게 가능해?
답변
기능을 제공하는 데이터베이스 당 한 번 추가 모듈을tablefunc
설치하십시오 . Postgres 9.1부터 다음을 사용할 수 있습니다 .crosstab()
CREATE EXTENSION
CREATE EXTENSION IF NOT EXISTS tablefunc;
테스트 케이스 개선
CREATE TABLE tbl (
section text
, status text
, ct integer -- "count" is a reserved word in standard SQL
);
INSERT INTO tbl VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7); -- ('C', 'Active') is missing
간단한 양식-누락 된 속성에 적합하지 않음
crosstab(text)
함께 1 개 입력 파라미터 :
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- needs to be "ORDER BY 1,2" here
) AS ct ("Section" text, "Active" int, "Inactive" int);
보고:
섹션 | 활성 | 비활성 --------- + -------- + ---------- A | 1 | 2 B | 4 | 5 C | 7 | -!!
- 캐스팅 및 이름을 바꿀 필요가 없습니다.
- 에 대한 잘못된 결과에 유의하십시오 . 첫 번째 열에
C
값7
이 채워집니다. 때로는이 동작이 바람직하지만이 사용 사례에는 적합하지 않습니다. - 간단한 입력 양식은 제공된 입력 쿼리에서 row_name , category , value의 정확히 3 개의 열로 제한됩니다 . 아래의 2- 파라미터 대안에서와 같이 추가 열을 위한 공간이 없습니다 .
안전한 형태
crosstab(text, text)
함께 2 개 입력 파라미터 :
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- could also just be "ORDER BY 1" here
, $$VALUES ('Active'::text), ('Inactive')$$
) AS ct ("Section" text, "Active" int, "Inactive" int);
보고:
섹션 | 활성 | 비활성 --------- + -------- + ---------- A | 1 | 2 B | 4 | 5 C | | 7 ~ !!
-
에 대한 올바른 결과를 참고하십시오
C
. -
두 번째 매개 변수 는 끝에 열 정의의 순서와 일치하는 속성 당 하나의 행 을 리턴하는 모든 조회 일 수 있습니다 . 종종 다음과 같이 기본 테이블에서 고유 속성을 쿼리하려고 할 것입니다.
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
그것은 매뉴얼에 있습니다.
어쨌든 열 정의 목록의 모든 열을 철자해야하므로 (사전 정의 된 변형 제외 ) 일반적으로 다음과 같은 표현식 으로 짧은 목록을 제공하는 것이 더 효율적입니다 .
crosstabN()
VALUES
$$VALUES ('Active'::text), ('Inactive')$$)
또는 (설명서에 없음) :
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
나는 인용을 쉽게하기 위해 달러 인용 을 사용했습니다 .
-
값 열의 텍스트 표현이 대상 유형에 유효한 입력 인 경우-를 사용 하여 다른 데이터 유형의 열을 출력 할 수도 있습니다
crosstab(text, text)
. 당신이있을 수 있습니다이 방법은 다른 종류의 출력의 속성text
,date
,numeric
각각의 속성 등. 이 장의crosstab(text, text)
끝에는 코드 예제 가 있습니다 .
db <> 바이올린 여기
고급 예
\crosstabview
psql에서
Postgres 9.6 은이 메타 명령을 기본 대화식 터미널 psql에 추가했습니다 . 첫 번째 crosstab()
매개 변수 로 사용할 쿼리를 실행하여 \crosstabview
즉시 또는 다음 단계로 전달할 수 있습니다. 처럼:
db=> SELECT section, status, ct FROM tbl \crosstabview
위와 비슷한 결과이지만 독점적으로 클라이언트 측 의 표현 기능 입니다. 입력 행은 약간 다르게 처리되므로 ORDER BY
필요하지 않습니다. \crosstabview
매뉴얼에 대한 자세한 내용 . 해당 페이지 하단에 더 많은 코드 예제가 있습니다.
Daniel Vérité (psql 기능의 저자)의 dba.SE 관련 답변 :
이전에 허용 대답은 구식이다.
-
함수의 변형
crosstab(text, integer)
이 오래되었습니다. 두 번째integer
매개 변수는 무시됩니다. 나는 현재 매뉴얼을 인용한다 :crosstab(text sql, int N)
…사용되지 않는 버전입니다
crosstab(text)
.N
값 열의 개수는 항상 호출 쿼리에 의해 결정되므로 매개 변수 가 무시됩니다. -
불필요한 캐스팅 및 이름 바꾸기.
-
행에 모든 속성이없는 경우 실패합니다. 누락 된 속성을 올바르게 처리하려면 위의 두 개의 입력 매개 변수가있는 안전한 변형을 참조하십시오.
-
ORDER BY
의 한 매개 변수 형식으로 필요crosstab()
합니다. 매뉴얼 :실제로 SQL 쿼리는 항상
ORDER BY 1,2
입력 행이 올바르게 정렬되도록 지정 해야합니다.
답변
데이터베이스 당 한 번 설치 해야하는 추가 모듈 tablefunc 의 crosstab()
기능을 사용할 수 있습니다 . PostgreSQL 9.1부터 다음을 사용할 수 있습니다 .CREATE EXTENSION
CREATE EXTENSION tablefunc;
귀하의 경우 다음과 같이 보일 것이라고 믿습니다.
CREATE TABLE t (Section CHAR(1), Status VARCHAR(10), Count integer);
INSERT INTO t VALUES ('A', 'Active', 1);
INSERT INTO t VALUES ('A', 'Inactive', 2);
INSERT INTO t VALUES ('B', 'Active', 4);
INSERT INTO t VALUES ('B', 'Inactive', 5);
SELECT row_name AS Section,
category_1::integer AS Active,
category_2::integer AS Inactive
FROM crosstab('select section::text, status, count::text from t',2)
AS ct (row_name text, category_1 text, category_2 text);
답변
SELECT section,
SUM(CASE status WHEN 'Active' THEN count ELSE 0 END) AS active, --here you pivot each status value as a separate column explicitly
SUM(CASE status WHEN 'Inactive' THEN count ELSE 0 END) AS inactive --here you pivot each status value as a separate column explicitly
FROM t
GROUP BY section
답변
JSON 집계 솔루션 :
CREATE TEMP TABLE t (
section text
, status text
, ct integer -- don't use "count" as column name.
);
INSERT INTO t VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7);
SELECT section,
(obj ->> 'Active')::int AS active,
(obj ->> 'Inactive')::int AS inactive
FROM (SELECT section, json_object_agg(status,ct) AS obj
FROM t
GROUP BY section
)X
답변
여기에서 테스트 할 수 없기 때문에 완료되지 않았지만 올바른 방향으로 벗어날 수 있습니다. 비슷한 쿼리를 만드는 내가 사용하는 것을 번역하고 있습니다.
select mt.section, mt1.count as Active, mt2.count as Inactive
from mytable mt
left join (select section, count from mytable where status='Active')mt1
on mt.section = mt1.section
left join (select section, count from mytable where status='Inactive')mt2
on mt.section = mt2.section
group by mt.section,
mt1.count,
mt2.count
order by mt.section asc;
내가 일하고있는 코드는 다음과 같습니다.
select m.typeID, m1.highBid, m2.lowAsk, m1.highBid - m2.lowAsk as diff, 100*(m1.highBid - m2.lowAsk)/m2.lowAsk as diffPercent
from mktTrades m
left join (select typeID,MAX(price) as highBid from mktTrades where bid=1 group by typeID)m1
on m.typeID = m1.typeID
left join (select typeID,MIN(price) as lowAsk from mktTrades where bid=0 group by typeID)m2
on m1.typeID = m2.typeID
group by m.typeID,
m1.highBid,
m2.lowAsk
order by diffPercent desc;
이는 typeID, 최고 가격 입찰 및 요청 된 최저 가격 및이 둘의 차이를 반환합니다.
답변
Crosstab
기능은 tablefunc
확장명에서 사용할 수 있습니다 . 데이터베이스에 대해이 확장을 한 번 작성해야합니다.
확장 만들기 tablefunc
;
크로스 탭을 사용하여 아래 코드를 사용하여 피벗 테이블을 만들 수 있습니다.
create table test_Crosstab( section text,
<br/>status text,
<br/>count numeric)
<br/>insert into test_Crosstab values ( 'A','Active',1)
<br/>,( 'A','Inactive',2)
<br/>,( 'B','Active',4)
<br/>,( 'B','Inactive',5)
select * from crosstab(
<br/>'select section
<br/>,status
<br/>,count
<br/>from test_crosstab'
<br/>)as ctab ("Section" text,"Active" numeric,"Inactive" numeric)
답변
