2016-12-07 123 views
0

下面是一個包含3個表的示例模式。我試圖運行一個查詢,返回所有子班次都是狀態6的所有作業。如果作業有一個狀態爲5的子班次,則不應返回作業。來自下面插入的示例數據的查詢的正確響應是沒有行返回。將PostgreSQL子查詢轉換爲連接

下面有一個工作查詢,註釋「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"; 

我如何重構「作品」查詢,使用聯接,而不是子查詢呢?「不工作」的查詢是我的嘗試。

+1

你的子查詢方法有什麼問題?子查詢似乎沒有關聯,所以從性能角度來看,它們可能不是一個大問題。 –

+0

連接不一定會返回與子查詢解決方案相同的結果。那麼你爲什麼要重寫呢? –

+0

您可能來自mysql後臺,其中子查詢幾乎總是比連接慢。在postgresql中並非如此。 **你不需要這樣做** – e4c5

回答

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 

它不完全沒有子查詢(做所有與連接相關的事情肯定會效率更低),但它會刪除一些不必要的檢查,所以可能會更快一點(我懷疑這是您的目標)。

與您的工作查詢有一個小的差異,因爲它返回所有班次狀態爲6的所有工作(正如您所說的那樣),而您的查詢還可確保工作至少有一次班次(狀態6)。