Use inner join and left join with more than 2 tables? [duplicate] - sql

This question already exists:
Use left join and inner join with more than 2 tables
Closed 4 months ago.
Here you can see I have three tables
Student table
Stud_id Name Br_id Email City_id
1001 Ankit 101 ankit#bmail.com 1
1002 Pranav 105 pranav#bmail.com 2
1003 Raj 102 raj#bmail.com 2
1004 Shyam 112 shyam#bmail.com 4
1005 Duke 112 duke#bmail.com 2
1006 Jhon 102 jhon#bmail.com 3
1007 Aman 101 aman#bmail.com 4
1008 Pavan 111 pavan#bmail.com 13
1009 Virat 112 virat#bmail.com 12
Branch Table
Br_id Br_name HOD Contact
101 CSE SH Rao 22345
102 MECH AP Sharma 28210
103 EXTC VK Reddy 34152
104 CHEM SK Mehta 45612
105 IT VL Shelke 22521
106 AI KH Verma 12332
107 PROD PG Kakde 90876
Address Table
City_id City Pincode
1 Mumbai 400121
2 Pune 450011
3 Lucknow 553001
4 Delhi 443221
5 Kolkata 213445
6 Chennai 345432
7 Nagpur 323451
8 Sri Nagar 321321
I am using here three tables first one is a student table and the second one is a Branch table and the third one is an Address table
So I am writing a query like this here you can see below
select [Name], Br_name, City
from student
inner join Branch on student.Br_id = Branch.Br_id
left join [Address] on student.City_id = [Address].City_id
I have three tables I want to show here the student's name and branch name city name, but I want to show the student who has their branch only. I also want to show the student who has their city as well as show a student who does not have any city.
I wrote the query above but here I am not getting the result. Here student's name who does not have any city what's wrong here in my above join SQL query?
Here as you can see I am getting this result which I do not want to show
Name Br_name City
Ankit CSE Mumbai
Pranav IT Pune
Raj MECH Pune
Jhon MECH Lucknow
Aman CSE Delhi
Why can I not get the students who do not have a city and who have a city? What's wrong here in my join query what I am missing here?
Please let me know what's wrong in my above join query what should I do to get proper result? I have given three tables above
You can see that and why I am not able to get the result what I want to show what is the wrong in the above my join query please let me know
I hope someone will help me. Thank you so much.

Related

I have 3 tables Flight_schedule, Flights and third is Route I need a stored procedure in SQL which give the cheapest flight on a given date

