Pull up the most recent record including joining 2 tables and filters - sql

I have seen a lot of posts on pulling up the most recent record. I haven't been able to find one that includes joining another table and filters.
What I need is information regarding the most recent document (record) created, but only if it meets certain criteria. PLUS I need to pull in some data from another table.
s504Plans Table
Student ID | Firstname | Startdate | Status
---------- --------- --------- ------
111111 Johnny 1/5/2015 F
222222 Sue 4/7/2016 I
333333 Barb 2/5/2016 F
111111 Johnny 2/1/2016 F
Cases Table
Student ID | School |
---------- ------
111111 Franklin
222222 Eisenhower
333333 Franklin
And the results I'd like to see are only the most recent document where the status of the document is F...
Student ID | Firstname | Startdate | Status | School
---------- --------- --------- ------ ------
111111 Johnny 2/1/2016 F Franklin
333333 Barb 2/5/2016 F Franklin
Thanks!

You can use inner join and where
select
a.Student_ID
, a.Firstname
, a.Startdate
, a.Status
, b.School
from s504Plans as a
inner join Cases as b on a.Student_ID = b.Student_ID
inner join ( select Student_ID, max(Startdate ) as max_startdate
from s504Plans
group by Student_ID) t
on ( a.Student_id = t.Student_id and a.Startdate = t.max_startdate)
where a.Status = 'F'

Related

How do I display rows from a max count?

I want to return all the data, from max count query with hospital that has most number of patients. What I seem to be getting when I try to nest queries is display of all rows of hospital data. I've tried to look at similar questions in stack overflow and other sites it seems to be a simple query to do but i am not getting it.
select max(highest_hospital) as max_hospital
from (select count(hospital) as highest_hospital
from doctor
group by hospital)
highest_hospital
-------------
3
Doc ID Doctor Patient Hospital Medicine Cost
------ ------- ------ --------- ------ --------
1 Jim Bob Patient1 Town 1 Medicine 1 4000
2 Janice Smith Patient2 Town 2 Medicine 3 3000
3 Harold Brown Patient3 Town 2 Medicine 5 2000
4 Larry Owens Patient4 Town 2 Medicine 6 3000
5 Sally Brown Patient5 Town 3 Medicine 7 4000
6 Bob Jim Patient6 Town 4 Medicine 8 6000
Outcome should be return of 3 rows
Doc ID Doctor Patient Hospital Medicine Cost
------ ------- ------ --------- ------ --------
2 Janice Smith Patient2 Town 2 Medicine 3 3000
3 Harold Brown Patient3 Town 2 Medicine 5 2000
4 Larry Owens Patient4 Town 2 Medicine 6 3000
You can use window functions:
select d.*
from (select d.*, max(hospital_count) over () as max_hospital_count
from (select d.*, count(*) over (partition by hospital) as hospital_count
from doctor d
) d
) d
where hospital_count = max_hospital_count;
Edit:
Using GROUP BY is a pain. If you are only looking for a single hospital (even when there are ties), then in Oracle 12C you can do:
select d.*
from doctor d
where d.hospital = (select d2.hospital
from doctor d2
group by d2.hospital
order by count(*) desc
fetch first 1 row only
);
You can do this in earlier versions of Oracle using an additional subquery.

Join multiple tables to return only one result for each record from main table

