tsql-Joining tables with group by - sql-server

Have 2 tables TableA
StudentID MeetingID TeacherID Date
001 1002581 1056 10-12-2012
001 1006789 1056 10-13-2012
001 1006754 1058 10-13-1012
Have one more table B
StudentID MeetingID TeacherID Date Value
001 1002581 1056 10-12-201 15
001 1002856 1056 10-20-2012 21
The conditions are max(date) of a particular student teacher meeting from table A matches the max(date) of the same student teacher meeting in table B with the value. I would like to see the resultset as something like
StudentID MeetingID TeacherID Date Value
001 1006789 1056 10-20-2012 21
How can i achieve the above resultset

First, I'm curious why you have the same data in two separate tables instead of linking them via ID. I.e. Meetings -> Values
Per your requirements, this should work. This finds the most recent meeting which is present in both tables.
SELECT B.*
FROM B INNER JOIN A ON B.StudentID = A.StudentID AND B.MeetingID = A.MeetingID AND B.Date = A.Date
WHERE B.Date = (SELECT MAX(Date) FROM A WHERE A.StudentID = B.StudentID AND A.MeetingID = B.MeetingID)
Here's the Fiddle: http://sqlfiddle.com/#!6/d15ca/4

SELECT TOP 1 c.StudentID,c.MeetingID,c.TeacherID,c.tab1_dates,c.VALUE
FROM
(
SELECT a.StudentID,a.MeetingID,a.TeacherID,a.Dates AS tab1_dates,b.Dates AS tab2_dates,b.VALUE,
ROW_NUMBER() OVER (ORDER BY a.Dates,b.Dates) AS RN1
FROM tab2 b
INNER JOIN
(
SELECT StudentID,MeetingID,TeacherID,Dates FROM tab1
) a
ON b.StudentID = a.StudentID
AND b.TeacherID = a.TeacherID
) c
ORDER BY RN1 DESC
--SQL Fiddle - http://www.sqlfiddle.com/#!3/c6cea/1
Sorry, couldn't format well.

Related

MS SQL Server - Join two tables where ID is equivalent to new ID

I am trying to join two tables but did not able to success
Test Supplier Table
SID NAME
1 Test
2 Test2
Test Stock Table
ID NewID SupID Qty
1 101 1 2
2 102 1 5
3 103 2 6
101 1 4
101 1 7
101 2 5
103 2 10
The output I am looking for
ID NAME Qty
2 Test 5
101 Test 13
101 Test2 5
103 Test2 16
My code is -
Select S.NAME, ST.ID, SUM(ST.Qty)
From Stock ST
Inner Join ST.SupID = S.SID
I need to combine those ID's which are matching with the new ID's with another ID's. If you see the results, I need to combine ID 1 qty with ID 101 because ID 1 has new ID 101 and no need to display ID 1. I have tried inner join but did not work.
First, you find those with NEW ID and those without NEW ID. For those with NewID, use NEWID, for those without use ID (old ID). then you use UNION ALL to combine both result and join to the Supplier table to obtain the NAME.
; with
cte as
(
-- with NewID
select ID = NewID, SupID, Qty = sum(Qty)
from Stock ST
where exists
(
select *
from Stock x
where x.ID = ST.NewID
)
group by NewID, SupID
union all
-- without NewID
select ID, SupID, Qty = sum(Qty)
from Stock ST
where not exists
(
select *
from Stock x
where x.ID = ST.NewID
)
group by ID, SupID
)
select c.ID, SP.NAME, Qty = sum(Qty)
from cte c
inner join Supplier SP on c.SupID = SP.SID
group by c.ID, SP.NAME
Start with the Stock table and join to the Supplier table (remembering to name the table in the join) and then self-left join to the IDs in the Stock table to determine if they exist or not. Then group by on whichever ID you want to keep.
SELECT
COALESCE(ST2.ID, ST.ID) ID
, S.NAME NAME
, SUM(ST.Qty) Qty
FROM Stock ST
INNER JOIN Supplier S
ON ST.SupID = S.SID
LEFT JOIN (
SELECT DISTINCT ID
FROM Stock
) ST2
ON ST.NewID = ST2.ID
GROUP BY
COALESCE(ST2.ID, ST.ID)
, S.NAME

Joining Two Tables, getting Aggregate and unique value of one

