Using IN operator on a correlated subquery - sql

Consider the following query on the two following Tables:
SELECT sid FROM Salesman SM WHERE sid IN(SELECT sid FROM Sale S WHERE s.sid<>sm.sid)
Sale Table
SALEID SID SLDATE
1001 1 01-Jan-14
1006 1 01-Jun-15
1003 4 01-Feb-14
1002 5 02-Jan-14
1005 2 01-Feb-14
1004 1 01-Mar-14
Salesman Table
SID SNAME LOCATION
1 Peter London
2 Michael Paris
3 John Mumbai
5 Kevin London
4 Harry Chicago
6 Alex Chicago
Why it doesn't fetch any results?
For example: on the first iteration of outer query, inner query should return 2,4,5. But it seems not. Why?
PS: Please ignore the practical use of such a query. This is for academic purpose.

Because it is impossible to fetch anything with this condition, I don't understand what you were trying to do..
As I see it you either meant to select all the sailsmans that didn't make any sales, and in that case this is the right query:
select sid from Salesman SM where sid not in (select sid from Sale S)
or you want only the salesmans that did make a sale, and in that case this is the right query:
select sid from Salesman SM where sid in (select sid from Sale S)

Related

How group by count from multiple tables

I have 3 different tables, country, city, and customer. Tables are shown below:
country table:
id country_name
1 UK
2 US
3 Brazil
:
n Canada
city table
id city_name postal_code country_id
1 London 30090 1
2 Dallas 20909 2
3 Rio 29090 3
4 Atlanta 30318 2
:
n Vancouver 32230 n
customer table
id customer_name city_id
1 John 1
2 Pete 3
3 Dave 2
4 May 2
5 Chuck 4
6 Sam 3
7 Henry 3
***country.id is references city.country_id, and city.id is references customer.city_id
I want to write a query that can extract the country name, city name and the count of the customer of the associate city. But with one condition, the query will return all cities with more customers than the average number of customers of all cities
It will look something like below, this is the correct output
UK London 2
Brazil Rio 3
but I kept getting this output, which isn't correct
UK London 2
US Dallas 2
US Atlanta 1
Brazil Rio 3
I fixed my SQL query but it doesn't give me the result that I want
SELECT country.country_name, city.city_name, COUNT(customer.city_id) from country
JOIN city on country.id = city.country_id
JOIN customer on city.id = customer.city_id
Group by city_name,country.country_name;
I am wondering how can I do this and fix my code?
add country.country_name in group by
SELECT country.country_name, city.city_name, COUNT(customer.city_id) from country
JOIN city on country.id = city.country_id
JOIN customer on city.id = customer.city_id
Group by city_name,country.country_name
You are missing country.country_name in the query it will give you error. As a general rule all columns on which aggregate function is not applied should be part of group by clause.
So either you write your query without country_name in the select or add country_name in the group by clause.

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.

get extra rows for each group where date doesn't exist

I've been playing with this for days, and can't seem to come up with something. I have this query:
select
v.emp_name as Name
,MONTH(v.YearMonth) as m
,v.SalesTotal as Amount
from SalesTotals
Which gives me these results:
Name m Amount
Smith 1 123.50
Smith 2 40.21
Smith 3 444.21
Smith 4 23.21
Jones 1 121.00
Jones 2 499.00
Jones 3 23.23
Jones 4 41.82
etc....
What I need to do is use a JOIN or something, so that I get a NULL value for each month (1-12), for each name:
Name m Amount
Smith 1 123.50
Smith 2 40.21
Smith 3 444.21
Smith 4 23.21
Smith 5 NULL
Smith 6 NULL
Smith ... NULL
Smith 12 NULL
Jones 1 121.00
Jones 2 499.00
Jones 3 23.23
Jones 4 41.82
Jones 5 NULL
Jones ... NULL
Jones 12 NULL
etc....
I have a "Numbers" table, and have tried doing:
select
v.emp_name as Name
,MONTH(v.YearMonth) as m
,v.SalesTotal as Amount
from SalesTotals
FULL JOIN Number n on n.Number = MONTH(v.YearMonth) and n in(1,2,3,4,5,6,7,8,9,10,11,12)
But that only gives me 6 additional NULL rows, where what I want is actually 6 NULL rows for each group of names. I've tried using Group By, but not sure how to use it in a JOIN statement like that, and not even sure if that's the correct route to take.
Any advice or direction is much appreciated!
Here's one way to do it:
select
s.emp_name as Name
,s.Number as m
,st.salestotal as Amount
from (
select distinct emp_name, number
from salestotals, numbers
where number between 1 and 12) s left join salestotals st on
s.emp_name = st.emp_name and s.number = month(st.yearmonth)
Condensed SQL Fiddle
You could do:
SELECT EN.emp_name Name,
N.Number M,
ST.SalesTotal Amount
FROM ( SELECT Number
FROM NumberTable
WHERE Number BETWEEN 1 AND 12) N
CROSS JOIN (SELECT DISTINCT emp_name
FROM SalesTotals) EN
LEFT JOIN SalesTotals ST
ON N.Number = MONTH(ST.YearMonth)
AND EN.emp_name = ST.emp_name

