SQL - Counting months passed by a Person Indicator - sql

I'm trying to count the number of months that have passed based on ID, it's possible that for some records the months will not increase by 1 each time (i.e. someone could have a record for 1/1/13 and 3/1/13 but not 2/1/13) however I only want a count of the records in my table. So missing months don't matter.
An example table would be: (notice the missing month and it's irrelevancy).
DATE ID Months Passed
----------- --- --------------
2013-11-01 105 1
2013-12-01 105 2
2014-02-01 105 3
2014-03-01 105 4
Essentially an Excel COUNTIFSin SQL, which I've written:
=COUNTIFS(IDColumn, ID, MonthColumn, "<=" & Month)
Does anyone know of a way to generate the desired column using SQL?

Try ROW_NUMBER(). If you just want the "Months Passed" column to increase by 1 each time, and for each ID, that will do the trick.
SELECT
Date,
Id,
Indicator,
ROW_NUMBER() OVER(PARTITION BY Id ORDER BY Date) AS RowNum
FROM YourTable
WHERE Indicator = 'YES'
UNION
SELECT
Date,
Id,
Indicator,
0 AS RowNum
FROM YourTable
WHERE Indicator = 'NO'

You could more simply count rows grouped by month (more complex if you have count months in different years separately):
SELECT COUNT(derived.monthVal)
FROM (SELECT MONTH(<your date field>) AS monthVal
FROM [your table]
WHERE [Your ID Column] = <the id>
GROUP BY MONTH(<your date field>)) AS derived;

Related

SQL Trailing Date Count

I have a need to do a calculation based on trailing dates when a customer placed an order.
SQL Code to get the following table:
select Date,Cust, ProdID, OrderLog
from AUDIT AS A
where Date >= '2021-02-07'
and Cust = '477'
and Prod ID = 'X'
order by A.Date desc
Date
Cust
ProdID
OrderLog
2/18/2021
477
X
Null
2/17/2021
477
X
1
2/16/2021
477
X
1
2/15/2021
477
X
1
2/14/2021
477
X
Null
2/13/2021
477
X
Null
What I want to do is count the days from 1st OrderLog Date, 2/15/2021, to last OrderLog Date 2/17/2021. For an outcome of 3.
I tried to do this in a window function using lag/over/partition with no luck. I also tried searching for the solution with no luck.
There is a need to do this in one query containing multiple Cust,PRODID and Dates. The count need to be at Cust and ProdID level.
Thanks for any help!
I think you want:
select Cust, ProdID,
max(date) - max(case when OrderLog = 1 then date end) as diff
from AUDIT AS A
where Date >= '2021-02-07' and
Cust = '477' and Prod ID = 'X'
group by cust, prodid;
Note that date/time functions vary among databases, so your database might use something other than - to subtract two dates.

Selecting the difference between dates in a stored procedure using a subquery

I can't get my head around whether this is even possible, but I feel like I might have done it before and lost that bit of code. I am trying to craft a select statement that contains an inner join on a subquery to show the number of days between two dates from the same table.
A simple example of the data structure would look like:
Name ID Date Day Hours
Bill 1 3/3/20 Thursday 8
Fred 2 4/3/20 Monday 6
Bill 1 8/3/20 Tuesday 2
Based on this data, I want to select each row plus an extra column which is the number of days between the date from each row for each ID. Something like:
Select * from tblData
Inner join (datediff(Select Top(1) Date from tblData where Date < Date), Date) And ID = ID)
or for simplicity:
Select * from tblData
Inner join (datediff(Select Top(1) Date from tblData where Date < 8/3/20), 8/3/20) And ID = 1)
The resulting dataset would look like:
Name ID Date Day Hours DaysBtwn
Bill 1 3/3/20 Thursday 8 4 (Assuming there was an earlier row in the table)
Fred 2 4/3/20 Monday 6 5 (Assuming there was an earlier row in the table)
Bill 1 8/3/20 Tuesday 2 5 (Based on the previous row date being 3/3/20 for Bill)
Does this make sense and am I trying to do this the wrong way? I want to do this for about 600000 rows in table and therefore efficiency is the key, so if there is a better way to do this, i'm open to suggestions.
You can use lag():
select t.*, datediff(day, lag(date) over(partition by id order by date), date) diff
from mytable t
I think you just want lag():
select t.*,
datediff(day,
lag(date) over (partition by name order by date),
date
) as diff
from tblData t;
Note: If you want to filter the data so rows in the result set are used for the lag() but not in the result set, then use a subquery:
select t.*
from (select t.*,
datediff(day,
lag(date) over (partition by name order by date),
date
) as diff
from tblData t
) t
where date < '2020-08-03';
Also note the use of the date constant as a string in YYYY-MM-DD format.

Finding id's available in previous weeks but not in current week