This may have been answered previously, but I'm having a difficult time describing my issue.
Let's say I have two tables
Table1
User, CalendarID
Joe 1
Joe 2
Joe 3
Sam 4
Bob 1
Jim 2
Jim 3
Table2
CalendarID, CalendarTime
1 2014-08-18 00:00:00.000
2 2015-01-19 00:00:00.000
3 2015-08-24 00:00:00.000
4 2016-01-18 00:00:00.000
What I would like to do is Join the two tables, only getting a single User Name, and Calendar ID based on what is this highest CalendarTime associated with that CalandarID.
So I would like the query to return
User CalendarID
Joe 3
Sam 4
Bob 1
Jim 3
The closest I've managed is
SELECT t1.User, MAX(t2.CalendarTIme) AS CalendarTime
FROM table1 t1
INNER JOIN table2 as t2
ON t1.CalendarID = t2.CalendarID
Group By t1.User
Which gets me the User and CalendarTime that I want, but not the Calendar ID, which is what I really want. Please help.
Closest to your script and pretty straightforward:
SELECT t1.User, t2.*
FROM table1 t1
INNER JOIN table2 as t2
ON t1.CalendarID = t2.CalendarID
WHERE NOT EXISTS
(
SELECT 1 FROM table1 t1_2
INNER JOIN table2 t2_2
ON t2_2.Calendar_ID = t1_2.Calendar_ID
WHERE t1_2.User = t1.User
AND t2_2.CalendarTime > t2.CalendarTime
)
This can be solved for the top N per group:
using top with ties with row_number():
select top 1 with ties
t1.User, t1.CalendarId, t2.CalendarTime
from table1 t1
inner join table2 as t2
on t1.Calendarid = t2.Calendarid
order by row_number() over (partition by t1.User order by t2.CalendarTime desc)
or using common table expression(or a derived table/subquery) with row_number()
;with cte as (
select t1.User, t1.CalendarId, t2.CalendarTime
, rn = row_number() over (partition by t1.User order by t2.CalendarTime desc)
from table1 t1
inner join table2 as t2
on t1.Calendarid = t2.Calendarid
)
select User, CalendarId, CalendarTime
from cte
where rn = 1

How to get department wise highest salary and highest salary holder Employee name,consider 3 tables are joined using keys

How to get department wise highest salary and highest salary holder Employee name,consider 3 tables are joined using keys
io/-
emptable, saltable,depttable
id name dept_id id sal dept_id dept_name
1 ram 10 1 100 10 xyz
2 sham 10 2 500 20 abc
3 jadu 20 3 900 30 por
4 john 20 4 999 40 stu
5 Madhu 30 5 300 50 xxx
o/p-
name,sal,dept_name
sham 500 abc
john 999 stu
Madhu300 xxx
SELECT DISTINCT
MAX(amount) OVER (PARTITION BY d.id ORDER BY s.amount DESC) AS sal,
FIRST_VALUE(e.name) OVER (PARTITION BY d.id ORDER BY s.amount DESC) AS emp,
d.name as dept
FROM emptable e
INNER JOIN depttable d
ON e.dept_id = d.id
INNER JOIN saltable s
ON s.id = e.id
I made some assumptions for column names in your tables. You can find my schema script here.
You can JOIN all the table and then use window function row_number to choose top two records per department:
select *
from (
select t.*,
row_number() over (
partition by dept_id order by salary desc
) rn
from (
select e.*,
s.salaray,
d.dept_name
from emptable e
join saltable s on e.emp_id = s.emp_id
join depttable d on d.dept_id = e.dept_id
) t
) t
where rn <= 2;
Your table are missing the column names. So, I assumed the names (hopefully correctly)

repeatation on output result according date insqlserver

