sql query question makes me confused please - mysql

Given the following two relational schemas, the EMPLOYEE relational schema records the employee number (ssn), age (age) and the department (dno), the primary key is ssn, and the DEPARTMENT relational schema records the department number (dnum ) and name (dname), The primary key is dnum, in which the foreign key "dno" of EMPLOYEE refers to the primary key "dnum" of DEPARTMENT,
please use SQL GROUP BY to write the query ''For each department that has more than two employees, retrieve the department name and the number of its employees who each is more than twenty-five years old)”.
Thank you guys

You can use as approach. It's not exactly your tables but you can easy match it tot your structure:
SELECT DEPARTMENT_NAME
FROM DEPARTMENTS D
JOIN EMPLOYEES E USING (DEPARTMENT_ID)
GROUP BY DEPARTMENT_ID, DEPARTMENT_NAME
HAVING COUNT(EMPLOYEE_ID) > 2
;
format sql online

SELECT d.dname, count(e.ssn) as cnt
FROM Employee e JOIN department d
on e.dno = d.dnum
WHERE e.age> = 25
Group BY e.dname
HAVING COUNT(ssn) >= 2;

Related

OQL and SQL queries. Select all department numbers whose employees have the same salary

So, I have two tables:
EMP {EMP_NO, EMP_SALARY, EMP_DEPT_NO}
DEPT {DEPT_NO, DEPT_MNG}
EMP_NO, DEPT_NO - primary keys, EMP_DEPT_NO - external key to DEPT, DEPT_MNG - external key to EMP.
I need to find all departments where every employee has the same salary.
You can use the COUNT DISTINCT in the HAVING section to achieve that. the COUNT DISTINCT will return how many variations of salary there are in a certain dept.
SELECT DEPT_NO
FROM DEPT JOIN EMP ON DEPT.DEPT_NO=EMP.EMP_DEPT_NO
GROUP BY DEPT_NO
HAVING COUNT(DISTINCT SALARY) =1

MySQL joins and selecting from multiple tables

I am using MySQL Workbench, and I have the following question:
Using the employees data, create select queries that will provide the following information:
Show a list of employees and what department they are in
Columns: Employee Name, Department Name
I have two statements which provide the exact same return, but it's 1000 rows! Am I doing this "join" properly?
SELECT
departments.dept_name, employees.last_name, employees.first_name
FROM
departments, employees
WHERE
departments.dept_name = employees.departments.dept_name;
and
SELECT
dept_name, last_name, first_name
FROM
departments
INNER JOIN
employees
ON
departments.dept_name = employees.departments.dept_name;
Tables employees and departments are always many to many. Therefore, we need input table between them, which has columns id_emp and id_dep or more often 4 column, id_emp, id_dep, from, to. After that, your question is clear and we can speak about.
Example:
Tables:
employees emp_dep departments
id_emp first_name id id_emp id_dep id_dep name
1 John 1 1 1 1 Finacial
2 Elsa 2 2 2 2 Human res
Note: id_emp & id_dep in table emp_dep can't be together primary key beacause every employee can work many times again in same department.
Query on 3 table:
SELECT e.first_name,
d.name
FROM (employees e
INNER JOIN emp_dep ed ON e.id_emp = ed.id_emp)
INNER JOIN departments d ON ed.id_dep = d.id_dep;
Output:
first_name name
John Financial
Elsa Human res
SQL for create this database and table:
CREATE DATABASE employees_dep;
CREATE TABLE employees (id_emp INT AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(10));
CREATE TABLE departments (id_dep INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(10));
CREATE TABLE emp_dep (id int AUTO_INCREMENT PRIMARY KEY, id_emp INT, id_dep INT);
Both are correct, but the second is better.
Both are same. However second one would be faster given large volume of data, but won't matter on small sized tables.

Return information about oldest employee in department, if department has more than 20 employees

