I don't have the right answer in SQL - sql

List the project numbers (PR_NO) for projects that have only received parts that are stored in (P_CITY) the same city as the project (show output of the query).
Table: EMP
Primary Key: E_NO
E_NO E_NAME E_RATE E_DEPT
1 A $400.00
2 B $200.00 1
3 C $150.00 2
4 D $150.00 3
5 E $120.00 1
6 F $100.00 1
7 G $100.00 2
8 H $50.00 2
9 I $50.00 3
10 J $50.00 3
11 K $150.00 3
Table: PART
Primary Key: P_NO
P_NO P_NAME P_CITY
1 P1 NY
2 P2 NY
3 P3 LA
4 P4 SF
5 P5 LA
6 P6 NY
Table: PROJECT
Primary Key: PR_NO
PR_NO PR_MGR PR_DEPT PR_LOC
1 2 1 NY
2 3 2 LA
3 2 1 NY
Table: SUPPLIER
Primary Key: S_NO
S_NO S_NAME S_LOC
1 S1 NY
2 S2 NY
3 S3 LA
Table: SUPPLY
Primary Key: P_NO + PR_NO + S_NO
Foreign Key: P_NO references PART
Foreign Key: PR_NO references PROJECT
Foreign Key: S_NO references SUPPLIER
P_NO PR_NO S_NO QTY
1 1 1 111
1 1 2 112
1 1 3 113
1 2 1 121
1 2 2 122
1 2 3 123
1 3 1 131
1 3 2 132
1 3 3 133
2 1 1 211
3 1 1 311
4 1 1 411
5 1 1 511
6 1 1 611
Table: WORK
Primary Key: E_NO + PR_NO
Foreign Key: E_NO references EMP
Foreign Key: PR_NO references PROJECT
E_NO PR_NO HRS
2 1 10
3 2 20
5 1 20
5 2 20
5 3 20
6 1 10
6 2 10
select distinct P.PR_NO
from PROJECT P, PART PA
where PA.P_CITY = P.PR_LOC;
The right answer question should be :
PR_NO
3
This is the error:
PR_NO
1
3
2

In order to achieve this task, you also need to use Supply table as follows:
select s.pr_no
from supply s
inner join part p
on p.p_no = s.p_no
group by s.pr_no
having max(p.p_city) = min(p.p_city)
and min(p.p_city) = (select pr_loc
from project
where pr_no = s.pr_no
)

I tested this query with your example data and it returns project #3 as expected:
SELECT DISTINCT S.PR_NO
FROM
SUPPLY S
INNER JOIN PROJECT PR
ON S.PR_NO = PR.PR_NO
INNER JOIN PART P
ON S.P_NO = P.P_NO
WHERE
PR.PR_LOC = P.P_CITY AND
NOT S.PR_NO IN
(
SELECT S2.PR_NO
FROM
SUPPLY S2
INNER JOIN PROJECT PR2
ON S2.PR_NO = PR2.PR_NO
INNER JOIN PART P2
ON S2.P_NO = P2.P_NO
WHERE PR2.PR_LOC <> P2.P_CITY
)
The SUPPLY table creates the link between PART and PROJECT. The main query looks for parts that are stored in the same city as the project. The sub-select in the where clause looks almost the same, except that it looks for parts stored in a different city. Projects with such cities are excluded with NOT S.PR_NO IN (...).

The main issue in your query is that you should correctly join the 2 tables PROJECT and PART before filtering; so in this case you should use the table SUPPLY.
SELECT DISTINCT S.PR_NO
FROM SUPPLY S
INNER JOIN PROJECT PR
ON S.PR_NO = PR.PR_NO
INNER JOIN PART P
ON S.P_NO = P.P_NO
WHERE PR.PR_LOC = P.P_CITY
AND S.PR_NO NOT IN ( SELECT DISTINCT S.PR_NO
FROM SUPPLY S
INNER JOIN PROJECT PR
ON S.PR_NO = PR.PR_NO
INNER JOIN PART P
ON S.P_NO = P.P_NO
WHERE PR.PR_LOC <> P.P_CITY );
Hope this helps!

Related

SQL select with three tables and foreign keys

I have three tables :
field:
f_id
f_start
f_end
1
10
20
2
15
25
3
5
10
person :
p_id
p_name
1
Roger
2
John
3
Alicia
affect :
id
fk_field
fk_person
1
2
1
2
1
2
3
3
3
And I would like to select the dates and the names associated to. Like this
p_name
f_start
f_end
Roger
15
25
John
10
20
Alicia
5
10
I'm new to SQL and I don't know if i have to use JOIN or not... Thanks
You must join all 3 tables on their related columns:
SELECT p.p_name, f.f_start, f.f_end
FROM person p
INNER JOIN affect a ON a.fk_person = p.p_id
INNER JOIN field f ON f.f_id = a.fk_field;
Depending on your requirement you may need LEFT instead of INNER joins, but for this sample data the INNER joins will do.

Query the sum of some cells in a table based on an id in another table

Let assume that we have two tables named family_data and person_info as below:
# family_data
person_id | family_id
1 1
2 2
3 1
4 1
5 2
# person_info
person_id | weight
1 50
2 80
3 30
4 60
5 40
How can I have a table which contains pairs of (family_id, sum_of_members_weight) as below:
# Query output:
family_id | total_weight
1 140
2 120
You can join and aggregate:
select f.family_id, sum(p.weight) total_weight
from family_data f
inner join person_info p on p.person_id = f.person_id
group by f.family_id

