Recursive query with time difference - sql

This is my first post here even though I am a daily reader. :)
I need to produce an MS SQL Server 2014 report that shows the clients that come back to do business with me in less than or equal to 3 days. I tried with INNER JOINS but I wasn't successful.
The way I thought of the solution is using the below Logic:
If product is same
and if userId is same
and if action was donedeal but now is new
and if date diff <= 3 days
and if type is NOT same
then show results
e.g of my Data:
id orderId userId type product date action
1 1001 654 ordered apple 01/05/2016 new
2 1002 889 ordered peach 01/05/2016 new
3 1001 654 paid apple 01/05/2016 donedeal
4 1002 889 paid peach 03/05/2016 donedeal
5 1003 654 ordered apple 03/05/2016 new
6 1004 889 ordered peach 04/05/2016 new
7 1005 122 ordered apple 04/05/2016 new
8 1006 978 ordered peach 04/05/2016 new
9 1005 122 paid apple 04/05/2016 donedeal
10 1007 122 ordered apple 10/05/2016 new
Desired results:
id orderId userId type product date Diff
3 1001 654 paid apple 01/05/2016 2 days
4 1002 889 paid peach 03/05/2016 1 day
5 1003 654 ordered apple 03/05/2016 2 days
6 1004 889 ordered peach 04/05/2016 1 day
Could you please direct me to the functions that can be useful for me to solve this?
Thanks in advance.
#
Update
Gordon Linoff gave me the suggested code below but since the Type had to be different I replicated the code and run it as per below and it worked:
select t.*
from (select t.*,
max(case when action = 'donedeal' and type='paid' then date end) over
(partition by user, product order by date) as last_donedealdate
from t
) t
where action = 'new' and type='ordered' date < dateadd(day, 3, last_donedealdate)
UNION ALL
select t.*
from (select t.*,
max(case when action = 'donedeal' and type='ordered' then date end) over
(partition by user, product order by date) as last_donedealdate
from t
) t
where action = 'new' and type='paid' date < dateadd(day, 3, last_donedealdate)

You can use window functions for this. To get the last done deal date, use max() with partition by and order by. The rest is just where clause logic:
select t.*
from (select t.*,
max(case when action = 'donedeal' then date end) over
(partition by user, product order by date) as last_donedealdate
from t
) t
where action = 'new' and date < dateadd(day, 3, last_donedealdate);

Related

Return scores of each ID based on its 2 months old record

I am new to SQL and am facing this challenge where I need to take the scores of IDs based on 2 month old record respectively. To put it in simple demo:
APP Date
ID
Score 1
Score 2
Score 3
2022-10-31
121
254
312
789
2022-09-30
121
261
542
774
2022-08-31
121
424
432
786
2022-07-30
121
322
764
963
I applied the max function to return the scores based on max APP Date but can't seem to figure out a way to return records that are 2 months old. Based on today's date (November 07) I am expecting to see the below result:
APP Date
ID
Score 1
Score 2
Score 3
2022-09-30
121
261
542
774
Note: All APP Dates are based on month end.
Could anyone please guide me with this? Thanks in advance all!
Query I have used (until now):
with maxdate as (
select ID, max([APP_DATE]) as maxdate
from [Table]
where ID is not null group by ID
)
SELECT [APP_DATE],
a.ID,
Score 1,
Score 2,
Score 3
FROM [Table] a
join maxdate md on a.ID = md.ID and maxdate = a.[APP_DATE]
ORDER BY ID
may be below query help you.:
SELECT top 1 * FROM score
WHERE appdate <= DATEADD(month, -1, GETDATE())
order by appdate desc

How to get the last day of the month without LAST_DAY() or EOMONTH()?

I have a table t with:
DATE
LOCATION
PRODUCT_ID
AMOUNT
2021-10-29
1
123
10
2021-10-30
1
123
9
2021-10-31
1
123
8
2021-10-29
1
456
100
2021-10-30
1
456
90
2021-10-31
1
456
80
2021-10-29
2
123
18
2021-10-30
2
123
17
2021-11-29
2
456
18
I need to find the AMOUNT of each PRODUCT_ID for each combination of LOCATION + PRODUCT_ID.
If a PRODUCT_ID has no entry for that day the AMOUNT is NULL.
So the result should look like:
DATE
LOCATION
PRODUCT_ID
AMOUNT
2021-10-31
1
123
8
2021-10-31
1
456
80
2021-10-31
2
123
NULL
2021-11-30
2
456
NULL
Sadly EXASOL has no LAST_DAY() or EOMONTH() function. How can I solve this?
You can get to the last day of the month using a date_trunc function in combination with date_add:
case
when t.date = date_add('day', -1, date_add('month', 1, date_trunc('month', t.date)))
then 'Y' else 'N' end as end_of_month
That being said, if you group your table for all combinations of locations and products, you will not get NULLs for products without sales on the last day of the month as shown in your output table.
When you group your data, any value that does not exist will simply not show up in your output table. If you want to force nulls to show up, you can create a new table that contains all combinations of products, locations, and hard-coded end of month dates.
Then, you can left join your old table with this new hard-coded table by date, location, and product. This method will give you the NULL values you expect.

