SQL: Have 4 Tables, Looking to find unmatched data - sql

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)
)

Related

SQL - joining multiple tables

I have three tables that I'm trying to join:
sales
order
employee
For example, the tables have the following attributes.
Sales:
ID
price
Order:
ID
tag
Employee:
tag
yearsWorked
I would like to keep only records that exist from the result of a left join in sales and order -> left join the result with employee
SELECT *
FROM ( SELECT *
FROM SALES
LEFT JOIN ORDER
ON SALES.ID = ORDER.ID) AS SO
LEFT JOIN EMPLOYEE
on SO.TAG = EMPLOEYE.TAG;
The above query does not work.
There is no need for a subquery. All you have to do is 2 LEFT JOIN, each for the respective table. This will make sure that only the results of the first left join are joined with the third table.
SELECT *
FROM SALES S
LEFT JOIN ORDER O ON S.ID = O.ID
LEFT JOIN EMPLOYEE E ON O.TAG = E.TAG;
I hope this works.
SELECT
*
FROM
Order
LEFT JOIN Sales
ON Order.ID = Sales.ID
LEFT JOIN Employee
ON Order.tag = Employee.tag

Senior Manager of Employee sql

I have an employee table:
I have a category table which joins userid and category id:
Category with value 1 is senior manager.
I want to find senior manager of each employee.Seniors Managers with category value of 1.
I need the output like this:
How can we achieve this in SQL Server 2008?
Any help appreciated.
Try:
WITH Emp_CTE AS (
Select ID,EmployeeName,Manager from employee
UNION ALL
SELECT ecte.ID,ecte.EmployeeName,c.Manager
FROM employee c
INNER JOIN Emp_CTE ecte ON ecte.Manager = c.ID
)
SELECT a.ID,a.EmployeeName,b.EmployeeName
FROM Emp_CTE a
left join employee b
on a.Manager = b.ID
left join category c
on a.Manager = c.UserID
where c.Category = '1'
As this query calls for a Self Join, this should work:
SELECT a.EMPLOYEENAME as Employee,
b.EMPLOYEENAME as Senior_Manager
FROM employee a
LEFT JOIN
employee b ON a.ID = b.Manager
LEFT JOIN
category c ON b.ID = c.UserID
WHERE c.Category = 1

SQL Server Circular Query

I have 4 tables, in that I want to fetch records from all 4 and aggregate the values
I have these tables
I am expecting this output
but getting this output as a Cartesian product
It is multiplying the expenses and allocation
Here is my query
select
a.NAME, b.P_NAME,
sum(a.DURATION) DURATION,
sum(b.[EXP]) EXPEN
from
(select
e.ID, a.P_ID, e.NAME, a.DURATION DURATION
from
EMPLOYEE e
inner join
ALLOCATION a ON e.ID = a.E_ID) a
inner join
(select
p.P_ID, e.E_ID, p.P_NAME, e.amt [EXP]
from
PROJECT p
inner join
EXPENSES e ON p.P_ID = e.P_ID) b ON a.ID = b.E_ID
and a.P_ID = b.P_ID
group by
a.NAME, b.P_NAME
Can anyone suggest something about this.
The following should work:
SELECT e.Name,p.Name,COALESCE(d.Duration,0),COALESCE(exp.Expen,0)
FROM
Employee e
CROSS JOIN
Project p
LEFT JOIN
(SELECT E_ID,P_ID,SUM(Duration) as Duration FROM Allocation
GROUP BY E_ID,P_ID) d
ON
e.E_ID = d.E_ID and
p.P_ID = d.P_ID
LEFT JOIN
(SELECT E_ID,P_ID,SUM(AMT) as Expen FROM Expenses
GROUP BY E_ID,P_ID) exp
ON
e.E_ID = exp.E_ID and
p.P_ID = exp.P_ID
WHERE
d.E_ID is not null or
exp.E_ID is not null
I've tried to write a query that will produce results where e.g. there are rows in Expenses but no rows in Allocations (or vice versa) for some particular E_ID,P_ID combination.
Use left join in select query by passing common id for all table
Hi I got the answer what I want from some modification in the query
The above query is also working like a charm and have done some modification to the original query and got the answer
Just have to group by the inner queries and then join the queries it will then not showing Cartesian product
Here is the updated one
select a.NAME,b.P_NAME,sum(a.DURATION) DURATION,sum(b.[EXP]) EXPEN from
(select e.ID,a.P_ID, e.NAME,sum(a.DURATION) DURATION from EMPLOYEE e inner join ALLOCATION a
ON e.ID=a.E_ID group by e.ID,e.NAME,a.P_ID) a
inner join
(select p.P_ID,e.E_ID, p.P_NAME,sum(e.amt) [EXP] from PROJECT p inner join EXPENSES e
ON p.P_ID=e.P_ID group by p.P_ID,p.P_NAME,e.E_ID) b
ON a.ID=b.e_ID and a.P_ID=b.P_ID group by a.NAME,b.P_NAME
Showing the correct output

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;

