Get employees who received a raise in 2 consecutive years - mysql

I am trying to Get employees who received a raise in 2 consecutive years, in this case employee 1000 is the right answer.
here is the data and the sql i have tried.
EID
SALARY
YEAR
1000
10,000
2016
1000
7,500
2015
1000
6,000
2014
1001
8,000
2016
1001
7,500
2015
1002
7,500
2016
1002
7,500
2015
1002
5,000
2014
1003
6,000
2016
1003
7,000
2015
1003
5,000
2014
i have used following code however it gets only row number by EID and not calcualtion of last year and present year, i need to find employee who got raise in 2 consecutive years.
output
select * ,
row_number() over(partition by eid order by salary and year desc)as rn
from gs;

You can do it using the LEAD window function that compute the two consecutive previous value of the salary. Then you can check how many employees have at least one row with salary1 < salary2 < salary3.
SELECT DISTINCT
eid
FROM (
SELECT
eid,
year,
salary,
(LEAD(salary, 1) OVER(PARTITION BY eid ORDER BY year DESC)) AS prev_salary1,
(LEAD(salary, 2) OVER(PARTITION BY eid ORDER BY year DESC)) AS prev_salary2
FROM
employees
) consecutive3
WHERE
salary > prev_salary1
AND
prev_salary1 > prev_salary2
The assumption is that there are no missing years for which a salary of a dependent was not recorded.
Here's the fiddle: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=8c0d8a1deec8e77bb32a173656c3e386.
EDIT: Detailed explanation
Let's do the example of Jennifer, who has worked for five years and got these salaries:
2018 -> 65000
2017 -> 55000
2016 -> 50000
She's a candidate for being selected as her salary was raised three times consecutively.
1. LEAD(salary, 1) OVER(PARTITION BY eid ORDER BY year DESC)
Allows you to get the salary for year "Y" and the salary for year "Y-1":
("year" -> "salary", "previous_salary")
2018 -> 65000 , 55000
2017 -> 55000 , 50000
2016 -> 50000 , NULL
2. LEAD(salary, 2) OVER(PARTITION BY eid ORDER BY year DESC)
Allows you to get the salary for year "Y" and the salary for year "Y-1":
("year" -> "salary", "previous_salary", "previous_salary_by_2_years")
2018 -> 65000 , 55000 , 50000
2017 -> 55000 , 50000 , NULL
2016 -> 50000 , NULL , NULL
3. WHERE salary > prev_salary1 AND prev_salary1 > prev_salary2
Some filtering on the employees who
have their year3 salary higher than their year2 salary (salary > prev_salary1)
have their year2 salary higher than their year1 salary (prev_salary1 > prev_salary2)

I know that this has already been answered but here is my take using the lag function to determine if there was an increase from the previous year and ran that twice.
SELECT *
FROM (
SELECT
t2.*,
LAG(increase) over (partition by eid order by year) AS increaseNextYear
FROM (
SELECT
t1.*,
COALESCE(salary - LAG(salary) over (partition by eid order by year), 0) > 0 AS increase
FROM tbl_test t1
) as t2
) t3 where increase AND increaseNextYear

with
dates as
(
select
a.*,
dense_rank() OVER (
partition by eid
order by year desc, salary
)
as rn,
case
when
lead(salary,2)over(partition by eid order by year, salary)
>
lead(salary,1)over(partition by eid order by year, salary)
and
lead(salary,1)over(partition by eid order by year, salary)
>
salary
then
1
else
0
end
as flag
from
employees a
)
select
eid
from
dates
where
rn = 3
and flag = 1

