[英]postgresql unnest and pivot int array column
我有下表
create table test(id serial, key int,type text,words text[],numbers int[] );
insert into test(key,type,words) select 1,'Name',array['Table'];
insert into test(key,type,numbers) select 1,'product_id',array[2];
insert into test(key,type,numbers) select 1,'price',array[40];
insert into test(key,type,numbers) select 1,'Region',array[23,59];
insert into test(key,type,words) select 2,'Name',array['Table1'];
insert into test(key,type,numbers) select 2,'product_id',array[1];
insert into test(key,type,numbers) select 2,'price',array[34];
insert into test(key,type,numbers) select 2,'Region',array[23,59,61];
insert into test(key,type,words) select 3,'Name',array['Chair'];
insert into test(key,type,numbers) select 3,'product_id',array[5];
我正在為用戶使用以下查詢 pivot 表。
select key,
max(array_to_string(words,',')) filter(where type='Name') as "Name",
cast(max(array_to_string(numbers,',')) filter(where type='product_id') as int) as "product_id",
cast(max(array_to_string(numbers,',')) filter(where type='price') as int) as "price" ,
max(array_to_string(numbers,',')) filter(where type='Region') as "Region"
from test group by key
但是我無法在 Pivot 期間取消嵌套 Region 列,以便使用 Region 列與另一個表連接。
我預期的 output 低於
由於我們使用 unnest("Region") 來處理 pivot。 每個產品必須有一行包含區域數據。 或者下面的代碼將通過創建一個 null 數組來解決問題。
unnest(CASE WHEN array_length("Region", 1) >= 1
THEN "Region"
ELSE '{null}'::int[] END)
架構:
create table test(id serial, key int,type text,words text[],numbers int[] ); insert into test(key,type,words) select 1,'Name',array['Table']; insert into test(key,type,numbers) select 1,'product_id',array[2]; insert into test(key,type,numbers) select 1,'price',array[40]; insert into test(key,type,numbers) select 1,'Region',array[23,59]; insert into test(key,type,words) select 2,'Name',array['Table1']; insert into test(key,type,numbers) select 2,'product_id',array[1]; insert into test(key,type,numbers) select 2,'price',array[34]; insert into test(key,type,numbers) select 2,'Region',array[23,59,61]; insert into test(key,type,words) select 3,'Name',array['Chair']; insert into test(key,type,numbers) select 3,'product_id',array[5];
select key,"Name",product_id,price,unnest(CASE WHEN array_length("Region", 1) >= 1 THEN "Region" ELSE '{null}'::int[] END) from ( select key, max(array_to_string(words,',')) filter(where type='Name') as "Name", cast(max(array_to_string(numbers,',')) filter(where type='product_id') as int) as "product_id", cast(max(array_to_string(numbers,',')) filter(where type='price') as int) as "price", max(numbers) filter(where type='Region') as "Region" from test group by key )t order by key
鑰匙 姓名 product_id 價格 不嵌套 1 桌子 2 40 23 1 桌子 2 40 59 2 表格1 1 34 23 2 表格1 1 34 59 2 表格1 1 34 61 3 椅子 5 null null
db<> 在這里擺弄
非常奇怪的數據庫設計......我假設你繼承了它?
如果沒有其他數組值的基數 > 1,那么您可以簡單地unnest
:
select
key,
(max (words) filter (where type = 'Name'))[1] as name,
(max (numbers) filter (where type = 'product_id'))[1] as product_id,
(max (numbers) filter (where type = 'price'))[1] as price,
unnest (max (numbers) filter (where type = 'Region')) as region
from test
group by key
如果它們可以有多個值,那也可以處理。
-- 編輯 2021 年 3 月 15 日 --
簡短版本:針對 null 的unnest
不會產生一行,因此如果將 null 值合並到單個 null 元素的數組中,則應注意以下部分:
select
key,
(max (words) filter (where type = 'Name'))[1] as name,
(max (numbers) filter (where type = 'product_id'))[1] as product_id,
(max (numbers) filter (where type = 'price'))[1] as price,
unnest (coalesce (max (numbers) filter (where type = 'Region'), array[null]::integer[])) as region
from test
group by key
order by key
現在對於你沒有問的部分......我和至少另一個人一直在輕輕地提醒你,你的數據庫設計將在每一個轉折點都會導致多個問題。 它在生產中的事實並不意味着您不應該盡快修復它。
這種設計就是所謂的 EAV - 實體 - 屬性 - 值。 它有它的用例,但像大多數好東西一樣,它也可以在不應該應用的時候應用。 想到的用例是,如果您希望用戶能夠為某些對象動態添加屬性。 即使那樣,也可能有更好/更簡單的方法。
舉個例子,如果你有 100 萬個對象,5 個屬性意味着你必須將其存儲為 500 萬行,並且大部分空間將用於重復鍵和屬性名稱。
只是思考的食物。 我們可以繼續對您發現的每個新場景進行分類,但最好重做設計。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.