Fetch Max from a date column grouped by a particular field - sql

I have a table similar to this:
LogId RefId Entered
==================================
1 1 2010-12-01
2 1 2010-12-04
3 2 2010-12-01
4 2 2010-12-06
5 3 2010-12-01
6 1 2010-12-10
7 3 2010-12-05
8 4 2010-12-01
Here, LogId is unique; For each RefId, there are multiple entries with timestamp. What I want to extract is LogId for each latest RefId.
I tried solutions from this link:http://stackoverflow.com/questions/121387/sql-fetch-the-row-which-has-the-max-value-for-a-column. But, it returns multiple rows with same RefId. The LogId as well as RefId should be unique.
Can someone help me with this?
Thanks
Vamyip

You need to use a subquery that extracts the latest Entered value for each RefId, and then join your source table to this on RefId, Entered:
SELECT DISTINCT MyTable.LogId, MyTable.Entered FROM MyTable
INNER JOIN (SELECT RefId, MAX(Entered) as Entered FROM MyTable GROUP BY RefId) Latest
ON MyTable.RefId = Latest.RefId AND MyTable.Entered = Latest.Entered

Since it appears auto-increment log ID, they would be date/time stamped in sequential order. So, by grabbing the last LogID per Reference ID, you'll have the "most recent" one in the "PreQuery" below, then join based on that single ID to the original table to get the actual date stamp info (or other details) you need from the actual log.
select PreQuery.RefID,
PreQuery.LastLogEntry,
L.Entered
from
( select RefID,
Max( LogID ) LastLogEntry
from
YourLog
group by
RefID ) PreQuery,
YourLog L
where
PreQuery.LastLogEntry = L.LogID

To handle the duplicates correctly:
SELECT m.*
FROM (
SELECT DISTINCT refid
FROM mytable
) md
JOIN mytable m
ON m.LogID =
(
SELECT LogID
FROM mytable mi
WHERE mi.refid = md.refid
ORDER BY
mi.refid DESC, mi.entered DESC, mi.logid DESC
LIMIT 1
)
Create an index on mytable (refid, entered, logid) for this to work fast.

Related

SQL - How to select row by compare date from 2 table

