将列值映射到表名并加入

时间:2017-06-07 17:17:35

标签: postgresql postgresql-9.4

我的复合类型看起来像

CREATE TYPE member AS (
    id BIGINT,
    type CHAR(1)
);

我有一个表依赖于带有数组的member类型。

CREATE TABLE relation (
    id BIGINT PRIMARY KEY,
    members member[]
);

我有三个其他表,每个表都有不同的架构(但有共同的id字段)

CREATE TABLE table_x (
    id BIGINT PRIMARY KEY,
    some_text TEXT
);

CREATE TABLE table_y (
    id BIGINT PRIMARY KEY,
    some_int INT
);

CREATE TABLE table_z (
    id BIGINT PRIMARY KEY,
    some_date TIMESTAMP
);
type类型中的

member字段只是一个字符,用于查找特定成员所属的表。 relation表格中的一行可以混合使用不同的type

我有一个场景需要返回relation个ID,其中至少有一个member根据其类型满足某个条件(让我们说x => some_text不为空或y => some_int大于10或z => some_date是从现在开始的一周)

我可以通过向数据库发出多个请求来在应用程序端实现此方案:

  • 不需要relation
  • member
  • 收集relation个数据
  • 发出新请求以查找relation s

我想知道是否有办法将列值映射到表名并加入它们。

2 个答案:

答案 0 :(得分:0)

假设

  • 我假设relation.members数组没有多个相同类型的成员元素。正确的吗?

查询尝试

with unnested_members as (
-- Unnest members array
select id, unnest(members) members
from relation
)
, members_joined as (
-- left join on a per type basis with table_x, table_y and table_z.
select r.id, (r.members).id idext, (r.members).type,
       x.some_text, y.some_int, z.some_date -- more types, more columns here
from unnested_members r
  left join table_x x on (x.id = (r.members).id and (r.members).type = 'x')
  left join table_y y on (y.id = (r.members).id and (r.members).type = 'y')
  left join table_z z on (z.id = (r.members).id and (r.members).type = 'z')
  -- More types, more tables to left join
)
select id,
  max(some_text) some_text, -- use max() to get not null value for this id
  max(some_int) some_int, -- use max() to get not null value for this id
  max(some_date) some_date -- use max() to get not null value for this id
  -- more types, more max() columns here
from members_joined
group by id -- get one row per relation.id with data from joined table_* columns

如果您需要包含更多表格,则必须在left join部分中包含这些表格,同时在select列表和max()部分中添加该列。

答案 1 :(得分:0)

@JNevill对这个数据库设计有一个很好的观点。尽管这种方法似乎不是最佳的,但它使表格定义明确分开,而它们之间没有任何关系。与其他三个表相比,relation表的大小也相当小。

我通过简单地获取每种类型的行并合并它们来解决问题:

SELECT relation.* FROM relation, UNNEST(relation.members) member INNER JOIN table_x ON member.id = table_x.id WHERE member.type = 'x' AND table_x.some_text = 'some text value' 
UNION 
SELECT relation.* FROM relation, UNNEST(relation.members) member INNER JOIN table_y ON member.id = table_y.id WHERE member.type = 'y' AND table_y.some_int = 123 
UNION 
SELECT relation.* FROM relation, UNNEST(relation.members) member INNER JOIN table_z ON member.id = table_z.id WHERE member.type = 'z' AND table_z.some_date > '2017-01-11 00:00:00';