Not a beautiful query, but straight-forward: find employees who had a salary in a year where the salary in the previous year was lower and the salary in the year before that even lower. Using LAG is more elegant, but I thought I'd throw this in, just to show an alternative.
select *
from employee
where exists
(
select null
from gs
where gs.eid = employee.id
and exists
(
select null
from gs prev
where prev.eid = gs.eid
and prev.year = gs.year - 1
and prev.salary < gs.salary
and exists
(
select null
from gs prevprev
where prevprev.eid = prev.eid
and prevprev.year = prev.year - 1
and prevprev.salary < prev.salary
)
)
);
Same thing with a join:
select *
from employee
where exists
(
select null
from gs
join gs prev on prev.eid = gs.eid
and prev.year = gs.year - 1
and prev.salary < gs.salary
join gs prevprev on prevprev.eid = prev.eid
and prevprev.year = prev.year - 1
and prevprev.salary < prev.salary
where gs.eid = employee.id
);

For versions prior to 8.0 (mine is 5.7) which lack the cutting edge features of the newer one, I tried a procedure to accomplish the job. First and foremost, get all the eid which have no less than three years' salary record, which is the minimum requirement of the consecutive bonus. The rest is to fetch and compare using a cursor from the eid pool. The result is stored in a temporary table t .
delimiter //
drop procedure if exists lucky_emp//
create procedure lucky_emp()
begin
declare old_eid int default 0;
declare old_salary int;
declare new_eid int ;
declare new_salary int;
declare bonus_year int;
declare fin bool default false;
declare c cursor for select eid,salary from salary where eid in(select eid from salary group by eid having count(eid)>=3) order by eid,year;
declare continue handler for not found set fin=true;
drop temporary table if exists t ;
create temporary table t (t_eid int);
open c;
lp:loop
fetch c into new_eid ,new_salary;
if fin=true then
leave lp;
end if;
if new_eid !=old_eid then
set old_eid=new_eid,old_salary=0,bonus_year=0;
end if;
if new_salary> old_salary then
set bonus_year=bonus_year+1,old_salary=new_salary;
else
set bonus_year=0;
end if;
if bonus_year=3 and new_eid not in(select t_eid from t) then
insert t values(new_eid);
end if;
end loop lp;
end//
delimiter ;
select * from t ;

Select a.*, b.prev_sal1, b.prev_sal2
from employees a
join (
Select eid ,year,
lag(salary,1) over (partition by eid order by year) as prev_sal1,
lag(salary,2) over (partition by eid order by year) as prev_sal2
from employees ) b
on a.eid=b.eid
and a.year = b.year
where salary>prev_sal1 and prev_sal1>prev_sal2
fiddle: https://dbfiddle.uk/rfGv31zM

Related

Display summary data for every month in SQL for last 3 years