Query extensibility with WHERE EXISTS with a large table

The following query is designed to find the number of people who went to a hospital, the total number of people who went to a hospital and the divide those two to find a percentage. The table Claims is two million plus rows and does have the correct non-clustered index of patientid, admissiondate, and dischargdate. The query runs quickly enough but I'm interested in how I could make it more usable. I would like to be able to add another code in the line where (hcpcs.hcpcs ='97001') and have the change in percentRehabNotHomeHealth be relfected in another column. Is there possible without writing a big, fat join statement where I join the results of the two queries together? I know that by adding the extra column the math won't look right, but I'm not worried about that at the moment. desired sample output: http://imgur.com/BCLrd
database schema
select h.hospitalname
,count(*) as visitCounts
,hospitalcounts
,round(count(*)/cast(hospitalcounts as float) *100,2) as percentRehabNotHomeHealth
from Patient p
inner join statecounties as sc on sc.countycode = p.countycode
and sc.statecode = p.statecode
inner join hospitals as h on h.npi=p.hospitalnpi
inner join
--this join adds the hospitalCounts column
(
select h.hospitalname, count(*) as hospitalCounts
from hospitals as h
inner join patient as p on p.hospitalnpi=h.npi
where p.statecode='21' and h.statecode='21'
group by h.hospitalname
) as t on t.hospitalname=h.hospitalname
--this where exists clause gives the visitCounts column
where h.stateCode='21' and p.statecode='21'
and exists
(
select distinct p2.patientid
from Patient as p2
inner join Claims as c on c.patientid = p2.patientid
and c.admissiondate = p2.admissiondate
and c.dischargedate = p2.dischargedate
inner join hcpcs on hcpcs.hcpcs=c.hcpcs
inner join hospitals as h on h.npi=p2.hospitalnpi
where (hcpcs.hcpcs ='97001' or hcpcs.hcpcs='9339' or hcpcs.hcpcs='97002')
and p2.patientid=p.patientid
)
and hospitalcounts > 10
group by h.hospitalname, t.hospitalcounts
having count(*)>10
You might look into CTE (Common Table Expressions) to get what you need. It would allow you to get summarized data and join that back to the detail on a common key. As an example I modified your join on the subquery to be a CTE.
;with hospitalCounts as (
select h.hospitalname, count(*) as hospitalCounts
from hospitals as h
inner join patient as p on p.hospitalnpi=h.npi
where p.statecode='21' and h.statecode='21'
group by h.hospitalname
)
select h.hospitalname
,count(*) as visitCounts
,hospitalcounts
,round(count(*)/cast(hospitalcounts as float) *100,2) as percentRehabNotHomeHealth
from Patient p
inner join statecounties as sc on sc.countycode = p.countycode
and sc.statecode = p.statecode
inner join hospitals as h on h.npi=p.hospitalnpi
inner join hospitalCounts on t.hospitalname=h.hospitalname
--this where exists clause gives the visitCounts column
where h.stateCode='21' and p.statecode='21'
and exists
(
select p2.patientid
from Patient as p2
inner join Claims as c on c.patientid = p2.patientid
and c.admissiondate = p2.admissiondate
and c.dischargedate = p2.dischargedate
inner join hcpcs on hcpcs.hcpcs=c.hcpcs
inner join hospitals as h on h.npi=p2.hospitalnpi
where (hcpcs.hcpcs ='97001' or hcpcs.hcpcs='9339' or hcpcs.hcpcs='97002')
and p2.patientid=p.patientid
)
and hospitalcounts > 10
group by h.hospitalname, t.hospitalcounts
having count(*)>10