Multiple JOINS in SQL with dataset - sql

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

Related

SQL query to select records WHERE NOT EXISTS

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

joining a table on 2 fields

I want to pull a person and their supervisor names from a table. The persons table has the supervisor_id and the person_id. The names table has name_id and a Full Name field. If I join Person ON either supervisor_id or person_id, how do I get the other to display as well?
You need to join twice, one for each relationship you have:
SELECT
-- Persons' columns
P.*,
-- Superviser name columns
SN.*,
-- Person name columns
PN.*
FROM
persons AS P
LEFT JOIN names AS SN ON P.supervisor_id = SN.name_id
LEFT JOIN names AS PN ON P.person_id = PN.name_id
Or you can join with an OR clause, but you won't be able to know which record did you join with unless you check with a CASE.
SELECT
-- Persons' columns
P.*,
-- name columns
N.*,
IsSupervisor = CASE WHEN P.supervisor_id = N.name_id THEN 'Yes' ELSE 'No' END
FROM
persons AS P
LEFT JOIN names AS N ON
P.supervisor_id = N.name_id OR
P.person_id = N.name_id
This last approach will display 2 rows as it will match either one or the other on different occasions, not both with the same persons row (as the first example).
A (self)join is what you need:
select p.*, supervisor=ps.name
from Person p join person ps on p.supervisor_id=ps.id

SQL Full join on two columns

I'm trying to join two tables but the columns emp_id and scheme_id may be null or not populated in either table but if it is populated in either then I need to return the total pen_ee for that employee for each scheme (further table descriptions below). I can't edit the table structure and have to work with what I have.
I've been trying to use a full join to do this but don't understand if you can do a full join on two fields emp_id & scheme_id to get the required result.
Table PAYAUDPEN
This is the first two months of the year.
- Employee A has given 44.06 to scheme BMAL.
- Employee B has given 98.06 to scheme BMAL.
- Employee B has given 98.06 to scheme CLFL.
emp_id, period_id, scheme_id, pen_ee
A, 201601, BMAL, 22.03
A, 201602, BMAL, 22.03
B, 201601, BMAL, 98.06
B, 201602, CLFL, 98.06
Table PAYISPEN
This is the third & current month of the year. The system always puts the current month into this table)
- Employee A gave 22.03.
- Employee B gave 98.06.
(Note employee B did not contribute to the BMAL scheme again in month 3 which is part of the issue).
emp_id, scheme_id, pen_ee
A, BMAL, 22.03
B, CLFL, 98.06
Required Result
The SQL statement needs to return the 3 periods added together, for each employee for each scheme that they contributed to.
- Employee A would be 44.06 + 22.03=66.09 for scheme BMAL.
- Employee B would be 98.06 + NULL =98.06 for scheme BMAL.
- Employee B would be 98.06 + 98.06=196.12 for scheme CLFL.
A, BMAL, 66.09
B, BMAL, 98.06
B, CLFL, 196.12
To create the basics of the two tables and populate with the example data above run the following queries.
CREATE TABLE [dbo].[payaudpen](
[emp_id] [char](10) NOT NULL,
[period_id] [char](6) NOT NULL,
[scheme_id] [char](10) NOT NULL,
[pen_ee] [numeric](15, 2) NULL)
CREATE TABLE [dbo].[payispen](
[emp_id] [char](10) NOT NULL,
[scheme_id] [char](10) NOT NULL,
[pen_ee] [numeric](15, 2) NULL )
INSERT INTO payaudpen VALUES ('A','201601','BMAL','22.03'), ('A','201602','BMAL','22.03'), ('B','201601','BMAL','98.06'), ('B','201602','CLFL','98.06')
INSERT INTO payispen VALUES ('A','BMAL','22.03'), ('B','CLFL','98.06')
Current statement that I'm using:
SELECT a.emp_id,
a.scheme_id,
SUM(a.pen_ee)+AVG(b.pen_ee)
FROM payaudpen a
FULL JOIN payispen b
ON a.emp_id=b.emp_id
GROUP BY a.scheme_id, a.emp_id
Incorrect result
Doesn't return the correct value for employee B for each scheme.
A, BMAL, 66.09
B, BMAL, 196.12
B, CLFL, 196.12
You are trying to sum across two tables, use union all to make the tables into one relation with more rows, instead of join to make the tables into a relation with more columns:
WITH all_records AS (SELECT emp_id
, scheme_id
, pen_ee
FROM payispen
UNION ALL
SELECT emp_id
, scheme_id
, pen_ee FROM payaudpen)
SELECT emp_id, scheme_id, SUM(pen_ee)
FROM all_records
GROUP BY emp_id, scheme_id
Results:
emp_id scheme_id (No column name)
A BMAL 66.09
B BMAL 98.06
B CLFL 196.12
Apparently you want to join only rows that have both the same emp_id and the same scheme_id. This is possible in outer joins, just as it is in inner joins. I infer that you also want to merge the emp_id and scheme_id columns from the two tables so that when a does not provide them, they come from b, instead. This will do it:
SELECT
COALESCE(a.emp_id, b.emp_id) AS emp_id,
COALESCE(a.scheme_id, b.scheme_id) AS scheme_id,
SUM(a.pen_ee)+AVG(b.pen_ee) AS pen_ee
FROM
payaudpen a
FULL JOIN payispen b
ON a.emp_id = b.emp_id AND a.scheme_id = b.scheme_id
WHERE
COALESCE(a.emp_id, b.emp_id) in ('A','B')
AND (a.period_id IS NULL OR a.period_id in ('201601','201602'))
GROUP BY COALESCE(a.scheme_id, b.scheme_id), COALESCE(a.emp_id, b.emp_id)
Note the use of COALESCE() to handle the cases where table a does not provide emp_id or scheme_id; with SQL Server you could also use ISNULL() in its place. Note also the allowance for a.period_id IS NULL in the WHERE condition -- this is necessary (in conjunction with the COALESCE()ing) to include data from b rows that do not have corresponding a rows.
The key thing you need to change in your solution is to use ISNULL() to make sure the key appears when table b has data but not table a. Otherwise, you'll get rows which look like:
NULL | NULL | 98.06
I recommend:
SELECT ISNULL(a.emp_id,b.emp_id) AS emp_id
ISNULL(a.scheme_id, b.scheme_id) AS scheme_id
SUM(a.pen_ee)+AVG(b.pen_ee) AS pen_ee
FROM payaudpen a
FULL JOIN payispen b
ON a.emp_id=b.emp_id
AND a.scheme_id=b.scheme_id
WHERE a.emp_id in ('A','B')
and period_id in ('201601','201602')
GROUP BY ISNULL(a.emp_id,b.emp_id), ISNULL(a.scheme_id, b.scheme_id)

