如何通过查询从组中的多个表中进行选择?

时间:2018-05-23 17:59:36

标签: sql postgresql

我有一些数据库表,其中包含人们需要签名的一些文档。表格定义(略微简化)如下。

create table agreement (
    id integer NOT NULL,
    name character varying(50) NOT NULL,
    org_id integer NOT NULL,
    CONSTRAINT agreement_pkey PRIMARY KEY (id)
    CONSTRAINT org FOREIGN KEY (org_id) REFERENCES org (id) MATCH SIMPLE
)

create table version (
    id integer NOT NULL,
    content text NOT NULL,
    publish_date timestamp NOT NULL,
    agreement_id integer NOT NULL,
    CONSTRAINT version_pkey PRIMARY KEY (id)
    CONSTRAINT agr FOREIGN KEY (agreement_id) REFERENCES agreement (id) MATCH SIMPLE
)

我跳过了组织表,以减少混乱。我一直在尝试编写一个查询,它可以为给定的组织提供所有正确的协议信息。到目前为止,我可以做到

SELECT a.id, a.name FROM agreement AS a
JOIN version as v ON (a.id = v.agreement_id)
JOIN org as o ON (o.id = a.org_id)
WHERE o.name = $1
GROUP BY a.id

这似乎为我提供了属于我想要的组织的每个协议的单个记录,并且至少有一个版本。但我还需要提供最新版本的内容和发布日期。我该怎么做?

另外,我有一个名为签名的单独表,它链接到用户和版本。如果可能,我想将此查询扩展为仅包含给定用户尚未签署最新版本的协议。

编辑:反映了对组织联接的需要,因为我按名称选择orgs而不是id

3 个答案:

答案 0 :(得分:2)

您可以使用相关子查询:

SELECT a.id, a.name, v.*
FROM agreement a JOIN
     version v
     ON a.id = v.agreement_id
WHERE a.org_id = $1 AND
      v.publish_date = (SELECT MAX(v2.publish_date) FROM version v2 WHERE v2.agreement_id = v.agreement_id);

注意:

  • org表格不需要,因为agreementorg_id
  • 此查询不需要聚合。您正在过滤最近的记录。
  • 相关子查询是一种检索最新版本的方法。

答案 1 :(得分:1)

SELECT a.id, a.name, max(v.publish_date) publish_date FROM agreement AS a
JOIN version as v ON (a.id = v.agreement_id)
JOIN org as o ON (o.id = a.org_id)
WHERE o.id = $1
GROUP BY a.id, a.name

答案 2 :(得分:1)

Postgresql有Window Functions。 窗口函数允许您对特定列或列集进行排序。 rank函数返回行在排序结果中的位置。如果您过滤到排名为1的位置,那么您将始终只获得一行,它将是分区的最高排序。

select u.id, u.name, u.content, u.publish_date from (
SELECT a.id, a.name, v.content, v.publish_date, rank() over (partition by a.id order by v.id desc) as pos
FROM agreement AS a
JOIN version as v ON (a.id = v.agreement_id)
JOIN org as o ON (o.id = a.org_id)
WHERE o.id = $1
) as u
where pos = 1