Snapshot Table Status Change - sql

I am trying to write a sql query (in amazon redshift) that counts the number of times that customer goes from not meeting criteria to meeting criteria, so when a 1 occurs the date after a 0.
I'm stuggling to figure out the logic to do this
ID Snapshot_date Meets Criteria
55 1/1/2018 0
55 1/5/2018 1
55 1/10/2018 1
55 1/15/2018 1
55 1/20/2018 0
55 1/25/2018 1

Use lag to get the previous value,check for the conditions and count.
select id,count(*)
from (select id,snapshot_date
,lag(meets_critetria,1) over(partition by id order by snapshot_date) as prev_m_c
from tbl
) t
where prev_m_c = 0 and meets_criteria = 1
group by id

Related

Computing rolling average and standard deviation by dates

I have the below table where I will need to compute the rolling average and standard deviation based on the dates. I have listed below the tables and expected results. I am trying to compute the rolling average for an id based on date. rollAvgA is computed based on metricA. For example, for the first occurrence of id for a particular date the result should return zero as it does not have any preceding values. Please let me know how this can be accomplished?
Current Table :
Date id metricA
8/1/2019 100 2
8/2/2019 100 3
8/3/2019 100 2
8/1/2019 101 2
8/2/2019 101 3
8/3/2019 101 2
8/4/2019 101 2
Expected Table :
Date id metricA rollAvgA
8/1/2019 100 2 0
8/2/2019 100 3 2.5
8/3/2019 100 2 2.3
8/1/2019 101 2 0
8/2/2019 101 3 2.5
8/3/2019 101 2 2.3
8/4/2019 101 2 2.25
You seem to want a cumulative average. This is basically:
select t.*,
avg(metricA * 1.0) over (partition by id order by date) as rollingavg
from t;
The only caveat is that the first value is an average of one value. To handle this, use a case expression:
select t.*,
(case when row_number() over (partition by id order by date) > 1
then avg(metricA * 1.0) over (partition by id order by date)
else 0
end) as rollingavg
from t;

Counting Consecutive Weeks based on separate numeric column

I'm working on a problem where the employees get a certain score each week. They will only have 1 score each week, being saved each Saturday. I want to count the number of consecutive weeks (working backwards from today) that they are above 50. If the previous week is not above 50 then they would have 0 consecutive weeks. If they've had a score above 50 each week for the past year, then they would have 52 consecutive weeks.
I've tried using the Row_Number() function to get this, but can't figure out how to incorporate the score as a factor in that.
This is an example of the data set:
EmpID Last Week Score
A 7/6/2019 60
A 6/29/2019 84
A 6/22/2019 21
B 7/6/2019 41
B 6/29/2019 92
C 7/6/2019 77
C 6/29/2019 55
C 6/22/2019 71
C 6/15/2019 63
This is what I've tried so far
SELECT
EmpID,
EOW,
SCORE,
ROW_NUMBER() OVER(PARTITION BY EMP ORDER BY EOW DESC) AS RN
FROM a
ORDER BY EmpID, EOW DESC
But that only gives me a row count of each employee. I need the count to stop when their score is below 50 as below:
EmpID Last Week Score RN
A 7/6/2019 60 1
A 6/29/2019 84 2
A 6/22/2019 21 -
B 7/6/2019 41 -
B 6/29/2019 92 -
C 7/6/2019 77 1
C 6/29/2019 55 2
C 6/22/2019 71 3
C 6/15/2019 63 4
I then need to get a single number of the consecutive weeks for each employee so that I can join the results to a larger query that pulls additional info about the employee. The scores are in a different table which is why I have to join it. The query should produce a result like:
EmpID Last Week Consecutive Week
A 7/6/2019 2
B 7/6/2019 0
C 7/6/2019 4
Does this make sense? Any help would be appreciated
I used conditional aggregation and running total.
The basic idea is:
If the number >= 50, the derived column will sum 0.
The consecutive zero(s) will stop at the first <50 value.
Then count the number of zeros.
I added the special case [group D]:
('D','7/6/2019' , 51 )
('D','6/29/2019' , 49)
('D','6/22/2019' ,52 )
There will be one single zero in this case.
If there is only one zero, I think the consecutive weeks should be zero instead of one.
I added [group D] into the test sample.
Try this:
SELECT B.EmpID,B.[Last Week], CASE WHEN B.TOTAL <= 1 THEN 0 ELSE B.TOTAL END AS RN
FROM (
SELECT A.EmpID, MAX(EOW) AS [Last Week], SUM(CASE WHEN A.COUNT1 = 0 THEN 1 ELSE 0 END) AS TOTAL
FROM
(
SELECT EMPID,EOW, Score
, SUM(CASE WHEN SCORE >= 50 THEN 0 ELSE 1 END) OVER (PARTITION BY EMPID ORDER BY EOW DESC) AS COUNT1
FROM TEST
GROUP BY EMPID,EOW,Score
)A
GROUP BY A.EmpID
)B
Test Result:
DB<>Fiddle

