Question

This is probably easier than I think it is, but I am stumped. I wrote the following query which sums up all the purchases made by a customer at a particular store, as well as the total amount of returns made by the same customer at the same store, and lastly, stores the result of subtracting total returns from total purchases in a calculated column called TOTAL_SPENT. Here is my query:

SELECT Account_Id,
  SUM(CASE WHEN Transaction_Code = 'Purchase' THEN Transaction_Amount ELSE 0 END) AS TOTAL_PURCHASED,
  SUM(CASE WHEN Transaction_Code = 'Return' THEN Transaction_Amount ELSE 0 END) AS TOTAL_RETURNED,
  (TOTAL_PURCHASED - TOTAL_RETURNED) AS TOTAL_SPENT
FROM Transactions_Table
WHERE Store = 'Store XYZ'
GROUP BY Account_Id
ORDER BY TOTAL_SPENT DESC

My problem is that this query returns hundreds of thousands of records, but I only care about approximately 10% of the data that's returned. So, say you only want to see data returned where TOTAL_SPENT >= 500.00. But for the life of me, I cannot figure out how to do this! hanging head in shame

Was it helpful?

Solution

In SQL, the WHERE clause is processed before the SELECT clause. So, when SQL begins filtering the rows from your table that are relevent to your query, it doesn't yet know about the column TOTAL_SPENT.

There's a few ways to fix that.

1) Repeat the expressions in your WHERE clause, rather than referring to a column name in your SELECT clause:

SELECT Account_Id,
  SUM(CASE WHEN Transaction_Code = 'Purchase' THEN Transaction_Amount ELSE 0 END) AS TOTAL_PURCHASED,
  SUM(CASE WHEN Transaction_Code = 'Return' THEN Transaction_Amount ELSE 0 END) AS TOTAL_RETURNED,
  (TOTAL_PURCHASED - TOTAL_RETURNED) AS TOTAL_SPENT
FROM Transactions_Table
WHERE Store = 'Store XYZ'
GROUP BY Account_Id
ORDER BY 
  (SUM(CASE WHEN Transaction_Code = 'Purchase' THEN Transaction_Amount ELSE 0 END) - SUM(CASE WHEN Transaction_Code = 'Return' THEN Transaction_Amount ELSE 0 END)) DESC

Note: If you're looking to find groups with a TOTAL_SPENT above 500, use the HAVING clause instead of WHERE.

2) Use a view. Remove your WHERE clause and create a VIEW with your query. Then, select from that view and add your WHERE clause.

CREATE VIEW Whatever AS
   SELECT Account_Id,
      SUM(CASE WHEN Transaction_Code = 'Purchase' THEN Transaction_Amount ELSE 0 END) AS    TOTAL_PURCHASED,
      SUM(CASE WHEN Transaction_Code = 'Return' THEN Transaction_Amount ELSE 0 END) AS TOTAL_RETURNED,
      (TOTAL_PURCHASED - TOTAL_RETURNED) AS TOTAL_SPENT
   FROM Transactions_Table
   GROUP BY Account_Id;

SELECT * From Whatever WHERE TOTAL_SPENT >= 500

3) Use a nested SELECT:

select * from (
  SELECT
    Account_Id,
    SUM(CASE WHEN Transaction_Code = 'Purchase' THEN Transaction_Amount ELSE 0 END) AS TOTAL_PURCHASED,
    SUM(CASE WHEN Transaction_Code = 'Return' THEN Transaction_Amount ELSE 0 END) AS TOTAL_RETURNED,
    (TOTAL_PURCHASED - TOTAL_RETURNED) AS TOTAL_SPENT
  FROM Transactions_Table
  WHERE Store = 'Store XYZ'
  GROUP BY Account_Id
) where TOTAL_SPENT > 500 ORDER BY TOTAL_SPENT DESC;

4) If your database supports it, use a CTE:

WITH MyQuery AS (
  SELECT
    Account_Id,
    SUM(CASE WHEN Transaction_Code = 'Purchase' THEN Transaction_Amount ELSE 0 END) AS TOTAL_PURCHASED,
    SUM(CASE WHEN Transaction_Code = 'Return' THEN Transaction_Amount ELSE 0 END) AS TOTAL_RETURNED,
    (TOTAL_PURCHASED - TOTAL_RETURNED) AS TOTAL_SPENT
  FROM Transactions_Table
  WHERE Store = 'Store XYZ'
  GROUP BY Account_Id
)
SELECT * FROM MyQuery WHERE TOTAL_SPENT > 500 ORDER BY TOTAL_SPENT DESC;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top