How to add Average into subquery - sql

So I tried a nested subquery to join three tables together to get the columns needed.
SELECT CAPACITY, Course.COURSE_NAME, SEMESTER
FROM COURSE, Section, Room
WHERE Section.COURSE_NUM
IN (SELECT Course.COURSE_NUMBER
FROM Course
WHERE SEMESTER='FALL' AND Section.ROOM
IN (SELECT Room.ROOM
FROM Room
WHERE AVG(CAPACITY)>CAPACITY
)
)
I had it all right before the second subquery I just need the Column capacity to display results greater then the average of the column. So this was the output before the nested subquery.
SELECT CAPACITY, Course.COURSE_NAME, SEMESTER
FROM COURSE, Section, Room
WHERE Section.COURSE_NUM
IN (SELECT Course.COURSE_NUMBER
FROM Course
WHERE SEMESTER='FALL'
)
I just need to be able to display the Column Capacity results that are greater then its average number.

I cannot tell by this that which table has the Capacity column and what is the relationship between the tables you have there, but all i can say is that you need to join the 3 tables again in the subquery to be able to access the Capacity there, somthing like this:
SELECT CAPACITY, Course.COURSE_NAME, SEMESTER
FROM COURSE, Section, Room
WHERE Section.COURSE_NUM
IN (SELECT Course.COURSE_NUMBER
FROM Course
WHERE SEMESTER='FALL' AND Section.ROOM
IN(
SELECT Room.ROOM
FROM Room
INNER JOIN SEMESTER
ON COLUMNS
INNER JOIN SECTION
ON COLUMNS
INNER JOIN COURSE
ON COLUMNS
WHERE AVG(CAPACITY)>CAPACITY
)

I seemed to be able to figure it out.
SELECT CAPACITY, Course.COURSE_NAME, SEMESTER
FROM COURSE, Section, Room
WHERE Section.COURSE_NUM
IN (SELECT Course.COURSE_NUMBER
FROM COURSE
WHERE SEMESTER='FALL' AND Room.ROOM
IN (SELECT Section.ROOM
FROM Section
WHERE CAPACITY>(SELECT AVG(CAPACITY) FROM Room)))
ORDER BY CAPACITY

Related

outer join with not in and for each in sql

This one has only one table with three columns student, lect and score. for each lecture I need to find the students who have not got any score.
I have written the below query which uses outer joins, but it can do so only for one lect at a time.
Eg: see below I passed 'L02'
How do I get this working for all the lect values as in (L01,L02,L03...etc)
select distinct * from
(
select distinct Student from import1
where lect ='L02'
)i1
right outer join
(select distinct Student from import1) i2
on i1.Student=i2.Student
where i1.Student is null
output of above is
This works for L02. But, how do I modify above to include for all lect values without hardcoding the values of lect?
Sample data from table:
Need a dataset of all possible student/lecture pairs. If the one table contains all the students and lectures that need to be considered, this dataset can be built with:
SELECT Student, Lect FROM (SELECT DISTINCT Student FROM import1) AS S, (SELECT DISTINCT Lect FROM import1) AS L
Otherwise, need a table of all students and a table of all lectures then query:
SELECT Student, Lect FROM Students, Lectures
Now join that query to the scores table with compound link on both identifier fields and use appropriate filter criteria.
SELECT Query1.Student, Query1.Lect, import1.Score
FROM Query1 LEFT JOIN import1
ON (Query1.Lect = import1.Lect) AND (Query1.Student = import1.Student)
WHERE Score Is Null;
Tested with an Access database.

Can't figure out whether I need to NEST or JOIN or something else?

I have 3 tables - continents, country info & flights.
I want to run a query that ranks the continents in DESC order by counting the number of countries within them that have 0 flights booked historically. But shows the continents NAME instead of its id
Continents table - cont_id (P-KEY), name varchar, notes varchar
Country table - cntry_id (P-KEY), name varchar, abbreviation varchar
Flights info table - cntry_id int, cont_id int, flights float, date date
I'm doing the on Metabase and thus far I've managed to get it to do everything but show the continents name, it only goes as far as showing its id. I have tried to NEST the main query and tried to using a join instead but neither have worked
SELECT "public"."flights_info"."cont_id", count(*) AS "count"
FROM "public"."flights_info"
WHERE "public"."flights_info"."flights" <= 0
GROUP BY "public"."flights_info"."cont_id"
ORDER BY "count" DESC
I'm successfully getting the cont_id, I just need a line of code that will make it run a lookup from the continents table and give me names that match the id's (I only want the names to show not the ID's)
So the simple answer is to take your query, reformat it a little, and then add an INNER JOIN to the continent table. Something like this would probably work:
SELECT
c.[name] AS continent_name,
COUNT(*) AS [count]
FROM
[public].flights_info f
INNER JOIN [public].continents c ON c.cont_id = f.cont_id
WHERE
f.flights <= 0
GROUP BY
c.[name]
ORDER BY
2 DESC;
However, I'm not convinced your original query is correct. You said you wanted to count the number of countries in each continent with no flights booked historically, and I don't think this is what you are counting at all. Instead you are counting the number of rows for each continent with a flights value of 0 or less than zero. Now maybe this is actually how your database works, and if so then cool, the query above should get you onto the right track.
However, if this database works anything like I think it should do then you would need a very different query, e.g. this one:
SELECT
c.[name] AS continent_name,
COUNT(DISTINCT cn.cntry_id) AS [count]
FROM
[public].continents c
INNER JOIN [public].country cn ON cn.cont_id = c.cont_id
LEFT JOIN [public].flights_info f ON f.cont_id = c.cont_id AND f.cntry_id = cn.cntry_id
WHERE
ISNULL(f.flights, 0) <= 0
GROUP BY
c.[name]
ORDER BY
2 DESC;
How does this work? Well it starts off with the continent table, and then links this to countries, to get a list of the countries in each continent. Then it performs a LEFT JOIN to the flights table, so it will get hits even if there's no flight data. Finally it counts up the number of countries where there was a flights value of 0 or less, or where there's no flights data at all.
Even this probably isn't correct, as if you had two rows for a country (I'm going to assume the flights table has a row for each continent, country, date), where one had a flights = 0 and one had a flights = 10, then this would still report that country as having no flights. But now I'm getting too far away from the original question I feel...
You can use join or sub-query to do this
Using JOIN
You just need to join with Continents table based cont_id column and fetch Continents name.
select Continents.name, count(*) AS "count"
FROM flights_info flights_info
join Continents Continents
on Continents.cont_id = flights_info.cont_id
WHERE flights_info.flights <= 0
GROUP BY flights_info.cont_id,Continents.name
ORDER BY "count" DESC
Using Sub-Query
You can write another query that give you Continents name by matching cont_id.
select (select Continents.name from Continents Continents where Continents.cont_id =
flights_info.cont_id ) Continent_name, count(*) AS "count"
FROM flights_info flights_info
WHERE flights_info.flights <= 0
GROUP BY flights_info.cont_id
ORDER BY "count" DESC

Subtracting values of columns from two different tables

I would like to take values from one table column and subtract those values from another column from another table.
I was able to achieve this by joining those tables and then subtracting both columns from each other.
Data from first table:
SELECT max_participants FROM courses ORDER BY id;
Data from second table:
SELECT COUNT(id) FROM participations GROUP BY course_id ORDER BY course_id;
Here is some code:
SELECT max_participants - participations AS free_places FROM
(
SELECT max_participants, COUNT(participations.id) AS participations
FROM courses
INNER JOIN participations ON participations.course_id = courses.id
GROUP BY courses.max_participants, participations.course_id
ORDER BY participations.course_id
) AS course_places;
In general, it works, but I was wondering, if there is some way to make it simplier or maybe my approach isn't correct and this code will not work in some conditions? Maybe it needs to be optimized.
I've read some information about not to rely on natural order of result set in databases and that information made my doubts to appear.
If you want the values per course, I would recommend:
SELECT c.id, (c.max_participants - COUNT(p.id)) AS free_places
FROM courses c LEFT JOIN
participations p
ON p.course_id = c.id
GROUP BY c.id, c.max_participants
ORDER BY 1;
Note the LEFT JOIN to be sure all courses are included, even those with no participants.
The overall number is a little tricker. One method is to use the above as a subquery. Alternatively, you can pre-aggregate each table:
select c.max_participants - p.num_participants
from (select sum(max_participants) as max_participants from courses) c cross join
(select count(*) as num_participants from participants from participations) p;

NTILE Function and Using Inner Join in Oracle

I am supposed to use the given Database(Its pretty huge so I used codeshare) to list last names and customer numbers of top 5% of customers for each branch. To find the top 5% of customers, I decided to use the NTILE Function, (100/5 = 20, hence NTILE 20). The columns are pulled from two separate tables so I used Inner joins. For the life of me, I honesly cannot figure out where I am going wrong. I keep getting "missing expression" errors but Do not know what exactly I am missing. Here is the Database
Database: https://codeshare.io/5XKKBj
ERD: https://drive.google.com/file/d/0Bzum6VJXi9lUX1d2ZkhudTE3QXc/view?usp=sharing
Here is my SQL Query so far.
SELECT
Ntile(20) over
(partition by Employee.Branch_no
order by sum(ORDERS.SUBTOTAL) desc
) As Top_5,
CUSTOMER.CUSTOMER_NO,
CUSTOMER.LNAME
FROM
CUSTOMER
INNER JOIN ORDERS
ON
CUSTOMER.CUSTOMER_NO = ORDERS.CUSTOMER_NO
GROUP BY
ORDERS.SUBTOTAL,
CUSTOMER.CUSTOMER_NO,
CUSTOMER.LNAME;
You need to join Employee and the GROUP BY must include all non-aggregated expressions. You can use a subquery to generate the subtotals and get the NTILE in the outer query, e.g.:
SELECT
Ntile(20) over
(partition by BRANCH_NO
order by sum_subtotal desc
) As Top_5,
CUSTOMER_NO,
LNAME
FROM (
SELECT
EMPLOYEE.BRANCH_NO,
CUSTOMER.CUSTOMER_NO,
CUSTOMER.LNAME,
sum(ORDERS.SUBTOTAL) as sum_subtotal
FROM CUSTOMER
JOIN ORDERS
ON CUSTOMER.CUSTOMER_NO = ORDERS.CUSTOMER_NO
JOIN EMPLOYEE
ON ORDERS.EMPLOYEE_NO = EMPLOYEE.EMPLOYEE_NO
GROUP BY
EMPLOYEE.BRANCH_NO,
CUSTOMER.CUSTOMER_NO,
CUSTOMER.LNAME
);
Note: you might want to include BRANCH_NO in the select list as well, otherwise the output will look confusing with duplicate customers (if a customer has ordered from employees in multiple branches).
Now, if you want to filter the above query to just get the top 5%, you can put the whole thing in another subquery and add a predicate on the Top_5 column, e.g.:
SELECT CUSTOMER_NO, LNAME
FROM (... the query above...)
WHERE Top_5 = 1;

SQL count after joining two tables

I am newbie to SQL, I would like to come up with a count, assume this example with 2 tables:
School(schoolID, name,....)
Student(StudentID, SchoolID, ...)
I tried:
SELECT COUNT(studentID)
FROM School s, Student t
WHERE s.schooldID = t.schoolID
How can I get a count of all students across all schools?
Since you have the school ID in the student table, it doesn't appear to me that you need to join to school at all. Just select a count from the student table and group by schoolID:
SELECT schoolID, COUNT(*) AS numStudents
FROM student
GROUP BY schoolID;
The only reason you'd need to join to School is if you want other information, such as school name and so on. If you just want the school id and number of students, the above will work.
To complete that last thought, possibly irrelevant to your question. If you did want school name, you just do an inner join and put school.name in your select statement, along with the count from the student table and group by school ID still:
SELECT s.name, st.COUNT(*) AS numStudents
FROM student st
JOIN school s ON s.id = st.schoolID
GROUP BY s.id;
If you want to get the count per school, you need a group by. Also, usually we prefer ANSI style joins, since in fact all database systems support them nowadays and they easier to read and maintain:
select count(t.studentID)
from Student t
join School s /* added join for your convenience, not necessary here */
on s.schooldID = t.schooldID
group
by t.schoolID