Skip to main content

Subqueries

Continuing with the sample database available via the docker images from the first post in this series, let’s look at some examples demonstrating the syntax of subqueries. A subquery is where you have a select statement nested inside of another query. You might utilize this approach based on performance tuning, the readability of your queries, or out of necessity based on your database schemas. A discussion of performance tuning is out of scope of this post. If you’re curious about knowing when you should or should not use a subquery based on performance tuning, search for ’explain statements’ for your database. MySQL, Maria, and SQL Server use the general syntax of ‘EXPLAIN <your query here>’ and there is plenty of documentation on Oracle’s Explain Plan. In short, explain produces an execution plan for your SQL statement which will tell you which indexes are being used to fetch the data from each table, how much data is being fetched from each table, etc., so you can compare different approaches to produce the same result set or trouble shoot a slow running query. But for this post, we’re going to just focus on the syntax of subqueries.

Subqueries In A Where Clause

You can use a subquery in a where clause to filter the data returned. This often involves using “exists” or “not exists” keywords. For example, I could use left joins to produce a list of the products in my catalog where we do not have inventory on hand currently.

select product.name,
       product.product_id
  from product
  left join inventory on inventory.product_id = product.product_id
 where inventory.product_id is null;

I could also get the same results using a subquery looking for product where there does not exist any inventory using a ’not exists’ condition.

select name,
       product_id
  from product
 where not exists (select 1
                     from inventory
                    where inventory.product_id = product.product_id);

Products with no inventory on hand

Products with no inventory on hand

You can also include subqueries in select clauses. When doing so, the subquery in the select statement must produce a single row for each row in the result set of the overall query. If your subquery returns more than one row, you’ll get the “Subquery returns more than 1 row” error. I’ve added a subquery to the select clause to one of our previous examples to provide an example.

select product.name,
       product.product_id,
       (select sum(order_quantity)
          from sales_order_line as sol
         where sol.product_id = product.product_id) as backorder_quantity
  from product
 where not exists (select 1
                     from inventory
                    where inventory.product_id = product.product_id);

Subqueries In A From Clause

In this example, we’re going to get the ordered quantity for which we don’t have any inventory on hand, the back ordered quantities. We could use left joins as follows.

select customer.first_name,
       so.sales_order_id,
       so.order_date,
       product.name,
       sol.order_quantity
  from sales_order as so
  join customer on customer.customer_id = so.customer_id
  join sales_order_line as sol on sol.sales_order_id = so.sales_order_id
  join product on product.product_id = sol.product_id
  left join inventory on inventory.product_id = product.product_id
 where inventory.product_id is null;

Back order quantities

Back order quantities

A quick example of some unions, and then we’ll circle back for inserts, updates, and deletes.