Select max value record from one-to-many join - sql

I want to join two tables, but the second table contains multiple rows of parameters on which I wish to build by join.
TABLE1
+------------+-----------+
| Ddate | ROOMNO |
+------------+-----------+
| 2018-22-11 | 101 |
| 2018-22-11 | 102 |
| 2018-22-11 | 103 |
| 2018-22-11 | 104 |
+------------+-----------+
TABLE2 (Multiple rows per Room No)
+------------+-----------+------------------+
| Ddate | ROOMNO | MaxVoltage |
+------------+-----------+------------------+
| 2018-22-11 | 101 | 230 |
| 2018-22-11 | 101 | 240 |
| 2018-22-11 | 101 | 250 -----MAX |
| 2018-22-11 | 102 | 230 |
| 2018-22-11 | 102 | 255 -----MAX |
+------------+-----------+------------------+
DESIRED RESULT (I want the Max Voltage for the Room on the Ddate)
+------------+-----------+------------+
| Ddate | ROOMNO | MaxVoltage |
+------------+-----------+------------+
| 2018-22-11 | 101 | 250 |
| 2018-22-11 | 102 | 255 |
| 2018-22-11 | 103 | 235 |
| 2018-22-11 | 104 | 238 |
| 2018-22-11 | 105 | 255 |
+------------+-----------+------------+

SELECT t2.d, t2.roomno, max(t2.maxvolt)
FROM table1 AS t1 JOIN table2 AS t2 ON t1.ddate = t2.ddate
AND t1.roomno = t2.roomno
GROUP BY t2.d, t2.roomno;

use subquery
select t1.dDate,t1.roomno,mvoltage from table1 t1 join
(select Ddate ,roomno,max(MaxVoltage ) as mvoltage from table2
group by Ddate,roomno
) t2 on t1.Ddate=t2.Ddate

Use apply:
select t1.*, t2.maxvoltage
from table1 t1 outer apply
(select top (1) t2.*
from table2 t2
where t2.roomno = t1.roomno and t2.ddate = t1.ddate
order by maxvoltage desc
) t2;

select t1.dDate,t1.roomno, mvoltage from table1 t1 join
(select Ddate ,roomno,max(MaxVoltage ) as mvoltage from table2
group by Ddate,roomno
) t2 on t1.Ddate=t2.Ddate and t1.Roomno = t2.RoomNo

First you will join between two tables in a regular way, using the date and room no.
then use the aggregate function max for the voltage field with over clause , then group by Room No and Date like following
select distinct t1.Ddate, t1.RoomNo, MAX(t2.MaxVoltage) over(partition by t1.RoomNo order by t1.Ddate) MaxVoltage
from Table1 t1
join Table2 t2 on t2.Ddate = t1.Ddate and t2.RoomNo = t1.RoomNo

Related

Update the column of table1 and get it on table2

How can I create a query where I can update the table1 column date that I get it on table2?
Here is some example of the tables
Table1:
| stud_id | start_date | birt_date | name | exam_date |
| s001 | 11/19/2018 | 05/20/1999 | john | 10/20/2018 |
| s003 | 01/01/2018 | 05/25/1995 | mike | 10/20/2018 |
| s005 | 12/23/2018 | 02/20/1999 | ed | 10/20/2018 |
| s005 | 12/23/2018 | 02/20/1999 | ed | 10/05/2017 |
Table2:
| stud_id | start_date | exam_date |
| s005 | 01/01/2017 | 10/20/2018 |
| s001 | 01/01/2017 | 10/20/2018 |
| s003 | 01/01/2017 | 10/20/2018 |
Basically I want to change just the start_date of the 3 so s006 will not change.
How can I accomplish that using query? I was thinking using in then select the table but I think its not gonna work.
I need to based on two or more column for the condition of my update so I want to update the table 1 where table1.stud_id = table2.stud_id and table1.exam_date = table2.exam_date
do join and update
update t1
set t1.stardate=t2.startdate,
t1.exam_date=t2.exam_date
from table1 t1 join table2 t2
on t1.stud_id=t2.stud_id
where t2.stud_id='s003' -- if you just need s003 update
You can also use CTE as well to update:
;With cte as
(
select t1.start_date as t1date,t2.start_date as t2date from table1 t1
join table2 t2
on t1.stud_id=t2.stud_id
and t1.exam_date=t2.exam_date
)
update cte set t1date=t2date
You can join the 2 tables:
UPDATE T1
SET Start_Date = T2.Start_Date
FROM Table1 AS T1
INNER JOIN Table2 AS T2
ON T1.stud_id = T2.stud_id
AND T1.exam_date = T2.exam_date

