Get the Recent changed value from History Table - sql

I have a history table with the following values
CREATE TABLE History (SnapShotDate DATETIME, UID VARCHAR(10), DUEDATE DATETIME)
INSERT INTO History VALUES ('03-23-2015','PT-01','2015-04-22')
INSERT INTO History VALUES ('03-30-2015','PT-01','2015-04-20')
INSERT INTO History VALUES ('04-06-2015','PT-01','2015-06-30')
INSERT INTO History VALUES ('03-23-2015','PT-02','2015-04-22')
INSERT INTO History VALUES ('03-30-2015','PT-02','2015-04-22')
INSERT INTO History VALUES ('04-06-2015','PT-02','2015-04-22')
INSERT INTO History VALUES ('03-23-2015','PT-03','2015-04-18')
INSERT INTO History VALUES ('03-30-2015','PT-03','2015-04-22')
INSERT INTO History VALUES ('04-06-2015','PT-03','2015-04-22')
I need an output in the below format. I need the most recent changed value for any given UID. Please help me in getting the below result
OUTPUT
UID PreviousDueDate CurrentDueDate
----------------------------------------
PT-01 2015-04-20 2015-06-30
PT-02 2015-04-22 2015-04-22
PT-03 2015-04-18 2015-04-22
Thanks

You can try with this SQL:
select UID,date_format(min(DUEDATE), '%Y-%m-%d') as PreviousDueDate,date_format(max(DUEDATE), '%Y-%m-%d') as CurrentDueDate from History group by UID;

I've never used the LAG function before so but seems super easy!!!
; WITH CTE AS (
SELECT UID,
LAG(DUEDATE,1,NULL) OVER (PARTITION BY UID ORDER BY SnapShotDate ASC) AS PreviousDueDate,
DUEDATE AS CurrentDueDate,
ROW_NUMBER() OVER (PARTITION BY UID ORDER BY SnapShotDate DESC) AS RowNumber
FROM History
)
SELECT UID, PreviousDueDate, CurrentDueDate
FROM CTE
WHERE ROWNUMBER = 1
Here is the fiddle.

You should use Convert function in sql server.
SELECT A.UID
,CONVERT(varchar(10),B.DUEDATE, 20) as PreviousDueDate
,CONVERT(varchar(10),A.DUEDATE, 20) as CurrentDueDate
FROM
(
SELECT *,row_number() OVER( PARTITION BY UID ORDER BY SnapShotDate DESC) AS ROWID
FROM History
)A
LEFT JOIN
(
SELECT *,row_number() OVER( PARTITION BY UID ORDER BY SnapShotDate DESC) AS ROWID
FROM History
)B ON A.UID=B.UID AND B.ROWID=2
WHERE A.ROWID=1
GROUP BY A.UID,A.DUEDATE,B.DUEDATE
Output:
UID PreviousDueDate CurrentDueDate
PT-01 2015-04-20 2015-06-30
PT-02 2015-04-22 2015-04-22
PT-03 2015-04-22 2015-04-22
PT-04 2015-04-22 2015-04-18

SELECT UID,
(SELECT DUEDATE FROM History WHERE SnapShotDate=(SELECT MIN(SnapShotDate) FROM History h2 WHERE h2.UID=h1.UID) )AS PreviousDueDate
(SELECT DUEDATE FROM History WHERE SnapShotDate=(SELECT MAX(SnapShotDate) FROM History WHERE h2.UID=h1.UID) )AS CurrentDueDate
FROM History h1
GROUP BY UID

SELECT UID,
(SELECT MIN(DUEDATE) FROM History HS WHERE HS.UID = H.UID GROUP BY UID )AS PreviousDueDate,
(SELECT Max(DUEDATE) FROM History HS WHERE HS.UID = H.UID GROUP BY UID )AS CurrentDueDate
FROM History H
GROUP BY UID

Related

Create a repost of latest and second latest value