Don't judge me, I'm new to SQL querying. I got scheme, like the one shown on picture below. So, there are 2 tables, first one Employees contains EmployeeID, FirstName, LastName, DateOfBirth and DepartmentID. The second one is called Department and contains DepartmentID and DepartmentName .
I want to return FirstName, LastName and DepartmentName for the oldest employee from each department containing more than 20 employees.
My solution is the following query :
SELECT FirstName, LastName, DepartmentName
FROM employees
LEFT JOIN department
ON employees.DepartmentID = department.DepartmentID
WHERE (employees.DateOfBirth =
(SELECT MIN(employees.DateOfBirth ) FROM (
SELECT *FROM employees WHERE employees.DepartmentID IN (
SELECT employees.DepartmentID FROM employees GROUP BY DepartmentID HAVING COUNT(*) > 20)));
I think that logic is fine, because inner SELECT statement will return ID's of every department with more than 20 employees, and the outer should return to oldest employee.
The problem that I have is when I try to execute this query, it is returning SQL error every derived table must have it's own alias.
I've tried putting alias on each derived table, but outcome is still the same.
Please, help me with this one.
Also, if someone has different solution, please share it.
Thank You.
Addition which strawberry asked for, Create queries
CREATE TABLE Employees
(
EmployeeID int,
FirstName varchar(10),
LastName varchar(15),
DateOfBirth date,
DeparmentID int
)
CREATE TABLE Department
(
DepartmentID int,
DepartmentName varchar(15)
)
Your query is tricky to read due to inconsistent formatting. So I'll clean it up as follows:
SELECT FirstName, LastName, DepartmentName
FROM employees
LEFT JOIN department
ON employees.DepartmentID = department.DepartmentID
WHERE (employees.DateOfBirth =
(
SELECT MIN(employees.DateOfBirth)
FROM (
SELECT *
FROM employees
WHERE employees.DepartmentID IN (
--Departments with more than 20 employees
SELECT employees.DepartmentID
FROM employees
GROUP BY DepartmentID
HAVING COUNT(*) > 20)
) -- You need an alias here.
-- Also from this point you were missing closing brackets.
Problems with your query:
Obviously the missing alias and closing brackets meant you couldn't even test your query.
Also SELECT MIN(employees.DateOfBirth) returns only a single value. Not a value per department.
So your overall result includes only the oldest employee across all the 'big' departments. (Unless the oldest employee in each department happened to have the same birth date.)
It could also include results from a smaller department if any employee happened to have the same birth date the oldest from the big departments. And that employee needn't even be the oldest in their department!
You also have some inefficiencies by using more sub-queries than necessary.
CTEs (common table expressions) are great at simplifying complex queries. But I don't know if mysql supports them. So this solution still uses sub-queries.
SELECT e.FirstName, e.LastName, d.DepartmentName
FROM employees e -- I prefer short aliases
INNER JOIN (
-- This sub-query returns the earliest birth date within each
-- big department. This needs to be an aliased query so you
-- can join to other tables for your desired columns.
SELECT DepartmentID, MIN(DateOfBirth) AS MinDOB -- Must alias column
FROM employees
WHERE DepartmentID IN (
-- Big departments
SELECT DepartmentID
FROM employees
GROUP BY DepartmentID
HAVING COUNT(*) > 20
)
GROUP BY DepartmentID
) ddob -- Alias Department Date of Birth
-- As a result of inner joining to ddob your employees
-- will be filtered to only those that match the relevant
-- ones identified in the query.
ON e.DepartmentID = ddob.DepartmentID
AND e.DateOfBirth = ddob.MinDOB
INNER JOIN Department d
ON d.DepartmentID = e.DepartmentID
Something to note in the above solution, if 2 employees are tied for being oldest in a department, both will be returned.
This approach is structurally similar to yours, but you could also approach the problem from another direction.
Start out getting oldest employees in ALL departments.
And only at the end filter the result according to department size.
I'll leave that to you to try. I suspect the query would be a little simpler.
The following SQL script correspond to your Class Diagram:
CREATE TABLE Departments (
DepartmentID int AUTO_INCREMENT PRIMARY KEY,
DepartmentName varchar(15)
);
CREATE TABLE Employees (
EmployeeID int AUTO_INCREMENT PRIMARY KEY,
FirstName varchar(10),
LastName varchar(15),
DateOfBirth date,
DepartmentID int,
FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID)
);
Following your classes diagram, there is a department for each employee. So, is the reason of using INNER JOIN. I think the following query do what you want:
SELECT ee.FirstName, ee.LastName, ee.DateOfBirth, t.DepartmentName
FROM
(
SELECT e.DepartmentID, d.DepartmentName, MIN(e.DateOfBirth) AS DateOfBirth
FROM Employees AS e
INNER JOIN Departments AS d ON e.DepartmentID = d.DepartmentID
WHERE e.DepartmentID IN (
SELECT DepartmentID
FROM Employees
GROUP BY DepartmentID HAVING COUNT(DepartmentID) > 20
)
GROUP BY e.DepartmentID
) AS t
INNER JOIN Employees AS ee
WHERE ee.DepartmentID = t.DepartmentID AND ee.DateOfBirth = t.DateOfBirth
Example of output:
FirstName LastName DateOfBirth DepartmentName
fisrt14 last14 02/01/2000 SI
fisrt31 last31 12/01/2003 Finance
You improve its performance!

how does the count function in mysql work?

First and foremost, this is part of an assignment, but I'm trying to get more clarification on how the count() function works when querying a db.
The question is: List the name, SSN and the number of courses the student has taken (courses with the same CourseNumber taken in different quarters are counted as different courses).
I've been querying using this:
SELECT S.Name, S.SSN, COUNT(*)
FROM Student S, Enrollment E
WHERE S.SSN = E.SSN
GROUP BY S.SSN
which seems to return the correct answer, but I'm not sure why. As a result, I can't seem to get the next questions (assuming courses with the same CourseNumber taken in different quarters are considered as one course) correct.
Here are the create table commands so you can see which table holds what info:
CREATE TABLE Student(
SSN INT(9),
Name VARCHAR(20),
Major VARCHAR(30),
PRIMARY KEY (SSN)
);
CREATE TABLE Course(
CourseNumber INT(5),
PrerequisiteCourseNumber INT(10),
CourseTitle VARCHAR(10),
NumberUnits INT(2),
PRIMARY KEY (CourseNumber)
);
CREATE TABLE Section(
CourseNumber INT(5),
Quarter VARCHAR(10),
RoomNumber INT(5),
DayTime VARCHAR(20),
PRIMARY KEY (CourseNumber,Quarter),
FOREIGN KEY (CourseNumber) REFERENCES Course(CourseNumber)
);
CREATE TABLE Enrollment(
SSN INT(9),
CourseNumber INT(5),
Quarter VARCHAR(10),
Grade VARCHAR(1),
PRIMARY KEY (SSN,CourseNumber,Quarter),
FOREIGN KEY (SSN) REFERENCES Student(SSN),
FOREIGN KEY (CourseNumber) REFERENCES Course(CourseNumber),
FOREIGN KEY (Quarter) REFERENCES Section(Quarter)
);
Any pointers?
what you are doing is using old join syntax (pre ansi syntax) where you do a cross join of tables and use the where to turn it into a join. an equivalent query would be this.
SELECT S.Name, S.SSN, COUNT(*)
FROM Student S
JOIN Enrollment E ON S.SSN = E.SSN
GROUP BY S.SSN
Now to answer your question about what the count is doing and stuff..
COUNT() returns a count of every row that is returned.
GROUP BY groups all of the records by a common ground aka your SSN field. so if a student has 5 SSN rows in the table then his count will be 5.
Now for the part you are looking for with course numbers.. you need to JOIN those tables on appropriate fields and add a field to your group by for each quarter
aka add to the previous code..
WHERE E.quarter = whatever_quarter_you_want
you can add more to this query if you need to. but add data to your question if you want a more full answer.
Your current query is:-
SELECT S.Name, S.SSN, COUNT(*)
FROM Student S
INNER JOIN Enrollment E
ON S.SSN = E.SSN
GROUP BY S.SSN
What this is doing is joining student to enrollment, so giving multiple rows for each student, one for each course / quarter they are enrolled on. It is then grouped by SSN (student number?) to count up the number of course / quarters they are enrolled on. You should really group by S.Name as well (while MySQL won't object, most flavours of SQL would).
Note that COUNT(*) counts the number of rows. You could use COUNT(E.CourseNumber) which would count the number of rows where course number is not null. Not really useful here, but can be useful with LEFT OUTER JOINs. You can also use COUNT(DISTINCT CourseNumber) to count the number of unique non null course numbers for the student.
A LEFT OUTER JOIN might also be better as this would enable you to return 0 as the counts for students who exist but who are not enrolled in any courses:-
SELECT S.Name, S.SSN, COUNT(DISTINCT E.CourseNumber)
FROM Student S
LEFT OUTER JOIN Enrollment E
ON S.SSN = E.SSN
GROUP BY S.Name, S.SSN
SELECT S.Name, S.SSN, COUNT(*)
FROM Student S, Enrollment E, Section Sec, Course C
WHERE S.SSN = E.SSN AND E.CourseNumber = Sec.CourseNumber
AND Sec.CourseNumber = C.CourseNumber AND Sec.Quarter like E.Quarter
GROUP BY S.Name, S.SSN

SQL query to find names of employees belonging to particular department

I have created two tables one employee table and the other is department table .Employee table has fields EmpId , Empname , DeptID , sal , Editedby and editedon where
EmpId is the primary key and Dept table has DeptID and deptname where DeptID is the secondary key.
I want the SQL query to show names of employees belonging to software departmant
The entries in dept table are as below :
DeptID Deptname
1 Software
2 Accounts
3 Administration
4 Marine
Use INNER JOIN:
SELECT
E.empname
FROM Employee E
INNER JOIN department D ON E.DeptID=D.DeptID
WHERE D.DeptID = '1'
Is this what you need?
SELECT EmpName FROM Employee WHERE DeptID = 1
Try this:
SELECT
E.empname
FROM Employee E
INNER JOIN department D ON E.DeptID=D.DeptID
where D.Deptname = 'Software'