If I have a table with columns id, name, score, date
and I wanted to run a sql query to get the record where id = 2 with the earliest date in the data set.
Can you do this within the query or do you need to loop after the fact?
I want to get all of the fields of that record..
If you just want the date:
SELECT MIN(date) as EarliestDate
FROM YourTable
WHERE id = 2
If you want all of the information:
SELECT TOP 1 id, name, score, date
FROM YourTable
WHERE id = 2
ORDER BY Date
Prevent loops when you can. Loops often lead to cursors, and cursors are almost never necessary and very often really inefficient.
SELECT TOP 1 ID, Name, Score, [Date]
FROM myTable
WHERE ID = 2
Order BY [Date]
While using TOP or a sub-query both work, I would break the problem into steps:
Find target record
SELECT MIN( date ) AS date, id
FROM myTable
WHERE id = 2
GROUP BY id
Join to get other fields
SELECT mt.id, mt.name, mt.score, mt.date
FROM myTable mt
INNER JOIN
(
SELECT MIN( date ) AS date, id
FROM myTable
WHERE id = 2
GROUP BY id
) x ON x.date = mt.date AND x.id = mt.id
While this solution, using derived tables, is longer, it is:
Easier to test
Self documenting
Extendable
It is easier to test as parts of the query can be run standalone.
It is self documenting as the query directly reflects the requirement
ie the derived table lists the row where id = 2 with the earliest date.
It is extendable as if another condition is required, this can be easily added to the derived table.
Try
select * from dataset
where id = 2
order by date limit 1
Been a while since I did sql, so this might need some tweaking.
Using "limit" and "top" will not work with all SQL servers (for example with Oracle).
You can try a more complex query in pure sql:
select mt1.id, mt1."name", mt1.score, mt1."date" from mytable mt1
where mt1.id=2
and mt1."date"= (select min(mt2."date") from mytable mt2 where mt2.id=2)
Related
I have a table with the following columns:
bkng_date
bkng_id (varchar)
villa_id (varchar)
This query
select bkng_date,count(*) as cnt
from tab_bkng_det
group by bkng_date;
returns the no.of records for each date as count.
Now I need to find dates in the resultset of this query where cnt = 2.
I tried a couple of subqueries but I'm not getting the desired results.
The simplest, correct and safe solution is adding having count(*) = 2 clause as Gordon said.
For completeness, if you were curious how to solve it using subqueries (you didn't provide your db vendor though it's very likely your vendor supports having clause), it would be:
select x.bkng_date, x.cnt from (
select bkng_date,count(*) as cnt
from tab_bkng_det
group by bkng_date
) x
where x.cnt = 2
or
with x as (
select bkng_date,count(*) as cnt
from tab_bkng_det
group by bkng_date
)
select * from x where cnt = 2
Best Option is to use the Having Clause as follows,
select bkng_date,count(*) as cnt
from tab_bkng_det
group by bkng_date
having count(*) = 2
I'm creating PREDICATE system for my application.
Please see image that I already
I have a question how can I select rows in SQL with latest date "Taken On" column tables for each "QuizESId" columns, before that I am understand how to select it but it only using one table, I learn from this
select rows in sql with latest date for each ID repeated multiple times
Here is what I have already tried
SELECT tt.*
FROM myTable tt
INNER JOIN
(SELECT ID, MAX(Date) AS MaxDateTime
FROM myTable
GROUP BY ID) groupedtt ON tt.ID = groupedtt.ID
AND tt.Date = groupedtt.MaxDateTime
What I am confused about here is how can I select from 3 tables, I hope you can guide me, of course I need a solution with good query and efficient performance.
Thanks
This is for SQL Server (you didn't specify exactly what RDBMS you're using):
if you want to get the "latest row for each QuizId" - this sounds like you need a CTE (Common Table Expression) with a ROW_NUMBER() value - something like this (updated: you obviously want to "partition" not just by QuizId, but also by UserName):
WITH BaseData AS
(
SELECT
mAttempt.Id AS Id,
mAttempt.QuizModelId AS QuizId,
mAttempt.StartedAt AS StartsOn,
mUser.UserName,
mDetail.Score AS Score,
RowNum = ROW_NUMBER() OVER (PARTITION BY mAttempt.QuizModelId, mUser.UserName
ORDER BY mAttempt.TakenOn DESC)
FROM
UserQuizAttemptModels mAttempt
INNER JOIN
AspNetUsers mUser ON mAttempt.UserId = muser.Id
INNER JOIN
QuizAttemptDetailModels mDetail ON mDetail.UserQuizAttemptModelId = mAttempt.Id
)
SELECT *
FROM BaseData
WHERE QuizId = 10053
AND RowNum = 1
The BaseData CTE basically selects the data (as you did) - but it also adds a ROW_NUMBER() column. This will "partition" your data into groups of data - based on the QuizModelId - and it will number all the rows inside each data group, starting at 1, and ordered by the second condition - the ORDER BY clause. You said you want to order by "Taken On" date - but there's no such date visible in your query - so I just guessed it might be on the UserQuizAttemptModels table - change and adapt as needed.
Now you can select from that CTE with your original WHERE condition - and you specify, that you want only the first row for each data group (for each "QuizId") - the one with the most recent "Taken On" date value.
I have a table with 3 columns (code, state, date), it records the history of a code state, each code may have changed state multiple times.
I want to show the last state of each code what I did was like this
SELECT code,MAX(date), ....
FROM table
GROUP BY code.
I don't know what to put exactly to get the state. I tried to just put state so it gets the state corresponding to the combination of code,max(date) but it gives me the error of not in aggregate function.
thank you in advance for your help.
If I understand you have data such as
CODE State Date
1 IL 1/1/2016
1 IA 1/1/2017
1 AL 1/1/2015
and you want to see in your results
1 IA 1/1/2017
using a window function and a common table expression (with): we assign a row number to each code based on the date in descending order and return only the first row for each.
With CTE AS (SELECT code
, date
, state
, Row_number() over (partition by code order by date desc) RN
FROM table )
SELECT Code, Date, State
FROM CTE
WHERE RN =1
Using a subquery: (we get the max date for each code and then join back to the base set to limit the rows returned.
SELECT A.code, A.date, A.state
FROM table A
INNER JOIN (SELECT max(date) mdate, code
FROM table
GROUP BY code) B
on A.Code = B.Code
and A.Date = B.MDate
The later query was used when/if window functions are not available. The modern method of solving your question is using the first approach.
In essence what the 1st query does is assign the # 1 to x for each code based on the date descending. So the max date gets a RN of 1 for each code. Thus when we say where RN = 1 we only return codes/states/records having max dates for the code in question. We use a with statement because we need the RN to materialize (actually get generated in memory) so that we can then limit by it in the second part of the with (common table expression) query.
If you're doing an aggregate, like MAX(), then all other non-aggregate columns that are in your select, need to also be in your GROUP BY. That's why you're getting the error when you add state to only the select. If you add it to the select and group by it, you'll get your results:
SELECT State, Code, MAX(Date)
FROM table
GROUP BY State, Code
If you want to user inner join like you mention in your post Inner join back to itself with matching code and date
SELECT *
FROM table t1
INNER JOIN (SELECT code,MAX(date)
FROM table
GROUP BY code) codeWithLatestDate ON t1.code = codeWithLatestDate.code AND t1.date = codeWithLatestDate.dat3
However I would suggest add state to your GROUP BY clause and SELECT cluase
SELECT code,MAX(date),state
FROM table
GROUP BY code, state
Youn can do it with a join to itself
SELECT State,Code,Date
FROM table t
JOIN (
SELECT Code, MAX(Date) as Date
FROM table
GROUP BY Code) t1 on t1.Code= t.Code and t.Date=t1.Date
Very simple basic SQL question here.
I have this table:
Row Id __________Hour__Minute__City_Search
1___1409346767__23____24_____Balears (Illes)
2___1409346767__23____13_____Albacete
3___1409345729__23____7______Balears (Illes)
4___1409345729__23____3______Balears (Illes)
5___1409345729__22____56_____Balears (Illes)
What I want to get is only one distinct row by ID and select the last City_Search made by the same Id.
So, in this case, the result would be:
Row Id __________Hour__Minute__City_Search
1___1409346767__23____24_____Balears (Illes)
3___1409345729__23____7______Balears (Illes)
What's the easier way to do it?
Obviously I don't want to delete any data just query it.
Thanks for your time.
SELECT Row,
Id,
Hour,
Minute,
City_Search
FROM Table T
JOIN
(
SELECT MIN(Row) AS Row,
ID
FROM Table
GROUP BY ID
) AS M
ON M.Row = T.Row
AND M.ID = T.ID
Can you change hour/minute to a timestamp?
What you want in this case is to first select what uniquely identifies your row:
Select id, max(time) from [table] group by id
Then use that query to add the data to it.
SELECT id,city search, time
FROM (SELECT id, max(time) as lasttime FROM [table] GROUP BY id) as Tkey
INNER JOIN [table] as tdata
ON tkey.id = tdata.id AND tkey.lasttime = tdata.time
That should do it.
two options to do it without join...
use Row_Number function to find the last one
Select * FROM
(Select *,
row_number() over(Partition BY ID Order BY Hour desc Minute Desc) as RNB
from table)
Where RNB=1
Manipulate the string and using simple Max function
Select ID,Right(MAX(Concat(Hour,Minute,RPAD(Searc,20,''))),20)
From Table
Group by ID
avoiding Joins is usually much faster...
Hope this helps
I am unioning two queries but I'm getting an ID that occurs in each query. I do not know how to keep only the first time the id occurs. Everything else about the row is different. In general, it will be hard to know which of the two queries I will have to keep a duplicate on, therefore, I need a general solution.
I was thinking about creating a temp table and choosing the min date (once the date has been converted to an int).
Any ideas on the proper syntax?
You can do this using the row_number() function. This will assign a sequential number, starting with 1, to each row with the same id (based on the partition by clause). The ordering of the sequence is determined by the order by clause. So, the following assigns 1 to the earliest date for each id:
select t.*
from (select t.*,
row_number() over (partition by id order by date asc) as seqnum
from ((select *
from <subquery1>
) union all
(select *
from <subquery2>
)
) t
) t
where seqnum = 1;
The final where clause simply filters for the first occurrence.
If you use the keyword UNION, then it will remove duplicates from the two data sets you are working with. UNION ALL preserves duplicates.
You can view the specifics here:
http://www.w3schools.com/sql/sql_union.asp
If you want to only have one of the 2 records and they are not identical you will have to filter them yourself. You may need to do something like the following. THis may be possible to do with the one (select union select) block but this should get you started.
select *
from (
select id
, date
, otherstuf
from table_1
union all
select id
, date
, otherstuf
from table_2
) x1
, (
select id
, date
, otherstuf
from table_1
union all
select id
, date
, otherstuf
from table_2
) x2
where x1.id = x2.id
and x1.date < x2.date
Although rethinking this if you go down a path like this why bother to UNION it?