Sql 如何基于第三个表过滤左连接的结果

Sql 如何基于第三个表过滤左连接的结果,sql,database,join,Sql,Database,Join,在这里扩展这个问题:,假设我有以下3个表(原始示例,请参见下面更好的示例): 首先,我想检索不存在结果的所有请求。使用左联接,这很容易。我还想要任何未对给定提供者执行的请求通俗易懂:我想要所有没有结果或只有其他提供商结果的请求 下面是一个更好的例子: customer: (id, email) vehicle: (id, modelname) testdrive: (id, vehicle_id REFERENCES vehicle(id), customer_id REFERENCES cus

在这里扩展这个问题:,假设我有以下3个表(原始示例,请参见下面更好的示例):

首先,我想检索不存在结果的所有请求。使用
左联接
,这很容易。我想要任何未对给定
提供者执行的
请求
通俗易懂:我想要所有没有结果或只有其他提供商结果的请求

下面是一个更好的例子:

customer: (id, email)
vehicle: (id, modelname)
testdrive: (id, vehicle_id REFERENCES vehicle(id), customer_id REFERENCES customer(id)
比如说鲍勃、爱丽丝、玛丽、弗雷德和乔参观了一家汽车经销商。鲍勃和爱丽丝试驾凯美瑞,鲍勃和玛丽试驾雅阁,弗雷德和乔什么都不试驾。经销商希望列出两个列表:

  • 谁没有试驾凯美瑞?玛丽、弗雷德、乔
  • 谁没有试驾雅阁?爱丽丝,弗雷德,乔
  • 下面是一个SQL Fiddle演示:

    提出了以下建议,但并不完全正确(请参见上面的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;
    
    试试这个:

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    
    查询1

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    
    查询2

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    
    试试这个:

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    
    查询1

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    
    查询2

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |
    

    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;
    
    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)
    
    | id |        email |
    |----|--------------|
    |  3 | Mary@baz.com |
    |  4 | Fred@int.edu |
    |  5 |  Joe@mut.var |
    
    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)
    
    | id |         email |
    |----|---------------|
    |  2 | Alice@bar.net |
    |  4 |  Fred@int.edu |
    |  5 |   Joe@mut.var |