postgresql查找唯一元组

postgresql查找唯一元组,postgresql,Postgresql,我有两张桌子 create table JobStaff ( Job integer references Job(id), staff integer references Staff(id), role integer references JobRole(id), primary key (course,staff,role) ); create table Job ( cid integer,

我有两张桌子

create table JobStaff (
    Job      integer references Job(id),
    staff       integer references Staff(id),
    role        integer references JobRole(id),
    primary key (course,staff,role)
);

create table Job (
    cid         integer, 
    branch     integer not null references Branches(id),
    term        integer not null references Terms(id),
    primary key (id)
);
我正在努力找到所有没有员工的工作。我该怎么做呢?

一种可能的方法:

SELECT *
FROM   job j
LEFT   JOIN jobstaff js ON js.job = j.id
WHERE  js.job IS NULL;
就在昨天,我在dba.SE上为这类问题写了一个更全面的答案: 一种可能的方法:

SELECT *
FROM   job j
LEFT   JOIN jobstaff js ON js.job = j.id
WHERE  js.job IS NULL;
就在昨天,我在dba.SE上为这类问题写了一个更全面的答案:

首先,修复create table查询,如下所示:

create table JobStaff (
    jobid         integer references Job(id),
    staffid       integer references Staff(id),
    roleid        integer references JobRole(id),
    primary key (jobid,staffid,roleid)
);

create table Job (
    id          integer, 
    branch      integer not null references Branches(id),
    term        integer not null references Terms(id),
    primary key (id)
);
  • JobStaff
    的主键应该使用
    jobid
    而不是
    courseid
  • Job
    的第一列应该是
    id
    ,而不是
    cid
  • 我建议在引用id列时使用有意义的列名,如
    jobid
然后,对于您的查询,您将需要以下内容:

SELECT * FROM Job
WHERE id NOT IN (SELECT DISTINCT jobid FROM JobStaff);

首先,修复create table查询,如下所示:

create table JobStaff (
    jobid         integer references Job(id),
    staffid       integer references Staff(id),
    roleid        integer references JobRole(id),
    primary key (jobid,staffid,roleid)
);

create table Job (
    id          integer, 
    branch      integer not null references Branches(id),
    term        integer not null references Terms(id),
    primary key (id)
);
  • JobStaff
    的主键应该使用
    jobid
    而不是
    courseid
  • Job
    的第一列应该是
    id
    ,而不是
    cid
  • 我建议在引用id列时使用有意义的列名,如
    jobid
然后,对于您的查询,您将需要以下内容:

SELECT * FROM Job
WHERE id NOT IN (SELECT DISTINCT jobid FROM JobStaff);

使用Francis p答案中的定义,但由于未定义的表中省略了
参考
,我建议PostgreSQL 8.4版或更高版本使用此选项(他在答案中链接的Erwin Brandstetter综合答案中的一个选项的变体):

SELECT *
  FROM Job j
  WHERE NOT EXISTS (SELECT * FROM jobstaff js WHERE js.jobid = j.id);
在PostgreSQL的最新版本中,这将与Erwin answer的优化相同,只是它将只显示来自Job的列,这似乎是您想要的。较窄的行(省略不需要的列)可能在缩放时表现稍好。在较旧版本的PostgreSQL(8.4版之前)中,使用Erwin的答案中显示的选项,您可能会获得更好的性能;8.4中增加了半连接和反连接优化,而
左连接
技巧是模拟它的最佳方法

请注意,在这种情况下不需要
DISTINCT


对于PostgreSQL中的这种情况,我建议不要使用
而不是
。虽然这在逻辑上并不重要,因为
主键
约束会隐式强制所涉及的列为
非NULL
非IN
在涉及支持NULL的列时具有令人惊讶的语义,处理这些语义的逻辑不如
不存在
左连接
那么有效。PostgreSQL不会浪费处理时间来查看参数是否可证明
不为空
,因此不管怎样,您都会得到较差的优化。

使用Francis p的答案中的定义,但由于
引用
忽略了未定义的表,我建议这样做(Erwin Brandstetter在其答案中链接到的综合答案中的一个选项的变体)对于PostgreSQL 8.4或更高版本:

SELECT *
  FROM Job j
  WHERE NOT EXISTS (SELECT * FROM jobstaff js WHERE js.jobid = j.id);
在最新版本的PostgreSQL中,这将与Erwin answer优化相同,只是它将仅显示作业中的列,这似乎是您想要的。较窄的行(忽略不需要的列)可能会在规模上表现稍好。在较旧版本的PostgreSQL中(8.4版之前)使用Erwin的答案中显示的选项,您可能会获得更好的性能;8.4中添加了半连接和反连接优化,而
左连接
技巧是模拟它的最佳方法

请注意,在这种情况下不需要
DISTINCT


对于PostgreSQL中的这种情况,我建议不要使用
不在
中。虽然在逻辑上这并不重要,因为
主键
约束会隐式地强制所涉及的列不为NULL
不在
中有令人惊讶的语义,当涉及到能够为NULL的列时,处理这些列的逻辑会令人惊讶语义的效率不如
not EXISTS
LEFT JOIN
那么高。PostgreSQL不会花费处理时间来查看参数是否可证明
不为NULL
,因此不管怎样,优化效果都很差。

主键中使用的
课程
列在定义中缺失?并且
id
为空表
作业
中缺少。如果代码示例中显示的表实际上可以通过复制/粘贴来创建,则会使那些试图回答您的人的生活更轻松。一点示例数据也不会有任何影响。以后,请在发布前在空测试数据库中尝试。@ErwinBrandstetter是的,这是我的错误,我复制并粘贴了它d从旧表中删除。定义中缺少主键中使用的列
course
,表
job
中缺少
id
。如果代码示例中显示的表实际上可以通过复制/粘贴来创建,则尝试回答您的人会更容易。少量示例数据也不会有任何影响。以后,请在发布之前在一个空的测试数据库中尝试一下。@ErwinBrandstetter是的,那是我的错,我从一个旧表复制并粘贴了它。