How to get latest records based on two columns of max

I have a table called Inventory with the below columns
item warehouse date sequence number value
111 100 2019-09-25 12:29:41.000 1 10
111 100 2019-09-26 12:29:41.000 1 20
222 200 2019-09-21 16:07:10.000 1 5
222 200 2019-09-21 16:07:10.000 2 10
333 300 2020-01-19 12:05:23.000 1 4
333 300 2020-01-20 12:05:23.000 1 5
Expected Output:
item warehouse date sequence number value
111 100 2019-09-26 12:29:41.000 1 20
222 200 2019-09-21 16:07:10.000 2 10
333 300 2020-01-20 12:05:23.000 1 5
Based on item and warehouse, i need to pick latest date and latest sequence number of value.
I tried with below code
select item,warehouse,sequencenumber,sum(value),max(date) as date1
from Inventory t1
where
t1.date IN (select max(date) from Inventory t2
where t1.warehouse=t2.warehouse
and t1.item = t2.item
group by t2.item,t2.warehouse)
group by t1.item,t1.warehouse,t1.sequencenumber
Its working for latest date but not for latest sequence number.
Can you please suggest how to write a query to get my expected output.
You can use row_number() for this:
select *
from (
select
t.*,
row_number() over(
partition by item, warehouse
order by date desc, sequence_number desc, value desc
) rn
from mytable t
) t
where rn = 1

Get the latest price SQLITE

I have a table which contain _id, underSubheadId, wefDate, price.
Whenever a product is created or price is edited an entry is made in this table also.
What I want is if I enter a date, I get the latest price of all distinct UnderSubheadIds before the date (or on that date if no entry found)
_id underHeadId wefDate price
1 1 2016-11-01 5
2 2 2016-11-01 50
3 1 2016-11-25 500
4 3 2016-11-01 20
5 4 2016-11-11 30
6 5 2016-11-01 40
7 3 2016-11-20 25
8 5 2016-11-15 52
If I enter 2016-11-20 as date I should get
1 5
2 50
3 25
4 30
5 52
I have achieved the result using ROW NUMBER function in SQL SERVER, but I want this result in Sqlite which don't have such function.
Also if a date like 2016-10-25(which have no entries) is entered I want the price of the date which is first.
Like for 1 we will get price as 5 as the nearest and the 1st entry is 2016-11-01.
This is the query for SQL SERVER which is working fine. But I want it for Sqlite which don't have ROW_NUMBER function.
select underSubHeadId,price from(
select underSubHeadId,price, ROW_NUMBER() OVER (Partition By underSubHeadId order by wefDate desc) rn from rates
where wefDate<='2016-11-19') newTable
where newTable.rn=1
Thank You
This is a little tricky, but here is one way:
select t.*
from t
where t.wefDate = (select max(t2.wefDate)
from t t2
where t2.underSubHeadId = t.underSubHeadId and
t2.wefdate <= '2016-11-20'
);
select underHeadId, max(price)
from t
where wefDate <= "2016-11-20"
group by underHead;

Isolating the date a value turns 0 and aggregating another value from that date back

I'm looking to see two things:
When a customer closed all of their accounts with us (date when
accounts goes to 0)
The total interactions a customer had with us up
until that point (sum of interactions from when accounts was a
number greater than one).
The total interactions a customer had with us up
until that point (sum of interactions from when accounts was a
number greater than one).
Basically I'm trying to get from the top table to the bottom table in the attached image.
Customer month Accounts Interactions
12345 Jan-15 3 5
12345 Feb-15 3 1
12345 Mar-15 2 7
12345 Apr-15 1 3
12345 May-15 1 9
12345 Jun-15 1 2
12345 Jul-15 0 3
67890 Feb-15 1 4
67890 Mar-15 1 4
67890 Apr-15 1 9
67890 May-15 0 5
Customer Month close date Interactions
12345 Jul-15 30
67890 May-15 23
When I first read the question it sounded like there would be a neat solution with window functions, but after re-reading it, I don't think that's necessary. Assuming that closing his last account would be the last interaction a customer would have with you, you just need the last interaction date per customer, which means this problem can be solved with simple aggregate functions:
SELECT customer, MAX(month), SUM(interactions)
FROM mytable
GROUP BY customer
To get the last three months you need an OLAP-function:
SELECT Customer, MAX(months), SUM(Interactions)
FROM
(
SELECT Customer, month, Interactions
FROM mytable
QUALIFY
-- only closed accounts
MIN(Accounts) OVER (PARTITION BY Customer) = 0
-- last three months
AND month >= oADD_MONTHS(MAX(month) OVER (PARTITION BY Customer), -3)
) AS dt
GROUP BY customer