How to select from a select in MySQL - mysql

I have the following data:
http://i.imgur.com/e4d8M8V.png?1
The first table is labeled "Offering" and the second is labeled "Instructor."
I am trying to sum the salaries of all the professors who do not have their instructor ID appear in the offering table.
What I did first was generate a table that has the data I need in it:
select distinct i.InstructorID, i.Salary
from Instructor i
where i.InstructorID NOT IN (select o.InstructorID from Offering o);
Which gives me the desired result here:
http://i.imgur.com/rkFKseX.png?1
I then want to add these two salaries and have the result displayed in a single salary column. I've tried code like:
$MySQL:> select sum(i.Salary)
from Instructor i
where i.Salary in ( select distinct i.InstructorID, i.Salary
from Instructor i
where i.InstructorID NOT IN (select o.InstructorID from Offering o));
And get "SQLException: java.sql.SQLException: Operand should contain 1 co." However, I am not sure how to contain the result from my previous query to one column. The way I see it is if I was going to sum all of the salaries that were on the list and I just did a distinct Salary, it would only return three salaries rather than eight salaries, so it would be wrong to do that for my case too.
How would I add the two columns I have generated, and is there an easier way to complete my goal than the method I am using?

You can use subqueries. They are described by this article

You should be able to just wrap this in a sub query:
select SUM(Salary)
from (
select distinct i.InstructorID, i.Salary
from Instructor i
where i.InstructorID NOT IN (select o.InstructorID from Offering o)
)
This will work in SQL Server, I think it will work in MYSQL.

You could probably join the two table and then do a group By.
Something like
select sum(salary) from a, b where a.instructorid = b.instructorid and .....

I think this is what you're trying to do :
$MySQL:> select sum(i.Salary)
from Instructor i
where i.Salary in ( select distinct i.Salary
from Instructor i
where i.InstructorID NOT IN (select o.InstructorID from Offering o));

I bet InstructorID is a primary key in Instructor table and I think you don't need "distinct" in select distinct InstructorID, Salary from Instructor.
select sum(Salary)
from Instructor
where InstructorID not in (select InstructorID from Offering);

Please test 3 different approaches and choose the best.
NOT IN
SELECT SUM(i.Salary)
FROM Instructor i
WHERE i.InstructorID NOT IN (select o.InstructorID from Offering o);
LEFT JOIN with IS NULL
SELECT SUM(i.Salary)
FROM Instructor i LEFT JOIN Offering o USING(InstructorID)
WHERE o.InstructorID IS NULL;
NOT EXISTS
SELECT SUM(i.Salary)
FROM Instructor i
WHERE NOT EXISTS (SELECT 1 FROM Offering o WHERE o.InstructorID = i.InstructorID);

Related

Making sense of Inner-Join with Sub-query in SQL Server 2008

I have 2 tables called 'table123' and 'table246'.
'table123' columns: 'ID', 'Dept_ID', 'First_Name', 'Surname', 'Salary', 'Address'.
'table246' columns: 'Dept_ID', 'Dept_Name'.
I want to find the Average Salary for each 'Dept_Name'. So I tried using the query below, which is an Equi-Join with a Sub-query:
SELECT Dept_Name, alt.Average_Salary AS Avg_Salary
FROM table123 a, table246 b,
(SELECT Dept_ID, AVG(Salary)Avg_Salary
FROM table123
GROUP BY Dept_ID)alt
WHERE a.Dept_ID = alt.Dept_ID
AND a.Salary = alt.Average_Salary
AND a.Dept_ID = b.Dept_ID;
However, when I run the above query, it gives the desired 2 column names 'Dept_Name' and 'Avg_Salary', but with no data in it (just a blank table).
What am I doing wrong in the code, which is causing this blank result table?
Also, is there an alternative method of getting the same result, using an Inner- Join? The Equi-Join is quite confusing.
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
Your query does not return results because no one has exactly the average value, so the salary condition fails. Based on what you are selecting, the subquery is the query you want:
SELECT Dept_ID, AVG(Salary) as Avg_Salary
FROM table123
GROUP BY Dept_ID;
Presumably, the other table brings in the name, so:
SELECT b.Dept_Name, AVG(a.Salary) as Avg_Salary
FROM table123 a JOIN
table246 b
ON a.Dept_ID = b.Dept_Id
GROUP BY b.Dept_Name;
What about:
SELECT Dept_Name, alt.Avg_Salary
FROM table246 b
INNER JOIN (SELECT Dept_ID, AVG(Salary)Avg_Salary
FROM table123
GROUP BY Dept_ID)alt ON B.DEPT_ID = ALT.DEPT_ID
Go through this maybe it will help you.
http://www.databasejournal.com/features/mysql/article.php/3835506/Fetching-Data-from-Multiple-Tables-using-Joins.htm

Get the first and last names of all employees who entered the project at the same time as at least one other employee

