TSQL Query to fetch row details of a table having the maximum value for a column - sql

I have two tables.
Table 1
Num
1
2
3
Table 2
Num Date Amount
1 12/31 30
1 12/30 31
1 12/29 20
2 12/31 100
2 12/30 90
3 12/31 12
4 11/1 1
Now my result should have
Num Date Amount
1 12/31 30
2 12/31 100
3 12/31 12
(for the 'Num' values in table 1, join with table2 where the date is the most recent)
I am trying to write a tsql query to achieve this.
Any help is appreciated. Thanks

If you want the most recent date for each table1 num individually:
with maxdates as (
select T1.num, max(T2.date) as date
from table2 T2
join table1 T1
on T2.num = t1.num
group by T1.num
)
select t2.num, t2.date, t2.amount
from table2 T2
join maxdates M
on T2.num = M.num
and T2.date = M.date
or if you want the most recent date for all matching records in the table:
with maxdate as (
select max(T2.date) as date
from table2 T2
join table1 T1
on T2.num = t1.num
)
select t2.num, t2.date, t2.amount
from table2 T2
join table1 T1
on T2.num = T1.num
join maxdate M
on T2.date = M.date

Try this query:
SELECT b.*
FROM Table1 a INNER JOIN
(
SELECT a.*,
ROW_NUMBER() OVER(PARTITION BY a.Num ORDER BY Date DESC) rnk
FROM Table2 a
) b
ON a.Num = b.Num
AND rnk = 1

Try this
select t2.* from table2 as t2 inner join table1 as t1 on t2.num=t2.num
inner join
(
Select t2.num,max(t2.amount) as amount from table2
group by t2.num
) as t3 on t2.amount=t3.amount

DECLARE #t1 TABLE(num INT)
DECLARE #t2 TABLE(num INT, [date] NVARCHAR(5), amount INT)
INSERT INTO #t1 (num) VALUES (1),(2),(3)
INSERT INTO #t2 (num,[date],amount) VALUES (1,'12/31',30)
INSERT INTO #t2 (num,[date],amount) VALUES (1,'12/30',31)
INSERT INTO #t2 (num,[date],amount) VALUES (1,'12/29',20)
INSERT INTO #t2 (num,[date],amount) VALUES (2,'12/31',100)
INSERT INTO #t2 (num,[date],amount) VALUES (2,'12/30',90)
INSERT INTO #t2 (num,[date],amount) VALUES (3,'12/31',12)
INSERT INTO #t2 (num,[date],amount) VALUES (4,'11/01',1)
SELECT t2.num,t2.[date],amount
FROM #t1 t1 JOIN #t2 t2 ON t1.num = t2.num
WHERE t2.[date] in (
SELECT MAX(t3.[date])
FROM #t2 t3
WHERE t3.num = t2.num
)
ORDER BY t2.num

Related

Pivot data using multiple join

