Home > Enterprise >  Nested SQL Query Guidance
Nested SQL Query Guidance

Time:09-01

I need help constructing an SQL nested query for a problem I'm trying to solve.

Given these two tables:

airlines_detail:

airplane_id airline_id total_seats
2187 425 260
4361 747 290
3478 747 270
7292 425 250
5833 425 310
3472 425 300
4472 747 290
2624 425 320

Bookings:

airplane_id booked
2187 40
4361 30
4361 10
5833 30
4361 30
2624 30
4472 40
4472 40
2624 10
7292 20
2187 20
4472 30
3478 20
3472 40
4472 30
4472 10
4361 20
3478 30
2187 30
2187 10

I need to get this result:

airplane_id airline_id empty_seats
2187 425 160
7292 425 230
5833 425 280
3472 425 260
2624 425 280
4361 747 90
3478 747 50
4472 747 150

The empty_seats column is a SUM() of the booked columns GROUP BY'd airplane_id. I have this query successfully built already (below), but I need to JOIN or otherwise subquery to get the airline_id column into my result which I'm unclear about.

TO REPRODUCE

  1. Go to https://www.mycompiler.io/new/sql
  2. Copy and paste the below code and run it to see what I have so far
-- drop tables if exists
DROP TABLE IF EXISTS airlines_detail;
DROP TABLE IF EXISTS bookings;

-- create airlines_detail table
CREATE TABLE airlines_detail (
  airplane_id INTEGER PRIMARY KEY,
  airline_id INTEGER NOT NULL,
  total_seats INTEGER NOT NULL
);

-- create bookings table
CREATE TABLE bookings (
  airplane_id INTEGER NOT NULL,
  booked INTEGER NOT NULL,
  FOREIGN KEY (airplane_id) REFERENCES airlines_detail(airplane_id)
);


-- insert some airlines_detail values
INSERT INTO airlines_detail VALUES (2187, 425, 260);
INSERT INTO airlines_detail VALUES (4361, 747, 290);
INSERT INTO airlines_detail VALUES (3478, 747, 270);
INSERT INTO airlines_detail VALUES (7292, 425, 250);
INSERT INTO airlines_detail VALUES (5833, 425, 310);
INSERT INTO airlines_detail VALUES (3472, 425, 300);
INSERT INTO airlines_detail VALUES (4472, 747, 290);
INSERT INTO airlines_detail VALUES (2624, 425, 320);

-- insert some bookings values
INSERT INTO bookings VALUES (2187, 40);
INSERT INTO bookings VALUES (4361, 30);
INSERT INTO bookings VALUES (4361, 10);
INSERT INTO bookings VALUES (5833, 30);
INSERT INTO bookings VALUES (4361, 30);
INSERT INTO bookings VALUES (2624, 30);
INSERT INTO bookings VALUES (4472, 40);
INSERT INTO bookings VALUES (4472, 40);
INSERT INTO bookings VALUES (2624, 10);
INSERT INTO bookings VALUES (7292, 20);
INSERT INTO bookings VALUES (2187, 20);
INSERT INTO bookings VALUES (4472, 30);
INSERT INTO bookings VALUES (3478, 20);
INSERT INTO bookings VALUES (3472, 40);
INSERT INTO bookings VALUES (4472, 30);
INSERT INTO bookings VALUES (4472, 10);
INSERT INTO bookings VALUES (4361, 20);
INSERT INTO bookings VALUES (3478, 30);
INSERT INTO bookings VALUES (2187, 30);
INSERT INTO bookings VALUES (2187, 10);



-- fetch some values
-- First, sum up total seats booked by airplane_id
SELECT
    airplane_id,
    SUM(booked)
FROM bookings
GROUP BY airplane_id;

-- Need to get airline_id in there somehow too

CodePudding user response:

First of all the number of empty seats is the total number of seats minus the booked ones.

Your query would only return aeroplanes for which at least one record exists in the booking table, but you'd need to return one record for each aeroplane even those for which there are no bookings.

You can get the airline id from the airlines_detail table, and then you can easily add that field to the select list and the group by list. Adding it to the group by list will not create more groups, but it is necessary to have it selected.

So for both of the above reasons, the query should really start out with the airlines_detail table.

With a subquery that would look like this:

SELECT    airplane_id,
          airline_id,
          total_seats - (
                SELECT COALESCE(SUM(booked), 0)
                FROM   bookings b
                WHERE a.airplane_id = b.airplane_id
          ) AS empty_seats
FROM      airlines_detail a
GROUP BY  airplane_id,
          airline_id;

COALESCE is used to deal with the case where there are no bookings. In that case we want to subtract the value 0, avoiding NULL.

Another approach is to join the two tables in a single query. As you want an output for all planes, even when nothing was booked, this join must be an outer join.

So:

SELECT    a.airplane_id,
          a.airline_id,
          a.total_seats - SUM(b.booked) AS empty_seats
FROM      airlines_detail a
LEFT JOIN bookings b
       ON a.airplane_id = b.airplane_id
GROUP BY  a.airplane_id,
          a.airline_id;
  •  Tags:  
  • sql
  • Related