Get the next and prev row data manipulations in SQL Server

I have a data like below format in table:
Id EmployeeCode JobNumber TransferNo FromDate Todate
--------------------------------------------------------------------------
1 127 1.0 0 01-Mar-19 10-Mar-19
2 127 1.0 NULL 11-Mar-19 15-Mar-19
3 127 J-1 1 16-Mar-19 NULL
4 136 1.0 0 01-Mar-19 15-Mar-19
5 136 J-1 1 16-Mar-19 20-Mar-19
6 136 1.0 2 21-Mar-19 NULL
And I want result like this:
Id EmployeeCode JobNumber TransferNo FromDate Todate
--------------------------------------------------------------------------
2 127 1.0 NULL 01-Mar-19 15-Mar-19
3 127 J-1 1 16-Mar-19 NULL
4 136 1.0 0 01-Mar-19 15-Mar-19
5 136 J-1 1 16-Mar-19 20-Mar-19
6 136 1.0 2 21-Mar-19 NULL
The idea is
If Job is same in continuous than Single row with max id with min date and max date. For example, for employee 127 first job and second job number is same and second and third row is different, then the first and second row will be returned, with minimum fromdate and max todate, and third row will be returned as is.
If job number is different with its next job number than all rows will be returned.
For example: for employee 136: first job number is different with second, second is different with third, so all rows will be returned.
You can group by jobNumber and EmployeeCode and use the Max/Min-Aggregate-Functions to get the dates you want
I doubt you will get a result from simple set-based queries.
So my advice: Declare a cursor on SELECT DISTINCT EmployeeCode .... Within that cursor select all rows with that EmployeeCode. Work in this set to figure out your values and construct a resultset from that.
This is an example of a gaps and islands problem. The solution here is to define the "islands" by their starts, so the process is:
determine when a new grouping begins (i.e. no overlap with previous row)
do a cumulative sum of the the starts to get the grouping value
aggregate
This looks like
select max(id), EmployeeCode, JobNumber,
min(fromdate), max(todate)
from (select t.*,
sum(case when fromdate = dateadd(day, 1, prev_todate) then 0 else 1 end) over
(partition by EmployeeCode, JobNumber order by id
) as grouping
from (select t.*,
lag(todate) over (partition by EmployeeCode, JobNumber order by id) as prev_todate
from t
) t
) t
group by grouping, EmployeeCode, JobNumber;
It is unclear what the logic is for TransferNo. The simplest solution is just min() or max(), but that will not return NULL.

Oracle select and update periodically records

I have a table that includes multiple records duplicated status values.
DEVICE STATUS CHANGE_DATE
1 1 21.11.2017 12:01
1 0 21.11.2017 13:05
1 1 21.11.2017 14:06
1 0 21.11.2017 14:26
1 1 21.11.2017 14:36
2 0 21.11.2017 15:28
2 1 21.11.2017 15:39
Device status change priodically.
First question is, I want to select by device id last status is 1.
Query result will be like this;
DEVICE STATUS CHANGE_DATE
1 1 21.11.2017 14:36
2 1 21.11.2017 15:39
The second query is about update for same result. If data comes like this:
DEVICE STATUS CHANGE_DATE
1 1 11.11.2017 12:36
1 1 21.11.2017 14:36
2 1 21.11.2017 15:39
Device 1 is an old date. And I want to update a record is older 2 days.
How can I create these oracle queries? Select and update older records.
I'm tempted to close the question as too broad. But, I'll answer the first part:
select t.*
from (select t.*,
row_number() over (partition by device order by change_date desc) as seqnum
from t
) t
where seqnum = 1;
I think the "update" should be a separate question.

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;