I have products audits table looks like this
id
product_id
column_updated
value
timestamp
1
product_1
name
Big Shoes.
"18 September 2022 6:42:50 PM GMT+05:30"
2.
product_1
name
Green Shoes
"18 September 2022 6:42:43 PM GMT+05:30"
3.
product_1
name
Big Green Shoes
"18 September 2022 6:43:43 PM GMT+05:30"
I want to show report of latest change happened on column
in form like below
product_id
column_updated
latest_value
previous_value
product_1
name
Green Shoes
Big Green Shoes
I have prepared a query to fetch last 2 record but not sure how I can merge them to form a view like this?
my query is
select product_id, column_updated, value
from audits
where product_id = 'product_1'
and column_updated = 'name'
order by timestamp desc
limit 2;
Please suggest any approach for this, Thanks in advance!
You need to use LEADa swindow function to hget the latest and previous value
WITH CTE as
(select product_id,
column_updated,
value as latest_value,
lead(value) over (
partition by product_id,column_updated order by timestamp desc
) as previous_value,
ROW_NUMBER() over (
partition by product_id,column_updated order by timestamp desc
) rn
from audits
where product_id = 'product_1'
and column_updated = 'name')
SELECT product_id, column_updated,latest_value,previous_value FROM CTE WHERE rn = 1
product_id
column_updated
latest_value
previous_value
product_1
name
Big Green Shoes
Big Shoes.
SELECT 1
fiddle
This problem can be solved by combination of window functions and CTE:
with data as (
select
product_id,
column_updated,
value,
lag(value) over (partition by product_id, column_updated order by updated_at asc) prev_value,
row_number() over (partition by product_id, column_updated order by updated_at desc) rn,
updated_at
from log
) select
product_id,
column_updated,
value,
prev_value,
updated_at
from data
where rn = 1;
online sql editor
where lag give us previous value and row_number give ability to filter only last change
You don't need both row_number and lag like the other answers. You can do it with just row_number. Give it a row number and then join back with the prior value having row number 2.
WITH rownumbered AS (
SELECT product_id, column_updated, value, updated_at
ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY updated_at DESC) rn,
FROM log
)
SELECT d.product_id, d,column_updated, d.value, p.value as prevous_value
FROM rownumbered d
JOIN rownumbered p ON d.product_id = p.product_id and p.rn = 2
WHERE d.rn = 1;
You may want to group by product_id and name -- if that is the case it looks like this:
WITH rownumbered AS (
SELECT product_id, column_updated, value, updated_at
ROW_NUMBER() OVER (PARTITION BY product_id, column_updated ORDER BY updated_at DESC) rn,
FROM log
)
SELECT d.product_id, d,column_updated, d.value, p.value as prevous_value
FROM rownumbered d
JOIN rownumbered p ON d.product_id = p.product_id
and d.column_updated = p.column_updated
and p.rn = 2
WHERE d.rn = 1;
can you use lag to get the previous value? https://www.postgresqltutorial.com/postgresql-window-function/postgresql-lag-function/
select product_id,
lag(column_updated) over (
partition by product_id order by timestamp desc
) as column_updated,
column_updated as latest_value
from ...

How to select the min and max date from a table into another table on the same row? in SQL

So I have an example of a table like below:
ID
Category
AdmissionDate
DischargeDate
A1
A
2017-07-20
2017-07-21
A1
B
2017-07-27
2017-07-28
I would like to select the Min and Max date and also create two new columns based on the min and max date as below:
ID
MinAdmissionDate
MaxDischargeDate
AdmittedCategory
DischargeCategory
A1
2017-07-20
2017-07-28
A
B
The admitted category would be based on the MinAdmissionDate while the dischargeCategory would be based on the MaxDischargeDate
You could try joining to grouped table:
select
grouped.ID,
grouped.AdmissionDate,
grouped.DischargeDate,
admission.Category admissionCategory,
discharge.Category dischargeCategory
from
(
select
ID,
min(AdmissionDate) AdmissionDate,
max(DischargeDate) DischargeDate
from testTable
group by ID
) [grouped]
left join testTable [admission] on
[grouped].ID = [admission].ID and
[grouped].AdmissionDate = [admission].AdmissionDate
left join testTable [discharge] on
[grouped].ID = [discharge].ID and
[grouped].DischargeDate = [discharge].DischargeDate
Database fiddle.
Try something like this:
WITH cte As
(
SELECT
ID,
Category,
AdmissionDate,
DischargeDate,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY AdmissionDate) As ARN,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DischargeDate DESC) As DRN
FROM
YourTable
)
SELECT
A.ID,
A.AdmissionDate As MinAdmissionDate,
D.DischargeDate As MaxDischargeDate,
A.Category As AdmittedCategory,
D.Category As DischargeCategory
FROM
cte As A
INNER JOIN cte As D
ON D.ID = A.ID
And A.ARN = 1
And D.DRN = 1
;
Demo
ROW_NUMBER