Currently I have three tables I am joining. I have data that was migrated from one system(old) to another system(new). I need to compare this data to ensure matches but also mismatches. I have three tables. One has the list of accounts being moved. The two systems have differnt ID types so this first table is a list of all IDs for the two tables and each account that was moved. So this is my base population.
ID1 ID2
ABC 123
ABC 123
ABC 123
DEF 456
DEF 456
DEF 456
I then have table 2 which is all the data from the old system.
ID Fname Lname
ABC John Smith
ABC Tom Smith
ABC Kate Smith
DEF Jason Thomas
DEF Ruby Thomas
DEF Alex Johnson
Then table 3 is all the data found in the new system.
ID Fname Lname
123 John Smith
123 Tom Smith
123 Kate Smith
456 Jason Thomas
456 Ruby Thomas
Right now when I join these tables on the ID I get a lot more rows than I need.
When I do my join I receive this:
ID Fname_old Lname_old ID2 Fname_new Lname_new
ABC John Smith 123 John Smith
ABC John Smith 123 Tom Smith
ABC John Smith 123 Kate Smith
I am trying to join them where it only returns the row that matches, and if it can't find a match I should still get the ID from the ID file and the data from table 2(old data) as this is the data that was sent to the new system.
ID1 ID2 Fname_old Lname_old Fname_new Lname_new
ABC 123 John Smith John Smith
ABC 123 Tom Smith Tom Smith
ABC 123 Kate Smith Kate Smith
DEF 456 Jason Thomas Jason Thomas
DEF 456 Ruby Thomas Ruby Thomas
DEF 456 Alex Johnson
The code I am using is:
Select a.ID1, a.ID2, b.fname as fname_old, b.lnam as lname_old,
c.fname as fname_new, c.lname as lname_new
from table1 a
left join table2 b
on a.ID1 = b.ID
left join table3 c
on a.ID2 = c.ID
If its just duplicate rows in your first table you could try distincting them in a derived table like below:
Select a.ID1, a.ID2, b.fname as fname_old, b.lnam as lname_old,
c.fname as fname_new, c.lname as lname_new
from (SELECT DISTINCT ID1, ID2 FROM table1) a
left join table2 b
on a.ID1 = b.ID
left join table3 c
on a.ID2 = c.ID
You are joining them on ID columns.
ID columns are usually UNIQUE while you have multiple identical IDs and specify join on those IDs.
Since you need to compare data, i suggest you lookup MATCH and how it works as that seems to be closer to what you are looking for here.
You can get a match using row_number():
Select a.ID1, a.ID2, b.fname as fname_old, b.lnam as lname_old,
c.fname as fname_new, c.lname as lname_new
from (select a.*,
row_number() over (partition by id order by id) as seqnum
from table1 a
) a left join
(select b.*,
row_number() over (partition by id order by id) as seqnum
from table2 b
) b
on a.ID1 = b.ID and a.seqnum = b.seqnum
(select c.*,
row_number() over (partition by id order by id) as seqnum
from table3 c
) c
on a.ID2 = c.ID and a.seqnum = c.seqnum;
Note: This does not preserve the "ordering" of the original values, so any rows can be matched with any other. Why? SQL tables represent unordered sets.
If there is an ordering in the tables, you can use that in the order by clauses to get a match consistent with the ordering.
If you have a compare chance for name and last name this code will work.
select DISTINCT a.ID1, a.ID2, b.fname as fname_old, b.lname as lname_old, c.fname as
fname_new, c.lname as lname_new from table2 b
left join table1 a on a.ID1=b.ID
left join table3 c on a.ID2=c.ID and b.Fname=c.Fname and b.Lname=c.Lname
My Result :
ID1 ID2 fname_old lname_old fname_new lname_new
ABC 123 John Smith John Smith
ABC 123 Kate Smith Kate Smith
ABC 123 Tom Smith Tom Smith
DEF 456 Alex Johnson NULL NULL
DEF 456 Jason Thomas Jason Thomas
DEF 456 Ruby Thomas Ruby Thomas
You say that this is data transferred to two systems. So you expect all data to match. You could hence reduce the query to only find data that doesn't match, if any.
Here is a SQL standard compliant query. You tagged your request with hive. I don't know about hive, so you may have to adjust the query.
select
t2.id as id1,
t3.id as id2,
t2.fname as fname_old,
t2.lname as lname_old,
t3.fname as fname_new,
t3.lname as lname_new
from table2 t2
full outer join t3
on t3.fname = t2.fname
and t3.lname = t2.lname
and exists (select null from table1 t1 where t1.id1 = t2.id and t1.id2 = t3.id)
where t2.id is null or t3.id is null;
This is a full anti join. It returns all rows that have no exact match in the other table. It doesn't, however guesstimate which deviating rows may be pairs. You will get a result like this:
ID1 | ID2 | Fname_old | Lname_old | Fname_new | Lname_new
----+-----+-----------+-----------+-----------+----------
DEF | | Alex | Johnson | |
GHI | | Jone | Miller | |
GHI | | Maxx | Miller | |
GHI | | Fritz | Miller | |
| 789 | | | Joan | Miller
| 789 | | | Max | Miller
| 799 | | | Fritz | Miller
As you see, you would have to examine this result manually. But ideally the query shouldn't return any row at all, which would just prove that everything went as expected and nobody (system or person) messed with the data :-)

