'Meta Recruiting SQL -- Join Part 1
I have done my best to neatly format the meta recruiting question below. My current query that I'm trying to ascertain the ratio is this. Returning correct 2/3 values but the ratio is returning as all 1's. Any help on where I'm going wrong?
Update: After much help from David Aldridge
I realized that SqlLite was the issue here and casting to numeric helped reach the final result with the query in the solution below.
BACKGROUND:
The following schema is a subset of a relational database of a grocery store chain. This chain sells many products of different product classes to its customers across its different stores. It also conducts many different promotion campaigns.
The relationship between the four tables we want to analyze is depicted below:
PROMPT:
- The CMO is interested in understanding how the sales of different
- product families are affected by promotional campaigns.
- To do so, for each of the available product families,
- show the total number of units sold,
- as well as the ratio of units sold that had a valid promotion
- to units sold without a promotion, -- ordered by increasing order of total units sold.
Solution:
SELECT product_family,
SUM(units_sold) as total_units_sold,
CAST(SUM(CASE WHEN s.promotion_id IS NOT 0 then units_sold * 1.0 ELSE 0 END) AS NUMERIC) /
CAST(SUM(CASE WHEN s.promotion_id = 0 THEN units_sold * 1.0 ELSE 0 END) as NUMERIC) as ratio_units_sold_with_promo_to_sold_without_promo
FROM products p
JOIN product_classes c ON c.product_class_id = p.product_class_id
JOIN sales s ON s.product_id = p.product_id
GROUP BY product_family
ORDER BY total_units_sold ASC;
Solution 1:[1]
SELECT product_family,
SUM(units_sold) as total_units_sold,
CAST(SUM(CASE WHEN s.promotion_id IS NOT 0 then units_sold * 1.0 ELSE 0 END) AS NUMERIC) /
CAST(SUM(CASE WHEN s.promotion_id = 0 THEN units_sold * 1.0 ELSE 0 END) as NUMERIC) as ratio_units_sold_with_promo_to_sold_without_promo
FROM products p
JOIN product_classes c ON c.product_class_id = p.product_class_id
JOIN sales s ON s.product_id = p.product_id
GROUP BY product_family
ORDER BY total_units_sold ASC;
Solution 2:[2]
This feels like what you're looking for (I added an extra column for clarity):
SELECT product_family,
SUM(units_sold) as total_units_sold,
SUM(CASE WHEN s.promotion_id > 0 then units_sold ELSE 0 END) as sold_when_promoted,
SUM(CASE WHEN s.promotion_id > 0 then units_sold ELSE 0 END)::numeric /
SUM(units_sold) AS ratio_units_sold_with_promo_to_sold_without_promo
FROM products p
JOIN product_classes c ON c.product_class_id = p.product_class_id
JOIN sales s ON s.product_id = p.product_id
GROUP BY product_family;
... or using a filter clause ...
SELECT product_family,
SUM(units_sold) as total_units_sold,
SUM(units_sold) filter(where s.promotion_id > 0) as sold_when_promoted,
SUM(units_sold) filter(where s.promotion_id > 0)::numeric /
SUM(units_sold) AS ratio_units_sold_with_promo_to_sold_without_promo
FROM products p
JOIN product_classes c ON c.product_class_id = p.product_class_id
JOIN sales s ON s.product_id = p.product_id
GROUP BY product_family;
I don't think you need to guard against division by zero, but if you had a sum of sales of zer for a product you'd need to handle that.
Edit: I think you don't need to reference the promotions table, actually.
Solution 3:[3]
select avg(case when is_low_fat_flg=1 and is_recyclable_flg=1 then 1 else 0 end)*100 as pct_low_fat_and_recyclable
from products
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | phtaedrus |
Solution 2 | |
Solution 3 | user2662006 |