How can we rewrite a query with a subquery in SELECT clause? - sql

How would you rewrite the following query into one without subquery as much as possible?
Select dept name,
(Select Count(*)
From instructor
Where department.dept name = instructor.dept name
) As num_instructors
From department;
I came up with the following. Is it a good equivalence to the above?
Select dept name, count(*)
From department, instructor
Where department.dept name = instructor.dept name
Group By department.dept_name;
Thanks.

The proper way to write the query uses explicit JOIN syntax:
select d.dept_name, count(i.dept_name)
from department d left join
instructor i
on d.dept_name = i.dept_name
group by d.dept_name;
If you only care about departments that have at least one instructor, then no join is necessary at all:
select i.dept_name, count(*)
from instructor i
group by i.dept_name;

Your attempt is really close, just a couple things..
You should use explicit joins (ie. JOIN, LEFT JOIN etc.) instead of implicit joins (commas in the FROM clause). Implicit joins are 25+ years depreciated.
Also, in this case you will want a LEFT JOIN or no departments will be displayed that don't have instructors. LEFT JOIN will retain departments without instructors and give you a 0 count (like the first query), where a JOIN would not display those at all.
SELECT d.dept_name, COUNT(i.dept_name) as num_instructors
FROM department d
LEFT JOIN instructors i on d.dept_name = i.dept_name
GROUP BY d.dept_name

Related

How to display the desired rows of two tables using a subquery?

My subquery:
select studentName, Course.dataStart
from Student,
Course
where Student.id in (select Course.id from Course);
I need a solution to this (above) subquery (not a join)
Why does the SQL subquery display one date for each name? (task: display the names of students from the Student table and the course start date from the Course table using a subquery)
With the help of Join, I get it as it should: (but I need to do it with a subquery)
You seem to be using implicit join syntax, but really you should be using an explicit inner join:
SELECT s.studentName, c.dataStart
FROM Student s
INNER JOIN Course c
ON c.id = s.course_id;
If you really wanted to use the implicit join syntax, it should be something like this:
SELECT s.studentName, c.dataStart
FROM Student s, Course c
WHERE c.id = s.course_id;
But again, please use the first version as its syntax is considered the best way to do it.
You can apply join :
SELECT S.studentName, C.dataStart
FROM Student S
INNER JOIN Course C
ON C.id = S.course_id;
With Sub query:
Select studentName, (Select Course.dataStart from Course
Where Course.id = course_id)
From Student
Asuming that Course.Id field is Student.Id (although it seems strange to me), I think the only way to get the results you want with a subquery would be using it in the SELECT clause:
select studentName, (SELECT Course.dataStart FROM Course WHERE Course.Id = Student.Id)
from Student
This would fail if you have more than 1 row in Course per Student, in that case you could use (SELECT DISTINCT Course.dataStart...)

SQL doesn't display rows where

The following sql query selects the employee name (from employee table), their manager's name (from manager table) and their performance (from rating table). However, if an employee's manager_id is missing, then it doesn't list that employee at all when outputting rows. Is there any way around this? Probably involving joins but not too sure. Thanks in advance :)
SELECT employee.name,
manager.name,
rating.performance
FROM employee,
manager,
rating
WHERE employee.manager_id = manager.id
AND rating.employee_id = employee.id;
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax. In this case, you want a LEFT JOIN:
SELECT e.name, m.name, r.performance
FROM employee e LEFT JOIN
manager m
ON e.manager_id = m.id LEFT JOIN
rating r
ON r.employee_id = e.id;
Notice that this also includes table aliases to the query is easier to write and to read.
By using a LEFT JOIN you get all rows of the "left" table despite not being able to "pair" with any rows in the joining tables.
SELECT
employee.name,
manager.name,
rating.performance
FROM
employee LEFT JOIN,
manager ON employee.manager_id = manager.id LEFT JOIN
rating ON empoyee.id = rating.employee_id

How to obtain all the tuples after a certain date in sql?