select the latest result based on DateTime field

I have a simple table with only 4 fields.
http://sqlfiddle.com/#!3/06d7d/1
CREATE TABLE Assessment (
id INTEGER IDENTITY(1,1) PRIMARY KEY,
personId INTEGER NOT NULL,
dateTaken DATETIME,
outcomeLevel VARCHAR(2)
)
INSERT INTO Assessment (personId, dateTaken, outcomeLevel)
VALUES (1, '2014-04-01', 'L1')
INSERT INTO Assessment (personId, dateTaken, outcomeLevel)
VALUES (1, '2014-04-05', 'L2')
INSERT INTO Assessment (personId, dateTaken, outcomeLevel)
VALUES (2, '2014-04-03', 'E3')
INSERT INTO Assessment (personId, dateTaken, outcomeLevel)
VALUES (2, '2014-04-07', 'L1')
I am trying to select for each "personId" their latest assessment result based on the dateTaken.
So my desired output for the following data would be.
[personId, outcomeLevel]
[1, L2]
[2, L1]
Thanks,
Danny
Try this:
;with cte as
(select personId pid, max(dateTaken) maxdate
from assessment
group by personId)
select personId, outcomeLevel
from assessment a
inner join cte c on a.personId = c.pid
where c.maxdate = a.dateTaken
order by a.personId
;with Cte as (Select personId,outcomeLevel, C= ROW_NUMBER()
over(PARTITION By personId Order By dateTaken desc)
From #Assessment
)
Select * from cte where C=1
Sample here
SELECT asst.personId,
asst.outcomeLevel
FROM dbo.Assessment asst
WHERE asst.dateTaken=(SELECT MAX(ast.dateTaken)
FROM assessment ast
WHERE asst.personid=ast.personId)
ORDER BY asst.personId
Result will be like this
personId outcomeLevel
1 L2
2 L1
Here is a possible solution using common table expression:
WITH cte AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY personId ORDER BY dateTaken DESC) AS rn
, personId
, outcomeLevel
FROM
[dbo].[Assessment]
)
SELECT
personId
, outcomeLevel
FROM
cte
WHERE
rn = 1
About CTEs
A common table expression (CTE) can be thought of as a temporary result set that is defined within the execution scope of a single SELECT, INSERT, UPDATE, DELETE, or CREATE VIEW statement. A CTE is similar to a derived table in that it is not stored as an object and lasts only for the duration of the query. Unlike a derived table, a CTE can be self-referencing and can be referenced multiple times in the same query. From MSDN: Using Common Table Expressions
try this:
SELECT a.personId, a.outcomeLevel
FROM Assessment a
INNER JOIN
(
SELECT max(dateTaken) as datetaken1, personId
FROM Assessment
GROUP BY personId ) b
ON a.dateTaken = b.datetaken1
demo: http://sqlfiddle.com/#!3/06d7d/9
Idea is to first derive a table with the max dates per person and then join that with the original table on the date field so you can get the outcome level for this maxed date...
This should work perfectly without cte :
SELECT [Table4].[personId], [Table4].[outcomeLevel]
FROM (
SELECT [Table1].[personId]
FROM [Assessment] AS [Table1]
GROUP BY [Table1].[personId]
) AS [Table2]
CROSS APPLY (
SELECT TOP (1) [Table3].[personId], [Table3].[outcomeLevel], [Table3].[dateTaken]
FROM [Assessment] AS [Table3]
WHERE [Table2].[personId] = [Table3].[personId]
ORDER BY [Table3].[dateTaken] DESC
) AS [Table4]
ORDER BY [Table4].[dateTaken] DESC