get multiple column from both table by joining a table on the basis of other max table column

1) vendor table
--------------------------------------------
VENDid VENDname
--- -----
1 ABC
2 XYZ
3 WXY
2)purchase table
---------------------------------------------
VENDid Purchasedate
------ ------------
1 12-01-2012
1 10-11-2013
2 22-02-2014
2 11-04-2014
3 10-05-2014
3 11-06-2014
1 14-06-2014
output(list all rows of vendor table and only max(purchasedate) from purchase table)
---------------------------------------------
VENDid VENDname PurchaseDate
------- -------- -------------
1 ABC 14-06-2014
2 XYZ 11-04-2014
3 WXY 11-06-2014
i got some queries like to solve previous problem-
SELECT v.VendID, VendName, Max(PurchaseDate)
FROM vendor v
INNER JOIN purchase p
ON v.VendID = p.VendID
Group By v.VendID, VendName
select VENDid, VENDname,
(select top 1 purchaseDate from purchase p
where p.VENDid=v.VENDid order by purchaseDate desc) as 'Purchase date'
from Vendor v
Que. If i will add some more column in purchase table like -
2)purchase table
------------------------------------------
VENDid Purchasedate amount_paid
------ ------------ ------------
1 12-01-2012 10000
1 10-11-2013 20000
2 22-02-2014 15000
2 11-04-2014 30000
3 10-05-2014 80000
3 11-06-2014 17000
1 14-06-2014 28000
and i want amount_paid along with previous output like-
---------------------------------------------
VENDid VENDname PurchaseDate amount_paid
------- -------- ------------- -------------
1 ABC 14-06-2014 28000
2 XYZ 11-04-2014 30000
3 WXY 11-06-2014 17000
then what will be query..
You appear to be using SQL Server. If so, you can use cross apply:
select v.VENDid, v.VENDname, p.PurchaseDate, p.Amount_Paid
from Vendor v cross apply
(select top 1 p.*
from purchase p
where p.VENDid = v.VENDid
order by p.purchaseDate desc
) p ;

How to bring together multiple delta tables?

I have a table with IDs and primary information. I also have two delta tables keyed on ID and date of change. I need to build a view that merges these three tables together indicating all changes over time.
Main Table:
ID Name
-- ------------------
1 Bob Jones
2 Dave Smith
First Attribute Table:
ID Date Attr1
-- ---------- -----
1 01/01/2013 25
1 02/15/2013 33
1 02/17/2013 47
1 03/02/2013 58
2 02/01/2013 1
...
Second Attribute Table
ID Date Attr2
-- ---------- -----
1 01/01/2013 ABC
1 01/05/2013 DEF
1 01/15/2013 RST
1 02/10/2013 XYZ
1 02/15/2013 Foo
1 03/05/2013 Blah
2 02/01/2013 Two
...
Based on that data, for Bob Jones, I need the view to return the following:
ID Name Date Attr1 Attr2
-- ----------- ---------- ----- -----
1 Bob Jones 01/01/2013 25 ABC
1 Bob Jones 01/05/2013 25 DEF
1 Bob Jones 01/15/2013 25 RST
1 Bob Jones 02/10/2013 25 XYZ
1 Bob Jones 02/15/2013 33 Foo
1 Bob Jones 02/17/2013 47 Foo
1 Bob Jones 03/02/2013 58 Foo
1 Bob Jones 03/05/2013 58 Blah
I tried outer joining the attribute tables to get all change values ordered by date and then used an outer join on the entire query with itself to get "prior" records:
with qry as (
select
rownum = ROW_NUMBER() OVER (ORDER BY m.ID, a.DATE),
m.ID,
m.Name,
a.DATE,
a.Attr1,
a.Attr2
from Main m
inner join (
select
COALESCE(a1.ID, a2.ID) as ID,
COALESCE(a1.LOAD_DATE, a2.LOAD_DATE) as LOAD_DATE,
a1.Attr1,
a2.Attr2
from Attributes1 a1
full outer join Attributes2 a2
on (a1.ID = a2.ID and a1.DATE = a2.DATE)
) a on (a.ID = m.ID)
)
select
COALESCE(qry.ID, prev.ID) as ID,
COALESCE(qry.Name, prev.Name) as Name,
COALESCE(qry.DATE, prev.DATE) as DATE,
COALESCE(qry.Attr1, prev.Attr1) as Attr1,
COALESCE(qry.Attr2, prev.Attr2) as Attr2,
from qry
left join qry prev
on (prev.rownum = qry.rownum - 1)
order by ID, DATE
However, that doesn't work when one attribute table changes quicker than the other because the attributes that didn't change are null in the results of the attribute table join and if two nulls show up back-to-back, the coalesce will return a null when I need the last non-null value that was in that column.
Can this even be done in a view in SQL Server 2012?

