Pick records n days after - sql

I have two tables in the below format
Table1
Date IPOName
01-01-2020 DUOL
01-20-2020 VAXX
05-01-2021 HOOD
07-01-2021 INST
and
Table2
CloseDate SYMBOL Value
01-01-2020 DUOL 100
01-02-2020 DUOL 102
01-03-2020 DUOL 120
01-30-2020 DUOL 110
03-01-2020 DUOL 150
04-02-2020 DUOL 110
01-20-2020 VAXX 50
02-20-2020 VAXX 100
03-20-2020 VAXX 150
Essentially Table1 contains the date of an IPO and the stock ticker and Table2 contains the daily closing price on a daily basis for each stock after launch.
I am looking to calculate a Table3 as follows
Table3
Stock 30DayPrice 60DayPrice 90DayPrice
DUOL 110 150 110
VAXX 50 100 150
The Table3 is essentially summarizing Stock, 30DayPrice, 60DayPrice and 90DayPrice after the launch, with each launch being on a different date.
I tried the use of case expressions with minimal success.
Any ideas on how I can achieve this?
My code is as follows:
with stock_list as (
select IPOname, date
from Table1 a
inner join Table2 b on (a.IPOName=b.SYMBOL)
)
select IPOname
, (case when dateadd('days',30,date)=CloseDate then Value end )"List30"
from stock_list
But I get only NULLS in the List30 column
Thanks!

Related

Match group of variables and values with the nearest datetime

I have a transaction table that looks like that:
transaction_start store_no item_no amount post_voided
2021-03-01 10:00:00 001 101 45 N
2021-03-01 10:00:00 001 105 25 N
2021-03-01 10:00:00 001 109 40 N
2021-03-01 10:05:00 002 103 35 N
2021-03-01 10:05:00 002 135 20 N
2021-03-01 10:08:00 001 140 2 N
2021-03-01 10:11:00 001 101 -45 Y
2021-03-01 10:11:00 001 105 -25 Y
2021-03-01 10:11:00 001 109 -40 Y
The table does not have an id column; the transaction_start for a given store_no will never be the same.
Whenever a transaction is post voided, the transaction is then repeated with the same store_no, item_no but with a negative/minus amount and an equal or higher transaction_start. Also, the column post_voided is then equal to 'Y'.
In the example above, the rows 1-3 have the same transaction_start and store_no, thus belonging to the same receipt, containing three different items (101, 105, 109). The same logic is applied to the other rows: rows 4-5 belong to a same receipt, and so on. In the example, 4 different receipts can be seen. The last receipt, given by the last three rows, is a post voided of the first receipt (rows 1-3).
What I want to do is to change the transaction_start for the post_voided = 'Y' transactions (in my example, only one receipt - represented by the last three rows - has it) to the next/closest datetime of a similar receipt that has the variables store_no, item_no and (negative) amount (but post_voided = 'N') (in my example, the similar ticket is given by the first three rows - store_no, all item_no and (positive) amount match). The transaction_start for the post voided receipt is always equal or higher than the "original" receipt.
Desired output:
transaction_start store_no item_no amount post_voided
2021-03-01 10:00:00 001 101 45 N
2021-03-01 10:00:00 001 105 25 N
2021-03-01 10:00:00 001 109 40 N
2021-03-01 10:05:00 002 103 35 N
2021-03-01 10:05:00 002 135 20 N
2021-03-01 10:08:00 001 140 2 N
2021-03-01 10:00:00 001 101 -45 Y
2021-03-01 10:00:00 001 105 -25 Y
2021-03-01 10:00:00 001 109 -40 Y
Here a link of the table: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=26142fa24e46acb4213b96c86f4eb94b
Thanks in advance!
Consider below
select a.* replace(ifnull(b.transaction_start, a.transaction_start) as transaction_start)
from `project.dataset.table` a
left join (
select * replace(-amount as amount)
from `project.dataset.table`
where post_voided = 'N'
) b
using (store_no, item_no)
if applied to sample data in your question - output is
Consider below for new / extended example (https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=91f9f180fd672e7c357aa48d18ced5fd)
select x.* replace(ifnull(y.original_transaction_start, x.transaction_start) as transaction_start)
from `project.dataset.table` x
left join (
select b.transaction_start, b.store_no, b.item_no, b.amount amount,
max(a.transaction_start) original_transaction_start
from `project.dataset.table` a
join `project.dataset.table` b
on a.store_no = b.store_no
and a.item_no = b.item_no
and a.amount = -b.amount
and a.post_voided = 'N'
and b.post_voided = 'Y'
and a.transaction_start < b.transaction_start
group by b.transaction_start, b.store_no, b.item_no, b.amount
) y
using (store_no, item_no, amount, transaction_start)
with output