SQL select latest record of particular student with particular status

Please help me to select latest record of each student with status=1. I have a table called stdData and columns
Student ID FDate Status
12 2014-03-12 1
12 2014-03-15 1
13 2014-02-03 1
13 2014-02-04 0
13 2014-02-05 1
How can I select latest record of each student with status=1?
You need to use group by
select student_id, max(date)
from table_name
where status=1
group by student_id;
fiddle
if you are using sql server then try this
Select top(1) * from StudentTable where status =1 order by student_id desc
In this query it is clear that status = 1 there for i add it in my select, like this:
Select Student_ID ,max(Date) Date, 1 status From table1
where status = 1 Group by Student_ID;
SQL Fiddle
In Sqlserver
Create table Student(
ID int identity(1,1) primary key not null,
S_Date datetime,
Status bit
)
insert into Student values ('2014-03-11',1)
insert into Student values ('2014-03-12',0)
insert into Student values ('2014-03-13',1)
insert into Student values ('2014-03-14',0)
insert into Student values ('2014-03-15',1)
select top 1 * from Student where Status=1 Order By S_Date Desc
You can use ROW_NUMBER function to achieve this:
SELECT Student_ID, Date , Status
FROM
(
SELECT ROW_NUMBER() OVER (PARTITION BY Student_ID ORDER BY Date DESC) AS rn, Student_ID, Date , Status
FROM your_table
WHERE Status = 1
) tab
WHERE tab.rn = 1
try this !
;with cte as
(
select *,rn=row_number() over(partition by Student_Id order by Date desc) from #t
)
select * from cte where rn=1 and status=1
SEE DEMO
try this !
SELECT LAST(column_name) FROM table_name;

selecting all values in GroupBy

I have a scenario wherein i have three columns in my table. ID(String),Desc (string) TerminationDate, Last Update Date(Time).
There is no primary key, so there might be multiple rows with same set of data but LastUpdate Date will always be different.
I need to write a SP wherein i need to get the latest modified result(ID,Desc, termination date). pls see the example below
ID Desc TerminationDate LastUpdtDt
A test 01-01-2013 01-01-2013
A test1 01-03-2013 25-01-2013
A test 01-01-2013 26-03-2013
B test 01-01-2011 01-01-2013
The result i shuld get is
A test 01-01-2013 26-03-2013
B test 01-01-2011 01-01-2013
Let me know in case you need more information.
SELECT ID, [DESC], TerminationDate, LastUpdtDt
FROM
(
SELECT ID, [DESC], TerminationDate, LastUpdtDt,
ROW_NUMBER() OVER(PARTITION BY ID
ORDER BY LastUpdtDt DESC) rn
FROM TableName
) ss
WHERE rn = 1
SQLFiddle Demo
You could return the rows with the max(LastUpdtDt) using a subquery:
select t1.id,
t1.[desc],
t1.terminationdate,
t1.LastUpdtDt
from yt t1
inner join
(
select max(LastUpdtDt) LastUpdtDt, id
from yt
group by id
) t2
on t1.id = t2.id
and t1.LastUpdtDt = t2.LastUpdtDt;
See SQL Fiddle with Demo.
SELECT ID ,
DESC ,
TERMINATION_DATE ,
LAST_UPDATE
FROM ( SELECT ID ,
DESC ,
TERMINATION_DATE ,
LAST_UPDATE ,
ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY LAST_UPDATE DESC ) SERIAL_ORDER
FROM LAST_UPDATE
) B
WHERE SERIAL_ORDER = 1