I have this T-SQL query that would be the total count of claims, dollar value for the date declared.
But I need to find the count and dollar value for each month beginning starting 2016 and until today / yesterday. I want to load the result set to a new table. Any thoughts or suggestions? Thanks in advance!
T-SQL query
DECLARE #AsofDATE AS DATE
DECLARE #AsofDateINT AS INT
SET #AsofDATE = '1/1/2018'
SET #AsofDateINT = 20180101
SELECT
COUNT(S.ClaimNum) Count_of_Claims,
SUM(ReserveIndemnityAmount) AS RD_REserve,
#AsofDATE AS AsofDate
-- INTO #tempRD
FROM
(SELECT
f.*,
ROW_NUMBER() OVER (PARTITION BY ClaimNum ORDER BY f.ModifiedDate DESC) AS Row_order_desc
FROM
[dbo].[Snapshot] f
WHERE
CAST(f.ModifiedDate AS DATE) <= #AsofDATE) S
LEFT OUTER JOIN
(SELECT
ClaimKey, SUM( t.LossRsvAmt) AS ReserveIndemnityAmount
FROM
Stg.Claim_Transaction t
WHERE
TransactionDate < #AsofDateINT
GROUP BY
ClaimKey) T ON t.ClaimKey = s.ClaimID
WHERE
S.Row_order_desc = 1
AND S.DerivedClaimStatus NOT IN ('Closed', 'Cancelled', 'Abandoned', 'Record only', 'Opened in error' )
AND s.specialty = 'RD'
Current result:
Count_of_Claims RD_REserve AsofDate
-------------------------------------------------
15317 112192.15 2018-01-01
Expected result:
Count_of_Claims RD_REserve AsofDate
-------------------------------------------------
15317 112192.15 2017-01-12
15567 111592.15 2017-01-11
15356 15492.15 2017-01-10
Your AsofDate is hardcoded to return. Why not replace that with ModifiedDate?
so something like
select
count(s.claimnum) countofclaims
,sum(amount) amount
,cast(eomonth(modifieddate) as date) [asofdate]
from your query...
group by
cast(eomonth(modifieddate) as date)

Calculate Date by number of working days from a certain Startdate

I've got two tables, a project table and a calendar table. The first containts a startdate and days required. The calendar table contains the usual date information, like date, dayofweek, and a column is workingday, which shows if the day is a saturday, sunday, or bank holiday (value = 0) or a regular workday (value = 1).
For a certain report I need write a stored procedure that calculates the predicted enddate by adding the number of estimated workddays needed.
Example:
**Projects**
Name Start_Planned Work_days_Required
Project A 02.05.2016 6
Calendar (04.05 is a bank holdiday)
Day Weekday Workingday
01.05.2016 7 0
02.05.2016 1 1
03.05.2016 2 1
04.05.2016 3 0
05.05.2016 4 1
06.05.2016 5 1
07.05.2016 6 0
08.05.2016 7 0
09.05.2016 1 1
10.05.2016 2 1
Let's say, the estimated number of days required is given as 6 (which leads to the predicted enddate of 10.05.2016). Is it possible to join the tables in a way, which allows me to put something like
select date as enddate_predicted
from calendar
join projects
where number_of_days = 6
I would post some more code, but I'm quite stuck on how where to start.
Thanks!
You could get all working days after your first date, then apply ROW_NUMBER() to get the number of days for each date:
SELECT Date, DayNum = ROW_NUMBER() OVER(ORDER BY Date)
FROM Calendar
WHERE IsWorkingDay = 1
AND Date >= #StartPlanned
Then it would just be a case of filtering for the 6th day:
DECLARE #StartPlanned DATE = '20160502',
#Days INT = 6;
SELECT Date
FROM ( SELECT Date, DayNum = ROW_NUMBER() OVER(ORDER BY Date)
FROM Calendar
WHERE WorkingDay = 1
AND Date >= #StartPlanned
) AS c
WHERE c.DayNum = #Days;
It's not part of the question, but for future proofing this is easier to acheive in SQL Server 2012+ with OFFSET/FETCH
DECLARE #StartPlanned DATE = '20160502',
#Days INT = 6;
SELECT Date
FROM dbo.Calendar
WHERE Date >= #StartPlanned
AND WorkingDay = 1
ORDER BY Date
OFFSET (#Days - 1) ROWS FETCH NEXT 1 ROWS ONLY
ADDENDUM
I missed the part earlier about having another table, and the comment about putting it into a cursor has prompted me to amend my answer. I would add a new column to your calendar table called WorkingDayRank:
ALTER TABLE dbo.Calendar ADD WorkingDayRank INT NULL;
GO
UPDATE c
SET WorkingDayRank = wdr
FROM ( SELECT Date, wdr = ROW_NUMBER() OVER(ORDER BY Date)
FROM dbo.Calendar
WHERE WorkingDay = 1
) AS c;
This can be done on the fly, but you will get better performance with it stored as a value, then your query becomes:
SELECT p.Name,
p.Start_Planned,
p.Work_days_Required,
EndDate = c2.Date
FROM Projects AS P
INNER JOIN dbo.Calendar AS c1
ON c1.Date = p.Start_Planned
INNER JOIN dbo.Calendar AS c2
ON c2.WorkingDayRank = c1.WorkingDayRank + p.Work_days_Required - 1;
This simply gets the working day rank of your start date, and finds the number of days ahead specified by the project by joining on WorkingDayRank (-1 because you want the end date inclusive of the range)
This will fail, if you ever plan to start your project on a non working day though, so a more robust solution might be:
SELECT p.Name,
p.Start_Planned,
p.Work_days_Required,
EndDate = c2.Date
FROM Projects AS P
CROSS APPLY
( SELECT TOP 1 c1.Date, c1.WorkingDayRank
FROM dbo.Calendar AS c1
WHERE c1.Date >= p.Start_Planned
AND c1.WorkingDay = 1
ORDER BY c1.Date
) AS c1
INNER JOIN dbo.Calendar AS c2
ON c2.WorkingDayRank = c1.WorkingDayRank + p.Work_days_Required - 1;
This uses CROSS APPLY to get the next working day on or after your project start date, then applies the same join as before.
This query returns a table with a predicted enddate for each project
select name,min(day) as predicted_enddate from (
select c.day,p.name from dbo.Calendar c
join dbo.Calendar c2 on c.day>=c2.day
join dbo.Projects p on p.start_planned<=c.day and p.start_planned<=c2.day
group by c.day,p.work_days_required,p.name
having sum(c2.workingday)=p.work_days_required
) a
group by name
--This gives me info about all projects
select p.projectname,p.Start_Planned ,c.date,
from calendar c
join
projects o
on c.date=dateadd(days,p.Work_days_Required,p.Start_Planned)
and c.isworkingday=1
now you can use CTE like below or wrap this in a procedure
;with cte
as
(
Select
p.projectnam
p.Start_Planned ,
c.date,datediff(days,p.Start_Planned,c.date) as nooffdays
from calendar c
join
projects o
on c.date=dateadd(days,p.Work_days_Required,p.Start_Planned)
and c.isworkingday=1
)
select * from cte where nooffdays=6
use below logic
CREATE TABLE #proj(Name varchar(50),Start_Planned date,
Work_days_Required int)
insert into #proj
values('Project A','02.05.2016',6)
CReATE TABLE #Calendar(Day date,Weekday int,Workingday bit)
insert into #Calendar
values('01.05.2016',7,0),
('02.05.2016',1,1),
('03.05.2016',2,1),
('04.05.2016',3,0),
('05.05.2016',4,1),
('06.05.2016',5,1),
('07.05.2016',6,0),
('08.05.2016',7,0),
('09.05.2016',1,1),
('10.05.2016',2,1)
DECLARE #req_day int = 3
DECLARE #date date = '02.05.2016'
--SELECT #req_day = Work_days_Required FROM #proj where Start_Planned = #date
select *,row_number() over(order by [day] desc) as cnt
from #Calendar
where Workingday = 1
and [Day] > #date
SELECT *
FROM
(
select *,row_number() over(order by [day] desc) as cnt
from #Calendar
where Workingday = 1
and [Day] > #date
)a
where cnt = #req_day

Date format not working in mysql procedure

{
delimiter &&
CREATE PROCEDURE `BPM_CLMBR_RPT_PROC` (IN customer_id INT,IN fromdate date,IN todate date)
BEGIN
-- distingushing the columns up,didntmove,down as well as group concatination
SELECT
RESPONSEDATE ,
ifnull(GROUP_CONCAT(CLIMBER, ''),0) AS 'up',
ifnull(GROUP_CONCAT(STATIC, ''),0) AS 'didntmove',
ifnull(GROUP_CONCAT(FALLER, ''),0) AS 'down',
ID
FROM
(
-- transposing the rows to column
SELECT
CASE
WHEN report = 'STATIC' THEN count
END AS 'STATIC',
CASE
WHEN report = 'CLIMBER' THEN count
END AS 'CLIMBER',
CASE
WHEN REPORT = 'FALLER' THEN COUNT
END AS 'FALLER',
RESPONSEDATE,
ID
FROM
(
-- counting the number of records in STATIC,CLIMBER,FALLER
SELECT
REPORT,RESPONSEDATE,COUNT(REPORT) count,ID
FROM (
-- grouping the records into STATIC,CLIMBER and FALLER
SELECT
CASE
WHEN (FNL.PREVIOUS_SCORE BETWEEN 0 AND 6 AND FNL.CURRENT_SCORE BETWEEN 0 AND 6) THEN 'STATIC'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 7 AND 8 AND FNL.CURRENT_SCORE BETWEEN 7 AND 8) THEN 'STATIC'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 9 AND 10 AND FNL.CURRENT_SCORE BETWEEN 9 AND 10) THEN 'STATIC'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 0 AND 6 AND FNL.CURRENT_SCORE BETWEEN 7 AND 8) THEN 'CLIMBER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 0 AND 6 AND FNL.CURRENT_SCORE BETWEEN 9 AND 10) THEN 'CLIMBER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 7 AND 8 AND FNL.CURRENT_SCORE BETWEEN 9 AND 10) THEN 'CLIMBER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 7 AND 8 AND FNL.CURRENT_SCORE BETWEEN 0 AND 6) THEN 'FALLER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 9 AND 10 AND FNL.CURRENT_SCORE BETWEEN 0 AND 6) THEN 'FALLER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 9 AND 10 AND FNL.CURRENT_SCORE BETWEEN 7 AND 8) THEN 'FALLER'
END AS 'REPORT',
FNL.RESPONSEDATE,
ID
FROM (
SELECT
-- group concatination using space but only one client responses is expected
CLIENTID,
CLIENTNAME,
GROUP_CONCAT(TEMP.CURRENT_SCORE, '') AS 'CURRENT_SCORE',
GROUP_CONCAT(TEMP.PREVIOUS_SCORE, '') AS 'PREVIOUS_SCORE',
GROUP_CONCAT(TEMP.COMMENT,'') AS 'COMMENT',
max(id) ID,
max(responsedate) RESPONSEDATE
FROM
(
-- Top two npsscores are taken into account and only 1st comment is taken
SELECT
CLIENTID,id,CLIENTNAME,
CASE
WHEN RANK = 1 THEN npsscore
END AS 'CURRENT_SCORE',
CASE
WHEN RANK = 2 THEN npsscore
END AS 'PREVIOUS_SCORE',
CASE
WHEN RANK=1 THEN COMMENT
END AS 'COMMENT',
RESPONSEDATE
FROM
(
-- NPS_CLIENT_STATUS is calculated and only the 1st and 2nd rank holders are selected
SELECT
CLMBR_RPT.*,CASE
WHEN CLMBR_RPT.NPSSCORE BETWEEN 0 AND 6 THEN 'DETRACTOR'
WHEN CLMBR_RPT.NPSSCORE BETWEEN 7 AND 8 THEN 'PASSIVE'
ELSE 'PROMOTER'
END 'NPS_CLIENT_STATUS'
FROM
(
-- rank funtion is in corporated rownum() in Oracle
SELECT
a.*,
(CASE a.CLIENTID
WHEN #curType THEN #curRow:=#curRow + 1
ELSE #curRow:=1 AND #curType:=a.CLIENTID
END) AS rank
FROM
(SELECT
NSR.*
FROM
nps_summary_report NSR
INNER JOIN
-- innerjoin is done to get all the client id for a given date span which jas multiple records in the nps_summary_report table
-- joined with nps_summary_report table will eliminate all the records in the nps_summary_report table which is not having
-- customerid , multiple responses and date
-- this is the innermost query and will execute first and eliminate all the unwanted records
(SELECT
CLIENTID
FROM
nps_summary_report
WHERE CUSTOMERID=customer_id -- TO BE PROVIDED
-- AND RESPONSEDATE between STR_TO_DATE(fromdate, '%m/%d/%Y') AND STR_TO_DATE(todate, '%m/%d/%Y') -- TO BE PROVIDED
AND RESPONSEDATE > fromdate and RESPONSEDATE< todate -- TO BE PROVIDED
-- AND RESPONSEDATE BETWEEN date_format(STR_TO_DATE(#fromdate, '%m/%d/%Y'),'%Y-%m-%d') AND date_format(STR_TO_DATE(#todate, '%m/%d/%Y'),'%Y-%m-%d')
-- AND RESPONSEDATE BETWEEN date_format(#fromdate,'%Y-%m-%d') AND date_format(#todate,'%Y-%m-%d')
GROUP BY CLIENTID
HAVING COUNT(*) > 1) CLNT_ID ON CLNT_ID.CLIENTID = NSR.CLIENTID ) a, -- REMOVING ALL THE CLIENT WHICH HAVE 1 FEEDBACK
(SELECT #curRow:=0, #curType:='') r
WHERE CUSTOMERID=customer_id -- RETREIVE ALL DATA FOR BOOKMYSHOW ONLY
ORDER BY CLIENTID , RESPONSEDATE ) CLMBR_RPT
WHERE
CLMBR_RPT.RANK BETWEEN 0 AND 2)STG_BMS_CLIMBER_RPT
GROUP BY CLIENTID , CASE
WHEN RANK = 1 THEN npsscore
END , CASE
WHEN RANK = 2 THEN npsscore
END,CASE
WHEN RANK=1 THEN COMMENT
END
) TEMP
GROUP BY CLIENTID) FNL ) TBL
GROUP BY RESPONSEDATE,REPORT)stg_temp) TEMP
GROUP BY RESPONSEDATE
order by RESPONSEDATE desc;
END
&&
delimiter ; }
I am calling the stored procedure by
{ call BPM_CLMBR_RPT_PROC(6,str_to_date('2015-10-01','%Y-%m-%d'),str_to_date('2015-12-31','%Y-%m-%d')); }
The query is returning all the records irrespective of the date constraints .But when a hard coded value is passed inside the code like
{
RESPONSEDATE BETWEEN date_format(STR_TO_DATE('11/1/2015', '%m/%d/%Y'),'%Y-%m-%d') AND date_format(STR_TO_DATE('12/13/2015', '%m/%d/%Y'),'%Y-%m-%d')
}
then the expected result is comming.