I have a table like this in SQL Server
name
tems
aver
a
1
12
a
2
13.5
b
1
19
b
2
15.5
c
2
5
d
1
16.75
How should I have following form with join clause? Not with group by, CTE, COALESCE, Null functions, conditional aggregation and PIVOT. Case clause in only allowed in join conditions.
select columns
from Table T1
join Table T2 on .......................
join Table T3 on .......................
name
aver1
aver2
a
12
13.5
b
19
15.5
b
Null
5
d
16.75
Null
I would recommend conditional aggregation:
select name,
max(case when tems = 1 then aver end) as aver1,
max(case when tems = 2 then aver end) as aver2
from mytable
group by name
If you insist on joining, then:
select t1.name, t1.aver as aver1, t2.aver as aver2
from mytable t1
inner join mytable t2 on t2.name = t1.name
and t1.tems = 1 and t2.tems = 2
One caveat with the above join technique is that it eliminates names that do not have both tems, so it would not produce the result you want for your sample data. You could work around this with a full join, but that would incur additional complexity. The conditional aggregation is simpler.
..for join...
declare #t table(name varchar(10), tems smallint, aver decimal(9,2));
insert into #t(name, tems, aver)
values
('a', 1, 12),
('a', 2, 13.5),
('b', 1, 19),
('b', 2, 15.5),
('c', 2, 5),
('d', 1, 16.75);
select coalesce(t1.name, t2.name) as name, t1.aver as aver1, t2.aver as aver2
from
(
select *
from #t
where tems = 1
) as t1
full outer join
(
select *
from #t
where tems = 2
) as t2 on t1.name = t2.name;
select coalesce(t1.name, t2.name) as name, t1.aver as aver1, t2.aver as aver2
from #t as t1
full outer join #t as t2 on t1.name = t2.name and t1.tems = 1 and t2.tems = 2
where t1.tems = 1
or
(t1.tems is null and t2.tems=2);
select t3.name, t1.aver as aver1, t2.aver as aver2
from #t as t1
full outer join #t as t2 on t1.name = t2.name and t1.tems = 1 and t2.tems = 2
join #t as t3 on case when t1.name is null then t2.name else t1.name end = t3.name
and case when t1.name is null then 2 else 1 end = t3.tems
where t1.tems = 1
or
t1.tems is null and t2.tems=2;

SQL joining on max ID or dates between date

I have the following tables:
Table 1:
with two columns (PatientID,Name)
Table 2:
with four columns (ID,PatientID,FromDate,ToDate)
I need to join (left join) table1 to table2 (on patientid) to get the values in table2 that has getdate() within Fromdate and todate and if there is no such record, then get the latest id.
I am using SQL 2016.
Table 1 Data:
1 Peter
2 Fady
Table 2 data
1 2019-01-01 2019-02-01
1 2019-03-01 2019-04-01
2 2019-06-01 2019-12-01
2 2020-01-01 2020-01-01
I should get:
1 2019-03-01 2019-04-01
2 2019-06-01 2019-12-01
I think apply does what you want. I think you simply want:
select t1.*, t2.*
from table1 t1 outer apply
(select top (1) t2.*
from table2 t2
where t2.patientid = t.patientid
order by fromdate desc
) t2;
I am guessing that you don't have future fromdates. If you do, then the order by can be tweaked to handle this.
EDIT:
If you can have future dates, then this would be tweaked to:
select t1.*, t2.*
from table1 t1 outer apply
(select top (1) t2.*
from table2 t2
where t2.patientid = t.patientid
order by (case when getdate() >= fromdate and getdate < todate() then 1 else 2 end), id desc
) t2;
You can use a temp table. First get the matching data, then update the missing IDs with the Max(Id) as below:
select table1.*, table2.ID
into #temp
from table1 t1
left outer join table2 t2 on t1.PatientID = t2.PatientID
where getdate() between t2.fromdate and t2.todate
update t
set ID = (select max(ID) from table2 t2 where t.PatientID=t2.PatientID)
from #temp t
where t.ID is null
select * from #temp
You can do a union, only one part will have value:
;WITH cte(ID,PatientID,FromDate,ToDate)
AS
(
SELECT t2.ID,t2.PatientID,t2.FromDate,t2.ToDate
FROM Table1 t1
INNER JOIN Table2 t2
ON t1.PatientID=t2.PatientID
WHERE t2.FromDate >=GETDATE() AND t2.Todate<=GETDATE()
),
cte1 (ID)
AS
(
SELEC TMAX(ID) FROM Table2 WHERE NOT EXISTS(SELECT 1 FROM cte)
)
SELECT ID,PatientID,FromDate,ToDate
FROM cte
UNION ALL
SELECT ID,NULL,NULL,NULL
FROM cte1

SQL Server Join two tables without duplicates in primary table

