将子查询的结果聚合为逗号分隔值

Posted

技术标签:

【中文标题】将子查询的结果聚合为逗号分隔值【英文标题】:Aggregate result of sub query to comma separated values 【发布时间】:2021-07-02 23:09:10 【问题描述】:

如何以逗号分隔值的形式获取子查询的结果。

我有三个表,locationstock_location_typelocation_label

我正在加入 location 和 stock_location_type 并且基于 SLT.inventory_location_cd 的结果,我正在查询另一个表 location_label

为此,我正在编写以下查询。

select L.stock_catalogue_id, SLT.inventory_location_cd,
       case
           when nventory_location_cd = 'base location' then  (select related_location_id from location_label where base_location_id = location_id)
           when nventory_location_cd != 'base location' then (select base_location_id from location_label where related_location_id = location_id)
           end as "Current Location",
       * from location L
join stock_location_type SLT on L.stock_location_type_id = SLT.stock_location_type_id;

这些子查询返回多行。

我尝试使用 string_agg 并转换 related_location_id 和 base_location_id(因为它们是 UUID)。但随后它抱怨 group by。

如果我使用 group by 那么它会出错,'multiple rows returned by subquery'

我错过了什么?

【问题讨论】:

【参考方案1】:

您可以使用string_agg 函数来聚合逗号分隔字符串中的值。所以你的子查询需要重写为

select string_agg(related_location_id, ', ') from location_label where base_location_id = location_id 

select string_agg(base_location_id, ', ') from location_label where related_location_id = location_id 

【讨论】:

【参考方案2】:

我用

重新创建了你的表集

location_label

create table location_label(location_id int, location_label varchar);
insert into location_label values(1, 'Home');
insert into location_label values(2, 'Office');
insert into location_label values(3, 'Garage');
insert into location_label values(4, 'Bar');

stock_location_type

create table stock_location_type (stock_location_type_id int, inventory_location_cd varchar);
insert into stock_location_type values(1, 'base location');
insert into stock_location_type values(2, 'Not base location');

location

create table location (stock_catalogue_id int, base_location_id int, related_location_id int, stock_location_type_id int);

insert into location values(1,1,2,1);
insert into location values(1,2,1,2);
insert into location values(1,3,3,1);

insert into location values(2,4,3,1);
insert into location values(2,3,1,1);
insert into location values(2,2,4,2);

如果我正确理解您的陈述,您将尝试使用base_location_idlocation_id 基于inventory_location_cd 列加入locationlocation_label 表。

如果这是您想要实现的目标,那么下面的查询应该可以做到。通过将连接条件移动到适当的位置

select L.stock_catalogue_id, 
 SLT.inventory_location_cd, 
 location_id "Current Location Id",
 location_label "Current Location Name"
from location L join stock_location_type SLT 
on L.stock_location_type_id = SLT.stock_location_type_id
left outer join location_label 
on (
  case when 
    inventory_location_cd = 'base location' 
  then base_location_id 
  else related_location_id 
  end) = location_id
;

结果是

 stock_catalogue_id | inventory_location_cd | Current Location Id | Current Location Name 
--------------------+-----------------------+---------------------+-----------------------
                  1 | base location         |                   1 | Home
                  1 | Not base location     |                   1 | Home
                  1 | base location         |                   3 | Garage
                  2 | base location         |                   3 | Garage
                  2 | base location         |                   4 | Bar
                  2 | Not base location     |                   4 | Bar
(6 rows)

如果您需要通过stock_catalogue_idinventory_location_cd 将其聚合起来,可以使用

select L.stock_catalogue_id, 
 SLT.inventory_location_cd,
 string_agg(location_id::text, ',') "Current Location Id",
 string_agg(location_label::text, ',') "Current Location Name"
from location L join stock_location_type SLT 
 on L.stock_location_type_id = SLT.stock_location_type_id
 left outer join location_label 
 on (case when inventory_location_cd = 'base location' then base_location_id else related_location_id end) = location_id
group by L.stock_catalogue_id, 
 SLT.inventory_location_cd;

结果是

 stock_catalogue_id | inventory_location_cd | Current Location Id | Current Location Name 
--------------------+-----------------------+---------------------+-----------------------
                  1 | base location         | 1,3                 | Home,Garage
                  1 | Not base location     | 1                   | Home
                  2 | base location         | 3,4                 | Garage,Bar
                  2 | Not base location     | 4                   | Bar
(4 rows)

【讨论】:

以上是关于将子查询的结果聚合为逗号分隔值的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法将列的值聚合和/或连接为 Group By 查询中的逗号分隔项?

将查询结果显示为以逗号分隔的文字

SQL中逗号分隔的查询结果转换成单个字符串放到in语句里

查询字段值为逗号分隔的值

从逗号分隔的值中查询结果并查询要显示的每个值

如何根据oracle plsql中列中的逗号分隔值拆分选择查询行