How to join my tables?

I'm using a Sqlite3 database and I have 3 tables which I want to join. My program basically has documents. And you can select multiple employees that belong to the document. But employees can also belong to other documents.
Below are my tables:
Table Employee:
id:Integer primary key
Table Document:
id:Integer primary key
Table DocEmp:
id:Integer primary key
docId:Integer
empId:Integer
state:Integer
The DocEmp table can be empty only the Employee and Document table is always filled. Most important is that i always want to load all employees!
So for example:
I have 3 employees with id's: 1,2 and 3. Have 2 documents with id 1 and 2.
The DocEmp has the following records:
Row1: 1,1,1,0
Row2: 2,1,2,1
So this means only document 1 has 2 employees with id 1 and 2. So when i'm in document 1 i want to load all 3 employees, and also want to know the state of the 2 employees that are filled in for that document in the DocEmp table. And because document 2 has no employees i need just all the employees.
If I understand your question correctly, I think you might be looking for a left join:
select e.id as employeeid,
d.id as documentid,
de.state as state
from employee e
--this could be an inner join but your example is confusing
left join document d on e.id = d.id
left join docemp de on e.id = de.empid
and d.id = de.docid;

SQL Inner join in a nested select statement

I'm trying to do an inner join in a nested select statement. Basically, There are first and last reason IDs that produce a certain number (EX: 200). In another table, there are definitions for the IDs. I'm trying to pull the Last ID, along with the corresponding comment for whatever is pulled (EX: 200 - Patient Cancelled), then the first ID and the comment for whatever ID it is.
This is what I have so far:
Select BUSN_ID
AREA_NAME
DATE
AREA_STATUS
(Select B.REASON_ID
A.LAST_REASON_ID
FROM BUSN_INFO A, BUSN_REASONS B
WHERE A.LAST_REASON _ID=B.REASON_ID,
(Select B.REASON_ID
A. FIRST_REASON_ID
FROM BUSN_INFO A, BUSN_REASONS B
WHERE A_FIRST_REASON_ID = B.REASON_ID)
FROM BUSN_INFO
I believe an inner join is best, but I'm stuck on how it would actually work.
Required result would look like (this is example dummy data):
First ID -- Busn Reason -- Last ID -- Busn Reason
1 Patient Sick 2 Patient Cancelled
2 Patient Cancelled 2 Patient Cancelled
3 Patient No Show 1 Patient Sick
Justin_Cave's SECOND example is the way I used to solve this problem.
If you want to use inline select statements, your inline select has to select a single column and should just join back to the table that is the basis of your query. In the query you posted, you're selecting the same numeric identifier multiple times. My guess is that you really want to query a string column from the lookup table-- I'll assume that the column is called reason_description
Select BUSN_ID,
AREA_NAME,
DATE,
AREA_STATUS,
a.last_reason_id,
(Select B.REASON_description
FROM BUSN_REASONS B
WHERE A.LAST_REASON_ID=B.REASON_ID),
a.first_reason_id,
(Select B.REASON_description
FROM BUSN_REASONS B
WHERE A.FIRST_REASON_ID = B.REASON_ID)
FROM BUSN_INFO A
More conventionally, though, you'd just join to the busn_reasons table twice
SELECT i.busn_id,
i.area_name,
i.date,
i.area_status,
i.last_reason_id,
last_reason.reason_description,
i.first_reason_id,
first_reason.reason_description
FROM busn_info i
JOIN busn_reason first_reason
ON( i.first_reason_id = first_reason.reason_id )
JOIN busn_reason last_reason
ON( i.last_reason_id = last_reason.reason_id )