How to Join three tables

I have 3 tables : Orders, Customers and Suppliers
Structure and Data:
Orders
================================
OrdNo, OrdDt, OrdType, CSID
--------------------------------
1 01/04/2011 C 2
2 01/04/2011 S 1
--------------------------------
Customers
----------
CID, CName
----------
1 John
2 Boby
----------
Suppliers
=========
SID, SName
----------
1 Tony
2 Mohan
----------
If OrdTYpe = "C" then pick data from Customers table for CSID = CID
If OrdTYpe = "S" then pick data from Suppliers table for CSID = SID
How to list the records like
--------------------------------------
OrdNo, OrdDt, OrdType, CSID CSName
--------------------------------------
1 01/04/2011 C 2 Boby
2 01/04/2011 S 1 Tony
--------------------------------------
Does this get what you want?
SELECT ordno, orddt, ordtype, csid,
COALESCE( c.name, s.name ) csname
FROM orders o
LEFT JOIN customer c ON o.ordtype='C' AND c.cid = o.csid
LEFT JOIN suppliers s ON o.ordtype='S' AND c.sid = o.csid
Another possibility, at least in Oracle, would be:
SELECT ordno, orddt, ordtype, csid,
CASE WHEN ordtype='C' THEN (SELECT name FROM customer WHERE cid = csid)
WHEN ordtype='S' THEN (SELECT name FROM suppliers WHERE sid = csid)
END csname
FROM orders;
Martin has a good point. I'm no pro, but I would suggest making an intermediate table that will allow you to keep customers and suppliers separate, yet still pull from a common set of id's
Orders
========================
OrdNo, OrdDt, CSID
------------------------
1 01/04/2011 2
2 01/04/2011 1
-------------------------
ClientIDs
---
ID
---
1
2
3
4
---
Customers
----------
CID, CName
----------
1 John
3 Boby
----------
Suppliers
=========
SID, SName
----------
2 Tony
4 Mohan
----------
That way you end up with something like this:
-------------------------------
OrdNo, OrdDt, CSID CSName
-------------------------------
1 01/04/2011 2 Tony
2 01/04/2011 1 John
-------------------------------
and by back tracking up through the (now) unique ID you will be able to tell if it is a customer, or supplier... also I'm pretty sure your SQL will run faster with this route (don't hold me to it though). If you like this idea, I could look into SQL to back it.
SELECT o.[OrdNo], o.[OrdDt], o.[OrdType], o.[CSID],
CASE WHEN o.[OrdType] = 'C'
THEN c.[CName]
ELSE s.[SName]
END as [CSName]
FROM Orders AS o
LEFT JOIN Customers AS c
ON o.[CSID] = c.[CID]
LEFT JOIN Suppliers AS s
ON o.[CSID] = s.[SID]