I have to fetch the latest record of the student which derived by joining 2 tables:
table 1: table 2:
id name id marks EXAM attended time status
-------- ----------------------------------------------
1 ABC 1 90 2019-04-05 06:00:00 PASS
2 DEF 1 25 2018-06-05 08:00:00 FAIL
2 45 2019-03-05 06:00:00 FAIL
2 22 2019-01-05 09:00:00 FAIL
On joining both tables I got this:
# name marks EXAM ATTENDED TIME status
------------------------------------------------------
1 ABC 90 2019-04-05 06:00:00 PASS
2 ABC 25 2018-06-05 08:00:00 FAIL
3 DEF 45 2019-03-05 06:00:00 FAIL
4 DEF 22 2019-01-05 09:00:00 FAIL
5 DEF 55 2019-04-05 09:00:00 PASS
6 DEF 66 2019-05-05 09:00:00 PASS
7 DEF 99 2018-05-05 09:00:00 PASS
I want to fetch the latest result on datetime and name.
The output I need is:
id name marks EXAM ATTENDED TIME status
------------------------------------------------------
1 ABC 90 2019-04-05 06:00:00 PASS
6 DEF 66 2019-05-05 09:00:00 PASS
You can try below using correlated subquery
select * from table1 a1
inner join table2 a on a1.id=a.id
where exam_attended_time in (select max(exam_attended_time) from table2 b where a.id=b.id)
OR you can use row_number() if your db supports it-
select * from
(
select a.name,a1.*,row_number(partition by a.id order by exam_attended_time desc)rn from table1 a1
inner join table2 a on a1.id=a.id
)X where rn=1
You could use a window function (ROW_NUMBER).
SELECT
x.id
, x.NAME
, x.marks
, x.ExamAttendTime
, x.status
FROM
(
SELECT
t1.id
, t1.NAME
, t2.marks
, t2.ExamAttendTime
, t2.status
, ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY t2.ExamAttendTime DESC) AS ROWNUMBER
FROM
dbo.Table1 t1
JOIN dbo.Table2 t2 ON t2.id = t1.id
) x
WHERE
x.ROWNUMBER = 1
i don't know how you fetch the record like marks '99' and '66' and EXAM attended time
'2019-05-05 09:00:00 ' which is not available in table itself.
though this will might help you on getting correct data .
select a.id,a.name,b.marks,b.[EXAM attended time],b.[status] from table 1 a
join table 2 b on a.id=b.id where [EXAM attended time] in
(select max([EXAM attended time])[EXAM attended time]from exam group by id)
IF you are using SQL SERVER then you can use TOP as below to fetch latest records
SELECT A.id,
A.name,
B.marks,
B.EXAM_attended_time,
B.Status
FROM table1 A
OUTER APPLY (SELECT TOP 1 *
FROM table2 B WHERE B.id = A.id
ORDER BY B.EXAM_attended_time DESC) B
WHERE B.ID = A.id
Related
I have a table historical_data
ID
Date
column_a
column_b
1
2011-10-01
a
a1
1
2011-11-01
w
w1
1
2011-09-01
a
a1
2
2011-01-12
q
q1
2
2011-02-01
d
d1
3
2011-11-01
s
s1
I need to retrieve the whole history of an id based on the date condition on any 1 row related to that ID.
date>='2011-11-01' should get me
ID
Date
column_a
column_b
1
2011-10-01
a
a1
1
2011-11-01
w
w1
1
2011-09-01
a
a1
3
2011-11-01
s
s1
I am aware you can get this by using a CTE or a subquery like
with selected_id as (
select id from historical_data where date>='2011-11-01'
)
select hd.* from historical_data hd
inner join selected_id si on hd.id = si.id
or
select * from historical_data
where id in (select id from historical_data where date>='2011-11-01')
In both these methods I have to query/scan the table ``historical_data``` twice.
I have indexes on both id and date so it's not a problem right now, but as the table grows this may cause issues.
The table above is a sample table, the table I have is about to touch 1TB in size with upwards of 600M rows.
Is there any way to achieve this by only querying the table once? (I am using Snowflake)
Using QUALIFY:
SELECT *
FROM historical_data
QUALIFY MAX(date) OVER(PARTITION BY id) >= '2011-11-01'::DATE;
Hi i have table1 and table2.
table1 is the logtime table of employees and table2 is the groupcode of the employee.
On table1 some employees has duplicate time in because they time in multiple time to just to secure their time in.
Table1
ID EMPID Time_IN
1 001 7:01 AM
2 004 7:04 AM
3 034 7:10 AM
4 034 7:11 AM
5 019 7:11 AM
6 019 7:12 AM
Table2
ID empID GroupName
1 001 AA
2 004 AB
3 034 AA
4 019 AA
result
GroupName CNT
AA 5
AB 1
Expected result
GroupName CNT
AA 3
AB 1
current query
Select b.GroupName, count(*) as cnt
from table1 a
inner join table2 b
on a.EMPID = b.empID
Group by b.GroupName
How can i achive as expected result above?
Thankyou in advance.
you can use distinct count as follows:
select t2.groupname, count(distinct empid) as cnt
from table1 t1 join table2 t2
on t1.empid = t2.empid
group by t2.groupname
The join is superfluous for the question you have asked:
select t2.GroupName, count(*) as cnt
from table2 t2
group by t2.GroupName;
This is much more efficient than joining and using count(distinct). You probably really have a different question, which should be asked as a new question.
I'm trying to lookup a unique value from table b and get it into table a.
Table b stores multiple values that are changing by date.
I would like to join but only getting the values with the latest date from table b.
Table a
Unique ID
1
2
Table b
Date Unique ID Price
01/01/2019 1 100
01/02/2019 1 101
01/03/2019 1 102
01/01/2019 2 90
01/02/2019 2 91
01/03/2019 2 92
Expected result
Unique ID Price Date
1 102 01/03/2019
2 92 01/03/2019
Appreciate your help!
Have a sub-query that returns each UniqueID together with its max date. IN that result.
select * from tablename
where (UniqueID, date) in (select UniqueID, max(date)
from tablename
group by UniqueID)
You want correlated subquery :
select b.*
from tableb b
where b.date = (select max(b1.date) from tableb b1 where b1.UniqueID = b.UniqueID);
If you want to go with JOIN then you can do JOIN with subquery :
select a.UniqueID , b.Price, b.Date
from tablea a inner join
tableb b
on b.UniqueID = a.UniqueID
where b.date = (select max(b1.date) from tableb b1 where b1.UniqueID = a.UniqueID);
A correlated subquery?
select b.*
from b
where b.date = (select max(b2.date) from b b2 where b2.unique_id = b.unique_id);
fileid custid dept1 dept2 date1 date2 date3
123 456 2 4 1/1/04 1/1/05 1/1/06
777 456 2 4 NULL 5/30/05 1/1/07
111 456 2 4 12/2/06 NULL 3/3/07
200 456 2 6 1/1/04 2/1/04 3/1/04
444 456 2 8 2/1/07 4/1/07 6/1/07
500 456 2 8 3/1/07 3/15/07 4/2/07
I trying to write some SQL that would pull the first 3 records above and display them as a 'set' based on the fact that the custid, dept1, and dept2 are the same and also that the dates 'overlap' ie, any of the dates in fileid 123 are earlier than the earliest date in fileid 777 and fileid 111. It wouldn't pull the 4th record because dept2 is different. And it would pull records 5 and 6 and display them as a separate set because custid, dept1, dept2 match and fileid 500's dates are 'inside' fileid 444's dates. Been pounding my head against a wall with this one. Can anyone help?
Here is an example of multiple rows with matching custiid, dept1 and dept2 not in the same set:
fileid custid dept1 dept2 date1 date2 date3
123 456 2 4 1/1/04 1/1/05 1/1/06
777 456 2 4 NULL 5/30/05 1/1/07
111 456 2 4 12/2/06 NULL 3/3/07
666 456 2 4 1/1/08 3/1/08 5/1/08
fileid 666 is not in the set because its dates don't overlap with any of the others.
I think that query gives your want. But i have to say this is not the cleanest answer. Also i get the conclusion in 3 query but it can be done with one query, but this will increase the complexity. In first query i find the duplicates in the second i list them and in the third i set the rules you want.
SELECT * INTO #temp FROM (Select custID,dept1,dept2 FROM #table
Group By custID,dept1,dept2
HAVING COUNT(custID) > 1) AS p
SELECT * INTO #temp2 FROM (Select ROW_NUMBER() OVER(PARTITION BY custID,dept1,dept2 Order By CustID ) as RN,*
FROM #table
Where custID IN (Select custID FROM #temp) AND dept1 IN (Select dept1 FROM #temp) AND dept2 IN (Select dept2 FROM #temp)
) AS x
Select * FROM #table Where fileID IN (
Select t1.fileID FROM #temp2 t1
INNER JOIN #temp2 t2 ON t1.RN = t2.RN-1 AND (
COALESCE(t2.date1,t2.date2) BETWEEN COALESCE(t1.date1,t1.date2) AND COALESCE(t1.date3,t1.date2)
OR
COALESCE(t2.date3,t2.date2) BETWEEN COALESCE(t1.date1,t1.date2) AND COALESCE(t1.date3,t1.date2)
)
AND t2.custID = t1.custID AND t2.dept1 = t1.dept1 AND t2.dept2 = t1.dept2)
OR
fileID IN (
Select t2.fileID FROM #temp2 t1
INNER JOIN #temp2 t2 ON t1.RN = t2.RN-1 AND (
COALESCE(t2.date1,t2.date2) BETWEEN COALESCE(t1.date1,t1.date2) AND COALESCE(t1.date3,t1.date2)
OR
COALESCE(t2.date3,t2.date2) BETWEEN COALESCE(t1.date1,t1.date2) AND COALESCE(t1.date3,t1.date2)
)
AND t2.custID = t1.custID AND t2.dept1 = t1.dept1 AND t2.dept2 = t1.dept2)
Here is a live link to this solution.
I'm new to SQL queries and I need to make a join starting from this query:
SELECT b.Name, a.*
FROM a INNER JOIN b ON a.VId = b.Id
WHERE b.SId = 100
AND a.Day >= '2016-05-05'
AND a.Day < '2016-05-09';
and adding 2 more columns to the first selected data (SCap and ECap from table c).
From what I've tried my code looks like this:
SELECT b.Name,a.*,
c.MaxDay,
c.Cap,
FROM a INNER JOIN b
ON a.VId = b.Id
INNER JOIN
(SELECT VId,
MAX(TimestampLocal) AS MaxDay,
CAST (TimestampLocal AS DATE) AS Day,
Cap,
FROM Info
GROUP BY VId,
CAST (TimestampLocal AS DATE),
Cap) AS c
ON a.VId = c.VId
AND a.Day = c.Day
WHERE b.SId = 33
AND a.Day >= '2016-05-05'
AND a.Day < '2016-05-09';
But I get more rows than needed.
I need the earliest and the latest TimestampLocal for a given vehicle in a daterange. That would come from two records in Info, and each would have its proper values for Cap.
For example:
I have two Names with values inside table Info for 2 days (Name 1) and only one day for Name 2:
- Day 1 2016-05-07:
- Name 1: Values at 2:45, 10:10 and 3.10
- Name 2: Values at 5:13 and 8:22
- Day 2 2016-05-09:
- Name 1: Values at 4:13, 6:15 and 9:20
I need to display (if I select daterange: 2016-05-05 to 2016-05-09) for Name 1 for SCap the value from 2016-05-07 from 2:45 and for ECap the value from 2016-05-09 from 9:20 and for Name 2 for SCap the value from 2016-05-07 from 5:13 and for ECap the value from 2016-05-07 from 8:22. This should be displayed in 2 lines.
Is there a way I can add those 2 columns into my query without adding more rows for the same Name?
EDIT!
Table a I have:
VId | Day
5251 | 05/09/2016
5382 | 05/09/2016
Table b:
Id | Name
5251 | N1
5382 | N2
Table Info:
VId | TimestampLocal | Cap
5251 | 2016-05-09 11:33:46.2000000 +03:00 | 0
5251 | 2016-05-09 11:37:11.4000000 +03:00 | 7
5251 | 2016-05-09 11:38:11.4000000 +03:00 | 4
5251 | 2016-05-09 11:39:11.7000000 +03:00 | 2
5382 | 2016-05-09 09:30:56.6000000 -04:00 | 5
5382 | 2016-05-09 09:31:56.6000000 -04:00 | 3
And I need to display - if I select a daterange from 2016-05-03 to 2016-05-10:
Id | Name | SCap | ECap
5251 | N1 | 0 | 2
5382 | N2 | 5 | 3
You can use a CTE with ROW_NUMBER in order to retrieve the two records:
;WITH Info_CTE AS (
SELECT VId,
CAST (TimestampLocal AS DATE) AS Day,
Cap,
ROW_NUMBER() OVER (PARTITION BY VId
ORDER BY TimestampLocal) AS rn1,
ROW_NUMBER() OVER (PARTITION BY VId
ORDER BY TimestampLocal DESC) AS rn2
FROM Info
)
SELECT b.Name,
a.*,
c.Day,
c.Cap
FROM a
INNER JOIN b ON a.VId = b.Id
INNER JOIN Info_CTE AS c ON a.VId = c.VId AND
a.Day = c.Day AND
1 IN (c.rn1, c.rn2)
WHERE b.SId = 33
AND a.Day >= '2016-05-05'
AND a.Day < '2016-05-09';
If you want ECap and SCap as separate columns then instead of
c.Cap
you can use:
CASE WHEN c.rn1 = 1 THEN c.Cap END AS ECap,
CASE WHEN c.rn2 = 1 THEN c.Cap END AS SCap
First, get the max and min timestamp for each id for a given date. Then join it twice, once with the max timestamp value and then with the min timestamp value for each id to tblinfo,to get the start and end cap values for those rows.
Add a where clause with a date filter to filter for specific days.
Sample demo
with maxandmin as
(select vid
,max(timestamplocal) maxtime
,min(timestamplocal) mintime
from tblinfo
group by vid,cast(timestamplocal as date))
select m.vid,b.name,i1.cap as Scap,i2.cap as Ecap
from maxandmin m
join tblinfo i1 on m.vid=i1.vid and m.mintime = i1.timestamplocal
join tblinfo i2 on m.vid=i2.vid and m.maxtime = i2.timestamplocal
join tableb b on b.id=m.vid
I found a solution for my query after some further investigations and here is what I managed to do:
SELECT b.Id,
b.Name,
c.S_Time,
c.E_Time,
s.Cap AS S_Cap,
e.Capa AS E_Cap,
FROM b
INNER JOIN (SELECT VId,
MIN(TimestampLocal) AS S_Time,
MAX(TimestampLocal) AS E_Time
FROM Info
where CAST (TimestampLocal AS DATE) >='2016-04-05'
and CAST (TimestampLocal AS DATE) <'2016-05-10'
GROUP BY VId
) AS c
ON b.Id = c.VId
INNER JOIN Info AS s
ON s.VId = c.VId
AND s.TimestampLocal = c.S_Time
INNER JOIN Info AS e
ON e.Vd = c.VId
AND e.TimestampLocal = c.E_Time
WHERE b.SId = 100