SQL compare two max Dates from the same table - sql

I dont know how to call this topic so I thought I just would explain what I need.
I have the following table:
Id IdPerson date successfully
1 1 01.01.2012 FALSE
2 1 01.01.2014 TRUE
3 2 01.01.2014 FALSE
Now I want all IdPerson where the newest entry is FALSE
So that would be just IdPerson 2 because IdPerson 1 is true in 2014.
I really have no clue how to do that.
Can somebody help me?
Greets

There is an interesting approach to this that uses conditional aggregation:
select idperson
from table t
group by idperson
having max(date) = max(case when successfully = 'false' then date end);
Note: this solution (as well as the others) assume that date is stored in a native date/time format. If not, you should fix the database, but this query would need to use convert().

If you are using SQL Server 2008 R2 (or higher), then you can use Apply
select p.* from Person P
cross Apply
(
select MAX(date) [maxdate] from Person group by Id
)a
where P.Date = a.maxdate and p.Successfully = 0

Use ROW_NUMBER() OVER (PARTITION BY ...) in a subquery to locate the newest entry per person. Then, in the outer query, select only those having successfully = 'FALSE':
SELECT Id, IdPerson, [date]
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY IdPerson ORDER BY [date] DESC) AS rn,
*
FROM MyTable ) t
WHERE t.rn = 1 AND t.successfully = 'FALSE'

I tried this in mysql:
SELECT Id,IdPerson,date,Status from MyTable
WHERE status='false' AND date= ALL( SELECT max(date) from MyTable
GROUP BY IdPerson);

Related

SQL Query to update earliest date for unique combinations

I am trying to update the Contract_Start date to be the earliest date for each unique Company and Route combination. For example, the Contract_Start for the first three records should be 1/15/12 as Company = 1 and Route = 1 for all three. The Contract_Start would then change to 1/20/12 for record 4 as that is the earliest date for the combination of Company = 1 and Route = 2. Any help would be greatly appreciated.
Company Route Driver Date Contract_Start
1 1 A 1/29/12
1 1 B 2/3/12
1 1 C 1/15/12
1 2 A 1/28/12
1 2 B 1/20/12
2 1 A 1/7/12
2 1 B 1/16/12
2 2 A 2/9/12
1 2 B 1/4/12
Update query with subquery can solve your problem
UPDATE TABLE TABLE T
SET CONTRACT_START = (
SELECT MIN(DATE)
FROM TABLE TI
WHERE T.COMPANY = TI.COMPANY
AND T.ROUTE = TI.ROUTE
)
Use window function to get Contract_Start. You needn't to store it at the table.
select Company, Route, Driver, Date, min(Date) over(partition by Company, Route) as Contract_Start
from myTable;
Use an updatable CTE with window functions:
with toupdate as (
select t.*, min(date) over (partition by company, route) as min_date
from t
)
update toupdate
set contract_start = min_date;
Updatable CTE/subqueries/views are a very handy feature in SQL Server and quite powerful when combined with window functions.
I hope this approach will resolve your issue and fulfill your task requirements.
UPDATE TABLE SET Contract_Start = CE.Date1
FROM Table_Name TB JOIN (
SELECT Company,Route,date1, Count(*) AS Countnum,
Row_Number() OVER(PARTITION BY Company, Route ORDER BY date1 ASC) AS Rownumber
FROM Table_Name GROUP BY Company,Route,date1) as CE ON TB.Company = CE.Company AND TB.Route = CE.Route
WHERE Rownumber = 1;

Select distinct rows based on two columns with additional columns