I have 3 tables Flight_schedule, Flights and third is Route I need a stored procedure in SQL which give the cheapest flight on a given date.
When the parameter date is passed to procedure suppose 2 February so the result would be the lowest fare flight on the 2 Feb.
Here is the code where I have joined the tables and passed the parameter to stored procedure but when I am confused in the condition part.
Create proc spCheapestFlight
#FLIGHT_DATE DATE
AS
BEGIN
SELECT Flight_schedule.FlightDate,Flight_schedule.Departure,route.source, route.destination,
Flight_schedule.Arrival
,Flight_schedule.Fare,Flights.Flight_name
FROM Flight_schedule
inner join route ON Flight_schedule.Route_id=route.Route_id inner join
Flights on Flights.Flight_id=Flight_schedule.Flight_id
where Flight_schedule.FlightDate = #FLIGHT_DATE
END
Flight_schedule
F_Id
Flight_id
Total_Fare
FlightDate
Departure
Arrival
Route_Id
Fare
10000
1
1001
2022-02-01
09:30:30.0000000
11:20:45.0000000
100
7500.8
10001
2
1002
2022-02-02
09:45:30.0000000
11:55:45.0000000
101
7000.9
10002
3
1003
2022-02-03
10:30:30.0000000
12:20:45.0000000
102
5111.5
10003
4
1004
2022-02-04
11:30:30.0000000
14:20:45.0000000
103
5500.9
10004
5
1005
2022-02-05
12:30:30.0000000
15:20:45.0000000
104
9000.7
10005
1
1006
2022-02-06
13:30:30.0000000
16:20:45.0000000
105
8675.5
10006
2
1007
2022-02-07
14:30:30.0000000
17:20:45.0000000
106
4000.5
10007
3
1008
2022-02-08
15:30:30.0000000
18:20:45.0000000
107
4100.5
10008
4
1009
2022-02-09
16:30:30.0000000
19:20:45.0000000
101
4000.3
10009
2
1006
2022-02-10
06:30:30.0000000
08:20:45.0000000
108
4000.3
Flights
Flight_id
Flight_name
Capacity
1
Vistara
30
2
Indigo
30
3
SpiceJet
30
4
Go_First
30
5
Air India
30
Route
route_id
source
destination
100
Mumbai
Delhi
101
Delhi
Ahmedabad
102
Ahmedabad
Delhi
103
Ahmedabad
Mumbai
104
Chennai
Mumbai
105
Chennai
Goa
106
Chennai
Delhi
107
Goa
Delhi
108
Bangalore
Delhi
109
Hyderabad
Delhi
your data does not show more than 1 flight per day, in addition there is no need for table Flights and table Route to get result, you should join table FlightSchedule with itself in order to get the minimum fare. your problem can be solve with table-value function(TVF). you should change you PROCEDURE as follows:
CREATE PROCEDURE spCheapest_Costliest_Flight (#FlightDate DATE)
AS
SELECT FS.FlightDate,FS.Departure,route.source, route.destination,
FS.Arrival ,T.Fare,Flights.Flight_name
FROM Flight_schedule FS
inner join route ON FS.Route_id=route.Route_id
inner join Flights on Flights.Flight_id=FS.Flight_id
inner join (select FlightDate FlightDate,MIN(Fare) Fare
from Flight_schedule GROUP BY FlightDate) T
ON T.FlightDate=FS.FlightDate and T.FlightDate=#FlightDate and FS.FlightDate=#FlightDate
GO

Replace Id of one column by a name from another table while using the count statement?

I am trying to get the count of patients by province for my school project, I have managed to get the count and the Id of the province in a table but since I am using the count statement it will not let me use join to show the ProvinceName instead of the Id (it says it's not numerical).
Here is the schema of the two tables I am talking about
The content of the Province table is as follow:
ProvinceId
ProvinceName
ProvinceShortName
1
Terre-Neuve-et-Labrador
NL
2
Île-du-Prince-Édouard
PE
3
Nouvelle-Écosse
NS
4
Nouveau-Brunswick
NB
5
Québec
QC
6
Ontario
ON
7
Manitoba
MB
8
Saskatchewan
SK
9
Alberta
AB
10
Colombie-Britannique
BC
11
Yukon
YT
12
Territoires du Nord-Ouest
NT
13
Nunavut
NU
And here is n sample data from the Patient table (don't worry it's fake data!):
SS
FirstName
LastName
InsuranceNumber
InsuranceProvince
DateOfBirth
Sex
PhoneNumber
2
Doris
Patel
PATD778276
5
1977-08-02
F
514-754-6488
3
Judith
Doe
DOEJ7712917
5
1977-12-09
F
418-267-2263
4
Rosemary
Barrett
BARR05122566
6
2005-12-25
F
905-638-5062
5
Cody
Kennedy
KENC047167
10
2004-07-01
M
604-833-7712
I managed to get the patient count by province using the following statement:
select count(SS),InsuranceProvince
from Patient
full JOIN Province ON Patient.InsuranceProvince = Province.ProvinceId
group by InsuranceProvince
which gives me the following table:
PatientCount
InsuranceProvince
13
1
33
2
54
3
4
4
608
5
1778
6
25
7
209
8
547
9
649
10
6
11
35
12
24
13
How can I replace the id's with the correct ProvinceShortName to get the following final result?
ProvinceName
PatientCount
NL
13
PE
33
NS
54
NB
4
QC
608
ON
1778
MB
25
SK
209
AB
547
BC
649
YT
6
NT
35
NU
24
Thanks in advance!
So you can actually just specify that in the select. Note that it's best practise to include the thing you group by in the select, but since your question is so specific then...
SELECT ProvinceShortName, COUNT(SS) AS PatientsInProvince
FROM Patient
JOIN Province ON Patient.InsuranceProvince=Province.ProvinceId
GROUP BY InsuranceProvince;
I would suggest:
select pr.ProvinceShortName, count(*)
from Patient p join
Province pr
on p.InsuranceProvince = pr.ProvinceId
group by pr.ProvinceShortName
order by min(pr.ProvinceId);
Notes:
The key is including the columns you want in the select and group by.
You seem to want the results in province number order, so I included an order by.
There is no need to count the non-NULL values of SS. You might as well use count(*).
Table aliases make the query easier to write and to read.
I assume that you need to show the patient count by province.
SELECT
Province.ProvinceShortName AS [ProvinceName]
,COUNT(1) as [PatinetCount]
FROM Patient
RIGHT JOIN Province ON Patient.InsuranceProvince = Province.ProvinceId
GROUP BY ProvinceShortName
Just altering your query to
select ProvinceShortName As PatientCount,count(InsuranceProvince) As PatientCount
from Patient
full JOIN Province ON Patient.InsuranceProvince = Province.ProvinceId
group by ProvinceShortName

Join multiple tables and pick results from most recent table

I have 4 tables. I want all the rows and cols from my first table tbl_2021 and only those data which are not in tbl_2021 but present in the the rest 3 tables, but based on one condition
if there id exist in tbl_2020, tbl_2019 and in tbl_2018 then i need the id and it's details from the most recent table that is tbl_2020.
if an id is across 2019 and 2018 table, then i need the data from 2019 so on like that.If in 2020 and 018 then 020 and so on
if the same is across 2021,2020,2019 and 2018 then the data from 2021 is selected.
And - I'm hail from a shell scripting background, and i've just started with sql. so if any noble mind could tell me the approach or what i should do to get these pieces together would mean more than happiness to me. Thank you
tbl_2021
id
name
addr
location
country
contintent
gdp
123
rob
dware
texas
us
us
8
456
lilly
gwood
london
uk
uk
5
670
rick
utown
newyrok
us
us
8
490
zang
kcity
hk
hongkong
hongkong
6
tbl_020
id
location
name
999
ger
roger
888
bel
leslie
670
us
marie
tbl_019
id
location
name
data
network
999
uk
roger
xx
na
555
rus
vladmir
ux
na
879
us
marie
xx
ua
481
cn
kim
tbl_018
id
location
name
data
network
823
uk
roger
xx
na
555
rus
vladmir
ux
na
879
us
maria
xx
ua
670
us
marie
xy
uy
888
in
raj
xx
jo
output:
id
name
addr
location
country
contintent
gdp
123
rob
dware
texas
us
us
8
456
lilly
gwood
london
uk
uk
5
670
rick
utown
newyrok
us
us
8
490
zang
kcity
hk
hongkong
hongkong
6
999
roger
ger
888
leslie
bel
555
vladmir
rus
879
marie
us
481
kim
cn
823
roger
uk
First, you should fix your data model. It is not a good idea to store such data in separate tables. Instead, you should store in a single table with a year column.
Second, I think you can solve your problem using full join, but it is a little tricky:
select coalesce(t21.id, t20.id, t19.id, t18.id) as id,
coalesce(t21.name, t20.name, t19.name, t18.name) as name,
t21.addr,
. . .
from tbl_2021 t21 full join
tbl_2020 t20
on t21.id = t20.id full join
tbl_2019 t19
on t19.id = coalesce(t21.id, t20.id) full join
tbl_2018 t18
on t18.id = coalesce(t21.id, t20.id, t19.id);
You need to carefully figure out how the columns should be pulled from the different tables.
First you can union all the data from four tables with union all. Then with row_number() we need to serialized rows for each id from higher to lower. Finally select one row for each id with highest year .
with cte as
(
select id,name addr ,location ,country, contintent,data,network, row_number()over (partition by id order by sl ) rn from
(
select id,name ,addr ,location , country, contintent,data,network, 1 sl from tbl_21
union all
select id,name ,'' addr ,location ,'' country,'' contintent, data, network, 2 sl from tbl_20
union all
select id,name ,'' addr ,location ,'' country,'' contintent, data,network, 3 sl from tbl_19
union all
select id,name ,'' addr ,location ,'' country,'' contintent, data,network, 4 sl from tbl_18
)t
)
select id,name ,addr ,location ,country, contintent,data,network from cte where rn=1

How to select data in SQL based on a filter which changes if there is no data in a specific table column?

I have tables similar to the three below. I need to join the first two tables based on id, and then join the third table based on second name. However the last table needs a filter where the city should be equal to London unless age is empty in which case the city should equal Manchester.
I tried the code below using CASE statement but it is not working. I am new to SQL so I was not sure how can I combine a where statement with an if clause where the filter for the selection changes depending on whether there is data in a different column than the one used to filter by. The DBMS I am using Toad for Oracle.
FIRST.NAME.TABLE
ID FIRST_NAME ENTRY_DATE
1 JOHN 09/09/2019
2 NICOLA 09/09/2019
3 PATRICK 05/09/2019
4 JOAN 01/09/2019
5 JAKE 09/09/2019
6 AMELIA 01/09/2019
7 CAMERON 09/09/2019
SECOND.NAME.TABLE
ID SECOND_NAME ENTRY_DATE
1 BROWN 09/09/2019
2 SMITH 09/09/2019
3 COLE 05/09/2019
4 HOUSTON 01/09/2019
5 FARRIS 09/09/2019
6 HATHAWAY 01/09/2019
7 JONES 09/09/2019
CITY.AGE.TABLE
CITY SECOND_NAME AGE
LONDON BROWN 24.00
LONDON SMITH
MANCHESTER COLE 30.00
MANCHESTER HOUSTON 66.00
LONDON FARRIS
LONDON HATHAWAY 32.00
GLASGOW JONES 28.00
MANCHESTER SMITH 32.00
LONDON FARRIS 62.00
SELECT FN.ID,
FN.FIRST_NAME,
SN.SECOND_NAME,
AC.CITY,
AC.AGE
FROM FIRST.NAME.TABLE AS FN
INNER JOIN SECOND.NAME.TABLE SN
ON FN.ID=SN.ID
INNER JOIN CITY.AGE.TABLE AS CA
ON SN.SECOND NAME=AC.SECOND_NAME
WHERE FN.ENTRY_DATE='09-SEP-19'
AND SN.ENTRY_DATE='09-SEP-19'
AND (CASE WHEN AC.CITY='LONDON' AND AC.AGE IS NOT NULL
THEN AC.CITY='LONDON'
ELSE AS.CITY='MANCHESTER' END)
You can express this as boolean logic:
WHERE FN.ENTRY_DATE = DATE '2019-09-09' AND
SN.ENTRY_DATE = DATE '2019-09-09' AND
(AC.AGE IS NOT NULL AND AC.CITY = 'LONDON' OR
AC.AGE IS NULL AND AC.CITY = 'MANCHESTER'
)
This answers your question about how to implement the logic using SQL. However, I'm not sure that is the logic that you really want. I speculate that you really want a LEFT JOIN to the age table.

SQL Select Distinct returning duplicates

I am trying to return the country, golfer name, golfer age, and average drive for the golfers with the highest average drive from each country.
However I am getting a result set with duplicates of the same country. What am I doing wrong? here is my code:
select distinct country, name, age, avgdrive
from pga.golfers S1
inner join
(select max(avgdrive) as MaxDrive
from pga.golfers
group by country) S2
on S1.avgdrive = s2.MaxDrive
order by avgdrive;
These are some of the results I've been getting back, I should only be getting 15 rows, but instead I'm getting 20:
COUN NAME AGE AVGDRIVE
---- ------------------------------ ---------- ----------
Can Mike Weir 35 279.9
T&T Stephen Ames 41 285.8
USA Tim Petrovic 39 285.8
Ger Bernhard Langer 47 289.3
Swe Fredrik Jacobson 30 290
Jpn Ryuji Imada 28 290
Kor K.J. Choi 37 290.4
Eng Greg Owen 33 291.8
Ire Padraig Harrington 33 291.8
USA Scott McCarron 40 291.8
Eng Justin Rose 25 293.1
Ind Arjun Atwal 32 293.7
USA John Rollins 30 293.7
NIr Darren Clarke 37 294
Swe Daniel Chopra 31 297.2
Aus Adam Scott 25 300.6
Fij Vijay Singh 42 300.7
Spn Sergio Garcia 25 301.9
SAf Ernie Els 35 302.9
USA Tiger Woods 29 315.2
You are missing a join condition:
select s1.country, s1.name, s1.age, s1.avgdrive
from pga.golfers S1 inner join
(select country, max(avgdrive) as MaxDrive
from pga.golfers
group by country
) S2
on S1.avgdrive = s2.MaxDrive and s1.country = s2.country
order by s1.avgdrive;
Your problem is that some people in one country have the same average as the best in another country.
DISTINCT eliminated duplicate rows, not values in some fields.
To get a list of countries with ages, names, and max drives, you would need to group the whole select by country.