Join on the first id where the date is the same or in the past

How can I join Table1 on Table2 on opid, only if the table1's date <= table2's date, AND it has no other matches?
Here are some example tables:
Table1
------------+-------+-----+
date | spend | opid|
------------+-------+-----+
2019-07-05 | 5 | 1 |
------------+-------+-----+
2019-07-07 | 4 | 2 |
------------+-------+-----+
2019-07-08 | 6 | 2 |
------------+-------+-----+
Table2
+------------+-------+-----+
| date | users | opid|
+------------+-------+-----+
| 2019-07-06 | 100 | 1 |
+------------+-------+-----+
| 2019-07-08 | 200 | 2 |
+------------+-------+-----+
Expected Table
+------------+-------+-------+
| date | spend | users |
+------------+-------+-------+
| 2019-07-05 | 10 | 100 |
+------------+-------+-------+
| 2019-07-07 | 4 | null |
+------------+-------+-------+
| 2019-07-08 | 6 | 200 |
+------------+-------+-------+
So 7-July doesn't join, because 8-July has already joined.
I think you should try with inner join.
select t1.id, t1.date, t1.spend, t2.id as table2_id, t2.users
from table1 t1 inner join
table2 t2
on t1.date <= t2.date;
This answers the original version of the question.
I think you want a full join:
select t1.id, t1.date, t1.spend, t2.id as table2_id, t2.users
from table1 t1 full join
table2 t2
on t1.date = t2.date;

SQL query join- unrelated tables

Can someone help me to join the two tables without any primary or secondary keys. Sample table is
TABLE 1
| ID | NAME |
| 1 | x |
| 2 | Y |
| 3 | z |
TABLE 2
| Num | NAME | DATE |
| 52 | X | 12-aug-17 |
| 53 | X | 11-apr-17 |
| 62 | X | 10-aug-11 |
| 12 | y | 2-jan-16 |
| 23 | Y | 3-apr-18 |
I want retrieve data from X
select *
from table2
where name = 'x';
| Num | NAME | DATE |
| 52 | X | 12-aug-17 |
| 53 | X | 11-apr-17 |
| 62 | X | 10-aug-11 |
Now I will get three data from table2. I'm little stuck after this step. I want to get top of data the from table 2 and combine with table one.
I want final output should be
| ID | NAME | Num | DATE |
| 1 | x | 52 | 12-aug-17 |
Can someone suggest me how can I join this table? Its easy to join when we have any primary key but here not the case
Thanks
You can use this:
SELECT TOP(1) table1.ID, table2.Num, table2.Name, table2.DATE
FROM table2 INNER JOIN table1 ON table1.NAME = table2.NAME
WHERE table2.NAME = 'x'
ORDER BY table2.DATE ASC
OR
SELECT table1.ID, table2.Num, table2.Name, table2.DATE
FROM table1 INNER JOIN
(SELECT TOP(1) * FROM table2 WHERE NAME = 'x' ORDER BY DATE ASC) table2
ON table1.NAME = table2.NAME
You need to get the maximum DATE using a subquery, as in:
select t1.id, t2.*
from table1 t1
join table2 t2 on t2.name = t1.name
where t2.date = (
select max(date) from table2 where name = 'x'
);

SELECT Earliest Date from Grouped Results in DATEDIFF