MS Access max date and recent date and their respective qty

Looking for MaxDate, its most recent date and the interval between. Of the MaxDate and most recent, I also need the quantities for each so I can also find the interval
Table "tblITEM_InventoryCount" structure is as follows:
Item_No Count Date Qty
001 08/29/2015 12
001 08/15/2015 17
001 07/15/2015 19
Item No 001
Max(CountDate) 08/29/2015
PriorCountDate 08/15/2015
Interval Days (MaxDate-RecentDate) 14
MaxDate Quantity 12
PriorCountDate Quantity 17
Interval Qty (17-12) 5
Currently using a query to find last two count dates for each ITEM_NO
SELECT tblITEM_InventoryCount.ITEM_NO, tblITEM_InventoryCount.Quantity, tblITEM_InventoryCount.CountDate
FROM tblITEM_InventoryCount
WHERE (((tblITEM_InventoryCount.CountDate)>=NthInGroup([tblITEM_InventoryCount].[ITEM_NO],2)))
ORDER BY tblITEM_InventoryCount.ITEM_NO, tblITEM_InventoryCount.CountDate DESC;
Then I am using a second query to calculate my data:
SELECT qryLAST2_InventoryCount_TRANSACTIONS.ITEM_NO, qryLAST2_InventoryCount_TRANSACTIONS.CountDate, (SELECT MAX([CountDate]) FROM [qryLAST2_InventoryCount_TRANSACTIONS] AS [Old Orders] WHERE [Old Orders].[CountDate] < [qryLAST2_InventoryCount_TRANSACTIONS].[CountDate] AND [Old Orders].[ITEM_NO] = [qryLAST2_InventoryCount_TRANSACTIONS].[ITEM_NO]) AS PriorCountDate, [CountDate]-[PriorCountDate] AS DaysInterval, qryLAST2_InventoryCount_TRANSACTIONS.Quantity, (SELECT Last([Quantity]) FROM [qryLAST2_InventoryCount_TRANSACTIONS] AS [OldCount] WHERE [OldCount].[Quantity] < [qryLAST2_InventoryCount_TRANSACTIONS].[Quantity] AND [OldCount].[ITEM_NO] = [qryLAST2_InventoryCount_TRANSACTIONS].[ITEM_NO]) AS PriorQuantity, [Quantity]-[PriorQuantity] AS QuantityInterval, [QuantityInterval]*30/[DaysInterval] AS [Usage]
FROM qryLAST2_InventoryCount_TRANSACTIONS
GROUP BY qryLAST2_InventoryCount_TRANSACTIONS.ITEM_NO, qryLAST2_InventoryCount_TRANSACTIONS.CountDate, qryLAST2_InventoryCount_TRANSACTIONS.Quantity
ORDER BY qryLAST2_InventoryCount_TRANSACTIONS.ITEM_NO, qryLAST2_InventoryCount_TRANSACTIONS.CountDate DESC;
I am not getting the results I need. The query returns two record lines for each item along with their max or last countdate, the previous countdate, intervaldays, qty, last qty, and interval.
I need max or last countdate and its qty count and prior countdate and its qty count.
Any help would be greatly appreciated.
Try this :
select
tab.item_no,
tab.Max_Date,
tab.PriorCountDate,
DateDiff ("d", tab.Max_Date, tab.PriorCountDate) as IntervalDays,
tab.MaxDateQty,
tab.PriorCountDateQty,
( tab.MaxDateQty-tab.PriorCountDateQty) as IntervalQty,
from
( select
temp1.item_no as item_no,
temp1.m as Max_Date,
(select MAX(count_date) from tblITEM_InventoryCount where count_date <> temp1.m ) as PriorCountDate,
temp1.q as MaxDateQty,
(select MAX(Qty) from tblITEM_InventoryCount where Qty <> temp1.q) as PriorCountDateQty,
from
( select item_no as i, Qty as q, MAX(count_date) as m
group by item_no, Qty ) as temp1
inner join
tblITEM_InventoryCount as temp2
on
temp1.item_no = temp2.item_no
)
as tab ;