How does select query works?

I having trouble with this query
it is executing quit well but I cannot make out
how is this select statement working.
Any help or explanation on this problem will be appreciated ..
thank you
these are my tables and query
here am looking for the employee who lives in same city as the the company for which they work
Table:-emp
eid name street city
----------- ---------------- ------------- ------------
1 yeman asd vasai
2 aksh adssd mumbai
3 chintan ghfgh mumbai
4 samual ghfdgh bandra
5 ddlj fghfgh andheri
6 jack fghnfg Bandra
7 bridge gfhfgh vasai
8 rahim ghfgh mumbai
9 chirag fghfghfg bandra
10 mistry hhhty bandra
11 ravi tytey andheri
Table:- company
cid companyname city
----------- ------------------- ------------
1 Vasai Industries vasai
2 Mumbai Pharmacy mumbai
3 bandra loft bandra
4 andheri tactics andheri
Table:= works
eid cid salary
----------- ----------- -----------
1 1 200
2 3 4831
3 4 4457
4 2 20001
5 1 32221
6 2 224
7 3 784
8 1 336
9 3 2489
10 2 4789
11 1 22541
Query
select * from emp
where eid
IN (select eid from works
where cid=(select cid from company
where city=emp.city))
why not use this query with joins and its easy to understand then a bunch of subqueries.
select * from emp
inner join works on works.eid = emp.eid
inner join company on company.city=emp.city
Explanation:
1.select cid from company where city=emp.city
Here you are getting city id regarding cities which are same in emp and company
2.
select eid from works
where cid=(select cid from company
where city=emp.city)
Here you getting collection of id's from works table which cid is same in emp and company
3.
select * from emp
where eid
IN (select eid from works
where cid=(select cid from company
where city=emp.city))
here you are getting all records based on emp id's whose cities are same in emp and city

How to get the student academic progress?

course Table
course_code course_name credit_points_reqd
1 Comp Science 300
2 Soft Engineering 300
subject Table
subject_code subject_name credit_points
CS123 C Prog 15
CS124 COBOL 15
enrolment table
student_id student_name course_code subject_code Results
1 Lara Croft 1 CS123 70
1 Lara Croft 1 CS124 50
2 Tom Raider 2 CS123 60
2 Tom Raider 2 CS124 40
3 James Bond 1 CS123 NULL
3 James Bond 1 CS124 40
OUTPUT TABLE
student_name course_name credit_points_obt credit_points_reqd
Lara Croft Comp Science 30 300
Tom Raider Soft Engineering 15 300
I'm currently using TSQL. So here's the situation. I've prepared these tables to get the output like the way it i showed u up there. I need to calculate the credit points obtained. Credit points are achieved if the student receives > 50 for a subject they took. I want to ignore students that has not received any credit points at all (eg, James Bond is ignored as he has not achieved any points yet)
select student_name, course_name,credit_points_obt,credit_points_reqd
FROM enrolment (SELECT student_full_name, SUM(credit_points) AS credit_points_obt
FROM enrolment
GROUP BY student_id),
Totally stuck...I have no idea where to go now.
You can sum conditionally to get points for subject. If none are given result will be null, so you filter out those student/course pairs in having clause.
I've changed > 50 condition to >= 50 because your results contradict your requirements. Also, by the data I'd say that you have omitted student table for brewity, but if you haven't, it is a must.
Live test is # Sql Fiddle.
select enrolment.student_name,
course.course_name,
course.credit_points_reqd,
sum(case when enrolment.results >= 50
then subject.credit_points
end) credit_points_obt
FROM enrolment
inner join course
on enrolment.course_code = course.course_code
inner join subject
on enrolment.subject_code = subject.subject_code
group by enrolment.student_name,
course.course_name,
course.credit_points_reqd
having sum(case when enrolment.results >= 50
then subject.credit_points
end) is not null