I have 2 table like that:
Table1:
ID | COMPANY_NAME | Rank | FIRST_REGIST_DATE
1 A 1 2017-09-01
2 B 2 2017-09-05
Table 2:
ID | COMPANY_NAME | RANK | FIRST_REGIST_DATE
1 A 3 2017-09-03
2 C 4 2017-09-04
I need to SELECT company with the data FIRST_REGIST_DATE and RANK
In case of company have 2 first regist date, we choose the earlier date and RANK greater
(EX: company A above will have first date: 2017-09-01)
The Expect result will like that:
Company A - Rank 3 - Date:2017-09-01
Please have me to SELECT in that case
This technically answers the question but avoids the elephant in the room (which ID takes preference?). As both tables have ID's that may overlap ({B,C} have an ID of 2) rules need to be defined as to which ID takes preference what will the other table ID's be renamed to.
Select COMPANY_NAME
,MIN(FIRST_REGIST_DATE) as REGIST_DATE
from (
SELECT *
FROM #table1
UNION ALL
SELECT *
FROM #table2
) t3
Group by COMPANY_NAME
OP dont change your question (by adding RANK) after the question has been answered.
For your changes: kindly contributed by #toha
Select COMPANY_NAME
,MIN(FIRST_REGIST_DATE) as REGIST_DATE
,MAX(RANK ) as RANK
from ( SELECT *
FROM #table1
UNION ALL
SELECT *
FROM #table2 ) t3
Group by COMPANY_NAME
If I understand the question correctly you have two tables with data containing company details and first registration date and you want to show the row with the earliest first registration date. The following query will help you.
SELECT company_name, MIN(fisrt_regist_date)
(
SELECT company_name, fisrt_regist_date
FROM table1
UNION ALL
SELECT company_name, fisrt_regist_date
FROM table2
) tab1
FROM tab1
GROUP BY company_name
The above query will combine the results of the first table and the second table and then show you the details of the company along with the oldest registration date.

Select a, min(b) but also want C from that same record

Select A, min(b) from TableX
group by a
This works but I want one more piece of information. The output will be one row for each A with A and the min(b) for that A.
But I also want C from that row.
I cannot figure out how to do it!
MS SQL Server 2012
"C" is the sysident of the row.
So table has
Sysident ID Date
1 100 2014-01-01
2 100 2014-01-02
3 200 2014-02-01
4 200 201-002-05
etc
I want output of
Sysident id Date
1 100 2014-01-01
3 200 2014-02-01
I can get the ID and min date with a simple Select ID, Min(date) group by ID but don't know how to get the Sysident for each of the rows.
When I write/edit this, my sample table looks like a table but when it displays it is all run together. I have searched HELP for formatting so it will look like a table but cannot find anything.
The question is very clear (to me). For every unique A, I want the sysident of the row with the oldest date and what that date is.
If you want the first date, you can use min:
select id
, min(sysident)
, min(date)
from YourTable
group by
id
If you want a specific version of sysident, say the first ordered by the date column, you can use SQL Server's row_number():
select *
from (
select row_number() over (
partition by id
order by [date]) as rn
, min([date]) over (partition by id) as min_date
, id
, sysident
from YourTable
) as SubQueryAlias
where rn = 1 -- Only oldest row per value of id
For more answers, check out the greatest-n-per-group tag.

Select particular not grouped column from grouped set

The topic might be a little bit unclear but I couldn't describe in a single sentence what I want to achieve.
Say I have a table that is (columns)
id INT PK
name VARCHAR
date DATE
I have a grouping select
select
name,
max(date)
from table
group by name
that gives me a name and the latest date.
What is the easiest way to join the id column to the current aggregated result set with the id value where the date was the maximum?
Let me explain what my goal is with an example:
The table is filled with the data as follows
id name date
1 david 2012-12-12
2 david 2013-12-02
3 patrick 2014-01-02
4 patrick 2012-11-11
and by my query I'd like to get the following result
id name date
2 david 2013-12-02
3 patrick 2014-01-02
Notice that all the records for name = 'david' are aggregated and the maximum date is selected. How to get the row id for this maximum date?
One option is to use ROW_NUMBER():
SELECT id, name, date
FROM (
SELECT id, name, date,
row_number() over (partition by name order by date desc) rn
FROM yourtable
) t
WHERE rn = 1
SQL Fiddle Demo
Another option is to join the table back to itself using the MAX() aggregate. This option could potentially result in ties if multiple id/name combinations share the same max date:
SELECT t.id, t.name, t.date
FROM yourtable t
JOIN (SELECT name, max(date) maxdate
FROM yourtable
GROUP BY name) t2 on t.name = t2.name AND t.date = t2.maxdate
More Fiddle

SQL Select list of last records with condition

I have the following table
ID Name CodSituation
1 John 1
2 Mary 2
3 Mary 3
4 Mary 4
5 John 5
6 John 2
7 Mary 1
I want to select the Names, ID's and CodSituation for all users where their last entry is CodSituation=2
In these results I will get just the id 6 As Mary's last entry was CodeSituation=4
if more than one users have their latest CodSituation=2 I want them too.
[FINAL EDIT]
After seeing what was posted at the end of this answer I figured out that the user was asking the wrong question:
What they were asking was 'show me everyone who has CodSituation=2' when they meant 'Show me all the users who's last entry in CodSituation field=2'
Here is the correct query for that:
select a.ID, a.Name, a.CodSituation
from table_name a
inner join (
select Name, max(ID) as MaxID
from table_name
group by Name
) b on a.Name = b.Name and a.ID = b.MaxID
where a.CodSituation = 2;
Here is the fiddle for that: http://sqlfiddle.com/#!2/a731d
[END]
[here are the previous queries, for reference]
Looks to me like you just need:
select * from table_name where CodSituation=2
To get all of the people with situation 2
To get only the last entry using mysql:
select * from table_name where CodSituation=2 order by id desc limit 1
To get the last entry using sql-server:
select top 1 * from table_name where CodSituation=2 order by ID desc;
See a working example here:
http://sqlfiddle.com/#!6/022fb/4
[edit]
OP supplied an actual dataset:
select Name from table_name where CodSituation=2 group by Name;
This shows all the unique users with a CodSituation of 2 (with one entry per person)
http://sqlfiddle.com/#!3/be404/2
Can be achieved like this, but may not be the best way to do this
Basically what I am doing is Create a temporary table and add the Name and Maximum row number.
Which then match again that the maximum row number row is associated with CodSituation=2
Create Table #Temp2(Name Varchar(10),RowN int)
;WITH CTE AS (SELECT *,RN=ROW_NUMBER() OVER(PARTITION BY Name ORDER BY ID)
FROM TableName)
insert into #Temp2
SELECT Name,MAX(RN)
FROM CTE
Group By Name
select TT.*
from
(
SELECT *,RN=ROW_NUMBER() OVER(PARTITION BY Name ORDER BY ID)
FROM TableName
)TT
cross apply (
select Name
from #Temp2 TB
where TB.Name=TT.Name and TB.RowN= TT.RN
) Tab
Where CodSituation=2
Fiddle Sample
I found an easier way concatenating fieds and using max solve this problem... Thanks!
SELECT
right(
max(
right(('0000000' + CONVERT(varchar,id) + '-'+ convert(varchar,codsituation)),4)),10),
name
FROM TABLE_NAME
GROUP BY name
HAVING
right(
max(
right(
('0000000' + CONVERT(varchar,id) + '-'+ convert(varchar,codsituation))
,4)),1) = 2
http://sqlfiddle.com/#!3/3dc1c/10

Fetch the row which has the Max value for a column in SQL Server

I found a question that was very similar to this one, but using features that seem exclusive to Oracle. I'm looking to do this in SQL Server.
I have a table like this:
MyTable
--------------------
MyTableID INT PK
UserID INT
Counter INT
Each user can have multiple rows, with different values for Counter in each row. I need to find the rows with the highest Counter value for each user.
How can I do this in SQL Server 2005?
The best I can come up with is a query the returns the MAX(Counter) for each UserID, but I need the entire row because of other data in this table not shown in my table definition for simplicity's sake.
EDIT: It has come to my attention from some of the answers in this post, that I forgot an important detail. It is possible to have 2+ rows where a UserID can have the same MAX counter value. Example below updated for what the expected data/output should be.
With this data:
MyTableID UserID Counter
--------- ------- --------
1 1 4
2 1 7
3 4 3
4 11 9
5 11 3
6 4 6
...
9 11 9
I want these results for the duplicate MAX values, select the first occurance in whatever order SQL server selects them. Which rows are returned isn't important in this case as long as the UserID/Counter pairs are distinct:
MyTableID UserID Counter
--------- ------- --------
2 1 7
4 11 9
6 4 6
I like to use a Common Table Expression for that case, with a suitable ROW_NUMBER() function in it:
WITH MaxPerUser AS
(
SELECT
MyTableID, UserID, Counter,
ROW_NUMBER() OVER(PARTITION BY userid ORDER BY Counter DESC) AS 'RowNumber'
FROM dbo.MyTable
)
SELECT MyTableID, UserID, Counter
FROM MaxPerUser
WHERE RowNumber = 1
THat partitions the data over the UserID, orders it by Counter (descending) for each user, and then labels each of the rows starting with 1 for each user. Select only those rows with a 1 for rownumber and you have your max. values per user.
It's that easy :-) And I get results something like this:
MyTableID UserID Counter
2 1 7
6 4 6
4 11 9
Only one entry per user, no matter how many rows per user happen to have the same max value.
I think this will help you.
SELECT distinct(a.userid), MAX(a.counterid) as counterid
FROM mytable a INNER JOIN mytable b ON a.mytableid = b.mytableid
GROUP BY a.userid
There are several ways to do this, take a look at this Including an Aggregated Column's Related Values Several methods are shown including the performance differences
Here is one example
select t1.*
from(
select UserID, max(counter) as MaxCount
from MyTable
group by UserID) t2
join MyTable t1 on t2.UserID =t1.UserID
and t1.counter = t2.counter
Try this... I'm pretty sure this is the only way to truly make sure you get one row per User.
SELECT MT.*
FROM MyTable MT
INNER JOIN (
SELECT MAX(MID.MyTableId) AS MaxMyTableId,
MID.UserId
FROM MyTable MID
INNER JOIN (
SELECT MAX(Counter) AS MaxCounter, UserId
FROM MyTable
GROUP BY UserId
) AS MC
ON (MID.UserId = MC.UserId
AND MID.Counter = MC.MaxCounter)
GROUP BY MID.UserId
) AS MID
ON (MID.UserId = MC.UserId
AND MID.MyTableId = MC.MaxMyTableId)
select m.*
from MyTable m
inner join (
select UserID, max(Counter) as MaxCounter
from MyTable
group by UserID
) mm on m.UserID = mm.UserID and m.Counter = mm.MaxCounter