SQL Server: select query from multiple tables - sql

I got 3 tables: projects, employee and project_employee
employee
ID (int, PK)
Name
projects
project_id (int, PK)
project_name
project_employee
project_id (int, PK)
employee_id (int, PK)
What I trying to do is write a query that get ID and Name of all employees that are not in a project, for example project number 9.
So I tried:
SELECT ID, Name
FROM [employee], [project_employee]
WHERE [employee].ID != [project_employee].emp_id AND [project_employee].project_id = 9;
but I always get empty result, something must be wrong with my logic?

You can do it using NOT EXISTS :
SELECT u.ID, u.Name
FROM [User] u
WHERE NOT EXISTS ( SELECT *
FROM [project_employee] pe
WHERE pe.project_id = 9
AND pe.employee_id = u.ID);

Instead try something like this, it should get you all users that are not part of project_id = 9
SELECT u.ID, u.Name
FROM [User] u
WHERE u.ID NOT IN (SELECT pe.employee_id
FROM [project_employee] pe
WHERE pe.project_id = 9);

SELECT ID, NAME
FROM employee e
LEFT JOIN project_employee pe
ON pe.employee_id = e.id
AND pe.project_id = 9
WHERE pe.employee_id IS NULL
You don't even need projects table since you are not looking for employees on a project.

You can use a LEFT JOIN to get the required data
select e.id,e.name
from employee e
left join project_employee pe
on e.id = pe.employee_id
left join projects p
on pe.project_id = p.project_id
where p.project_id is null
(OR) Just left join with project_employee table. No condition has been checked assuming that all employees with no project at hand is the desired output.
select e.id,e.name
from employee e
left join project_employee pe
on e.id = pe.employee_id
where pe.project_id is null

He asked for the ability to check that the employees are not in a specific project. The not in solution is fine, but I generally prefer using left joins.
SELECT ID, NAME
FROM employee e
LEFT JOIN project_employee pe
ON pe.emp_id = e.id
and pe.project_id = 9
WHERE pe.employee_id IS NULL

Related

SQL query to show Name and Department in a table

Can you please help me, I don't know how to create this query. I am a front end dev.
Expected result should be table with 2 columns
Name(one) DepartmentName(many)
The tables and their relationship are shown in this image:
You can do this with a couple of INNER JOINS. You don't need to reference the Location table in this query because Employee.LocationId is the same as EmployeeDepartment.LocationId.
This simple query will return all employee names and all department names they are related to. The employee name may be repeated, as this query puts only one department name in the column, so if an employee is in two departments, you get the employee name twice.
SELECT
EmployeeName = e.Name
,DepartmentName = d.Name
FROM Employee e
INNER JOIN EmployeeDepartment ed ON ed.LocationId = e.LocationId
INNER JOIN Department d ON d.id = ed.DepartmentId
This query is a bit more complicated, but returns each employee name only once, and the department names will be a comma-separated string of names. This is accomplished by using STUFF() in conjunction with FOR XML.
;WITH EmployeesAndDepartments AS
(
SELECT
EmployeeName = e.Name
,DepartmentName = d.Name
FROM Employee e
INNER JOIN EmployeeDepartment ed ON ed.LocationId = e.LocationId
INNER JOIN Department d ON d.id = ed.DepartmentId
)
SELECT
ead.EmployeeName
,Departments = STUFF((
SELECT ',' + DepartmentName
FROM EmployeesAndDepartments
FOR XML PATH('')
) , 1, 1, ''
)
FROM EmployeesAndDepartments ead
GROUP BY ead.EmployeeName
This should work
SELECT
e.Name
, d.Name AS DepartmentName
FROM
Employee e
LEFT OUTER JOIN
EmployeeDepartment ed
ON e.LocationId = ed.LocationId
LEFT OUTER JOIN
Department d
ON ed.DepartmentId = d.id
Note that the use of LEFT OUTER JOIN will return the employee even if they don't have a corresponding record in EmployeeDeparatment and/or Department. If you only want to retrieve employees that do have corresponding EmployeeDepartment and Department records, use INNER JOIN instead

