arrays - 根据同一表中的两个键获取记录数组

标签 arrays postgresql postgresql-9.3

我已经在下表中尝试过了,

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 .

表格脚本:

 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”

最佳答案

这应该可以实现您的输出。该技巧适用于条件 group by 子句,以处理 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 与自连接中“选择的”行匹配的情况。选项 #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 并选择除 id 之外的所有列,然后在 from 子句中引用该 CTE。

关于arrays - 根据同一表中的两个键获取记录数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39173041/

相关文章:

javascript - 如何在javascript中基于相同的键和值合并两个对象数组?

android - 如果使用 postgresql 在 android 中某些字符不正确,则获取搜索结果

sql - 将总和转换为 float 的 Cast 语法

php阻止来自mysql数据库的单词

javascript - Array.prototype.includes 函数如何比较对象

sql - 在 JOOQ DSL 中使用带有连接别名的 PosgreSQL array_agg

sql - 从函数返回时复合数据类型缺少值

用于检查非 ascii 字符的 Postgresql 约束

django - PostgreSQL 9.3 的 REFRESH MATERIALIZED VIEW 命令仅持续 Django 连接的长度

arrays - 数组 SDE 面试问题的恒定空间限制。 AND 对经典面试问题的疑惑