SQL query to select records WHERE NOT EXISTS - sql

I was having some problem when trying to write SQL query to filter out certain data. Basically my table design is 1 ward can have many beds, and 1 bed can have many enrollments.
My ward table has w_id as PK, bed table with b_id as PK and w_id as FK, enrollment table with e_id as PK and b_id as FK.
What I am trying to do now is get the list of beds together with ward details that is not exist in enrollment table. I tried my SQL query in Oracle database:
SELECT * FROM bed b
INNER JOIN ward w ON b.WARD_ID = w.ID
WHERE NOT EXISTS ( SELECT * FROM bed b2
INNER JOIN enroll e ON e.BED_ID = b2.ID
WHERE b2.ID = b.ID );
It did managed to returned me the desired result. However, when I tried to put the above query as native query in Spring Boot, I am getting the error message:
Encountered a duplicated sql alias [ID] during auto-discovery of a native-sql query; nested exception is org.hibernate.loader.custom.NonUniqueDiscoveredSqlAliasException: Encountered a duplicated sql alias [ID] during auto-discovery of a native-sql query
Any ideas? Thanks!

SELECT * FROM bed b
INNER JOIN ward w ON b.WARD_ID = w.ID
It appears the bed and ward table both have columns named id. By doing select * you are implicitly including all the columns from both the bed and the ward table. So you are including two columns named id. The not exists part is a distraction. Some sql clients will allow this, but hibernate is more strict. I don't have an environment to do an immediate test on, but something like the following would fix, if this is the issue.
SELECT b.id, b.ward_id, w.ward_name FROM bed b
INNER JOIN ward w ON b.WARD_ID = w.ID
WHERE NOT EXISTS ( SELECT b2.id FROM bed b2
INNER JOIN enroll e ON e.BED_ID = b2.ID
WHERE b2.ID = b.ID );

I don't know if this is related to your problem, but you don't need the JOIN in the subquery. A simpler version is:
SELECT *
FROM bed b INNER JOIN
ward w
ON b.WARD_ID = w.ID
WHERE NOT EXISTS (SELECT 1
FROM enroll e
WHERE e.BED_ID = b.ID
);

Related

Multiple JOINS in SQL with dataset

I have 3 tables that I need to JOIN in SQL.
Table A: Contains Employee ID
Table B: Contains Employee ID AND fica number
Table C: Contains fica number
Table A and B both contain an employee ID column. Table B and C both contain a column that has an employee's fica number. I need to find out all of the employees that are present in table C but not in table A. I wanted to do that by joining the fica number from table A and table A, then from there I was going to match up the employee ID that correlates to the fica number and try and JOIN that with table A. I try writing the syntax like this:
select distinct(a.employee_id), c.FICA_NBR, b.first_name, b.last_name from benefit A
join B on b.employee_id = a.employee_id
left join C on c.FICA_NBR = b.FICA_NBR
where c.FICA_NBR IS NULL
order by a.employee_id;
How would I go about editing this syntax?
select distinct a.employee_id, c.FICA_NBR, b.first_name, b.last_name from C
join B on c.FICA_NBR = b.FICA_NBR
left join benefit A on b.employee_id = a.employee_id
where A.employee_id IS NULL
order by a.employee_id;
The above code should help you achieve the goal since your condition is data is not present in table a, then its primary key should be null.
Hope I answered your question

Listing Pairs on same table with different criteria on Oracle Sql