MySQL sequence create

I need some help pulling records that happen in a sequence in the MySQL environment.
My dataset consists of cross-country games and the winning and losing country. I need to identify countries which have won atleast 3 games in a row. Below is a reproducible example. I created a matches dataset.
CREATE TABLE matches (date DATE, winner CHAR(10), loser CHAR(10));
INSERT INTO matches (date,winner,loser) VALUES (STR_TO_DATE('3-03-2013', '%m-%d-%Y') ,'USA','CHINA');
INSERT INTO matches (date,winner,loser) VALUES (STR_TO_DATE('3-05-2013', '%m-%d-%Y') ,'USA','RUSSIA');
INSERT INTO matches (date,winner,loser) VALUES (STR_TO_DATE('3-06-2013', '%m-%d-%Y') ,'FRANCE','GERMANY');
INSERT INTO matches (date,winner,loser) VALUES (STR_TO_DATE('3-09-2013', '%m-%d-%Y') ,'USA','RUSSIA');
INSERT INTO matches (date,winner,loser) VALUES (STR_TO_DATE('3-11-2013', '%m-%d-%Y') ,'USA','INDIA');
INSERT INTO matches (date,winner,loser) VALUES (STR_TO_DATE('3-15-2013', '%m-%d-%Y') ,'USA','AUSTRALIA');
INSERT INTO matches (date,winner,loser) VALUES (STR_TO_DATE('3-15-2013', '%m-%d-%Y') ,'USA','NEW ZEALAND');
I created another dataset which has a row number for each country ordered by date.
CREATE TABLE matches2
(
date DATE,
winner CHAR(10),
loser CHAR(10),
row INT
);
INSERT INTO matches2
(
row,
winner,
date,
loser
)
SELECT row,
winner,
date ,
loser
FROM
(
SELECT winner,
(#winner:=#winner+1) AS row,
date ,
loser
FROM matches ,
(SELECT #winner := 0) r
) x
ORDER BY date;
The table matches2 looks like below
date winning losing row
2013-03-03 USA CHINA 1
2013-03-05 USA RUSSIA 2
2013-03-06 FRANCE GERMANY 3
2013-03-09 USA RUSSIA 4
2013-03-11 USA INDIA 5
2013-03-15 USA AUSTRALIA 6
2013-03-15 USA NEW ZEALAN 7
As the data shows, USA has won >3 games in a row. how I write a code to capture this sequence ?
You can do this with a sequence of joins:
select m1.*, m2.date, m3.date
from matches2 m1 join
matches2 m2
on m2.row = m1.row + 1 and m2.winner = m1.winner join
matches2 m3
on m3.row = m2.row + 1 and m3.winner = m2.winner join
matches2 m4
on m4.row = m3.row + 1 and m4.winner = m3.winner;
Here's another approach to returning the "winner" of at least three in a row, if we consider only the matches that the country participated in as a series. That is, an intervening match between two different countries isn't considered to break another teams winning streak.
SELECT z.winner
FROM (SELECT #cnt := IF(v.team=#prev_team AND v.winner=#prev_winner,#cnt+1,1) AS cnt
, #prev_team := v.team AS team
, #prev_winner := v.winner AS winner
FROM (SELECT t.team
, m.winner
, m.loser
, m.date
FROM (SELECT #prev_team := NULL, #prev_winnner := NULL, #cnt := 0) i
CROSS
JOIN ( SELECT w.winner AS team
FROM matches w
GROUP BY w.winner
) t
JOIN matches m
ON m.winner = t.team
ORDER BY t.team, m.date
) v
) z
WHERE z.cnt = 3
GROUP BY z.winner
Here's an example test case:
CREATE TABLE matches (`date` DATE, `winner` VARCHAR(12), `loser` VARCHAR(12), `row` INT);
INSERT INTO matches (`date`,`winner`,`loser`,`row`) VALUES
(STR_TO_DATE('3-03-2013', '%m-%d-%Y') ,'USA' ,'CHINA' ,1)
,(STR_TO_DATE('3-05-2013', '%m-%d-%Y') ,'USA' ,'RUSSIA' ,2)
,(STR_TO_DATE('3-06-2013', '%m-%d-%Y') ,'FRANCE' ,'GERMANY' ,3)
,(STR_TO_DATE('3-08-2013', '%m-%d-%Y') ,'USA' ,'RUSSIA' ,4)
,(STR_TO_DATE('3-10-2013', '%m-%d-%Y') ,'FRANCE' ,'RUSSIA' ,5)
,(STR_TO_DATE('3-12-2013', '%m-%d-%Y') ,'SRI LANKA','MALAYSIA' ,6)
,(STR_TO_DATE('3-14-2013', '%m-%d-%Y') ,'USA' ,'AUSTRALIA' ,7)
,(STR_TO_DATE('3-16-2013', '%m-%d-%Y') ,'FRANCE' ,'RUSSIA' ,8)
,(STR_TO_DATE('3-18-2013', '%m-%d-%Y') ,'USA' ,'NEW ZEALAND',9);
In the matches that 'USA' participated in, they won every time. They played 5 matches, and they won 5 matches.
France also won three matches that they participated in, with no "loss" between those wins.
The query in this answer reports both 'USA' and 'FRANCE' as winning "three in a row".