From this table T2, I need to select the earliest date from each group by ID where the Prog is 'YY' and use it in DATEDIFF with respect to EDate:
+----+-----------+-----------+------+
| ID | SDate | Edate | Prog |
+----+-----------+-----------+------+
| 1 | 4/12/2016 | 5/18/2016 | XX |
| 1 | 4/1/2016 | 4/4/2016 | YY |
| 1 | 5/23/2016 | 5/28/2016 | YY |
| 2 | 9/21/2016 | 9/26/2016 | XX |
| 2 | 8/7/2016 | 8/9/2016 | YY |
| 3 | 8/2/2015 | 8/12/2015 | YY |
| 3 | 4/12/2015 | 4/18/2015 | YY |
+----+-----------+-----------+------+
And then show it with the aggregate level in Table T1 as the Desired Output:
+----+------+-----+-----------+------+
| ID | Name | Age | SDate | Days |
+----+------+-----+-----------+------+
| 1 | A | 52 | 4/1/2016 | 3 |
| 2 | B | 11 | 8/7/2016 | 2 |
| 3 | C | 24 | 4/12/2015 | 6 |
+----+------+-----+-----------+------+
Attempt:
SELECT
T1.ID,
T1.Name,
T1.Age,
MIN(T2.SDate) AS [SDate],
--DATEDIFF(day,MIN(T2.SDate),T2.EDate) AS [Days]
FROM T1
INNER JOIN T2
ON T1.ID=T2.ID
WHERE T2.Prog='YY'
GROUP BY
T1.ID,
T1.Name,
T1.Age
I commented out the DATEDIFF function for Days since I am not sure how to formulate that. Obviously, something like DATEDIFF(day,SELECT MIN(SDate) FROM T2 WHERE Prog='YY','Another Date') won't work since I will get an overall MIN(SDate) which won't be partitioned by ID and I can't do SELECT ID,MIN(SDate) FROM T2 WHERE Prog='YY' GROUP BY ID in the inner subquery either since DATEDIFF will only accept a Date field.
So how do I extract MIN(SDate) and calculate the DATEDIFF for corresponding Edate, for each grouped ID in that case?
Use the min window function to get the min sdate for each id and use it for computing the date difference.
SELECT ID,NAME,Age,DATEDIFF(DD,SDate,EDate)
FROM (
SELECT
T1.ID,
T1.Name,
T1.Age,
MIN(CASE WHEN T2.PROG = 'YY' THEN T2.SDate END) OVER(PARTITION BY T2.ID) AS [SDate],
T2.EDate
FROM T1
INNER JOIN T2 ON T1.ID=T2.ID
) x
Use MIN as a window function:
SELECT T1.ID,
T1.Name,
T1.Age,
DATEDIFF(day,
MIN(T2.SDate) OVER PARTITION BY (T1.ID, T1.Name, T1.Age),
T2.EDate) AS [Days]
FROM T1
INNER JOIN T2
ON T1.ID = T2.ID
WHERE T2.Prog = 'YY'

How can I write a select statement for this use case?

Please help me compose a SELECT statement. I have these two tables:
Table1 Table2
---------------- ------------------------------------------------
ID | PName | | ID | NameID | DateActive | HoursActive |
---------------- ------------------------------------------------
1 | Neil | | 1 | 1 | 8/2/2013 | 3 |
2 | Mark | | 2 | 1 | 8/3/2013 | 4 |
3 | Onin | | 3 | 2 | 8/2/2013 | 2 |
---------------- | 4 | 2 | 8/6/2013 | 5 |
| 5 | 3 | 8/7/2013 | 1 |
| 6 | 3 | 8/8/2013 | 10 |
------------------------------------------------
And I just want to retrieve the earliest DateActive but no duplicate PName. Like this:
PName | DateActive | HoursActive |
----------------------------------------
Neil | 8/2/2013 | 3 |
Mark | 8/2/2013 | 2 |
Onin | 8/7/2013 | 1 |
----------------------------------------
Something like this might do it. You need to find the min date for each NameID first, then join back to the table to get the hours.
SELECT
PName, MaxDate as DataActive, HoursActive
From
Table1 t1
inner Join Table2 t2 on t1.ID = t2.NameID
Inner Join (Select min(DateActive) as mindate, NameID from Table2 Group by NameID) as t3 on t3.mindate = t2.ActiveDate and t3.NameID = t2.NameId
This should be a pretty standard solution:
select t.pname,
t2.dateactive,
t2.hoursac
from table1 t
join table2 t2 on t.id = t2.nameid
join (
select nameid, min(dateactive) mindateactive
from table2
group by nameid
) t3 on t2.nameid = t3.name
and t3.mindateactive = t2.dateactive
If you are using an RDBMS that supports partition by statements, then this would be more efficient:
select pname, dateactive, HoursActive
from (
select t.pname,
t2.dateactive,
t2.hoursactive,
rank() over (partition by t.id order by t2.dateactive) rownum
from table1 t
join table2 t2 on t.id = t2.nameid
) t
where rownum = 1