How to get column value from next record - mysql

I have a following result set:
POST | DATE
--------------------------------------
Senior Software Engg. | 2018-04-18
Software Engg. | 2017-04-18
Assoc. Software Engg. | 2016-04-18
SQL query:
SELECT DISTINCT designation_id as id, d.title as POST, DATE(dt_datetime) as DATE
FROM users_history_check u
INNER JOIN
designations d
ON d.id = u.designation_id
WHERE u.id = $userID
ORDER BY DATE DESC
I want to fetch next record and perform date difference calculation in months, and display records.
Expected Output :
POST | Start DATE | End DATE | MONTHS
---------------------------------------------------------------
Senior Software Engg. | 2018-04-18 | - |
Software Engg. | 2017-04-18 | 2018-04-18 | 12
Assoc. Software Engg. | 2016-04-18 | 2017-04-18 | 12
Something like :
SELECT DISTINCT designation_id as id, d.title as POST, DATE(dt_datetime) as Start DATE, NEXT_RECORD(DATE(dt_datetime)) as End DATE, DATEDIFF(Start DATE, End DATE) as MONTHS....
Any help is very much appreciated. Thanks.

SELECT `POST`,
`DATE`,
IFNULL(END_DATE,'') AS END_DATE,
IFNULL(MONTH,'') AS MONTH
FROM
(SELECT `POST`,
`DATE`,
#prev AS END_DATE,
TIMESTAMPDIFF(month,DATE,#prev) AS MONTH,
#prev := T.DATE AS VarDate
FROM Table1 T,
(SELECT #prev:=null)R
) T1
OUTPUT
POST DATE END_DATE MONTH
Senior Software Engg. 2018-04-18
Software Engg. 2017-04-18 2018-04-18 12
Assoc. Software Engg. 2016-04-18 2017-04-18 12
Demo Link
http://sqlfiddle.com/#!9/33260/15
EXPLANATION:
In Sub query, I am saving the Date value in #prev variable and in each row using that variable to calculate the END_DATE before assigning the current date value from Column Date.
Then using the sub query to present the data in a proper way.

You can get the previous date using variables:
SELECT id, post, date,
(CASE WHEN (#tmp_prevd := #prevd) = NULL THEN NULL -- never happens
WHEN (#prevd := date) = NULL THEN NULL -- never happens
ELSE #tmp_prevd
END) as prev_date
FROM (SELECT DISTINCT designation_id as id, d.title as POST, DATE(dt_datetime) as DATE
FROM users_history_check u INNER JOIN
designations d
ON d.id = u.designation_id
WHERE u.id = $userID
ORDER BY DATE DESC
) ud CROSS JOIN
(SELECT #prevd := NULL) params;
This is tricky, because all references to a variable need to be in the same expression. That is why this uses CASE in a rather arcane way.
In MySQL 8.0 and basically all other databases, you could use LEAD() instead.

Try This....
SELECT T1.POST,T1.DATE ,T2.DATE,DATEDIFF(MONTH,T1.DATE,T2.DATE)
FROM(
SELECT ROW_NUMBER()OVER(ORDER BY DATE DESC) AS SlNo,*
FROM Mytable)T1
LEFT JOIN (SELECT ROW_NUMBER()OVER(ORDER BY DATE DESC)+1 AS SlNo,*
FROM Mytable)T2
ON(T1.SlNo = T2.SlNo )

I suggest using self-join like this
select d1.post,
d1.d `start DATE`,
min(d2.d) `end DATE`,
timestampdiff(month, d1.d, min(d2.d)) `MONTHS`
from data d1
left join data d2 on d1.d < d2.d
group by d1.post, d1.d
dbfiddle demo
The data table is the result of your SQL. It can be added using WITH or you may use subquery as well.

SELECT * ,Datediff(Month,[Date],endate)
FROM
(
SELECT *,Lead( [Date], 1, Null) OVER (
ORDER BY [Date]) AS Endate --INTO SourceTable
FROM
(
SELECT 'Senior Software Engg.' POST , '2018-04-18' DATE UNION ALL
SELECT 'Software Engg.' POST , '2017-04-18' DATE UNION ALL
SELECT 'Assoc. Software Engg.' POST , '2016-04-18' DATE
)A
)B
ORDER BY [Date] desc

Related

Need to Pick Max Date when status = N otherwise No in MYSQL

I have a table which have records like this
ID DATEADD STATUS
'A0011' '04/01/2018 11:58:31' 'C'
'A0011' '31/05/2019 10:02:36' 'N'
'B0022' '04/01/2018 11:58:31' 'N'
'B0022' '31/05/2019 10:02:36' 'N'
'B0022' '30/04/2020 19:44:36' 'C'
'C0033' '04/01/2018 11:58:31' 'N'
'C0033' '30/05/2019 06:02:36' 'C'
'C0033' '29/04/2020 05:44:36' 'C'
I'm trying to get the Max Date for each ID which have STATUS = 'N'. If I get MAX DATE and STATUS = 'C' then I don't want that record.
Output :
ID DATEADD STATUS
'A0011' '31/05/2019 10:02:36' 'N'
SCRIPT :
SELECT I.* FROM INVOICE I
INNER JOIN (
Select ID,MAX(DATEADD)DATEADD,STATUS FROM INVOICE WHERE STATUS = 'N'
GROUP BY ID,STATUS) O
ON I.ID = O.ID AND O.DATEADD = I.DATEADD
But I'm not able to get desired output.
If your mysql version support the window function, we can try to use ROW_NUMBER window function to get each ID latest DATEADD then compare the STATUS
SELECT *
FROM (
SELECT *,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY DATEADD DESC) rn
FROM INVOICE
) t1
WHERE rn = 1 AND STATUS = 'N'
sqlfiddle
if your MySQL version didn't support the window function we can try to use correlated subquery
SELECT *
FROM (
SELECT *, (SELECT COUNT(*)
FROM INVOICE tt
WHERE tt.ID = t1.ID AND tt.DATEADD > t1.DATEADD) rn
FROM INVOICE t1
) t1
WHERE rn = 1 AND STATUS = 'N'
sqlfiddle
You can use NOT EXISTS:
SELECT i1.*
FROM INVOICE i1
WHERE i1.STATUS = 'N'
AND NOT EXISTS (
SELECT 1
FROM INVOICE i2
WHERE i2.ID = i1.ID
AND STR_TO_DATE(i2.DATEADD, '%d/%m/%Y %H:%i:%s') > STR_TO_DATE(i1.DATEADD, '%d/%m/%Y %H:%i:%s')
);
If the column's DATEADD data type is DATETIME or TIMESTAMP the last condition would be simpler:
...AND i2.DATEADD > i1.DATEADD
See the demo.
We can use ORDER BY and LIMIT 1 to get the row that we want without using any functions, sub-queries, CTE etc.
Thank you to D-Shih for the test schema.
If we want the maximum date with status 'N' for each ID we can use the second query.
SELECT
ID,
DATEADD,
STATUS
FROM INVOICE
ORDER BY
STATUS DESC,
DATEADD DESC
LIMIT 1;
ID | DATEADD | STATUS
:---- | :--------- | :-----
A0011 | 2019-05-31 | N
SELECT
ID,
MAX(DATEADD) AS DATEADD,
STATUS
FROM INVOICE
WHERE STATUS = 'N'
GROUP BY ID
ORDER BY ID;
ID | DATEADD | STATUS
:---- | :--------- | :-----
A0011 | 2019-05-31 | N
B0022 | 2019-05-31 | N
C0033 | 2018-01-04 | N
db<>fiddle here

SQL running total from previous year

How to do running total or cumulative sum from this query? Is it possible to run by correlated subquery? The cumulative sum results will be show as 'New value'.
SELECT
sum(data2.quantity/1000) AS UnitMT
FROM
data2
INNER JOIN itmnocate ON data2.item = itmnocate.ItemNumber
and Source in ('imported','local','by product')
WHERE date1 >= DATE_FORMAT('2018-04-12', '%Y-01-01')- INTERVAL 1 YEAR
AND date1 <= DATE_FORMAT('2018-04-12', '%Y-12-31') - INTERVAL 1 YEAR
AND data2.unit = 'KG'
and data2.customeracc not in (select Customeraccount from custlist WHERE Custcat = 'bcsb')
GROUP BY month(date1)
This is a cumulative problem If your mysql version support window function you can use SUM with window function to do cumulative.
The DATE1 column can be used as the basis for order by to do cumulative.
SELECT *,
sum(UnitMT) over (order by month(date1)) 'New value'
FROM T t1
sqlfiddle
If your mysql version didn't support window function, you can try to use subquery in select to do cumulative.
CREATE TABLE T( date1 DATE,UnitMT int);
INSERT INTO T VALUES ('2017-01-01',66535);
INSERT INTO T VALUES ('2017-02-01',108337);
INSERT INTO T VALUES ('2017-03-01',132767);
INSERT INTO T VALUES ('2017-04-01',100687);
INSERT INTO T VALUES ('2017-05-01',125151);
Query 1:
SELECT *,
(SELECT SUM(UnitMT) FROM T tt WHERE month(tt.date1) <= month(t1.date1)) 'New value'
FROM T t1
Results:
| date1 | UnitMT | New value |
|------------|--------|-----------|
| 2017-01-01 | 66535 | 66535 |
| 2017-02-01 | 108337 | 174872 |
| 2017-03-01 | 132767 | 307639 |
| 2017-04-01 | 100687 | 408326 |
| 2017-05-01 | 125151 | 533477 |
Note
T symbol your current result set data.
You could try this query, it's efficient and works an all MySQL versions:
select #cumSum := 0;
select UnitMT, #cumSum := #cumSum + UnitMT
from tbl
order by date1;
Demo
For your specific problem, you can use variables and a subquery:
SELECT mon, UnitMT,
(#sum := #sum + UnitMT) as running_sum
FROM (SELECT month(date1) as mon, sum(data2.quantity/1000) AS UnitMT
FROM data2 INNER JOIN
itmnocate
ON data2.item = itmnocate.ItemNumber AND
Source IN ('imported', 'local', 'by product')
WHERE date1 >= DATE_FORMAT('2018-04-12', '%Y-01-01') - INTERVAL 1 YEAR AND
date1 <= DATE_FORMAT('2018-04-12', '%Y-12-31') - INTERVAL 1 YEAR AND
data2.unit = 'KG' AND
data2.customeracc not in (select Customeraccount from custlist WHERE Custcat = 'bcsb')
GROUP BY month(date1)
ORDER BY month(date1)
) m CROSS JOIN
(SELECT #sum := 0) params;

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)

MYSQL - Total registrations per day

I have the following structure in my user table:
id(INT) registered(DATETIME)
1 2016-04-01 23:23:01
2 2016-04-02 03:23:02
3 2016-04-02 05:23:03
4 2016-04-03 04:04:04
I want to get the total (accumulated) user count per day, for all days in DB
So result should be something like
day total
2016-04-01 1
2016-04-02 3
2016-04-03 4
I tried some sub querying, but somehow i have now idea how to achieve this with possibly 1 SQL statement. Of course if could group by per day count and add them programmatically, but i don't want to do that if possible.
You can use a GROUP BY that does all the counts, without the need of doing anything programmatically, please have a look at this query:
select
d.dt,
count(*) as total
from
(select distinct date(registered) dt from table1) d inner join
table1 r on d.dt>=date(r.registered)
group by
d.dt
order by
d.dt
the first subquery returns all distinct dates, then we can join all dates with all previous registrations, and do the counts, all in one query.
An alternative join condition that can give some improvements in performance is:
on d.dt + interval 1 day > r.registered
Not sure why not just use GROUP BY, without it this thing will be more complicated, anyway, try this;)
select
date_format(main.registered, '%Y-%m-%d') as `day`,
main.total
from (
select
table1.*,
#cnt := #cnt + 1 as total
from table1
cross join (select #cnt := 0) t
) main
inner join (
select
a.*,
if(#param = date_format(registered, '%Y-%m-%d'), #rowno := #rowno + 1 ,#rowno := 1) as rowno,
#param := date_format(registered, '%Y-%m-%d')
from (select * from table1 order by registered desc) a
cross join (select #param := null, #rowno := 0) tmp
having rowno = 1
) sub on main.id = sub.id
SQLFiddle DEMO

Aging of Data Week Wise in Mysql

Here i have a table of task that contains task_id, created_date, completed_date, priority .
I need output that give me the records priority wise and no of week task open .
if completed_date is null than it should calculate the difference from current date.
I need mysql query that return me the record like
-----------------------------------------------------------------
|week of created | priority | Count | no of week task open |
-----------------------------------------------------------------
|40 | hi | 20 | 2(week diff of completed |
and create date)
Here is the query that give me the data when completed date is exist.
select yearweek(created_Date) AS year_week
, priority, count(*) as cnt
, yearweek(completed_date) - yearweek(created_date) as Diff
from lss_analyseTaskLogView
where diffs is not null
and diffs <> ''
and completed_date is not null
and completed_Date <> '0000-00-00'
group
by Diff
, priority;
Here is the query that give me the data when completed date is not exist.
select yearweek(created_Date) as year_week
, priority
, count(*) as cnt
, yearweek(CURRENT_DATE) - yearweek(created_date) as Diff
from lss_analyseTaskLogView
where diffs is not null
and diffs <> ''
and (completed_date is null or completed_Date = '0000-00-00 00:00')
group
by Diff
, priority;
I had combine count of both query when week difference and priority same using query
select A.year_week, A.priority, A.cnt + B.cnt As Cnt, A.Diff from
(select yearweek(created_Date) AS year_week ,priority, count(*) as cnt,
yearweek(completed_date) - yearweek(created_date) as Diff
from lss_analyseTaskLogView
where diffs is not null and diffs <> '' and completed_date is not null
and completed_Date <> '0000-00-00' group by Diff,priority) A,
(select yearweek(created_Date) as year_week,priority, count(*) as cnt,
yearweek(CURRENT_DATE) - yearweek(created_date) as Diff
from lss_analyseTaskLogView
where diffs is not null and diffs <> ''
and (completed_date is null or completed_Date = '0000-00-00 00:00')
group by Diff,priority) B
where A.Diff = B.Diff and A.priority = B.priority and A.year_week = B.year_week;
but how can i get record of first two query which are not consider in last query.
how can i get the desire set of record.
suggest me any query regarding my question .
Thanks in Advance.