Home > Net >  SQL using subquery and/or case when to divide rows
SQL using subquery and/or case when to divide rows

Time:10-22

I have a table that looks like this:

Unique ID    Product    Price       Date
112          XYZ        $10.00     10/10/21
112          XYZ        $10.00     10/11/21
112          XYZ        $10.00     10/12/21
113          ABC        $15.99     10/10/21
113          ABC        $17.99     10/11/21
113          ABC        $17.99     10/12/21
114          LMO        $5.00      10/10/21
114          LMO        $5.00      10/11/21 
115          DEF        $9.00      10/10/21
115          DEF        $8.00      10/11/21

I am trying to use the 10/10/21 date as my benchmark to map out price changes by product. I created an index column so now my table looks like this:

Unique ID   Product      Price      Date            Index
112           XYZ       $10.00     10/10/21         Index
112           XYZ       $10.00     10/11/21          No
112           XYZ       $10.00     10/12/21          No
113           ABC       $15.99     10/10/21        Index
113           ABC       $17.99     10/11/21          No
113           ABC       $17.99     10/12/21          No
114           LMO       $5.00      10/10/21         Index
114           LMO       $5.00      10/11/21          No
115           DEF       $9.00      10/10/21         Index
115           DEF       $8.00      10/11/21          No

Next, I'm trying to add a column to show % change for each product based on the index column, so output should look something like this:

Unique_id   Product    Price       Date         Index      Price_change
112          XYZ      $10.00      10/10/21      Index             0%
112          XYZ      $10.00      10/11/21      No                0%
112          XYZ      $10.00      10/12/21      No                0%
113          ABC      $15.99      10/10/21      Index             0%
113          ABC      $17.99      10/11/21      No              12.5%
113          ABC      $17.99      10/12/21      No              12.5%
114          LMO      $5.00       10/10/21      Index             0%
114          LMO      $5.00       10/11/21       No               0%
115          DEF      $9.00       10/10/21     Index              0%
115          DEF      $8.00       10/11/21      No             -11.1%

My SQL statement to do this looks like this:

select *
  , case when index = 'index' 
  THEN (select price/price -1)  
  ELSE ( price / (select price from my_table where product = 'XYZ' and index = 'index') - 1) 
  END AS price_change
from my_table
where product = 'XYZ'

This works for the unique product XYZ, but I'm not able to figure out how to do this for the whole data frame across all the products. Is there where I need to use a subquery? Any help would be appreciated.

CodePudding user response:

This should work. Assuming there is a value for 10-10-2021 for every product.

Select
a.product,
a.price,
(a.price-b.price)*100/b.price as percent_change
from
my_table a
inner join
(select Product,price from my_table where date = '2021-10-10' group by Product,price )b
on a.product=b.product

CodePudding user response:

I presume that the index value is the earliest date:

select
    "Unique Id", product, price, "Date", "Index",
    price / first_value(price)
              over (partition by "Unique Id" order by "Date") * 100.00
      - 100.00 as Percent_Change
from tbl

If you want to use the "Index" column then just pick it out with a case expression:

select
    "Unique Id", product, price, "Date", "Index",
    price / min(case when "Index" = 'Index' then price end)
              over (partition by "Unique Id") * 100.00
      - 100.00 as Percent_Change
from tbl

CodePudding user response:

https://dbfiddle.uk/?rdbms=mysql_5.5&fiddle=448996f2f534d1142e5c23b219a9879e

Try this fiddle. Also, provide a basic fiddle, along with some other information when you post database questions. It will help people answer. Since I don't know what database you are using, I answered in mySQL 5.5. I also assumed that "index" was the first date. If so, it's not necessary to mark it specifically. You can just use the query to get the first date.

There are absolutely better ways to do this, but in earlier versions of mySQL (before the introduction of CTE) I don't believe there is a way to do this without several nested joins: one to get the max and min dates, another to get the prices associated with those dates, and then a third query to get the values and pct change (I actually used a fourth nest to calculate the pct change because I thought it would read better. It was not absolutely necessary).

Or you can do it in two nested queries by using group_concat and ORDER BY to isolate the first and last prices, but it's a little hacky. Again, I gave the two answers that I knew would work in a random version of mySQL. There is also a way to do it with session variables, but I believe those are deprecated.

If you need a running percent change, see the last query.

Let me know what your actual version is, and maybe I can do better.

  •  Tags:  
  • sql
  • Related