【问题标题】:How to filter results of left join based on third table如何根据第三张表过滤左连接的结果
【发布时间】:2016-01-13 23:09:46
【问题描述】:

在这里扩展这个问题:Efficient way to select records missing in another table,假设我有以下 3 个表(原始示例,请参见下面更好的示例):

request: (id, name)
response: (id, request_id, provider_id, resource)
provider: (id, name)

首先,我想检索所有不存在结果的请求。这很容易,使用LEFT JOIN。我想要任何尚未针对给定provider 执行的requests简单的英语:我想要所有没有结果的请求或只有其他提供商的结果。

这是一个更好的例子:

customer: (id, email)
vehicle: (id, modelname)
testdrive: (id, vehicle_id REFERENCES vehicle(id), customer_id REFERENCES customer(id)

假设 Bob、Alice、Mary、Fred 和 Joe 拜访一家汽车经销商。鲍勃和爱丽丝试驾凯美瑞,鲍勃和玛丽试驾雅阁,弗雷德和乔不试驾任何东西。经销商想列出两个清单:

  1. 谁没有试驾凯美瑞?玛丽、弗雷德、乔
  2. 谁没有试驾雅阁?爱丽丝、弗雷德、乔

这是一个 SQL Fiddle 演示:http://sqlfiddle.com/#!15/80d6a

以下是建议的,但它并不完全正确(参见上面的 SQL Fiddle 链接),因为它也给了我试驾其他车型的人:

SELECT c.email
FROM customer AS c
    LEFT JOIN testdrive AS t ON c.id=t.customer_id
    LEFT JOIN vehicle AS v ON t.vehicle_id=v.id AND v.modelname='Camry'
WHERE v.id IS NULL;

【问题讨论】:

    标签: sql database join


    【解决方案1】:

    试试这个:

    SQL Fiddle

    PostgreSQL 9.3 架构设置

    BEGIN;
    
    -- DROP TABLE IF EXISTS customer;
    -- DROP TABLE IF EXISTS vehicle;
    -- DROP TABLE IF EXISTS testdrive;
    
    CREATE TABLE customer (
        id SERIAL PRIMARY KEY,
        email TEXT
    );
    
    CREATE TABLE vehicle (
        id SERIAL PRIMARY KEY,
        modelname TEXT
    );
    
    CREATE TABLE testdrive (
        id SERIAL PRIMARY KEY,
        vehicle_id INTEGER REFERENCES vehicle(id),
        customer_id INTEGER REFERENCES customer(id)
    );
    
    INSERT INTO customer (email) VALUES
        ('Bob@foo.org'), ('Alice@bar.net'), ('Mary@baz.com'),
        ('Fred@int.edu'), ('Joe@mut.var');
    
    INSERT INTO vehicle (modelname) VALUES ('Camry'), ('Accord');
    
    INSERT INTO testdrive (vehicle_id, customer_id)
    VALUES
        (1, 1), -- Camry, Bob
        (1, 2), -- Camry, Alice
        (2, 1), -- Accord, Bob
        (2, 3); -- Accord, Mary
    
    -- Fred and Joe never test drove anything.
    -- Mary didn't test drive the Camry.
    -- Alice didn't test drive the Accord.
    
    -- How do I query to find the list of customers who didn't test
    -- drive anything, for each vehicle model?
    
    -- Customers who didn't test drive the Camry:
    -- Mary, Fred, Joe
    SELECT c.email
    FROM customer AS c
        LEFT JOIN testdrive AS t ON c.id=t.customer_id
        LEFT JOIN vehicle AS v ON t.vehicle_id=v.id AND v.modelname='Camry'
    WHERE v.id IS NULL;
    
    -- Customers who didn't test drive the Accord:
    -- Alice, Fred, Joe
    
    COMMIT;
    

    查询 1

    SELECT *
    FROM customer c
    WHERE NOT EXISTS 
    ( SELECT * 
      FROM testdrive t 
      INNER JOIN vehicle v 
         on v.id = t.vehicle_id
      WHERE v.modelname = 'Camry' AND t.customer_id = c.id)
    

    Results

    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    

    查询 2

    SELECT *
    FROM customer c
    WHERE NOT EXISTS 
    ( SELECT * 
      FROM testdrive t 
      INNER JOIN vehicle v 
         on v.id = t.vehicle_id
      WHERE v.modelname = 'Accord' AND t.customer_id = c.id)
    

    Results

    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    

    【讨论】:

      【解决方案2】:
      SELECT c.email
      FROM  customer AS c
      WHERE NOT c.customer_ID IN (SELECT customer_id FROM testdrive WHERE vehicle_id=@Camry);
      

      【讨论】:

        猜你喜欢
        • 2014-10-26
        • 1970-01-01
        • 2016-07-02
        • 2022-12-16
        • 2014-09-07
        • 1970-01-01
        • 1970-01-01
        • 2014-04-12
        • 2011-02-01
        相关资源
        最近更新 更多