Creating a Separate Column for Prior Week Values (PostgreSQL)

How would I go about having a separate column that shows the prior week's value? For example, if Product A's value for 01/03/2021 was 100, I would like 01/10/2021 to show its date value as well as the 01/03/2021 value in a separate column.
Desired table below (for simplicity sake I added random numbers for the prior week values for 01/03 and 01/04):
Date
Product
Value
Prior Week Value
01/03/2021
Product A
100
50
01/04/2021
Product A
200
55
01/10/2021
Product A
600
100
01/11/2021
Product A
700
200
01/03/2021
Product B
250
40
01/04/2021
Product B
550
45
01/10/2021
Product B
460
250
01/11/2021
Product B
100
550
If you want exactly 7 days before, you can use window functions with a range specification:
select t.*,
max(value) over (partition by product
order by date
range between '7 day' preceding and '7 day' preceding
) as value_prev_week
from t;

Many to many join with filter

I have two tables like so -
Table 1 -
patient admit_dt discharge_dt
323 2020-01-09 2020-02-01
323 2020-02-18 2020-02-27
231 2020-02-13 2020-02-17
Table 2 -
patient admit_dt discharge_dt
323 2020-02-05 2020-02-07
231 2020-02-23 2020-02-28
The output I am needing is
patient
323
The logic is - if one patient goes from table 1 into table 2 and ends up back in table 1 within 30 days, we want to count them in the output.
Patient 231 is not included in the result because they didn't go back to table 1.
If I understand correctly, you can use join:
select t1.patient
from table1 t1 join
table2 t2
on t2.patient = t1.patient and
t2.admit_dt > t1.discharge_dt join
table1 tt1
on tt1.patient = t1.patient and
tt1.admit_dt > t2.discharge_dt;

result is wrong when retrieving the date

I'm working with PostgreSQL. I have two database tables,i want to get the min and max date stored in table1 daterange column which is of type character varying. table1 and table2 is mapped using sid. i want to get the max and min date range of table1 when compared with sid of table2. Please find the demo here. The result is wrong.
table1:
sid daterange
100 5/25/2017
101 1/24/2017
102 4/4/2014
103 11/12/2007
104 4/24/2012
105 01/15/2017
106 1/1/2017
107 3/11/2016
108 10/10/2001
109 1/10/2016
110 12/12/2016
111 4/24/2017
112 06/28/2015
113 5/24/2017
114 5/22/2017
table2:
sid description
100 success
101 pending
104 pending
105 success
106 success
107 success
110 success
111 pending
112 failed
113 failed
114 pending
Below is my query:
select min(daterange) as minDate,max(daterange) as maxDate from (SELECT to_date(table1.daterange, 'DD/MM/YYYY') as daterange FROM table1,table2 where
table1.sid = table2.sid) tt;
The result is as below which is wrong(mindate and maxdate displayed are wrong dates).
mindate maxdate
2013-12-07 2019-01-07
Please advice. daterange column in table1 is of type character varying.I cannot use ::date to convert to date type, because i need to use this query in my java hibernate code and the java code is not recognizing ::
You have day and month mixed up in the date format string.
Should be
to_date(table1.daterange, 'MM/DD/YYYY')

Combine multiple rows using SUM that share a same column value but has different other column values

I thought this would be a very simple query but for some reason, I can't seem to get the results I'm looking for. I have a table that has this structure. I just want a single entry for each account while summing the charges. I don't really care which date I keep, just one of them.
Account Charges Charges2 Date
1 100 50 1/1/2015
1 50 0 1/2/2015
2 50 0 2/4/2015
2 70 30 2/19/2015
3 100 0 1/12/2014
4 0 20 4/3/2015
4 40 20 4/9/2015
The result I want is:
Account Charges Charges2 Date
1 150 50 1/1/2015
2 120 30 2/4/2015
3 100 0 1/12/2014
4 40 40 4/3/2015
The result I currently get is:
Account Charges Charges2 Date
1 100 50 1/1/2015
2 70 30 2/19/2015
3 100 0 1/12/2014
4 40 40 4/9/2015
I thought this would be very simple and I tried below. But this doesn't sum them up, it just seems to return the rows where Charges2 is NOT 0.
SELECT Account, SUM(Charges) As TotCharges, SUM(Charges2) AS TotCharges2
FROM TABLE
GROUP BY Account
ORDER BY Account
You can apply the min() aggregate function to the date to limit the number of rows returned to one per account:
SELECT
Account,
SUM(Charges) AS TotCharges,
SUM(Charges2) AS TotCharges2,
MIN(Date) AS Date
FROM TABLE
GROUP BY Account
ORDER BY Account
Sample SQL Fiddle