将PostgreSQL子查询转换为连接

时间:2016-12-07 04:35:59

标签: sql postgresql

下面是一个包含3个表的示例模式。我正在尝试运行一个查询,返回所有子移位状态为6的所有作业。如果作业有一个状态为5的子Shift,则不应返回作业。从下面插入的示例数据中查询的正确响应是没有返回任何行。

下面有一个工作查询,注释“Works”。我试图重构“工作”查询以使用连接而不是子查询。注释“不工作”的查询是我的尝试。

-- begin setup and table creation: only run this section once.

CREATE EXTENSION "uuid-ossp";

CREATE TABLE jobs
(
  id uuid NOT NULL DEFAULT uuid_generate_v4(),
  CONSTRAINT jobs_pkey PRIMARY KEY (id)
);

CREATE TABLE bookings
(
  id uuid NOT NULL DEFAULT uuid_generate_v4(),
  job_id uuid,
  CONSTRAINT bookings_pkey PRIMARY KEY (id)
);

CREATE TABLE shifts
(
  id uuid NOT NULL DEFAULT uuid_generate_v4(),
  booking_id uuid,
  status integer,
  CONSTRAINT shifts_pkey PRIMARY KEY (id)
);

insert into jobs (id) values ('e857c86c-bc31-11e6-9aae-57793f585d49');

insert into bookings (id, job_id) values ('736da82c-bc32-11e6-b9b8-f36753d321ac', 'e857c86c-bc31-11e6-9aae-57793f585d49');
insert into bookings (id, job_id) values ('7d839e5c-bc32-11e6-8bb3-4fa95be86a74', 'e857c86c-bc31-11e6-9aae-57793f585d49');

insert into shifts (booking_id, status) values ('736da82c-bc32-11e6-b9b8-f36753d321ac', 6);
insert into shifts (booking_id, status) values ('7d839e5c-bc32-11e6-8bb3-4fa95be86a74', 5);

-- end setup and table creation

我们希望所有子女轮班的所有工作都处于状态6.如果某个工作的子班次状态为5,则不应该返回该工作。来自上面插入的样本数据的查询的正确响应是没有返回任何行。

不起作用:(

SELECT "jobs".* 
FROM "jobs" 
   inner join bookings b1 on jobs.id = b1.job_id 
   inner join shifts s1 on b1.id = s1.booking_id 
   left outer join bookings b2 on jobs.id = b2.job_id 
   left outer join shifts s2 on b2.id = s2.booking_id and s2.status IN (2,3,4,5) 
WHERE s1.status = 6 
  AND s2.id IS NULL 
GROUP BY "jobs"."id";

作品

SELECT "jobs".*
FROM "jobs"
WHERE jobs.id IN (
    SELECT job_id
    FROM bookings
    WHERE bookings.id IN (
        SELECT booking_id FROM shifts WHERE status = 6
    )
) AND jobs.id NOT IN (
    SELECT job_id FROM bookings WHERE bookings.id IN (
        SELECT booking_id FROM shifts WHERE status IN (2,3,4,5)
    )
)
GROUP BY "jobs"."id";

如何重构“works”查询以使用连接而不是子查询? “无效”查询是我的尝试。

1 个答案:

答案 0 :(得分:0)

试试这个(没有经过测试,因此可能存在拼写错误):

with prohibited_jobs as (
    select distinct jobs.id
    from jobs
        join bookings on jobs.id == bookings.job_id
        join shifts on shifts.booking_id = booking.job_id
    where shift.status != 6
)
select jobs.*
from jobs
    left outer join prohibited_jobs p on p.id = jobs.id
where
    p.id IS NULL

它没有完全摆脱子查询(使用连接做任何事情肯定会效率低下),但它会删除一些不必要的检查,因此可能会更快一点(我怀疑这是你的目标)。 / p>

您的工作查询存在细微差别,因为它返回所有班次都具有状态6的所有作业(如您所说),而您的查询还确保作业至少有一个班次(状态为6) )。