Skip to content
Advertisement

Decluttering a SQL query

For a practice project i wrote the following query and i was wondering if there is way to make it more efficient than writing everything 12 times like a for loop for sql.

CREATE TABLE temp (month INT, total_sales INT, market_share decimal(5,2), year_change decimal(5,2))

insert into temp (month)
Values (1)

UPDATE temp
SET total_sales = (
    SELECT COUNT(purchases_2020.purchaseid)
    FROM purchases_2020
    JOIN categories ON purchases_2020.purchaseid = categories.purchase_id
    WHERE (categories.category = 'whole milk' OR categories.category = 'yogurt' OR categories.category = 'domestic eggs') AND (purchases_2020.fulldate BETWEEN '2020-01-01' AND '2020-01-31')
) 
WHERE month = 1

UPDATE temp
SET market_share = (
        SELECT (SELECT 100 * COUNT(purchases_2020.purchaseid)
                FROM purchases_2020
                JOIN categories ON purchases_2020.purchaseid = categories.purchase_id
                WHERE (categories.category = 'whole milk' OR categories.category = 'yogurt' OR categories.category = 'domestic eggs') AND (purchases_2020.fulldate BETWEEN '2020-01-01' AND '2020-01-31'))
       * 1. /  
               (SELECT COUNT(purchases_2020.purchaseid) 
               FROM purchases_2020
               WHERE purchases_2020.fulldate BETWEEN '2020-01-01' AND '2020-01-31')
) 
WHERE month = 1

UPDATE temp
SET year_change = (
    SELECT market_share - 
        (SELECT 
            (SELECT 100 * COUNT(purchases_2019.purchase_id)
            FROM purchases_2019
            JOIN categories ON purchases_2019.purchase_id = categories.purchase_id
            WHERE (categories.category = 'whole milk' OR categories.category = 'yogurt' OR categories.category = 'domestic eggs') AND (purchases_2019.full_date BETWEEN '2019-01-01' AND '2019-01-31'))
        * 1./  
            (SELECT COUNT(purchases_2019.purchase_id) 
            FROM purchases_2019
            WHERE purchases_2019.full_date BETWEEN '2019-01-01' AND '2019-01-31'))
    FROM temp
    WHERE month = 1
) 
WHERE month = 1

EDIT

I was given the 3 tables represented on the following database schema , and im trying to create a table with the total sales of dairy every month, the monthly market share of the dairy products and the difference between the 2020 monthly market share and the 2019 monthly market share (the year change colunm)

There is also an aritmethic error somewhere, when checking the project i get the following message ResultSet does not contain the correct numeric values! and im at my wits end looking for it butmy priority is to decluter the query.

Advertisement

Answer

Your error message tells me that you are trying to run this from a reporting tool or a host language.

It also makes no sense to put the data into separate tables by years.

SQL is a declarative language that works with data as sets.

Instead of pushing the results into table temp, try writing a query like this:

with all_data as (
  select p.fulldate, p.purchaseid, c.category,
         extract(year  from p.fulldate) as year,
         extract(month from p.fulldate) as month
    from purchases_2020 p
         join categories c on c.purchase_id = p.purchaseid
  union all
  select p.fulldate, p.purchaseid, c.category,
         extract(year  from p.fulldate) as year,
         extract(month from p.fulldate) as month
    from purchases_2019 p
         join categories c on c.purchase_id = p.purchaseid
), kpis as (
  select year, month, 
         count(purchaseid) 
           filter (where category in ('whole milk', 'yogurt', 'domestic eggs'))
             as dairy_sales,
         count(purchaseid) * 1.0 as total_sales
    from all_data
   group by year, month
)
select ty.month, ty.dairy_sales as total_sales,
       100.0 * ty.dairy_sales / ty.total_sales as market_share,
       100.0 * (   (ty.dairy_sales / ty.total_sales) 
                 - (ly.dairy_sales / ly.total_sales)) as year_change
  from kpis ty
       join kpis ly
         on (ly.year, ly.month) = (ty.year - 1, ty.month);

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement