[英]JOIN with multiple columns in postgresql
我在PostgreSQL中有以下兩個表:
TABLE: act_codes
===================
activity act_desc
____________________
1 sleeping
2 commuting
3 eating
4 working
TABLE: data
===================
act1_1 act_1_2 act1_3 act1_4
---------------------------------------------
1 1 3 4
1 2 2 3
1 1 2 2
1 2 2 3
1 1 1 2
1 1 3 4
1 2 2 4
1 1 1 3
1 3 3 4
1 1 4 4
act_codes表基本上是一個活動表(帶有代碼和描述),而數據表包含(在這種情況下)4個不同時間(act1_1,act1_2,act1_3和act1_4)的活動代碼。
我試圖對此進行查詢以獲取每個活動的計數表。 我已經設法對每個單獨的列(在本例中為act1_4)執行以下操作:
SELECT A.act_code, A.act_desc, COUNT (act1_4)
FROM act_codes AS A
LEFT JOIN data AS D
ON D.act1_4 = A.act_code
GROUP BY A.act_code, A.act_desc;
對於該列,該方法很好用,但我要處理的列非常多,因此,如果在SQL查詢中可以做到這一點,則最好使用它。
我現在有以下查詢(非常感謝banazs):
SELECT
ac.act_code,
ac.act_desc,
act_time,
COUNT(activity) AS act_count
FROM
(SELECT
UNNEST(array['act1_1','act1_2','act1_3','act1_4']) AS act_time,
UNNEST(array[d.act1_1, d.act1_2, d.act1_3, d.act1_4]) AS activity
FROM
data d) t
RIGHT JOIN
act_codes ac ON t.activity = ac.act_code
GROUP BY
ac.act_code,
ac.act_desc,
act_time, activity
ORDER BY
activity,
act_time
;
哪個輸出:
act_code act_desc act_time act_count
---------------------------------------------------------
1 sleeping act1_1 10
1 sleeping act1_2 6
1 sleeping act1_3 2
2 commuting act1_2 3
2 commuting act1_3 4
2 commuting act1_4 2
3 eating act1_2 1
3 eating act1_3 3
3 eating act1_4 3
4 working act1_3 1
4 working act1_4 5
基本上這就是我想要的。 理想情況下,可以以某種方式添加計數為零的行,但是我想這也許最好作為單獨的過程來完成(例如,在R中構建交叉表或其他方法)。
您可以使用UNNEST
“ UNNEST
”數據:
SELECT
UNNEST(array['act1_1','act1_2','act1_3','act1_4']) AS column_name,
UNNEST(array[d.act1_1, d.act1_2, d.act1_3, d.act1_4]) AS value
FROM
data d
;
計算活動:
SELECT
ac.act_code,
ac.act_desc,
COUNT(*)
FROM
(SELECT
UNNEST(array['act1_1','act1_2','act1_3','act1_4']) AS column_name,
UNNEST(array[d.act1_1, d.act1_2, d.act1_3, d.act1_4]) AS val
FROM
data d) t
INNER JOIN
act_codes ac ON t.val = ac.act_code
GROUP BY
ac.act_code,
ac.act_desc
;
感謝@banazs-這對於幫助我理解如何構建這樣的查詢非常有用。
但是,我仍然很難安排查詢來拆分輸出,以便每次都有一列計數。 抱歉-我認為這里的標簽有點混亂(act1_1指的是在time_1完成的活動,而“ act1_2”指的是time_2等)。 我試圖得到的結果看起來像這樣:
act_code act_desc count_act1_1 count_act1_2 count_act1_3 count_act1_4
----------------------------------------------------------------------------------------
1 sleeping 10 6 2 0
2 commuting 0 3 4 2
3 eating 0 1 3 3
4 working 0 0 1 5
我不關心列中的輸出-我可以很容易地調整它的形狀,但是在表中存在零是很重要的。 這可能嗎?
為了獲得上述表格,需要對查詢進行一些重新設計。
首先,您必須創建一個輔助表,其中包含列名稱和活動的笛卡爾乘積 :
SELECT
*
FROM
act_codes ac
-- if you have lots of columns you can query their
-- names from the information_schema.columns system
-- table
CROSS JOIN -- the CROSS JOIN combine each rows from both tables
(SELECT
column_name
FROM
information_schema.columns
WHERE
table_schema = 'stackoverflow'
AND table_name = 'data'
AND column_name LIKE 'act%') cn
;
將活動數添加到此:
SELECT
ac.act_code,
ac.act_desc,
cn.column_name,
-- the COALESCE add zero values where the original is NULL
COALESCE(ad.act_no ,0) AS act_no
FROM
act_codes ac
CROSS JOIN
(SELECT
column_name
FROM
information_schema.columns
WHERE
table_schema = 'stackoverflow'
AND table_name = 'data'
AND column_name LIKE 'act%') cn
-- you need to use LEFT JOIN to preserve all rows
-- from the cartesian product
LEFT JOIN
(SELECT
t.column_name,
t.act_code,
COUNT(*) AS act_no
FROM
(SELECT
UNNEST(array['act1_1','act1_2','act1_3','act1_4']) AS column_name,
UNNEST(array[d.act1_1, d.act1_2, d.act1_3, d.act1_4]) AS act_code
FROM
data d) t
GROUP BY
t.column_name,
t.act_code) ad ON ad.act_code = ac.act_code AND ad.column_name = cn.column_name
;
可以將結果格式化為看起來像您的結果,但是有點混亂。 您需要創建兩個表,第一個必須包含上一個查詢的結果集,第二個必須包含列名。
CREATE TABLE acts AS
SELECT
ac.act_code,
ac.act_desc,
cn.column_name,
COALESCE(ad.act_no ,0) AS act_no
FROM
act_codes ac
CROSS JOIN
(SELECT
column_name
FROM
information_schema.columns
WHERE
table_schema = 'stackoverflow'
AND table_name = 'data'
AND column_name LIKE 'act%') cn
LEFT JOIN
(SELECT
t.column_name,
t.act_code,
COUNT(*) AS act_no
FROM
(SELECT
UNNEST(array['act1_1','act1_2','act1_3','act1_4']) AS column_name,
UNNEST(array[d.act1_1, d.act1_2, d.act1_3, d.act1_4]) AS act_code
FROM
data d) t
GROUP BY
t.column_name,
t.act_code) ad ON ad.act_code = ac.act_code AND ad.column_name = cn.column_name
;
CREATE TABLE column_names AS
SELECT
column_name
FROM
information_schema.columns
WHERE
table_schema = 'stackoverflow'
AND table_name = 'data'
AND column_name LIKE 'act%'
;
安裝tablefunc擴展名 。
CREATE EXTENSION tablefunc;
它提供了crosstab()函數,並使用它可以獲取描述的輸出。
SELECT
*
FROM
crosstab(
'SELECT act_desc, column_name, act_no FROM acts ORDER BY 1',
'SELECT * FROM column_names'
)
AS
ct (
"act_desc" text,
"act1_1" int,
"act1_2" int,
"act1_3" int,
"act1_4" int
);
;
+-----------+--------+--------+--------+--------+
| act_desc | act1_1 | act1_2 | act1_3 | act1_4 |
+-----------+--------+--------+--------+--------+
| commuting | 0 | 3 | 4 | 2 |
| eating | 0 | 1 | 3 | 3 |
| sleeping | 10 | 6 | 2 | 0 |
| working | 0 | 0 | 1 | 5 |
+-----------+--------+--------+--------+--------+
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.