PostgreSQL查询包含来自单独表的ID的数组

时间:2018-01-24 00:00:07

标签: postgresql

我有一个users表,其结构如下:

CREATE TABLE users (
  id integer NOT NULL,
  email text,
  account_id integer,
  segment_ids integer[]
);

具有此结构的segments表:

CREATE TABLE segments (
  id integer NOT NULL,
  name text
);

我已经构建了一个这样的查询来查找属于段的所有用户:

SELECT * FROM users 
  WHERE segment_ids @> (
    SELECT ARRAY(
      SELECT id from segments 
        WHERE name IN ('Melbourne', 'Male', 'Team #1')
    )
  )

但是,我不满意使用子查询是实现此目的的最佳方法。是否有更简洁的方式来编写此查询,即使用连接,或者是子查询的方式?

2 个答案:

答案 0 :(得分:1)

您可以使用unnest功能执行此操作:

例如,使用上面的表和这些数据:

insert into segments values (1, 'one');
insert into segments values (2, 'two');
insert into segments values (3, 'three');

insert into users values (1, 'email@example.com', 1, array[1,2]);
insert into users values (2, 'email2@example.com', 2, array[2,3]);

运行以下查询:

select u.id, u.email, u.account_id, u.segment_id, s.name from 
(select u.id, u.email, u.account_id, unnest(u.segment_ids) segment_id from users u) as u 
right join segments s on s.id = u.segment_id

的产率:

1   "email@example.com"     1   1   "one"
1   "email@example.com"     1   2   "two"
2   "email2@example.com"    2   2   "two"
2   "email2@example.com"    2   3   "three" 

答案 1 :(得分:1)

如果你真的想要,你可以进行加入。

Fiddle

SELECT DISTINCT users.* 
FROM users 
JOIN segments 
  ON ( segments.id = ANY( users.segment_ids ) )
ORDER BY 1;

如果你真的需要查看它匹配的segment_id:

SELECT DISTINCT users.*, array_agg(segments.id) "matched segment id"
FROM users 
JOIN segments 
  ON ( segments.id = ANY( users.segment_ids ) )
GROUP BY users.id, email, account_id, segment_ids
ORDER BY 1;

在您认为合适的地方插入WHERE segments.name IN(...)

信用:@JamesFry用于小提琴中的DDL语句