Get latest record from a subset in a Query - sql

I have two related tables.
Table 1:
recordid | OrderNumber | MobileNumber
1 | 1234 | 9999999999
2 | 1234 | 9888888888
3 | 1234 | 9777777777
4 | 5433 | 9666666666
5 | 1444 | 9555555555
6 | 1444 | 9444444444
7 | 1544 | 9333333333
8 | 1632 | 9222222222
Table 2
recordid | modifiedon
1 | 15/1/2013
2 | 17/1/2013
3 | 13/1/2013
4 | 10/1/2013
5 | 16/1/2013
6 | 01/1/2013
7 | 09/1/2013
8 | 08/1/2013
what i want to do is get a unique set of OrderNumber and their corresponding MobileNumbers. If there is are more than one record for one OrderNumber, then the query should get OrderNumber and MobileNumber of the latest modified record.
So basically i should get the following result.
OrderNumber | MobileNumber
1234 | 9888888888
5433 | 9666666666
1444 | 9555555555
1544 | 9333333333
1632 | 9222222222
i have tried
select OrderNumber, MobileNumber from Table1
where OrderNumber in
(
Select Distinct table1. rderNumber, table2.ModifiedOn
from Table1, Table2
group by table2.ModifiedOn desc
)
This is urgent and I would be very greatly to receive quick responses.

It's easier with a CTE and ROW_NUMBER:
WITH cte AS
(SELECT t1.ordernumber,
t1.mobilenumber,
RN = Row_number()
OVER (
partition BY t1.ordernumber
ORDER BY t2, modifiedon DESC)
FROM table1 t1
INNER JOIN table2 t2
ON t1.recordid = t2.recordid)
SELECT ordernumber,
mobilenumber
FROM cte
WHERE rn = 1
Apart from that, you had a DESC after a GROUP BY.

select *
from
(
select t1.*,
row_number()
over (PARTITION BY t1.OrderNumber
ORDER BY t2.modifiedon DESC ) as rn
from t1
left join t2 on (t1.recordid=t2.recordid)
)
where RN=1

Related

Gather the max of a set of data by 2 columns in SQL?

