Sub query for two tables base on status using SQL - sql

I have two tables Patient and PatientStatusLog using SQL tables
1.Patient
sno patientid status createdby Reegion
1 481910 D 1222 India
2 476795 D 1222 India
2.PatientStatusLog
sno patientid status comments createdby CreatedDate(dd/mm/yyyy)
1 481910 A mycommnet 1222 01/01/2000
2 481910 A mycommnet 1222 02/01/2000
3 481910 B mycommnet 1222 01/01/2000
4 481910 C mycommnet 1222 01/01/2000
I need output like below who have status A and createddate should recent pass date from PatientStatusLog table using patientid of both tables
Region status CreatedDate
India A 02/01/2000

You can use window functions:
select . . . -- whatever columns you want
from Patient p join
(select psl.*,
rank() over (partition by patientid order by createddate desc) as seqnum
from PatientStatusLog psl
) psl
on p.patientid = psl.patientid
where psl.seqnum = 1 and psl.status = 'A';
Note that this uses rank() because the creation date appears to have duplicates.

Try this:
SELECT TOP 1
p.Region,
psl.Status,
psl.CreatedDate
FROM
Patient [p]
JOIN PatientStatusLog [psl] ON psl.patientid = p.patientid
AND psl.status = 'A'
ORDER BY
psl.CreatedDate DESC
For the subquery request:
SELECT
p.Region,
x.status,
x.CreatedDate
FROM
(
SELECT TOP 1
PatientId,
Status,
CreatedDate
FROM
PatientStatusLog
WHERE
status = 'A'
ORDER BY
CreatedDate DESC
) AS x
JOIN Patient [p] ON p.PatientId = x.PatientId
Note that this is definitely not the best way to handle this, both from a code readability and optimization perspective.

Related

SQL MAX aggregate function not bringing the latest date

Purpose: I am trying to find the max date of when the teachers made a purchase and type.
Orders table
ID
Ordertype
Status
TeacherID
PurchaseDate
SchoolID
TeacherassistantID
1
Pencils
Completed
1
1/1/2021
1
1
2
Paper
Completed
1
3/5/2021
1
1
3
Notebooks
Completed
1
4/1/2021
1
1
4
Erasers
Completed
2
2/1/2021
2
2
Teachers table
TeacherID
Teachername
1
Mary Smith
2
Jason Crane
School table
ID
schoolname
1
ABC school
2
PS1
3
PS2
Here is my attempted code:
SELECT o.ordertype, o.status, t.Teachername, s.schoolname
,MAX(o.Purchasedate) OVER (PARTITION by t.ID) last_purchase
FROM orders o
INNER JOIN teachers t ON t.ID=o.TeacherID
INNER JOIN schools s ON s.ID=o.schoolID
WHERE o.status in ('Completed','In-progress')
AND o.ordertype not like 'notebook'
It should look like this:
Ordertype
Status
teachername
last_purchase
schoolname
Paper
Completed
Mary Smith
3/5/2021
ABC School
Erasers
Completed
PS1
2/1/2021
ABC school
It is bringing multiple rows instead of just the latest purchase date and its associated rows. I think i need a subquery.
Aggregation functions are not appropriate for what you are trying to do. Their purpose is to summarize values in multiple rows, not to choose a particular row.
Just a window function does not filter any rows.
You want to use window functions with filtering:
SELECT ordertype, status, Teachername, schoolname, Purchasedate
FROM (SELECT o.ordertype, o.status, t.Teachername, s.schoolname,
o.Purchasedate,
ROW_NUMBER() OVER (PARTITION by t.ID ORDER BY o.PurchaseDate DESC) as seqnum
FROM orders o JOIN
teachers t
ON t.ID = o.TeacherID
schools s
ON s.ID = o.schoolID
WHERE o.status in ('Completed', 'In-progress') AND
o.ordertype not like 'notebook'
) o
WHERE seqnum = 1;
You can use it in different way. it's better to use Group By for grouping the other columns and after that use Order by for reorder all records just like bellow.
SELECT top 1 o.ordertype, o.status, t.Teachername, s.schoolname
,o.Purchasedate
FROM orders o
INNER JOIN teachers t ON t.ID=o.TeacherID
INNER JOIN schools s ON s.ID=o.schoolID
having o.status in ('Completed','In-progress')
AND o.ordertype not like 'notebook'
group by o.ordertype, o.status, t.Teachername, s.schoolname
order by o.Purchasedate Desc