I need to list pairs of customer names as follows;
> CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME, CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME
such that each pair of customers has the same zip code (which is also in the customers table).
On the task there is a hint which says
HINT: Your output should have four columns: CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME, CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME
This is what I have written so far:
SELECT DISTINCT CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME, CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME
FROM CUSTOMERS
WHERE CUSTOMER_ZIP = CUSTOMER_ZIP
But I am not sure how to continue since I've only started learning SQL yesterday. I have also tried to Join the same table which resulted in ambiguity errors.
Update#1:
I've written this code using aliases as suggested by #kpater87
SELECT DISTINCT C1.CUSTOMER_FIRST_NAME, C1.CUSTOMER_LAST_NAME , C2.CUSTOMER_FIRST_NAME, C2.CUSTOMER_LAST_NAME
FROM CUSTOMERS C1
INNER JOIN CUSTOMERS C2
ON C1.CUSTOMER_ZIP = C2.CUSTOMER_ZIP
But even though I have a distinct statement it will show duplicate data. Is this to be expected or am I missing something?
Your updated query looks fine. The only problem in your query is it will be joining also the same records.
If you have a primary key in the table you can improve your query by adding WHERE condition:
SELECT DISTINCT C1.CUSTOMER_FIRST_NAME,
C1.CUSTOMER_LAST_NAME ,
C2.CUSTOMER_FIRST_NAME,
C2.CUSTOMER_LAST_NAME
FROM CUSTOMERS C1
INNER JOIN CUSTOMERS C2
ON C1.CUSTOMER_ZIP = C2.CUSTOMER_ZIP
WHERE C1.PK <> C2.PK;
PK - is a column being a primary key in the table.
If you don't have primary key you can try this one:
SELECT C1.CUSTOMER_FIRST_NAME,
C1.CUSTOMER_LAST_NAME ,
C2.CUSTOMER_FIRST_NAME,
C2.CUSTOMER_LAST_NAME
FROM CUSTOMERS C1
INNER JOIN CUSTOMERS C2
ON C1.CUSTOMER_ZIP = C2.CUSTOMER_ZIP
WHERE C1.CUSTOMER_FIRST_NAME <> C2.CUSTOMER_FIRST_NAME
AND C2.CUSTOMER_LAST_NAME <> C2.CUSTOMER_LAST_NAME
But there still be a problem that in your output you will get e.g.
Mary Smith James Bond
James Bond Mary Smith
To remove permutations:
SELECT C1.CUSTOMER_FIRST_NAME,
C1.CUSTOMER_LAST_NAME ,
C2.CUSTOMER_FIRST_NAME,
C2.CUSTOMER_LAST_NAME,
C1.CUSTOMER_ZIP
FROM T_CUSTOMERS C1
LEFT JOIN T_CUSTOMERS C2
ON (C1.CUSTOMER_ZIP = C2.CUSTOMER_ZIP
AND
C1.CUSTOMER_NUMBER > C2.CUSTOMER_NUMBER );
See also: SQL: self join using each rows only once

SQL query returns student id, course section id, and grade when section id 1000

Using Oracle Apex Browser, image of database
http://imgur.com/a/Hhblp#0
select s_ID, c_sec_ID, grade
from s_ID.ID, c_sec_ID.csID, grade.ID, grade.csID
where c_sec_ID = 1000
^ All I think of and I'm not sure if I'm suppose to join them together or group them either.
You have to join these tree tables COURSE_SECTION, ENROLLMENT and STUDENT to get desired output. Put INNER JOIN on three tables and add
Where Clause to filter records.
You can try this
SELECT S.s_ID, C.c_sec_ID, E.grade
FROM COURSE_SECTION C INNER JOIN ENROLLMENT E ON C.C_SEC_ID = E.C_SEC_ID
INNER JOIN STUDENT S ON S.S_ID = E.S_ID
WHERE C.C_SEC_ID = 1000

Representing 'not in' subquery as join