I am trying to get the latest of a set of columns by a PersonID out of a set of YearIDs.
If I have a table like this:
| DataID | PersonID | YearID | Data1A | Data1B | Data2A | Data2B |
|--------|----------|--------|--------|--------|--------|--------|
| 1 | 888 | A100 | d | 0.00 | a | 1.00 |
| 2 | 888 | A101 | NULL | NULL | b | 2.00 |
| 3 | 888 | A102 | c | 3.00 | NULL | NULL |
| 4 | 333 | A100 | a | 3.40 | e | 4.00 |
| 5 | 333 | A101 | d | 0.00 | NULL | NULL |
| 6 | 333 | A102 | NULL | NULL | NULL | NULL |
How do I get the latest of column sets Data1A, Data1B and Data2A, Data2B sorted by YearID per PersonID?
This is given that Data1A and Data1B are related and Data2A and Data2B are related and can not be separated, and most recent year is A102. DataID is just an incremental PK column.
My resulting table should look like this, with Year being removed as it's no longer necessary. It should ignore NULLs but not 0's:
| DataID | PersonID | Data1A | Data1B | Data2A | Data2B |
|--------|----------|--------|--------|--------|--------|
| 1 | 888 | c | 3.00 | b | 2.00 |
| 2 | 333 | d | 0.00 | e | 4.00 |
This is what I have so far, but I don't know how to take into account the fact that I want the 'max'/latest of a set of Years by PersonID. Right now it gets the max of each column but I want the most recent valid data by latest year, and it also has Data1 and Data2 not being related at all but I need them to be.
SELECT DISTINCT
T1.SID,
GroupedT1.Data1,
GroupedT1.Data2,
FROM #Table1 T1
INNER JOIN
(SELECT SID,
MAX(Data1) AS Data1,
MAX(Data2) AS Data2,
FROM #Table1
GROUP BY PersonID) GroupedT1
ON T1.PersonID = GroupedT1.PersonID
Editing thanks to Gordon for the previous answer, this is how I tried to fix my new problem:
With this solution I'm trying to get the latest for Data1 and Data2, ignoring as many NULL columns as there is, and picking data from any YearID as long as it's the latest. So if in the year A102, Data1A is NULL then it should pick year A101's Data1A, and if Data2A is null for many years, it should pick the latest (in this case, year A100). At the moment it's close but it only picks by row, and needs to pick by year and with any number of NULL data.
select t1.PersonID, t1.Data1A, t1.Data1B, t1.Data2A, t1.Data2B
from (select t1.*,
row_number() over (partition by SID order by
(case when Data1A is not null then 1 else 2 end),
(case when Data2A is not null then 1 else 2 end),
YearID desc) as seqnum
from #Table1 t1
) t1
where seqnum = 1
This answers the original question.
I think you want a simple filtering before applying logic such as row_number():
select t1.*
from (select t1.*,
row_number() over (partition by personid order by yearid desc) as seqnum
from #table1 t1
where data1 is not null and data2 is not null
) t1
where seqnum = 1;
EDIT:
To answer the revised question, you need to handle each columns separately. You can do this using outer apply:
select p.personid, d1.data1, d2.data2, . . .
from (select distinct personid from #table1) p outer apply
(select top (1) t1.data1
from #table1 t1
where t1.personid = p.personid and t1.data1 is not null
order by t1.yearid desc
) d1 outer apply
(select top (1) t1.data2
from #table1 t1
where t1.personid = p.personid and t1.data2 is not null
order by t1.yearid desc
) d2 . . .
You can use the not exists keywork
SELECT DataID, PersonID, Data1, Data2
FROM #Table1 T1
where not exists(select 1 from #Table1 T2
where T1.DataID = T2.DataID and T2.YearID > T1.YearID)

SELECT only latest record of an ID from given rows

I have this table shown below...How do I select only the latest data of the id based on changeno?
+----+--------------+------------+--------+
| id | data | changeno | |
+----+--------------+------------+--------+
| 1 | Yes | 1 | |
| 2 | Yes | 2 | |
| 2 | Maybe | 3 | |
| 3 | Yes | 4 | |
| 3 | Yes | 5 | |
| 3 | No | 6 | |
| 4 | No | 7 | |
| 5 | Maybe | 8 | |
| 5 | Yes | 9 | |
+----+---------+------------+-------------+
I would want this result...
+----+--------------+------------+--------+
| id | data | changeno | |
+----+--------------+------------+--------+
| 1 | Yes | 1 | |
| 2 | Maybe | 3 | |
| 3 | No | 6 | |
| 4 | No | 7 | |
| 5 | Yes | 9 | |
+----+---------+------------+-------------+
I currently have this SQL statement...
SELECT id, data, MAX(changeno) as changeno FROM Table1 GROUP BY id;
and clearly it doesn't return what I want. This should return an error because of the aggrerate function. If I added fields under the GROUP BY clause it works but it doesn't return what I want. The SQL statement is by far the closest I could think of. I'd appreciate it if anybody could help me on this. Thank you in advance :)
This is typically referred to as the "greatest-n-per-group" problem. One way to solve this in SQL Server 2005 and higher is to use a CTE with a calculated ROW_NUMBER() based on the grouping of the id column, and sorting those by largest changeno first:
;WITH cte AS
(
SELECT id, data, changeno,
rn = ROW_NUMBER() OVER (PARTITION BY id ORDER BY changeno DESC)
FROM dbo.Table1
)
SELECT id, data, changeno
FROM cte
WHERE rn = 1
ORDER BY id;
You want to use row_number() for this:
select id, data, changeno
from (SELECT t.*,
row_number() over (partition by id order by changeno desc) as seqnum
FROM Table1 t
) t
where seqnum = 1;
Not a well formed or performance optimized query but for small tasks it works fine.
SELECT * FROM TEST
WHERE changeno IN (SELECT MAX(changeno)
FROM TEST
GROUP BY id)
for other alternatives :
DECLARE #Table1 TABLE
(
id INT, data VARCHAR(5), changeno INT
);
INSERT INTO #Table1
SELECT 1,'Yes',1
UNION ALL
SELECT 2,'Yes',2
UNION ALL
SELECT 2,'Maybe',3
UNION ALL
SELECT 3,'Yes',4
UNION ALL
SELECT 3,'Yes',5
UNION ALL
SELECT 3,'No',6
UNION ALL
SELECT 4,'No',7
UNION ALL
SELECT 5,'Maybe',8
UNION ALL
SELECT 5,'Yes',9
SELECT Y.id, Y.data, Y.changeno
FROM #Table1 Y
INNER JOIN (
SELECT id, changeno = MAX(changeno)
FROM #Table1
GROUP BY id
) X ON X.id = Y.id
WHERE X.changeno = Y.changeno
ORDER BY Y.id

How to get Previous Value for Null Values

I have the Below Data in my Table.
| Id | FeeModeId |Name | Amount|
---------------------------------------------
| 1 | NULL | NULL | 20 |
| 2 | 1 | Quarter-1 | 5000 |
| 3 | NULL | NULL | 2000 |
| 4 | 2 | Quarter-2 | 8000 |
| 5 | NULL | NULL | 5000 |
| 6 | NULL | NULL | 2000 |
| 7 | 3 | Quarter-3 | 6000 |
| 8 | NULL | NULL | 4000 |
How to write such query to get below output...
| Id | FeeModeId |Name | Amount|
---------------------------------------------
| 1 | NULL | NULL | 20 |
| 2 | 1 | Quarter-1 | 5000 |
| 3 | 1 | Quarter-1 | 2000 |
| 4 | 2 | Quarter-2 | 8000 |
| 5 | 2 | Quarter-2 | 5000 |
| 6 | 2 | Quarter-2 | 2000 |
| 7 | 3 | Quarter-3 | 6000 |
| 8 | 3 | Quarter-3 | 4000 |
Since you are on SQL Server 2012... here is a version that uses that. It might be faster than other solutions but you have to test that on your data.
sum() over() will do a running sum ordered by Id adding 1 when there are a value in the column and keeping the current value for null values. The calculated running sum is then used to partition the result in first_value() over(). The first value ordered by Id for each "group" of rows generated by the running sum has the value you want.
select T.Id,
first_value(T.FeeModeId)
over(partition by T.NF
order by T.Id
rows between unbounded preceding and current row) as FeeModeId,
first_value(T.Name)
over(partition by T.NS
order by T.Id
rows between unbounded preceding and current row) as Name,
T.Amount
from (
select Id,
FeeModeId,
Name,
Amount,
sum(case when FeeModeId is null then 0 else 1 end)
over(order by Id) as NF,
sum(case when Name is null then 0 else 1 end)
over(order by Id) as NS
from YourTable
) as T
SQL Fiddle
Something that will work pre SQL Server 2012:
select T1.Id,
T3.FeeModeId,
T2.Name,
T1.Amount
from YourTable as T1
outer apply (select top(1) Name
from YourTable as T2
where T1.Id >= T2.Id and
T2.Name is not null
order by T2.Id desc) as T2
outer apply (select top(1) FeeModeId
from YourTable as T3
where T1.Id >= T3.Id and
T3.FeeModeId is not null
order by T3.Id desc) as T3
SQL Fiddle
Please try:
select
a.ID,
ISNULL(a.FeeModeId, x.FeeModeId) FeeModeId,
ISNULL(a.Name, x.Name) Name,
a.Amount
from tbl a
outer apply
(select top 1 FeeModeId, Name
from tbl b
where b.ID<a.ID and
b.Amount is not null and
b.FeeModeId is not null and
a.FeeModeId is null order by ID desc)x
OR
select
ID,
ISNULL(FeeModeId, bFeeModeId) FeeModeId,
ISNULL(Name, bName) Name,
Amount
From(
select
a.ID , a.FeeModeId, a.Name, a.Amount,
b.ID bID, b.FeeModeId bFeeModeId, b.Name bName,
MAX(b.FeeModeId) over (partition by a.ID) mx
from tbl a left join tbl b on b.ID<a.ID
and b.FeeModeId is not null
)x
where bFeeModeId=mx or mx is null
SELECT
T.ID,
ISNULL(T.FeeModeId,
(SELECT TOP 1 FeeModeId
FROM TableName AS T1
WHERE ID < T.ID AND FeeModeId IS NOT NULL
ORDER BY ID DESC)) AS FeeModeId,
ISNULL(Name,
(SELECT TOP 1 Name
FROM TableName
WHERE ID < T.ID AND Name IS NOT NULL
ORDER BY ID DESC)) AS Name,
T.Amount
FROM
TableName AS T
try this -
SELECT Id,
CASE
WHEN Feemodeid IS NOT NULL THEN
Feemodeid
ELSE
(SELECT Feemodeid
FROM Table_Name t_2
WHERE t_2.Id = (SELECT MAX(Id)
FROM Table_Name t_3
WHERE t_3.Id < t_1.Id
AND Feemodeid IS NOT NULL))
END Feemodeid,
CASE
WHEN NAME IS NOT NULL THEN
NAME
ELSE
(SELECT NAME
FROM Table_Name t_2
WHERE t_2.Id = (SELECT MAX(Id)
FROM Table_Name t_3
WHERE t_3.Id < t_1.Id
AND NAME IS NOT NULL))
END NAME,
Amount
FROM Table_Name t_1
id name
1 toto
2 NULL
3 NULL
4 titi
5 NULL
6 NULL
7 tutu
8 NULL
9 NULL
SELECT
id_table
,name
FROM
(
SELECT
T_01.id AS 'id_table'
,max(T_02.id) AS 'id_name'
FROM
names AS T_01
cross join
(
SELECT
id
,name
FROM
names
WHERE
name IS NOT NULL
) AS T_02
WHERE
T_02.id <= T_01.id
GROUP BY
T_01.id
) AS tt02
left join names
ON names.id = tt02.id_name
id_table name
1 toto
2 toto
3 toto
4 titi
5 titi
6 titi
7 tutu
8 tutu
9 tutu

How to select row with the latest timestamp from duplicated rows in a database table?

I have a table with duplicate & triplicate rows - how do I select the rows that are duplicated but have the latest timestamp as well as the un-duped rows?
-------------------------------------
| pk_id | user_id | some_timestamp |
|-------------------------------------|
| 1 | 123 | 10-Jun-12 14.30 |
| 2 | 123 | 19-Jun-12 21.50 |
| 3 | 567 | 10-Jun-12 09.23 |
| 4 | 567 | 12-Jun-12 09.45 |
| 5 | 567 | 13-Jun-12 08.40 |
| 6 | 890 | 13-Jun-12 08.44 |
-------------------------------------
So that I end up with:
-------------------------------------
| pk_id | user_id | some_timestamp |
|-------------------------------------|
| 2 | 123 | 19-Jun-12 21.50 |
| 5 | 567 | 13-Jun-12 08.40 |
| 6 | 890 | 13-Jun-12 08.44 |
-------------------------------------
SELECT * FROM (
SELECT pk_id,
user_id,
some_timestamp,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY some_timestamp DESC) col
FROM table) x
WHERE x.col = 1
try this
select * from table
where some_timestamp
in (select max(some_timestamp)
from table group by user_id)
Try this, I made a SQLFIDDLE which returns the correct set of data
SELECT * FROM YourTable AS T1
INNER JOIN
( SELECT user_id , MAX(some_timestamp) AS some_timestamp FROM YourTable
GROUP BY user_id
) AS T2
ON T1.User_Id = T2.User_Id AND T1.some_timestamp = T2.some_timestamp
ORDER BY 1
http://sqlfiddle.com/#!6/f7bba/6
Try this:
select * from my_table
where (user_id, some_timestamp) IN (select user_id, max(some_timestamp) from my_table group by user_id);
select YourTable.*
from
YourTable JOIN
(select User_Id, Max(Some_Timestamp) as Mx
from YourTable
group by User_Id) Mx
on YourTable.User_Id=Mx.User_Id
and YourTable.Some_Timestamp=Mx.Mx