Concatenate values from multiple columns of 3 tables and display in one column. Date field is datetime.now my problem is if date is repeat of one table then amt2,amt3 is also repeat on same date
table1:
date amt1
1-1-2016 10:44:00 111
1-1-2016 10:44:02 222 repeat date
3-4-2016 11:44:00 111
table2:
date amt2
1-1-2016 10:44:02 101
2-2-2016 10:44:02 333
2-3-2016 10:44:02 444
table3:
date amt3
2-2-2016 10:44:04 001
2-3-2016 10:44:02 002
3-3-2016 10:44:02 003
query
SELECT
COALESCE(t1.date, t2.date, t3.date)
, t1.amt1
, t2.amt2
, t3.amt3
FROM tb_amount t1
FULL JOIN tb_cashamt t2 ON t1.date =t2.date
FULL JOIN tb_grandtotal t3 ON t2.date = t3.date
output:
date amt1 amt2 amt3
1-1-2016 10:44:00 111 null NULL
1-1-2016 10:44:02 111 101 null data repeat on amt1(111)
2-2-2016 10:44:02 NULL 333 null
2-2-2016 10:44:04 NULL 333 001 data repeat on amt2(111)
TOTAL --- --- -----
Desired output:
date amt1 amt2 amt3
1-1-2016 111 101 NULL
2-2-2016 NULL 333 001
TOTAL total(amt1) total(amt1) total(amt1)
I have problem with smalldatetime datatype on datecolumn. I want a result on each date and amt1,amt2,amt3 show total data on this date
Use FULL JOIN
SELECT
COALESCE(t1.date, t2.date, t3.date)
, t1.amt1
, t2.amt2
, t3.amt3
FROM Table1 t1
FULL JOIN Table2 t2 ON t1.date =t2.date
FULL JOIN Table3 t3 ON t2.date = t3.date
You'll need to use the FULL JOIN, also known as FULL OUTER JOIN as explained on Using Outer Joins:
To retain the nonmatching information by including nonmatching rows in the results of a join, use a full outer join. SQL Server provides the full outer join operator, FULL OUTER JOIN, which includes all rows from both tables, regardless of whether or not the other table has a matching value.
;
WITH Table1 AS
( SELECT [Date], Amt1
FROM ( VALUES
('2016-01-01', 111),
('2016-02-02', 222),
('2016-04-03', 111)
) AS Table1(Date, Amt1)
), Table2 AS
( SELECT [Date], Amt2
FROM ( VALUES
('2016-01-01', 101),
('2016-02-02', 333),
('2016-03-02', 444),
('2016-03-03', 456),
('2016-04-01', 101),
('2016-04-03', 111)
) AS Table2(Date, Amt2)
), Table3 AS
( SELECT [Date], Amt3
FROM ( VALUES
('2016-02-02', 001),
('2016-03-02', 002),
('2016-03-03', 003),
('2016-04-01', 555),
('2016-04-02', 666),
('2016-04-03', 777)
) AS Table3(Date, Amt3)
)
SELECT ISNULL(Table1.Date, ISNULL(Table2.Date, Table3.Date)) Date,
Table1.Amt1, Table2.Amt2, Table3.Amt3
FROM Table1
FULL JOIN Table2 ON Table1.Date = Table2.Date
FULL JOIN Table3 ON Table2.Date = Table3.Date
ORDER BY ISNULL(Table1.Date, ISNULL(Table2.Date, Table3.Date))
If you need only one row per date, you need to group by + sum each of the tables on date level first before joining + you can use rollup for the total:
select coalesce(T1.Date,T2.Date,T3.Date), sum(T1.Amt1),Sum(T2.Amt2),Sum(T3.Amt3)
from
(
select convert(date, date) as Date, sum(Amt1) as Amt1
from Table1
group by convert(date, date)
) T1
full outer join (
select convert(date, date) as Date, sum(Amt2) as Amt2
from Table2
group by convert(date, date)
) T2 on T1.Date = T2.Date
full outer join (
select convert(date, date) as Date, sum(Amt3) as Amt3
from Table3
group by convert(date, date)
) T3 on isnull(T1.Date,T2.Date) = T3.Date
group by rollup(coalesce(T1.Date,T2.Date,T3.Date))

Fetch only one of each entry based on date

Im currently working with SQL Compact 4 and Razor and im trying to fetch only one of each entry based on latest date
id Name Number LastDate
1 Joe 1111 2014-01-01
2 Sam 2222 2014-01-02
3 Joe 1111 2014-04-11
4 Sam 2222 2014-04-12
5 Lee 3333 2014-04-12
I'm trying to write the data out to a webgrid but i can't find the correct SQL statement to only load id 3, 4 and 5 since they are the last updated entries.
Try with
SELECT id, Name, Number, LastDate FROM yourTable t1 INNER JOIN
(SELECT Number, MAX(LastDate) AS MaxDate FROM yourTable GROUP BY Number) t2
ON t1.Number = t2.Number AND t1.LastDate = t2.MaxDate
You can do this with one query:
select t.*
from t
where not exists (select 1
from t t2
where t2.number = t.number and
t2.lastdate > t.lastdate
);
This implements the logic: "Get me all rows from t where there is no row with the same number and a later lastdate".
I think something like this should work (assuming you want the last record by the "Number" column and that there are no duplicate dates by number):
select max(lastdate) as lastdate, number into #temp
from t
group by number
select * from #temp t1
inner join t on t.number = t1.number and t.lastdate = t1.lastdate
Here is a SQL Fiddle: http://www.sqlfiddle.com/#!6/01357/5
(Thinking about this further, even if there were duplicate dates by number, the only field that would differ would be the id column which you could perhaps take the MAX of depending on your requirements.)
You can use row_number() in the OVER statement like this:
select id, name, number, lastdate
from
(
select
id, name, number, lastdate,
row_number() OVER (PARTITION BY Number ORDER BY LastDate DESC) as dateord
from table
) t
where t.dateord = 1

Resources