I have two tables that I want to join together such that all foreign rows are returned and the primary table's rows are not duplicated. For example:
T1
pk code value
1 One 100
2 Two 200
T2
fk value
1 10
1 15
1 30
2 25
I want all records of T2 without the T1 records duplicating, so the result set I want to look like this:
T2.fk T1.code T1.value T2.value
1 One 100 10
1 NULL NULL 15
1 NULL NULL 30
2 Two 200 25
Is there a SQL Server join method for achieving that?
You need to rank your rows in T2 and do a left join including rank as a join condition:
with cte as(select *, row_number() over(partition by fk order by value) as rn from T2)
select c.fk, t.code, t.value, c.value
from cte c
left join T1 t on c.fk = t.pk and c.rn = 1
Here is the full example:
DECLARE #t1 TABLE
(
pk INT ,
code VARCHAR(MAX) ,
value INT
)
INSERT INTO #t1
VALUES ( 1, 'One', 100 ),
( 2, 'Two', 200 )
DECLARE #t2 TABLE ( fk INT, value INT )
INSERT INTO #t2
VALUES ( 1, 10 ),
( 1, 15 ),
( 1, 30 ),
( 2, 25 );
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY fk ORDER BY value ) AS rn
FROM #t2
)
SELECT c.fk ,
t.code ,
t.value ,
c.value
FROM cte c
LEFT JOIN #t1 t ON c.fk = t.pk
AND c.rn = 1
Try this:
select T2.fk,
CASE
WHEN (SELECT COUNT(*) FROM t2 tother WHERE tother.fk = t2.fk
AND tother.value > t2.value) > 0 THEN NULL ELSE t1.code
END,
CASE
WHEN (SELECT COUNT(*) FROM t2 tother WHERE tother.fk = t2.fk
AND tother.value > t2.value) > 0 THEN NULL ELSE t1.value
END,T2.value
from t2
join t1
on t2.fk = t1.pk
DECLARE #t1 TABLE (pk int,code varchar(10),value int)
DECLARE #t2 TABLE (fk int,value int)
INSERT INTO #t1
SELECT 1,'one',100
UNION
SELECT 2,'two',200
INSERT INTO #t2
SELECT 1,10
UNION SELECT 1,15 UNION SELECT 1,30 UNION SELECT 2,25
;WITH cte AS(
SELECT t2.fk,t2.value t2val,t1.pk,t1.code,t1.value t1val,ROW_NUMBER() OVER(PARTITION BY fk ORDER BY fk) rno FROM #t2 t2 LEFT JOIN #t1 t1 on t2.fk=t1.pk)
SELECT fk,code=(CASE WHEN rno=1 THEN code ELSE null END),t1val=(CASE WHEN rno=1 THEN t1val ELSE NULL END),t2val FROM cte
output
fk code t1val t2val
1 one 100 10
1 NULL NULL 15
1 NULL NULL 30
2 two 200 25

Is there any way to get TOP N records from table 1 where N based on Table 2

Table1
Rowno name Date
------------------------------------
1 sathish Dec 21
2 kumar Dec 22
3 sathish Dec 21
4 sathish Dec 22
5 sathish Dec 21
5 sathish Dec 22
Table 2
Date NoofTran
-----------------------
Dec22 2
Dec21 1
I want to get the records from table1 based on the table2 nooftran values and randomly.
On dec22nd, the number of transaction is 2 in the table 2, so two records should take it from table 1 on the respective date and it should be random case. So out of 3 records on Dec22 , two should come randomly.
What SQL query should I use?
If you are using SQL Server you can use a cross apply like this
select t1.*
from Table2 as t2
cross apply
(
select top (select T2.nooftran) *
from Table1 as t1
where t2.Date = t1.date
order by newid()
) as t1
Sample
declare #T1 table (rowno int, name varchar(max), [date] date);
declare #T2 table ([date] date, nooftran int);
insert into #T1 values
(1, 'sathish', '2015-01-01'),
(2, 'kumar', '2016-01-01'),
(3, 'sathish', '2015-01-01'),
(4, 'sathish', '2016-01-01'),
(5, 'sathish', '2015-01-01'),
(5, 'sathish', '2016-01-01');
insert into #T2 values ( '2016-01-01', 2), ( '2015-01-01', 1);
select t1.*
from #T2 as t2
cross apply
(
select top (select T2.nooftran) *
from #T1 as t1
where t2.Date = t1.date
order by newid()
) as t1
SELECT rs.RowNo, rs.DATE, rs.NAME
FROM (
SELECT t1.ROWNO, t1.DATE, t1.NAME, Rank() OVER (
PARTITION BY t1.DATE ORDER BY newid()
) AS Rank
FROM table1 t1
) rs
INNER JOIN Table2 T2 ON rs.DATE = t2.DATE
WHERE Rank <= t2.NoofTran

Best practices for multi table join query

Tables structure are below :
Table1 (ID int, value1 int,...)
ID Value1
---- --------
1 10
2 20
5 12
Table2 (ID int, value2 int,...)
ID Value2
---- --------
1 13
3 24
4 11
Table3 (ID int, value3 int,...)
ID Value3
---- --------
4 150
5 100
My expected output is below.
ID Value1 Value2 Value3
---- -------- -------- --------
1 10 13 NULL
2 20 NULL NULL
3 NULL 24 NULL
4 NULL 11 150
5 12 NULL 100
It should be noted that above tables is huge and I want to have best performance.
My query suggestion is below :
Select ID,
SUM(Value1) AS Value1,
SUM(Value2) AS Value2,
SUM(Value3) AS Value3
From (
Select ID, Value1 , NULL as value2, NULL as value 3
From Table1
Union ALL
Select ID, NULL , value2, NULL
From Table2
Union ALL
Select ID, NULL, NULL, value 3
From Table3
)Z
Group By Z.ID
Assuming you only have one value per id, this should do the trick:
SELECT aux.ID, t1.Value1, t2.Value2, t3.Value3
FROM
(SELECT ID FROM Table1
UNION
select ID FROM Table2
UNION
SELECT ID FROM Table3) aux
LEFT OUTER JOIN Table1 t1 ON aux.ID = t1.ID
LEFT OUTER JOIN Table2 t2 ON aux.ID = t2.ID
LEFT OUTER JOIN Table3 t3 ON aux.ID = t3.ID
If you've more than one value:
SELECT aux.ID, SUM(t1.Value1) as 'Value1', SUM(t2.Value2) as 'Value2', SUM(t3.Value3) as 'Value3'
FROM
(SELECT ID FROM Table1
UNION
select ID FROM Table2
UNION
SELECT ID FROM Table3) aux
LEFT OUTER JOIN Table1 t1 ON aux.ID = t1.ID
LEFT OUTER JOIN Table2 t2 ON aux.ID = t2.ID
LEFT OUTER JOIN Table3 t3 ON aux.ID = t3.ID
GROUP BY aux.ID
I intially wrote the same answer as aF. did above. So, removed it, and used a different approach.
Here,
1st query get all from table1
2nd query gets all from table2 skipping
those already present in table1 3rd query gets all remaining skipping those in above two query.
SELECT T1.ID, T1.VALUE1, T2.VALUE2, T3.VALUE3 --all T1
FROM TABLE1 T1
LEFT JOIN TABLE2 ON T1.ID=T2.ID
LEFT JOIN TABLE3 ON T1.ID=T3.ID
UNION
SELECT T2.ID, T1.VALUE1, T2.VALUE2, T3.VALUE3 --all T2 where T1 is NULL
FROM TABLE1 T2
LEFT JOIN TABLE1 ON T2.ID=T1.ID
LEFT JOIN TABLE3 ON T2.ID=T3.ID
WHERE T1.ID IS NULL
UNION
SELECT T3.ID, T1.VALUE1, T2.VALUE2, T3.VALUE3 --all T3 where T1 is NULL AND T2 IS NUL
FROM TABLE1 T3
LEFT JOIN TABLE1 ON T3.ID=T1.ID
LEFT JOIN TABLE2 ON T3.ID=T2.ID
WHERE T1.ID IS NULL
AND T2.ID IS NULL