Getting the whole row from grouped result

Here's a sample database table :
| ID | ProductID | DateChanged | Price
| 1 | 12 | 2011-11-11 | 93
| 2 | 2 | 2011-11-12 | 12
| 3 | 3 | 2011-11-13 | 25
| 4 | 4 | 2011-11-14 | 17
| 5 | 12 | 2011-11-15 | 97
Basically, what I want to happen is get the latest price of grouped by ProductID.
The result should be like this :
| ID | ProductID | Price
| 2 | 2 | 12
| 3 | 3 | 25
| 4 | 4 | 17
| 5 | 12 | 97
If you notice, the first row is not there because there is a new price for ProductID 12 which is the row of ID 5.
Basically, it should be something like get ID,ProductID and Price grouped by productID where DateChanged is the latest.
SELECT ID, ProductId, Price
FROM
(
SELECT ID, ProductId, Price
, ROW_NUMBER() OVER (PARTITION BY ProductID ORDER BY DateChanged DESC) AS rowNumber
FROM yourTable
) AS t
WHERE t.rowNumber = 1
SELECT ID, ProductID,DateChanged, Price
FROM myTable
WHERE ID IN
(
SELECT MAX(ID)
FROM myTable
GROUP BY ProductID
)
select a.id, a.productid, a.price
from mytable a,
(select productid, max(datechanged) as maxdatechanged
from mytable
group by productid) as b
where a.productid = b.productid and a.datechanged = b.maxdatechanged
SELECT ID, ProductId, Price
from myTable A
where DateChanged >= all
(select DateChanged
from myTable B
where B.ID = A.ID);