I have to obtain the male employee with highest number of requests in the second half of April 2014.
I have these tables:
Employee (EmployeeID, firstName, LastName, gender)
Workplace (CompanyID, EmployeeID, CompanyName)
Extras (ExtraID, CompanyID, Requests, Description, Date)
Extras.Requests is a string, not numerical.
My SQL attempt looks like this:
SELECT
Employee.FirstName, Employee.LastName,
SUM(COUNT(Extras.ExtraID)
FROM
Employee
INNER JOIN
(Workplace
INNER JOIN
Extras ON Workplace.CompanyID = Extras.CompanyID)
ON Workplace.EmployeeID = Employee.EmployeeID
WHERE
Employee.Gender = "male"
AND Extras.Date BETWEEN #4/15/2014# AND #4/30/2014#
SORT BY
SUM(COUNT(Extras.ExtraID) DESC;
LIMIT 1;
I'm not sure if my query is correct or not, thanks in advance.
There are several issues with your querySUM(COUNT(...)) nesting aggregate functions like this isn't permitted
You also need a GROUP BY clause to use aggregation function with non-aggregating columns (which are Employee.FirstName, Employee.LastName in your query).
Sorting is performed by an ORDER BY clause
Your original query includes a nested inner join which is likely to produce unexpected results.
FROM Employee
INNER JOIN(Workplace
INNER JOIN Extras ON Workplace.CompanyID=Extras.CompanyID
) ON Workplace.EmployeeID=Employee.EmployeeID
While nesting joins is allowed it is rarely used, I suggest you avoid it.
I would expect the query to look more like this
SELECT
Employee.FirstName, Employee.LastName, COUNT(Extras.ExtraID)
FROM ((Employee
INNER JOIN Workplace
ON Workplace.EmployeeID = Employee.EmployeeID)
INNER JOIN Extras
ON Workplace.CompanyID = Extras.CompanyID)
WHERE Employee.Gender = "male"
AND Extras.Date BETWEEN #4/15/2014# AND #4/30/2014#
GROUP BY
Employee.FirstName
,Employee.LastName
ORDER BY
COUNT(Extras.ExtraID) DESC;
LIMIT 1;
It's been years since I used access, I think it still wants parentheses in the from clause as I've shown above. In most SQL implementation they are not required, and it is more common for literals to use single quotes e.g. WHERE Employee.Gender = 'male'.

is this a subquery or just an inner join

I am studying the subquery concept, below is one query which is extracted from wikipedia https://en.wikipedia.org/wiki/Correlated_subquery
SELECT employees.employee_number, employees.name
FROM employees INNER JOIN
(SELECT department, AVG(salary) AS department_average
FROM employees
GROUP BY department) AS temp ON employees.department = temp.department
WHERE employees.salary > temp.department_average;
the sql is a rewritten version of an correlated subquery as below
SELECT
employee_number,
name,
(SELECT AVG(salary)
FROM employees
WHERE department = emp.department) AS department_average
FROM employees AS emp;
And now my question :
Is the sql from the rewritten version a subquery? I am so confused on it
INNER JOIN
(SELECT department, AVG(salary) AS department_average
FROM employees
GROUP BY department) AS temp ON employees.department = temp.department
WHERE employees.salary > temp.department_average;
Welcome to Stackoverflow. This is certainly confusing, so I'd make it a little bit simpler by using two different tables and no table aliases.
I'd say if it's in the FROM clause, it's called a join:
SELECT employee_id, department_name
FROM employees JOIN departments USING (department_id);
If it's in the WHERE clause, it's called a subquery:
SELECT employee_id
FROM employees
WHERE employee_id = (
SELECT manager_id
FROM departments
WHERE employees.employee_id = departments.manager_id);
If it's in the SELECT clause, it's called a scalar subquery (thanks, #Matthew McPeak):
SELECT employee_id,
(SELECT department_name
FROM departments
WHERE departments.department_id = employees.department_id)
FROM employees;
Not exactly. The equivalent would be a left join. The correlated version keeps all rows in the employees table, even when there is no match. The inner join requires that there be a match.
In general, the execution plans are not going to be exactly the same, because the SQL engine does not know before-hand if all rows match.
With the additional filtering condition, the two versions are equivalent. Note that the filter for the correlated version requires a subquery or CTE because the where clause does not recognize column aliases.

How to use GROUP BY in SQL subquery without arithmetic count

The result are many repeat rows (all conlums repeat)
how use group by without inner join?
I ned use a subquery inn this case.
This is fictional example, don't worry the logic or sense this example. I need use group by in subquery from many tables.
I can use group by with inner join, but this case I can't use inner join.
select
NAME,
AGE,
JOB
from (
select
pe.name NAME,
pe.age AGE,
jb.work JOB
from
pearson pe,
job jb
)
group by NAME, AGE, JOB
Yes you can use a group by in this case, but you will need to create an alias name of the inner query as shown below:
SELECT A.NAME, A.AGE, A.JOB
FROM (
SELECT pe.name NAME, pe.age AGE, jb.`function` JOB
FROM pearson pe, job jb
) A
GROUP BY A.NAME, A.AGE, A.JOB;