根据同一 table 中的两个键获取记录数组

Get array of records based on two keys in same table

我已经在以下 table,

上试过了
SELECT DISTINCT
  a.main_id,
 array_agg(distinct a.secondary_id )  AS arr                    
FROM table1 a JOIN table1 b ON a.secondary_id = b.secondary_id or a.tertiary_id = b.tertiary_id
group by a.main_id, a.secondary_id , b.tertiary_id

我添加了 distinct 以省略重复项但是我无法将整行作为数组中的一个元素,根据下面提到的要求甚至没有将行放在一起到数组中。我正在关注 this

Table 脚本:

 Create table table1 
(  
   id bigserial NOT NULL,
   main_id integer NOT NULL,
   secondary_id integer,
   tertiary_id integer,
   data1 text,
   data2 text,
   CONSTRAINT table1_pk PRIMARY KEY (main_id)

)

数据:

INSERT INTO table1(
             main_id, secondary_id, tertiary_id, data1, data2)
    VALUES (1,2,NULL,'data1_1_2_N','data2_1_2_N'),
       (2,2,NULL,'data1_2_2_N','data2_2_2_N'),
       (3,3,5,'data1_3_3_5','data2_3_3_5'),
       (4,3,5,'data1_4_3_5','data2_4_3_5'),
       (5,NULL,1,'data1_5_N_1','data2_5_N_1'),
       (6,NULL,1,'data1_6_N_1','data2_6_N_1'),
       (7,NULL,1,'data1_7_N_1','data2_7_N_1'),
       (8,NULL,2,'data1_8_N_2','data2_8_N_2'),
       (9,NULL,2,'data1_9_N_2','data2_9_N_2'),
       (10,NULL,3,'data1_10_N_3','data2_10_N_3'),
       (11,12,12,'data1_11_12_12','data2_11_12_12'),
       (12,12,11,'data1_12_12_11','data2_12_12_11') 

要求:

如果 secondary_id 在两行或更多行中相等,则应将它们视为一组, 否则如果 tertiary_id 相等,则可以将它们视为一组。

预期结果:

   1 | {(1,2,NULL,'data1_1_2_N','data2_1_2_N'),(2,2,NULL,'data1_2_2_N','data2_2_2_N')}
   2 | {(3,3,NULL,'data1_3_3_N','data2_3_3_N'),(4,3,NULL,'data1_4_3_N','data2_4_3_N')}
   3 | {(5,NULL,1,'data1_5_N_1','data2_5_N_1'),(6,NULL,1,'data1_6_N_1','data2_6_N_1'),(7,NULL,1,'data1_7_N_1','data2_7_N_1')}
   4 | {(8,NULL,2,'data1_8_N_2','data2_8_N_2'),(9,NULL,2,'data1_9_N_2','data2_9_N_2')}
   5 | {(10,NULL,3,'data1_10_N_3','data2_10_N_3')}
   6 | {(11,12,12,'data1_11_12_12','data2_11_12_12'),(12,12,11,'data1_12_12_11','data2_12_12_11') }

版本"PostgreSQL 9.3.11"

这应该可以实现您的输出。该技巧坚持在条件分组中处理 secondary_idtertiary_id 对于在这两个字段上都有匹配记录的记录相同的情况。

select array_agg(distinct t1) 
from table1 t1 
join table1 t2 on 
  t1.secondary_id = t2.secondary_id 
  or t1.tertiary_id = t2.tertiary_id 
group by
  case 
    when t1.secondary_id is null or t1.secondary_id is null 
      then concat(t1.secondary_id,'#',t1.tertiary_id) -- #1
    when t1.secondary_id is not null and t1.tertiary_id is not null and t1.secondary_id = t2.secondary_id 
      then t1.secondary_id::TEXT -- #2
    when t1.secondary_id is not null and t1.tertiary_id is not null and t1.tertiary_id = t2.tertiary_id 
      then t1.tertiary_id::TEXT -- #3
    end 
order by 1

标准情况是任何字段为空,代表#1。我们需要按两列进行分组,我们通过将列中的两个值与 # 标记连接起来并按此连接的列进行分组来欺骗它。

对于 #2 和 #3,我们需要将分组值转换为类型 text 以使其通过(CASE 语句返回的类型需要相同)。

选项 #2 适用于两个值都不为 null 且 secondary_id 与来自自连接的 "chosen" 行匹配的情况。选项 #3 是类比的,但对于 tertiary_id 匹配。

输出:

                                                 array_agg
------------------------------------------------------------------------------------------------------------
 {"(1,1,2,,data1_1_2_N,data2_1_2_N)","(2,2,2,,data1_2_2_N,data2_2_2_N)"}
 {"(3,3,3,5,data1_3_3_5,data2_3_3_5)","(4,4,3,5,data1_4_3_5,data2_4_3_5)"}
 {"(5,5,,1,data1_5_N_1,data2_5_N_1)","(6,6,,1,data1_6_N_1,data2_6_N_1)","(7,7,,1,data1_7_N_1,data2_7_N_1)"}
 {"(8,8,,2,data1_8_N_2,data2_8_N_2)","(9,9,,2,data1_9_N_2,data2_9_N_2)"}
 {"(10,10,,3,data1_10_N_3,data2_10_N_3)"}
 {"(11,11,4,4,data1_11_4_4,data2_11_4_4)","(12,12,4,11,data1_12_4_11,data2_12_4_11)"}

如果您想从记录中删除列 id,您可以使用 CTE 和 select 除 id 之外的所有列,然后在 from 子句中引用该 CTE。