【问题标题】:postgresql unnest and pivot int array columnpostgresql unnest 和 pivot int 数组列
【发布时间】:2023-03-10 13:51:01
【问题描述】:

我有下表

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,
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 列与另一个表连接。

我的预期输出低于

【问题讨论】:

    标签: sql postgresql pivot


    【解决方案1】:

    因为我们使用 unnest("Region") 来做枢轴。每个产品必须有一行包含区域数据。 或者下面的代码将通过创建一个空数组来解决问题。

    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
    
    key Name product_id price unnest
    1 Table 2 40 23
    1 Table 2 40 59
    2 Table1 1 34 23
    2 Table1 1 34 59
    2 Table1 1 34 61
    3 Chair 5 null null

    db小提琴here

    【讨论】:

    • 嗨,我在表格中添加了新行(key=3 和 Name='Chair')。但是这个新行并没有导致您建议的查询。你能更新你的查询吗
    • 它不工作@Hari 吗?只是注意到不赞成。这就是为什么要问。
    【解决方案2】:

    非常奇怪的数据库设计......我假设你继承了它?

    如果没有其他数组值的基数 > 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 日--

    短版:unnest 反对 null 不会产生一行,因此如果您将 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 - 实体 - 属性 - 值。它有它的用例,但像大多数好东西一样,它也可以在不应该应用的时候应用。想到的用例是,如果您希望用户能够为某些对象动态添加属性。即使那样,也可能有更好/更简单的方法。

    举个例子,如果您有一百万个对象,五个属性意味着您必须将其存储为 500 万行,并且大部分空间将用于重复键和属性名称。

    只是思考的食物。我们可以继续对您发现的每个新场景进行分类,但最好重做设计。

    【讨论】:

    • 未继承。这可以灵活地引入新功能而无需更改表结构,例如新列 product_category 等。
    • @Hambone,我在表格中添加了新行(key=3 和 Name='Chair')。但是这个新行并没有导致您建议的查询。您能否更新您的查询以产生所有键
    • @Hari:为键/值对使用单个 JSON 列可能会让你的生活更轻松
    • @Hari:你的意思是这样吗? dbfiddle.uk/…
    • @Hari:您应该认真重新考虑该设计。我确实认为从长远来看这会给你带来很多麻烦。从样本来看,我倾向于认为一个适当的归一化模型是一个更好的选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 2015-02-06
    • 1970-01-01
    • 2022-10-04
    • 2023-01-16
    • 2020-08-23
    • 2020-04-28
    相关资源
    最近更新 更多