I am trying to convert the following query:
select *
from employees
where emp_id not in (select distinct emp_id from managers);
into a form where I represent the subquery as a join. I tried doing:
select *
from employees a, (select distinct emp_id from managers) b
where a.emp_id!=b.emp_id;
I also tried:
select *
from employees a, (select distinct emp_id from managers) b
where a.emp_id not in b.emp_id;
But it does not give the same result. I have tried the 'INNER JOIN' syntax as well, but to no avail. I have become frustrated with this seemingly simple problem. Any help would be appreciated.
Assume employee Data set of
Emp_ID
1
2
3
4
5
6
7
Assume Manger data set of
Emp_ID
1
2
3
4
5
8
9
select *
from employees
where emp_id not in (select distinct emp_id from managers);
The above isn't joining tables so no Cartesian product is generated... you just have 7 records you're looking at...
The above would result in 6 and 7 Why? only 6 and 7 from Employee Data isn't in the managers table. 8,9 in managers is ignored as you're only returning data from employee.
select *
from employees a, (select distinct emp_id from managers) b
where a.emp_id!=b.emp_id;
The above didnt' work because a Cartesian product is generated... All of Employee to all of Manager (assuming 7 records in each table 7*7=49)
so instead of just evaluating the employee data like you were in the first query. Now you also evaluate all managers to all employees
so Select * results in
1,1
1,2
1,3
1,4
1,5
1,8
1,9
2,1
2,2...
Less the where clause matches...
so 7*7-7 or 42. and while this may be the answer to the life universe and everything in it, it's not what you wanted.
I also tried:
select *
from employees a, (select distinct emp_id from managers) b
where a.emp_id not in b.emp_id;
Again a Cartesian... All of Employee to ALL OF Managers
So this is why a left join works
SELECT e.*
FROM employees e
LEFT OUTER JOIN managers m
on e.emp_id = m.emp_id
WHERE m.emp_id is null
This says join on ID first... so don't generate a Cartesian but actually join on a value to limit the results. but since it's a LEFT join return EVERYTHING from the LEFT table (employee) and only those that match from manager.
so in our example would be returned as e.emp_Di = m.Emp_ID
1,1
2,2
3,3
4,4
5,5
6,NULL
7,NULL
now the where clause so
6,Null
7,NULL are retained...
older ansii SQL standards for left joins would have been *= in the where clause...
select *
from employees a, managers b
where a.emp_id *= b.emp_id --I never remember if the * is the LEFT so it may be =*
and b.emp_ID is null;
But I find this notation harder to read as the join can get mixed in with the other limiting criteria...
Try this:
select e.*
from employees e
left join managers m on e.emp_id = m.emp_id
where m.emp_id is null
This will join the two tables. Then we discard all rows where we found a matching manager and are left with employees who aren't managers.
Your best bet would probably be a left join:
select
e.*
from employees e
left join managers m on e.emp_id = m.emp_id
where
m.emp_id is null;
The idea here is you're saying that you want to select everything from employees, including anything that matches in the manager table based on emp_id and then filtering out the rows that actually have something in the manager table.
Use Left Outer Join instead
select e.*
from employees e
left outer join managers m
on e.emp_id = m.emp_id
where m.emp_id is null
left outer join will preserve the rows from m table even if they do not have a match i e table based on the emp_id field. The we filter on where m.emp_id is null - give me all the rows from e where there's no matching record in m table.
A bit more on the subject can be found here:
Visual representation of joins
from employees a, (select distinct emp_id from managers) b implies cross join - all posible combinations between tables (and you needed left outer join instead)
The MINUS keyword should do the trick:
SELECT e.* FROM employees e
MINUS
Select m.* FROM managers m
Hope that helps...
select *
from employees
where Not (emp_id in (select distinct emp_id from managers));

Sql query with multiple condition but some of item is not available in certain table

I am facing problem with sql query when I try to join this tree table and get the data. I am using Oracle database.
Personal
id_no name
-------------
0001 John
0002 Peter
0003 Mike
position
id_no name
-------------
0001 programmer
0002 Engineer
0003 Clerk
extra_skill
employee_id skill
--------------------------
0001 Visual Studio 2008
0003 Crystal Report
Requirement:
Display details of employees:
Example:
Employee No : 0001
Employee Name : John
Employee Position : Programmer
Employee Skill : Visual Studio 2008
My sql statement is
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id = "USER INPUT";
The problem is when
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id = "0002";
This query give me NULL because in the table extra_skill does not have 0002.
I want it possible to get data even in the third table no value.
Expected result:
Employee No : 0002
Employee Name : Peter
Employee Position : Engineer
Employee Skill :
How can I implement such a query?
Your attentions and helps are much appreciated.
Thank you, Siti..:)
The way to do this is with outer joins. I have used the ANSI joining syntax (introduced in Oracle 9i) for this example, because it is clearer and also Oracle now recommend using it.
SELECT a.id_no, a.name, b.name as position, c.skill
FROM personal a INNER JOIN position b
on (a.id_no = b.id_no )
LEFT OUTER JOIN extra_skill c
on ( a.id_no = c.employee_id )
WHERE a.id_no = '0002';
Note that I have changed the filter condition to select on PERSONAL.ID. If you attempt to use c.employee_id = '0002' (as you do in your question) you will get no rows returned.
You could include EXTRA_SKILLS.EMPLOYEE_ID in the join condition rather than the WHERE clause.
SELECT a.id_no, a.name, b.name as position, c.skill
FROM personal a INNER JOIN position b
on (a.id_no = b.id_no )
LEFT OUTER JOIN extra_skill c
on ( a.id_no = c.employee_id
and c.employee_id = '0002');
Generally including filters in the join section is not considered good practice, because it can effect the result set in ways we're not expecting. In your case it will return every row in PERSONAL and POSITION and no values from EXTRA_SKILL. This is probably not what you want to happen. Here is a SQL Fiddle to prove it.
You will have to use an outer join.
The purpose of an outer join is to include non-matching rows, and the outer join returns these missing columns as NULL values.
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id(+) = "USER INPUT";