SQL: Which person took which test or not

I want to people and exams they did or did not participate in
I can't figure it out for some reason
Tables
EXAM: ID, NAME, ...etc
PERSON: ID, NAME, ...etc
PERSON_EXAM: ID, PERSON_ID, EXAM_ID, ...etc
Desired result
PERSON_ID EXAM_ID PERSON_EXAM_ID
1 1 1
1 2 NULL
1 3 2
2 1 NULL
2 2 NULL
2 3 3
Currently I did this
select
p.ID as PERSON_ID,
e.ID as EXAM_ID,
(select pe.ID from PERSON_EXAM pe
where pe.PERSON_ID = p.ID and pe.EXAM_ID = e.ID) as PERSON_EXAM_ID
from PERSON p, EXAM e
But I fear it will be slow
I tried to join two tables with one but I can't do that for some reason as
select p.ID as PERSON_ID, e.ID as EXAM_ID, pe.ID as PERSON_EXAM_ID
from PERSON p, EXAM e
left join PERSON_EXAM pe on
p.ID = pe.PERSON_ID and // 'p' isn't recognized because the join is on 'e'
e.ID = pe.ITEM_ID
You have the right idea. Just use the correct syntax. Never use commas in the FROM clause. Always use proper, explicit JOIN syntax:
select p.ID as PERSON_ID, e.ID as EXAM_ID, pe.ID as PERSON_EXAM_ID
from PERSON p cross join
EXAM e left join
PERSON_EXAM pe
on p.ID = pe.PERSON_ID and
e.ID = pe.ITEM_ID;
The semantics of the archaic comma mean that the table alias is not recognized in subsequent on clauses.

SQL JOIN 3 TABLES WITH COUNT AND GROUP BY CLAUSE

I Have 3 tables like that:
EXPEDITION (ID, CreateDate, Status);
PACKAGE (ID, EXPEDITION_ID)
ITEM (ID, EXPEDIITONPACKAGE_ID);
I need to know, for each expedition, the quantity of packages and the quantity of items.
UPDATE
This is the query that seems to have it.
SELECT
E.ID,
P.Packages,
I.Items
FROM EXPEDITION E
LEFT JOIN (
SELECT DISTINCT E.ID, COUNT(P.ID) AS "Packages" FROM EXPEDITION E
LEFT JOIN PACKAGE P
ON E.ID = P.EXPEDITION_ID
GROUP BY E.ID
) P
ON E.ID = P.ID
LEFT JOIN (
SELECT DISTINCT P.ID as "PackageID", COUNT(I.ID) AS "Items" FROM PACKAGE P
JOIN ITEM I
ON P.ID = I.EXPEDIITONPACKAGE_ID
GROUP BY P.ID
) I
ON P.ID = I.PackageId
GROUP BY
E.ID,
P.Packages,
I.Items
ORDER BY
E.ID
It has two inner queries, that count the IDs separately, and they are joined in the main query to show the results.
Try this. Not tested yet...but it should work..
;With c1 as
(
Select e.expid, count(e.expid) as qtyPck
From packages p inner join
Expeditions e on p.expid = e.expid
Group by e.expid
),
C2 as
(
Select i.pakId, count(i.pakId) as qtyItems
From items i inner join packages p
On i.pakId = p.pakId
Group by i.pakid
)
Select e.expId, p.qtyPck, I.qtyItems
From expeditions e
Join packages p on p.expId = e.expId
Join items i on i.pakId = p.pakId;

Conditional JOIN different tables