I have a table such as this
Blog
Id ColumnId DateCreated Type
1 1 2018-01-01 1
1 1 2018-01-02 2
1 1 2018-02-01 3
I need to select all unique rows based on the combination of Id and ColumnId. Then it needs to grab me the latest date and largest Type. I can't seem to figure this out.
I started of with just getting distinct values like this:
SELECT Id, ColumnId
FROM Blog
GROUP BY Id, ColumnId
Then I figured if I maybe joined it on itself I can pull out the rest, but I'm having no luck how to accomplish this
SELECT *
FROM ( SELECT Id, ColumnId
FROM Blog
GROUP BY Id, ColumnId) A
INNER JOIN Blog B ON A.Id = B.Id AND A.ColumnId = B.ColumnId
But that just gives me back all 3 rows.
In my live example the Id column is not int, but uniqueidentifier. For sake of simplicity I made it int in my example.
Expected Result Sample:
Id ColumnId DateCreated Type
1 1 2018-02-01 3
Have you tried using MAX?
SELECT Id, ColumnId, MAX(DateCreated), MAX([Type])
FROM Blog
GROUP BY Id, ColumnId
Use row_number():
select b.*
from (select b.*,
row_number() over (partition by id, columnid order by date desc, type desc) as seqnum
from blog b
) b
where seqnum = 1;
This grabs the largest type on the latest date, which is how I interpret "it needs to grab me the latest date and largest Type."
seems you need the last
you could use an inner join on the max date
select * from blog
inner join (
select id, columnId, max(DateCreated) as max_date
from blog
group by id, columnId
) t on t.id = blog.id, t.columnId = blog.columnId and t.max_date = blog.DateCreated
Maybe is not the best solution, but you could try to use a subselect in your query.
Something like this
SELECT DISTINCT Id, ColumnId, (SELECT MAX(Type) FROM blog) AS type
FROM Blog

SQL retrieve recent record

I want to retrieve TOPIC 1 SCORES with the most recent score (excluding null) (sorted by date) for each detailsID, (there are only detailsID 2 and 3 here, therefore only two results should return)
What about getting rid of Topic 1 Scores in GROUP BYdetailsID,Topic 1 Scores ?
Use a subquery to get the max and then join to it.
SELECT a.detailsID,`Topic 1 Scores`, a.Date
FROM Information.scores AS a
JOIN (SELECT detailsID, MAX(Date) "MaxDate"
FROM Information.scores
WHERE `Topic 1 Scores` IS NOT NULL
GROUP BY detailsID) Maxes
ON a.detailsID = Maxes.detailsID
AND a.Date = Maxes.MaxDate
WHERE `Topic 1 Scores` IS NOT NULL
Assuming SQL Server:
SELECT
ROW_NUMBER() OVER (PARTITION BY detailsID ORDER BY Date DESC) AS RowNumber,
detailsID, Date, Topic 1 Scores
FROM
Information.scores
Try doing
SELECT detailsID,`Topic 1 Scores`, MAX(Date) as "Date" GROUP BY "Date"

SQL Server query distinct

I'm trying to do a query in SQL Server 2008. This is the structure of my table
Recno ClientNo ServiceNo
---------------------------------
1234 17 27
2345 19 34
3456 20 33
4567 17 34
I'm trying to select RecNo however, filtering by distinct ClientNo, so for some clients such as client no 17 - they have more than 1 entry, I'm trying to count that client only once. So basically, looking at this table, I'm only supposed to see 3 RecNo's, since there are only 3 distinct clients. Please help
Select RecNo, Count(ClientNo)
from TblA
where Count(clientNo)<2
Something like this?
EDIT:
The value of RecNo is not relevant, I only need to have an accurate number of records. In this case, I'd like to have 3 records.
oaky you are getting some crazy answers probably becuase your desired result is not clear so I suggest if some of these are not what you need that you clarify your desired result.
If you want the answer 3, I can only assume you want a count of DISTINCT ClientNo's if so it is simply aggregation.
SELECT COUNT(DISTINCT ClientNo) as ClientNoDistinctCount
FROM
TblA
GROUP BY
ClientNo
Ok, this will give you the count that you want:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY ClientNo ORDER BY Recno)
FROM TblA
)
SELECT COUNT(DISTINCT Recno) N
FROM CTE
WHERE RN = 1;
Try this..
;with cte1
As(SELECT Recno,clientno
,row_number() over(partition by clientno order by Recno )RNO FROM TblA)
Select Recno,clientno
From cre1 where RNO=1
Choose only ClientNo having the max Recno (or replace < with > to choose the min one).
Select *
from TblA t1
where not exists(select 1
from TblA t2
where t1.ClientNo = t2.ClientNo and t1.Recno < t2.Recno )
BTW, the other solution already mentioned, utilizing row_number() needs no CTE in this case
SELECT TOP(1) WITH TIES *
FROM TblA
ORDER BY ROW_NUMBER() OVER(PARTITION BY ClientNo ORDER BY Recno)