Select rows with specific multiple values from the same column?

I have database where 2 roles can't be associated with each other, and I need to display any users who have conflicting roles.
For example: an (id 2) accountant can't also be a (id 5) trainer
this has to be done without using CTE's
Table a Table b table c
--------------- ------------------- ------------
userID | roleID roleID | conflictID roleID | Role Name
1 2 2 5 1 chef
1 3 2 accountant
1 5 3 driver
2 3 4 barmaid
2 1 5 trainer
3 2
3 3
the result should contain only the userID who has both roles 2 and 5
userID
------
1
Join the b table with the a table twice, to get userID's with conflicting combinations:
select distinct a1.userid
from tableb b
join tablea a1 on b.roleID = a1.roleID
join tablea a2 on b.conflictID = a2.roleID
and a1.userID = a2.userID

SQL- Add Missing data in Left outer joing query

I have following data
Components
componentid title
1 houseRent
2 medical
3 Travelling Allowance
empPayrollMaster
MasterID EmployeeID SalaryMonthID
1 101 1
2 102 1
3 103 1
empPayrollDetail
DetailID MasterID ComponentID amount
1 1 1 100
2 1 2 500
3 2 1 300
4 2 3 250
5 3 1 150
6 3 2 350
7 3 3 450
Required Output
EmployeeID MasterID ComponentID amount
101 1 1 100
101 1 2 500
101 1 3 0
102 2 1 300
102 1 2 0
102 2 3 250
103 3 1 150
103 3 2 350
103 3 3 450
To get the required output if i do left outer join between components and empPayrollDetail I get null in EmployeeID and MasterID and amount Columns. How to modify left join to get the required output
You need to do a CROSS JOIN on Components and empPayrollMaster to generate first all combination of employees and components. Then, do a LEFT JOIN on empPayrollDetail to achieve the result, using ISNULL(amount, 0) for NULL amounts.
SQL Fiddle
SELECT
epm.EmployeeID,
epm.MasterID,
c.ComponentID,
amount = ISNULL(epd.amount, 0)
FROM empPayrollMaster epm
CROSS JOIN Components c
LEFT JOIN empPayrollDetail epd
ON epd.MasterID = epm.MasterID
AND epd.ComponentID = c.ComponentID
Try this
select empPayrollMaster.EmployeeID,empPayrollMaster.MasterID,
Components.componentid,isnull(empPayrollDetail.amount,0)
from empPayrollMaster
left join Components
on empPayrollMaster.EmployeeID is not null
left join empPayrollDetail
on empPayrollDetail.MasterID = empPayrollMaster.MasterID
and empPayrollDetail.ComponentID = Components.componentid
Try this way
select c.EmployeeID,d.MasterID,c.ComponentID,isnull(d.amount,0) as amount from (
select * from Components a
Cross join empPayrollMaster b) c
left outer join empPayrollDetail d on d.componentid =c.componentid
As you want the component amount for each employee in the master table you should use a insull(payrole_detail.amount,0) or, as #Turophile pointed out, the SQL standard function coalesce(payrole_detail.amount,0) for the amounts column.
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;

Show COUNT of each possible grade for an employee, showing zero when there are no grade entries

I have only one table available. I want to show the grade and the count of the number of times an employee has that grade recorded, but it must show a 0 for the grade if there are no records for that employee. I know how to do this using left join when two tables are present, but I only have 1 table.
How is this possible?
For example:
TABLE
empID | dept | grade
1 | 11 | a
2 | 11 | a
3 | 11 | b
1 | 22 | c
2 | 22 | f
3 | 22 | d
1 | 33 | a
2 | 33 | a
3 | 33 | a
If I run SELECT grade, count(grade) from table where empID = 1 Group by grade;, for example, it ends up printing out only grades the employee got and the count. Now I want to also print out the 0s for grades the employee did not have.
i think you're asking for this?
SQL> select e.grade, count(e2.empid)
2 from (select distinct grade from e) e
3 left outer join e e2
4 on e2.grade = e.grade
5 and e2.empid = 1
6 group by e.grade
7 order by grade;
G COUNT(E2.EMPID)
- ---------------
a 2
b 0
c 1
d 0
f 0
or as you have no rows with "e" grade then if you have a lookup table called grade:
SQL> select * from grade;
G
-
a
b
c
d
e
f
SQL> select e.grade, count(e2.empid)
2 from grade emp
3 left outer join emp e2
4 on e2.grade = e.grade
5 and e2.empid = 1
6 group by e.grade
7 order by grade;
G COUNT(E2.EMPID)
- ---------------
a 2
b 0
c 1
d 0
e 0
f 0
Let's say your query to select a value is:
select value from tbl;
You can ensure a 0 is returned if there are no rows in tbl t:
select nvl(t.value, 0) value
from dual d
left join tbl t on 1=1;
Sounds like you want the NVL function. With NVL, you can conditionally return an alternate value if the value is null. See the documentation.
So, if you had the following...
SELECT fooName, fooNumber FROM foo
and these were your results
fooName, fooNumber
Blah, 1
Asdf, null
Qwer, 3
poiu, null
you could rewrite the query like this...
SELECT fooName, NVL(fooNumber, 0) FROM foo
and your results would now be...
fooName, fooNumber
Blah, 1
Asdf, 0
Qwer, 3
poiu, 0
http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions105.htm