Select based on max date from another table

I'm trying to do a simple Select query by getting the country based on the MAX Last update from the other table.
Order#
1
2
3
4
The other table contains the country and the last update:
Order# Cntry Last Update
1 12/21/2019 9:19 PM
1 US 1/10/2020 1:07 AM
2 JP 7/29/2020 12:15 PM
3 CA 4/12/1992 2:04 PM
3 GB 11/6/2001 9:26 AM
3 DK 2/1/2005 3:04 AM
4 CN 8/20/2013 12:04 AM
4 10/1/2015 4:04 PM
My desired result:
Order# Country
1 US
2 JP
3 DK
4
Not sure the right solution for this. So far i'm stuck with this:
SELECT Main.[Order#], tempTable.Cntry
FROM Main
LEFT JOIN (
SELECT [Order#], Cntry, Max([Last Update]) as LatestDate FROM Country
GROUP BY [Order#], Cntry
) as tempTable ON Main.[Order#] = tempTable.[Order#];
Thanks in advance!
If needs only number of order and country,maybe don't need two tables:
SELECT distinct order, country
FROM
(
SELECT order, LAST_VALUE (country) OVER (PARTITION by [order] order by last_update) country FROM Country
) X
In SQL Server, you can use a correlated subquery:
update main
set country = (select top (1) s.country
from secondtable s
where s.order# = main.order#
order by s.lastupdate desc
);
EDIT:
A select would look quite simimilar:
select m.*,
(select top (1) country
from secondtable s
where s.order# = main.order#
order by s.lastupdate desc
)
from main m
I don't have time to try it with sample data, but is that what you are looking for?
select order orde, cntry
from table
where last_update =
(select max(last_update) from table where order = orde)

Create a subquery in a view SQL- ORACLE

I am setting up a database view.
I have a table PERSON and a RELATION_COMPANY related by the person_id. I amb trying to obtain the min date from the relation_company for each person_id.
I need to use a subquery?
This is what I have tried so far.
CREATE OR REPLACE VIEW PEOPLE_ADDRESS
select
p.id as ADDRESS_CODE,
case p.type_
when 1 then 'JURIDICAL'
when 0 then 'NATURAL'
end PERSON_TYPE,
(select min(start_date) from relation_company where relation_company.person_id = p.id) as INITIAL_dATE
P.ID as PERSON_CODE,
p.ADDRESS_NAME as ADDRESS,
p.POSTAL_CODE as POSTAL_CODE,
case P.COUNTRY_ID
when 68 then 'NO'
else 'YES'
end FOREIGN_INDICATOR
from
PERSON p join relation_company r on relation_company = p.id ;
That's my person table:
ID TYPE_ ADDRESS_NAME NAME OTHER COLUMNS
1 0 AVENUE SMITH, 19 MICHAEL SCOTT ....
2 1 OXFORD STREET , 119 COMPANY A ....
3 1 CHESTHAM ROAD, 7 COMPANY B ....
That's the RELATION_COMPANY table:
ID PERSON_ID START_DATE
1 1 2016-12-12 00:00:00
2 1 1981-07-09 00:00:00
3 2 1991-10-10 00:00:00
4 2 1981-03-09 00:00:00
5 3 1984-07-05 00:00:00
6 3 1981-08-11 00:00:00
7 3 1987-07-09 00:00:00
8 3 2011-07-09 00:00:00
select min(START_DATE) from RELATION_COMPANY group by PERSON_ID;
The result should be:
ADDRESS_CODE PERSON_TYPE INITIAL_dATE other columns
1 NATURAL 1981-07-09 00:00:00 ....
2 JURIDICAL 1981-03-09 00:00:00 ....
3 JURIDICAL 1981-08-11 00:00:00
I want to get the min(start_date) for each person_id and print it to the view to the column INITIAL_dATE.
I am having trouble to create that query.
You Already have the solution, this query are missing the "person_id" column in your SELECT statement.
Change this query
select min(START_DATE) from RELATION_COMPANY group by PERSON_ID;
To this.
select min(START_DATE),PERSON_ID from RELATION_COMPANY group by PERSON_ID;
Hope this helps.
You don't need a subquery for your solution.
Only add a group-clause to your query.
like this one:
select
p.id as PERSON_ID,
case p.type_
when '1' then 'JURIDICAL'
when '0' then 'NATURAL'
end PERSON_TYPE,
min(start_date) as INITIAL_dATE,
p.ADDRESS_NAME as ADDRESS,
p.POSTAL_CODE as POSTAL_CODE,
case P.COUNTRY_ID
when 68 then 'NO'
else 'YES'
end FOREIGN_INDICATOR
from PERSON p join relation_company r on r.person_id = p.id
group by p.id, type_, ADDRESS_NAME, POSTAL_CODE, P.COUNTRY_ID;

SQL Server joining two tables, order by and display one record

I am having trouble with a SQL Server statement. The perfect scenario is the order and another table (jobs) by date created then display the contact information in descending order. Currently I can get the script to show all records, however if the user has more than one job then they are displayed more than once.
SELECT
c.*,
p.date_created
FROM
[db].[dbo].[Contact] AS c
JOIN
[db].[dbo].[job] AS p ON p.contact_id = c.contact_id
UNION
SELECT
*,
0 as date_created
FROM
[db].[dbo].[Contact]
ORDER BY
p.date_created DESC
The output
contact_id| date_created | contact_name
1 | 8/29/2016 1:07:18 PM | sam
1 | 8/26/2016 1:04:01 PM | sam
14 | 8/24/2016 5:07:22 PM | steve
The final output should just show the newest date created and for one user. Help is much appreciated.
The column in union select must match for number and type so convert 0 in a proper date
SELECT
c.contact_id
,max(p.date_created)
,c. contact_name
FROM [db].[dbo].[Contact] AS c
JOIN [db].[dbo].[job] AS p
ON p.contact_id = c.contact_id
GROUP BY c.contact_id,c. contact_name
union
select
c.contact_id
, convert(datetime, '01/01/1070', 101) as date_created
, c. contact_name
from [db].[dbo].[Contact]
ORDER BY p.date_created desc`
The result you need anyway should be obtainable with only
SELECT
c.contact_id
,max(p.date_created) as max_date_created
,c. contact_name
FROM [db].[dbo].[Contact] AS c
LEFT JOIN [db].[dbo].[job] AS p
ON p.contact_id = c.contact_id
GROUP BY c.contact_id,c. contact_name
ORDER BY c.contact_id,c. contact_name, max_date_created

SQL Server - select min date and id from foreign key

These are my tables:
USER:
id_user name email last_access id_company
1 jhonatan abc#abc.com 2014-12-15 1
2 cesar cef#cef.com 2014-12-31 1
3 john 123#123.com 2015-01-09 2
4 steven 897#asdd.cpom 2015-01-02 2
5 greg sd#touch.com 2014-12-07 1
6 kyle fb#fb.com 2014-11-20 1
COMPANY:
id_company company
1 Facebook
2 Appslovers
I need to know, what are the users which has the MIN last_access per company (just one). It could be like this:
id_user name last_access company
6 kyle 2014-11-20 Facebook
4 steven 2015-01-02 Appslovers
Is it possible ?
Use window function
SELECT id_user,
NAME,
last_access,
company
FROM (SELECT id_user,
NAME,
last_access,
company,
Row_number()OVER(partition BY company ORDER BY last_access) rn
FROM users u
JOIN company c
ON u.id_company = c.id_company) a
WHERE rn = 1
or join both the tables find the min last_access date per company then join the result back to the users table to get the result
SELECT id_user,
NAME,
a.last_access,
a.company
FROM users u
JOIN(SELECT u.id_company,
Min(last_access) last_access,
company
FROM users u
JOIN company c
ON u.id_company = c.id_company
GROUP BY u.id_company,
company) a
ON a.id_company = u.id_company
AND u.last_access = a.last_access
This can be done in many ways, for example by using a window function like row_number to partition the data and then selecting the top rows from each group like this:
;with cte (id_user, name, last_access, company, seq) as (
select
id_user,
name,
last_access,
company,
seq = row_number() over (partition by u.id_company order by last_access)
from [user] u
inner join [company] c on u.id_company = c.id_company
)
select id_user, name, last_access, company
from cte where seq = 1