More than 1 rows returned from SELECT inside SELECT

Mateusz :

I'm trying to create a query to find what is the total amount owed by each customer to the company. It is the GROUP BY customerNumber in the sub query that is creating the problem.

SELECT customerName,
       customers.customerNumber,
       SUM(quantityOrdered * priceEach) - ( SELECT SUM(amount) AS MoneyPayed FROM payments GROUP BY customerNumber ) AS AmountOwed
FROM payments
INNER JOIN customers ON payments.customerNumber = customers.customerNumber
INNER JOIN orders ON customers.customerNumber = orders.customerNumber
INNER JOIN  orderdetails ON  orders.orderNumber = orderdetails.orderNumber
GROUP BY customerNumber;

The tables I'm trying to link are payments and orderdetails.

When I get rid of the GROUP BY I get results in negatives as the total SUM of amount is subtracted from each row of SUM(quantityOrdered * priceEach).

How can I change this so that I can return multiple rows from payments to subtract from SUM(quantityOrdered * priceEach) from the order details table.

Link to DB as StackOverflow doesn't allow me to post images

https://i.stack.imgur.com/N6o1w.png

Thanks for help, sorry if format is bad, this is my first post.

O. Jones :

You will need a couple of subqueries to meet your requirement. Let us break it down.

First, you need the total value of orders from each customer. You're very close to the correct query for that. It should be

               SELECT orders.customerNumber,
                      SUM(orderdetails.quantityOrdered * orderdetails.priceEach) owed
                 FROM orders
                 JOIN orderdetails ON  orders.orderNumber = orderdetails.orderNumber
             GROUP BY orders.customerNumber

This subquery's result set gives customerNumber and owed, the amount owed. Notice that orders::orderdetails is a one::many relationship, so we're sure we're counting each detail just once, so the SUMs will be correct.

Next we need the amount paid by each customer. This subquery is fairly simple.

               SELECT customerNumber,
                      SUM(amount) paid
                 FROM payments
                GROUP BY customerNumber

Now for the operation you're missing in your question: we need to join these two subqueries to your customers table.

SELECT customers.customerName, customers.customerNumber
       owed.owed - paid.paid balance
  FROM customers
  LEFT JOIN (
               SELECT orders.customerNumber,
                      SUM(orderdetails.quantityOrdered * orderdetails.priceEach) owed
                 FROM orders
                 JOIN orderdetails ON  orders.orderNumber = orderdetails.orderNumber
             GROUP BY orders.customerNumber
       ) paid ON customers.customerNumber = paid.customerNumber
  LEFT JOIN (
               SELECT customerNumber,
                      SUM(amount) paid
                 FROM payments
                GROUP BY customerNumber
       ) owed ON customers.customerNumber = owed.customerNumber

See how this works? We join a table and two subqueries. Each subquery has either zero or one rows for each row in the table, so we need not use SUMs or GROUP BY in the outer query.

There's only one complication left: what if a customer has never paid anything? Then the value of paid.paid will be NULL after the LEFT JOIN operation. That will force the value of owed - paid to be NULL. So we need more smarts in the SELECT statement to yield correct sums.

SELECT customers.customerName, customers.customerNumber
       COALESCE(owed.owed,0) - COALESCE(paid.paid,0) balance
       ...

COALESCE(a,b) is equivalent to if a is not null then a else b.

Pro tip In queries or subqueries with JOIN operations, always mention table.column instead of just column. The next person to work on your query will thank you.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=298238&siteId=1