Question:
Get the first and last names of all employees who entered the project at the same time as at least one other employee.
I have four tables Employee, Department, Project, Works_on as shown in below.
I tried the query:
SELECT
emp_fname,
emp_lname
FROM employee a,
works_on b
WHERE a.empno=b.empno;
Please let me know what is wrong with what I am doing?
for this you need to use both Employee (emp_no,emp_fname,emp_lname) and Works_on (emp_no, Enter_date) relationship linked through emp_no on both tables.
in your query you just used Employee table which does not have connection with checking project submitted times.
You can use either of the below query to get the desired results. I have used partition by clause to group related data.
WITH QUERY1 AS (
SELECT EMP_NO,ENTER_DATE, COUNT(*) OVER (PARTITION BY ENTER_DATE ORDER BY EMP_NO ) "t" FROM works_on)
select t2.emp_fname, t2.emp_lname from query1 t1 inner join employee t2 on t1.emp_no=t2.emp_no where "t">1;
select emp_fname, emp_lname from employee where emp_no in (
SELECT EMP_NO FROM (
SELECT EMP_NO,ENTER_DATE, COUNT(*) OVER (PARTITION BY ENTER_DATE ORDER BY EMP_NO ) "t" FROM works_on
) query1 where query1."t">1);
First of all your query will return employee names who ever worked on any project, and better you would use INNER JOIN.
If I understand right; you want employee who work on the same project (let's say ProjectX) and again the employee who entered ProjectX on same time and also there must be at least 2 employee having the same time on ProjectX.
If I am correct with the above:
You need to group your data. For instance first group projects that have at least 2 same enter_date like
SELECT Project_no, Enter_date FROM Works_on having Count(emp_no)>=2
This will give you all projects and dates that have employee more or equal than 2. Now we can find employee that worked on these projects at these dates.
SELECT emp_fname, emp_lname FROM Employee INNER JOIN Works_on AS WO ON WO.emp_no=Employee.emp_no
INNER JOIN
(
SELECT Project_no, Enter_date FROM Works_on having Count(emp_no)>=2
) AS PWith2MoreEmployee
ON PWith2MoreEmployee.Project_no=WO.Project_no
AND
PWith2MoreEmployee.Enter_date=WO.Enter_date
I hope this will give you what you are looking for.

mysql counting without using having

So I'm asked to try and convert this statement:
SELECT C.cid, C.cname
FROM Customer C, Buys B
WHERE C.cid = B.cid
GROUP BY C.cid
HAVING count(pid) > 100
to the same thing but not use the HAVING clause. I've been trying to figure it out for the last hour or so but am unsure on how to do this properly. I've been trying to figure out how to use the WHERE clause properly. You can only use the aggregate functions using the HAVING clause correct?
This is what the tables look like
Product(pid, name, price, mfgr)
Buys(cid, pid)
Customer(cid, cname, age)
Simply quoting #zfus answer in comment, just so this question appears to have an answer in the list to avoid further traffic.
SELECT cid, cname
FROM (
SELECT cid, cname, count(*) AS counter
FROM customer c
INNER JOIN buys b on (c.cid=b.cid)
GROUP BY cid, cname
) AS result
WHERE counter > 100

Calculating the AVG of a COUNT() in mysql

I am trying to issue the following query:
SELECT
AVG(`count`)
FROM
(SELECT
COUNT(s_id) AS `count`
FROM
instructor,
advisor
WHERE instructor.ID = advisor.i_id
AND dept_name = 'CIS'
GROUP BY dept_name) nested ;
to calculate the average of a counted value. However, the nested query returns to me a single row with the counted value = 2. This value 2 is a result of 2 rows of records that match the query.
Now when I apply the average function to it I get 2.0000. However the expected answer is 1.0000.
Any idea how I can get around to getting the expected value?
This is your query:
SELECT AVG(`count`)
FROM (SELECT COUNT(s_id) AS `count`
FROM instructor join
advisor
on instructor.ID = advisor.i_id
WHERE dept_name = 'CIS'
GROUP BY dept_name
) nested
You are selecting one department name and then grouping by that. The where clause means that you are only getting one row. So, the average is the same as the count. The average of one thing is the value of the thing.
If you want the average across all departments, you can remove the where:
SELECT AVG(`count`)
FROM (SELECT COUNT(s_id) AS `count`
FROM instructor join
advisor
on instructor.ID = advisor.i_id
GROUP BY dept_name
) nested;
Or, you don't really need the subquery:
SELECT count(*) / count(distinct dept_name)
FROM instructor join
advisor
on instructor.ID = advisor.i_id ;
AVG(s_id) will calculate the average s_id so if the two rows has the id's of 1 and 3 it will result as 2.

mysql count one value display multiple columns

I couldnt find this, i'm sure its simple.
Table (196 rows)
tech, name, area, manager
------------------------------
Joe,mary,pa,sally
Kim,brad,ga,tim
kelly,Joe,pa,sally
Joe,jose,pa,sally
a tech is assigned to multiple name/area/managers. I want to do a report that shows all the rows of the table with a column showing the number of assignments for the tech.
My desired results
tech, name, area, manager, (count of number of tech assignments)
Joe,mary,pa,sally,2
Kim,brad,ga,tim,1
kelly,Joe,pa,sally,1
Joe,jose,pa,sally,2
I'm guessing you want a subquery on the SELECT clause:
SELECT
name,
area,
manager,
(SELECT COUNT(*) FROM tablename WHERE tech = x.tech) AS assignments
FROM tablename x
And here is a possibly more efficient way to do the same thing:
SELECT
t.name,
t.area,
t.manager,
sub.assignments
FROM tablename t
INNER JOIN (
SELECT tech, COUNT(*) AS assignments
FROM tablename
GROUP BY tech
) sub
ON sub.tech = t.tech
select
a.tech, a.name, a.area, a.manager,
b.cnt
from table a, (
select count(*) cnt, tech
from table
group by tech) b
where a.tech=b.tech;
Is this what you want?
SELECT tech, count(name) AS total_records FROM db_table GROUP BY tech
Not sure this is what you're looking for though.
Oh yeah, looks like you really need to use subquery.
Thanks for the examples, that helped.
SELECT tech, name, area, manager, assignments
FROM table
INNER JOIN (
SELECT tech, COUNT(*) AS assignments
FROM table
GROUP BY tech
) t
USING (tech)
Explanation:
Select all columns from table and join them with table containing tech column and count of rows from table having particular tech. Keyword USING says how those two table merge.