This query will work, to SELECT
more columns from the products table add them to both the SELECT
and GROUP BY
clauses:
SELECT p.product_id
,SUM(IFNULL(ps.product_quantity,0)) AS product_quantity_sold
,SUM(IFNULL(ps.product_total_price,0)) AS total_price_sold
FROM product p
LEFT JOIN product_sold ps ON p.product_id = ps.product_id
LEFT JOIN sales s ON ps.product_sales_id = s.sales_id
WHERE p.product_subcategory_id = $subcategory_id
AND ( s.sales_id IS NULL
OR ( s.sales_approved = '1'
AND s.sales_approved_time > '$start_timestamp'
AND s.sales_approved_time < '$end_timestamp'
)
)
GROUP BY p.product_id
ORDER BY SUM(IFNULL(ps.product_quantity,0)) DESC
Explanation
This query would have been much simpler if you could have used product_sold_approved
and product_sold_approved_time
in the WHERE
clause instead of values from the sales table.
You LEFT JOIN product_sold
, a LEFT JOIN
means you keep all records from the products
table, and those that have been sold will get joined to each of the product_sold
records. Then you do the same for the sales
table.
So at this stage, you have lots of rows that are product + product_sold + sales
but you also have all the unsold products product + NULL + NULL
. You need to filter out all the joined records where the matching sale fields do not meet your criteria, but you need to leave all the records that failed to join alone.
To achieve this you have a WHERE clause that deals with each set of records separately. WHERE (condition A) OR (condition B)
.
Condition A deals with our unsold products, WHERE s.sales_id IS NULL
- all records that couldn't join to a sale are included in the result set and don't have to match the other criteria.
OR (sales_approved = 1 AND ... AND ...)
records where s.sales_id isn't NULL will have to pass this half of the where clause, hence we filter out unwanted sales.
At the end we're left with a result set that contains all records that didn't have any sales + all product/product_sales/sales record that met your criteria. Then we can just GROUP BY product_id AND SUM what's left.
I have IFNULL
s in my SQL, these are because if you're summing lots of values and some of them might be NULL
, if a single value is NULL
then the result of the SUM
is NULL
. The IFNULL(column,0)
protects against this by converting any NULL
values to a 0
. 1 + NULL = NULL
, 1 + 0 = 1
. HOWEVER, on reflection I thats probably not needed for the query - remove them and you should notice the change.