How to find if an id which was present in previous weeks but not available in current week on a rolling basis. For e.g
Week1 has id 1,2,3,4,5
Week2 has id 3,4,5,7,8
Week3 has id 1,3,5,10,11
So I found out that id 1 and 2 are missing in week 2 and id 2,4,7,8 are missing in week 3 from previous 2 weeks But how to do this on a rolling window for a large amount of data distributed over a period of 20+ years
Please find the sample dataset and expected output. I am expecting the output to be partitioned based on the week_end Date
Dataset
ID|WEEK_START|WEEK_END|APPEARING_DATE
7152|2015-12-27|2016-01-02|2015-12-27
8350|2015-12-27|2016-01-02|2015-12-27
7152|2015-12-27|2016-01-02|2015-12-29
4697|2015-12-27|2016-01-02|2015-12-30
7187|2015-12-27|2016-01-02|2015-01-01
8005|2015-12-27|2016-01-02|2015-12-27
8005|2015-12-27|2016-01-02|2015-12-29
6254|2016-01-03|2016-01-09|2016-01-03
7962|2016-01-03|2016-01-09|2016-01-04
3339|2016-01-03|2016-01-09|2016-01-06
7834|2016-01-03|2016-01-09|2016-01-03
7962|2016-01-03|2016-01-09|2016-01-05
7152|2016-01-03|2016-01-09|2016-01-07
8350|2016-01-03|2016-01-09|2016-01-09
2403|2016-01-10|2016-01-16|2016-01-10
0157|2016-01-10|2016-01-16|2016-01-11
2228|2016-01-10|2016-01-16|2016-01-14
4697|2016-01-10|2016-01-16|2016-01-14
Excepted Output
Partition1: WEEK_END=2016-01-02
ID|MAX(LAST_APPEARING_DATE)
7152|2015-12-29
8350|2015-12-27
4697|2015-12-30
7187|2015-01-01
8005|2015-12-29
Partition1: WEEK_END=2016-01-09
ID|MAX(LAST_APPEARING_DATE)
7152|2016-01-07
8350|2016-01-09
4697|2015-12-30
7187|2015-01-01
8005|2015-12-29
6254|2016-01-03
7962|2016-01-05
3339|2016-01-06
7834|2016-01-03
Partition3: WEEK_END=2016-01-10
ID|MAX(LAST_APPEARING_DATE)
7152|2016-01-07
8350|2016-01-09
4697|2016-01-14
7187|2015-01-01
8005|2015-12-29
6254|2016-01-03
7962|2016-01-05
3339|2016-01-06
7834|2016-01-03
2403|2016-01-10
0157|2016-01-11
2228|2016-01-14
Please use below query,
select ID, MAX(APPEARING_DATE) from table_name
group by ID, WEEK_END;
Or, including WEEK)END,
select ID, WEEK_END, MAX(APPEARING_DATE) from table_name
group by ID, WEEK_END;
You can use aggregation:
select t.*, max(week_end)
from t
group by id
having max(week_end) < '2016-01-02';
Adjust the date in the having clause for the week end that you want.
Actually, your question is a bit unclear. I'm not sure if a later week end would keep the row or not. If you want "as of" data, then include a where clause:
select t.id, max(week_end)
from t
where week_end < '2016-01-02'
group by id
having max(week_end) < '2016-01-02';
If you want this for a range of dates, then you can use a derived table:
select we.the_week_end, t.id, max(week_end)
from (select '2016-01-02' as the_week_end union all
select '2016-01-09' as the_week_end
) we cross join
t
where t.week_end < we.the_week_end
group by id, we.the_week_end
having max(t.week_end) < we.the_week_end;

Getting maximum sequential streak with events - updated question

I've previously posted a similar question to this, but an update on the parameters has meant that the solution posted wouldn't work, and I've had trouble trying to work out how to integrate the revised requirement. I'm not sure the protocol in here- it appears that I can't post an updated question to the original post at Getting maximum sequential streak with events
I’m looking for a single query, if possible, running PostgreSQL 9.6.6 under pgAdmin3 v1.22.1
I have a table with a date and a row for each event on the date:
Date Events
2018-12-10 1
2018-12-10 1
2018-12-10 0
2018-12-09 1
2018-12-08 0
2018-12-08 0
2018-12-07 1
2018-12-06 1
2018-12-06 1
2018-12-06 0
2018-12-06 1
2018-12-04 1
2018-12-03 0
I’m looking for the longest sequence of dates without a break. In this case, 2018-12-08 and 2018-12-03 are the only dates with no events, there are two dates with events between 2018-12-08 and today, and three between 2018-12-8 and 2018-12-07 - so I would like the answer of 3.
I know I can group them together with something like:
Select Date, count(Date) from Table group by Date order by Date Desc
To get just the most recent sequence, I’ve got something like this- the subquery returns the most recent date with no events, and the outer query counts the dates after that date:
select date, count(distinct date) from Table
where date>
( select date from Table
group by date
having count (case when Events is not null then 1 else null end) = 0
order by date desc
fetch first row only)
group by date
But now I need the longest streak, not just the most recent streak.
I had assumed when I posted previously that there were rows for every date in the range. But this assumption wasn't correct, so the answer given doesn't work. I also need the query to return the start and end date for the range.
Thank you!
You can assign group by doing a cumulative count of the 0s. Then count the distinct dates in each group:
select count(*), min(date), max(date), count(distinct date)
from (select t.*,
count(*) filter (where events = 0) over (order by date) as grp
from t
) t
group by grp
order by count(distinct date) desc
limit 1;

Oracle get the last date for one month

I am not very good with Queries and Database.
I have the the following data table
Date ID Value
20160601 1 300
20160607 1 301
20160601 2 600
20160607 2 601
20160501 1 250
20160507 1 240
20160501 2 800
20160507 2 801
my requirement is to select the last date of a given month for each ID and show the value.
for example, If I choose month 5 the result would be:
Date ID Value
20160507 1 240
20160507 2 801
and so on based on the month the user will enter.
I know it may look simple but I am really stuck and I would appreciate some help. Thanks.
Assuming date is an actual date column (as it should be), you can use extract to compare the month value, and then the row_number() over ... analytic function to get the latest row per id value:
select date, id, value
from (select date, id, value,
row_number() over (partition by id order by date desc) as rn
from tbl
where extract(month from date) = 5)
where rn = 1
Of course, I assume that your actual date column is called something else, as date is a reserved word.
Find the maximum date then select all rows with that date.
select *
from table
where date = (select max(date) from table where date like '201605%')