how do I query sql for a latest record date for each user

I have a table that is a collection entries as to when a user was logged on.
username, date, value
--------------------------
brad, 1/2/2010, 1.1
fred, 1/3/2010, 1.0
bob, 8/4/2009, 1.5
brad, 2/2/2010, 1.2
fred, 12/2/2009, 1.3
etc..
How do I create a query that would give me the latest date for each user?
Update: I forgot that I needed to have a value that goes along with the latest date.
This is the simple old school approach that works with almost any db engine, but you have to watch out for duplicates:
select t.username, t.date, t.value
from MyTable t
inner join (
select username, max(date) as MaxDate
from MyTable
group by username
) tm on t.username = tm.username and t.date = tm.MaxDate
Using window functions will avoid any possible issues with duplicate records due to duplicate date values, so if your db engine allows it you can do something like this:
select x.username, x.date, x.value
from (
select username, date, value,
row_number() over (partition by username order by date desc) as _rn
from MyTable
) x
where x._rn = 1
Using window functions (works in Oracle, Postgres 8.4, SQL Server 2005, DB2, Sybase, Firebird 3.0, MariaDB 10.3)
select * from (
select
username,
date,
value,
row_number() over(partition by username order by date desc) as rn
from
yourtable
) t
where t.rn = 1
I see most of the developers use an inline query without considering its impact on huge data.
Simply, you can achieve this by:
SELECT a.username, a.date, a.value
FROM myTable a
LEFT OUTER JOIN myTable b
ON a.username = b.username
AND a.date < b.date
WHERE b.username IS NULL
ORDER BY a.date desc;
From my experience the fastest way is to take each row for which there is no newer row in the table.
Another advantage is that the syntax used is very simple, and that the meaning of the query is rather easy to grasp (take all rows such that no newer row exists for the username being considered).
NOT EXISTS
SELECT username, value
FROM t
WHERE NOT EXISTS (
SELECT *
FROM t AS witness
WHERE witness.username = t.username AND witness.date > t.date
);
ROW_NUMBER
SELECT username, value
FROM (
SELECT username, value, row_number() OVER (PARTITION BY username ORDER BY date DESC) AS rn
FROM t
) t2
WHERE rn = 1
INNER JOIN
SELECT t.username, t.value
FROM t
INNER JOIN (
SELECT username, MAX(date) AS date
FROM t
GROUP BY username
) tm ON t.username = tm.username AND t.date = tm.date;
LEFT OUTER JOIN
SELECT username, value
FROM t
LEFT OUTER JOIN t AS w ON t.username = w.username AND t.date < w.date
WHERE w.username IS NULL
To get the whole row containing the max date for the user:
select username, date, value
from tablename where (username, date) in (
select username, max(date) as date
from tablename
group by username
)
SELECT *
FROM MyTable T1
WHERE date = (
SELECT max(date)
FROM MyTable T2
WHERE T1.username=T2.username
)
This one should give you the correct result for your edited question.
The sub-query makes sure to find only rows of the latest date, and the outer GROUP BY will take care of ties. When there are two entries for the same date for the same user, it will return the one with the highest value.
SELECT t.username, t.date, MAX( t.value ) value
FROM your_table t
JOIN (
SELECT username, MAX( date ) date
FROM your_table
GROUP BY username
) x ON ( x.username = t.username AND x.date = t.date )
GROUP BY t.username, t.date
If your database syntax supports it, then TOP 1 WITH TIES can be a lifesafer in combination with ROWNUMER.
With the example data you provided, use this query:
SELECT TOP 1 WITH TIES
username, date, value
FROM user_log_in_attempts
ORDER BY ROW_NUMBER() OVER (PARTITION BY username ORDER BY date DESC)
It yields:
username | date | value
-----------------------------
bob | 8/4/2009 | 1.5
brad | 2/2/2010 | 1.2
fred | 12/2/2009 | 1.3
Demo
How it works:
ROWNUMBER() OVER (PARTITION BY... ORDER BY...) For each username a list of rows is calculated from the youngest (rownumber=1) to the oldest (rownumber=high)
ORDER BY ROWNUMBER... sorts the youngest rows of each user to the top, followed by the second-youngest rows of each user, and so on
TOP 1 WITH TIES Because each user has a youngest row, those youngest rows are equal in the sense of the sorting criteria (all have rownumber=1). All those youngest rows will be returned.
Tested with SQL-Server.
SELECT DISTINCT Username, Dates,value
FROM TableName
WHERE Dates IN (SELECT MAX(Dates) FROM TableName GROUP BY Username)
Username Dates value
bob 2010-02-02 1.2
brad 2010-01-02 1.1
fred 2010-01-03 1.0
This is similar to one of the answers above, but in my opinion it is a lot simpler and tidier. Also, shows a good use for the cross apply statement. For SQL Server 2005 and above...
select
a.username,
a.date,
a.value,
from yourtable a
cross apply (select max(date) 'maxdate' from yourtable a1 where a.username=a1.username) b
where a.date=b.maxdate
You could also use analytical Rank Function
with temp as
(
select username, date, RANK() over (partition by username order by date desc) as rnk from t
)
select username, rnk from t where rnk = 1
SELECT MAX(DATE) AS dates
FROM assignment
JOIN paper_submission_detail ON assignment.PAPER_SUB_ID =
paper_submission_detail.PAPER_SUB_ID
SELECT Username, date, value
from MyTable mt
inner join (select username, max(date) date
from MyTable
group by username) sub
on sub.username = mt.username
and sub.date = mt.date
Would address the updated problem. It might not work so well on large tables, even with good indexing.
SELECT *
FROM ReportStatus c
inner join ( SELECT
MAX(Date) AS MaxDate
FROM ReportStatus ) m
on c.date = m.maxdate
For Oracle sorts the result set in descending order and takes the first record, so you will get the latest record:
select * from mytable
where rownum = 1
order by date desc
SELECT t1.username, t1.date, value
FROM MyTable as t1
INNER JOIN (SELECT username, MAX(date)
FROM MyTable
GROUP BY username) as t2 ON t2.username = t1.username AND t2.date = t1.date
Select * from table1 where lastest_date=(select Max(latest_date) from table1 where user=yourUserName)
Inner Query will return the latest date for the current user, Outer query will pull all the data according to the inner query result.
I used this way to take the last record for each user that I have on my table.
It was a query to get last location for salesman as per recent time detected on PDA devices.
CREATE FUNCTION dbo.UsersLocation()
RETURNS TABLE
AS
RETURN
Select GS.UserID, MAX(GS.UTCDateTime) 'LastDate'
From USERGPS GS
where year(GS.UTCDateTime) = YEAR(GETDATE())
Group By GS.UserID
GO
select gs.UserID, sl.LastDate, gs.Latitude , gs.Longitude
from USERGPS gs
inner join USER s on gs.SalesManNo = s.SalesmanNo
inner join dbo.UsersLocation() sl on gs.UserID= sl.UserID and gs.UTCDateTime = sl.LastDate
order by LastDate desc
My small compilation
self join better than nested select
but group by doesn't give you primary key which is preferable for join
this key can be given by partition by in conjunction with first_value (docs)
So, here is a query:
select
t.*
from
Table t inner join (
select distinct first_value(ID) over(partition by GroupColumn order by DateColumn desc) as ID
from Table
where FilterColumn = 'value'
) j on t.ID = j.ID
Pros:
Filter data with where statement using any column
select any columns from filtered rows
Cons:
Need MS SQL Server starting with 2012.
I did somewhat for my application as it:
Below is the query:
select distinct i.userId,i.statusCheck, l.userName from internetstatus
as i inner join login as l on i.userID=l.userID
where nowtime in((select max(nowtime) from InternetStatus group by userID));
Here's one way to return only the most recent record for each user in SQL Server:
WITH CTE AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY date DESC) AS rn
FROM your_table
)
SELECT *
FROM CTE
WHERE rn = 1;
This uses a common table expression (CTE) to assign a unique rn (row number) to each record for each user, based on the user_id and sorted in descending order by date. The final query then selects only the records with rn equal to 1, which represents the most recent record for each user.
SELECT * FROM TABEL1 WHERE DATE= (SELECT MAX(CREATED_DATE) FROM TABEL1)
You would use aggregate function MAX and GROUP BY
SELECT username, MAX(date), value FROM tablename GROUP BY username, value