I want to know if a user has an entry in any of 2 related tables.
Tables
USER (user_id)
EMPLOYEE (id, user_id)
STUDENT (id, user_id)
A User may have an employee and/or student entry. How can I get that info in one query?
I tried:
select * from [user] u
inner join employee e
on e.user_id = case when e.user_id is not NULL
then u.user_id
else null
end
inner join student s
on s.user_id = case when s.user_id is not NULL
then u.user_id
else null
end
But it will return only users with entries in both tables.
SQL Fiddle example
You could use an outer join:
select *
from USER u
left outer join EMPLOYEE e ON u.user_id = e.user_id
left outer join STUDENT s ON u.user_id = s.user_id
where s.user_id is not null or e.user_id is not null
alternatively (if you're not interested in the data from the EMPLOYEE or STUDENT table)
select *
from USER u
where exists (select 1 from EMPLOYEE e where e.user_id = u.user_id)
or exists (select 1 from STUDENT s where s.user_id = u.user_id)
If you want to get all user data together You might have:
SELECT
user_id
,'Employee' AS Source
FROM
employee
UNION
SELECT
user_id
,'Student' AS Source
FROM
student
http://sqlfiddle.com/#!3/90216/22
Which can also be done with a full join and a CASE statement:
SELECT
ISNULL(e.user_id,s.user_id) AS user_id
,CASE WHEN e.user_id IS NULL THEN 'Student'
ELSE 'Employee'
END AS SOURCE
FROM
employee AS e
FULL JOIN student AS s
ON s.user_id = e.user_id
http://sqlfiddle.com/#!3/90216/29
the latter will combine people who are both students adn employees into one row and call them and employee. compare:
http://sqlfiddle.com/#!3/2aa3e/1
and
http://sqlfiddle.com/#!3/2aa3e/2
where I have made user 1 a student and a employee
Such solution also can help you.
SELECT S.*, P.*
,CASE
WHEN S.ShipmentType = 'import' THEN SP.SupplierName
WHEN S.ShipmentType = 'export' THEN C.CustomerName
END AS ShipmentDesination
FROM tblShippments S
INNER JOIN tblProducts P ON S.productId = P.productID
LEFT OUTER JOIN tblCustomers C ON S.companyId = C.customerId AND S.ShipmentType = 'export'
LEFT OUTER JOIN tblSuppliers SP ON S.companyId = SP.supplierId AND S.ShipmentType = 'import'
If you look at employee and student tables as one, you can use left join:
select *
from user u
left join
(
select 'Employee' as UserType,
id,
user_id
from employee e
union all
select 'Student',
id,
user_id
from student s
) r
ON u.user_id = r.user_id
How about UNION which you write as 2 separate SELECT statements
For example:
SELECT * FROM User U
JOIN Employee E ON E.User_Id = U.User_Id
UNION
SELECT * FROM User U
JOIN student S ON S.User_Id = U.User_Id
I couldn't see why you needed the CASE statement it looked superfluous. If you wanted all Users and to show nulls then use LEFT OUTER JOIN.
work for mysql v5.6+
schema:
CREATE TABLE USER (user_id INT);
CREATE TABLE employee (id INT, user_id INT);
CREATE TABLE student (id INT, user_id INT);
INSERT INTO USER SELECT 1;
INSERT INTO USER SELECT 2;
INSERT INTO USER SELECT 3;
INSERT INTO USER SELECT 4;
INSERT INTO employee SELECT 1, 1;
INSERT INTO employee SELECT 2, 4;
INSERT INTO student SELECT 1, 2;
first solution
,full outer join does not work for mysql v5.6+:
SELECT
IF(e.user_id IS NULL,s.user_id,e.user_id) AS user_id
,CASE WHEN e.user_id IS NULL THEN 'Student'
ELSE 'Employee'
END AS SOURCE
FROM
employee AS e
LEFT JOIN student AS s
ON (s.user_id = e.user_id)
UNION
SELECT
IF(e.user_id IS NULL,s.user_id,e.user_id) AS user_id
,CASE WHEN e.user_id IS NULL THEN 'Student'
ELSE 'Employee'
END AS SOURCE
FROM
employee AS e
RIGHT JOIN student AS s
ON (s.user_id = e.user_id)
alternative solution:
SELECT IF(e.user_id IS NULL,s.user_id,e.user_id) AS user_id,
CASE WHEN e.user_id IS NULL THEN 'Student'
ELSE 'Employee'
END AS SOURCE
FROM USER AS u
LEFT OUTER JOIN employee e ON (u.user_id = e.user_id)
LEFT OUTER JOIN student s ON (u.user_id = s.user_id)
WHERE s.user_id IS NOT NULL OR e.user_id IS NOT NULL
other, alternative solution:
SELECT u.user_id,SOURCE
FROM USER u
INNER JOIN
(
SELECT 'Employee' AS SOURCE,id,user_id FROM employee e
UNION ALL
SELECT 'Student',id,user_id FROM student s
) r ON u.user_id = r.user_id
SELECT OrderID, Quantity, O.ProductID , ProductName,
CASE
WHEN Quantity > 3 THEN 'The quantity is More than 3'
WHEN Quantity = 3 THEN 'The quantity is Equal to 3'
ELSE 'The quantity is Less than 3'
END AS QuantityText
FROM tb_OrderDetail O
INNER JOIN tb_Product P ON O.ProductID = P.ProductID

SQL: Have 4 Tables, Looking to find unmatched data

I've always done this back asswards in PHP or ASAP, so I figure it's time to actually learn the proper way to do it in SQL. I have the following 4 tables in a database:
Category (Fields: CategoryNumber, Desc) (small table with 15 rows)
Media (Fields: MediaID, Desc, CategoryNumber, etc) (huge table with 15,000 rows)
Sales (Fields: Date, MediaID, EmployeeID etc) (huge table with 100,000 rows)
Employees (Fields: EmployeeID, Name, etc) (small table with only 20 rows)
Category only links to Media
Media has links to both Category and Sales.
Sales links to both the Media and Employee
Employee only links to Sales
What I would like to do is to write a query which tells me what categories a given employee has never sold any media in.
I can write a simple query that looks for unmatched data between 2 tables, but I have no clue how to do it when I'm dealing with 4 tables.
Thanks for your time and help!
Here's my suggestion:
select *
from Category c
where not exists (
select *
from Employee e
inner join Sales s on s.EmployeeId = e.EmployeeId
inner join Media m on m.MediaID = s.MediaID
where e.Name = 'Ryan' and m.CategoryNumber = c.CategoryNumber
)
To query all employes with the categories in which they didn't sell anything:
select e.EmployeeName, c.CategoryNumber
from Category c
cross join Employee e
where not exists (
select *
from Sales s
inner join Media m on m.MediaID = s.MediaID
where c.categoryNumber = m.CategoryNumber
and s.EmployeeId = e.EmployeeId
)
SELECT c.CategoryNumber, c.Desc
FROM Category c
WHERE NOT EXISTS
(
SELECT *
FROM Employees e
INNER JOIN Sales s on s.EmployeeID = e.EmployeeID
INNER JOIN Media m on m.MediaID = s.MediaID
WHERE e.Name = "Ryan"
AND m.CategoryNumber = c.CategoryNumber
)
MS Access evidently needs a lot of parentheses (thanks, Ryan!):
select *
from Category c
where not exists
( select *
from ( Employee e
inner join Sales s on (s.EmployeeId = e.EmployeeId))
inner join Media m on (m.MediaID = s.MediaID)
where (e.Name = 'Ryan' and m.CategoryNumber = c.CategoryNumber) )
select c.desc
from category
left outer join (select s.employeeid,m.categorynumber
from sales s
inner join media m on s.mediaid=m.mediaid
inner join employee e on e.employeeid=s.employeeid
where e.name = 'JOE'
group by employeeid,categorynumber) t on t.categorynumber=c.categorynumber
where s.employeeid is null
Modified Answer based on the solution provided by Carl in Access SQL Syntax:
select *
from Category c
where not exists (
select *
from (Employee e
inner join Sales s on (s.EmployeeId = e.EmployeeId))
inner join Media m on (m.MediaID = s.MediaID)
where (e.Name = 'Ryan' and m.CategoryNumber = c.CategoryNumber)
)