Sqlite - Joining two related tables - sql

I have two tables which are related in the following way:
Table A is a list of college courses and instances of that course, for example the "course" Maths runs on a Tuesday and a Thursday and therefore has two "course_periods". This is described in the following table:
Table A
id
name
type
0001
Maths
course
0002
Maths (Thursday)
course_period
0003
Maths (Tuesday)
course_period
There is another table which connects all the "course periods" to their parent "courses" and looks like this:
Table B
id
source
destination
0001
0001
0002
0002
0001
0003
I would like to produce the last below table which joins the two tables A & B in the following way:
destination_id
name_course_period
source_id
name_course
0002
Maths(Thursday)
0001
Maths
0003
Maths(Tuesday)
0001
Maths
I simply can't find the correct join statement to produce the desired result.

You must join TableB to 2 copies of TableA:
SELECT b.destination destination_id,
a2.name name_course_period,
b.source source_id,
a1.name name_course
FROM TableB b
INNER JOIN TableA a1 ON a1.id = b.source
INNER JOIN TableA a2 ON a2.id = b.destination;
See the demo.

Recreating your tables as cte, you need to start with table a as your base table. Join this table to b.
You then need to join back to a to get the name of the destination.
with a as (
select '0001' id, 'Maths' name, 'course' type
union all select '0002', 'Maths (Thursday)','course_period'
union all select '0003', 'Maths (Tuesday)', 'course_period'
)
, b as (
select '0001' id, '0001' source, '0002' destination
union all select '0002', '0001', '0003'
)
select
b.id as destination_id
, ref.name as name_course_period
, b.source as source_id
, a.name as name_course
from a
inner join b on b.source = a.id
inner join a ref on ref.id = b.destination --join back to a for name

Related

SQL - FILTER condition in JOIN clause

I am inserting data to an already existing TableA and the following query is a part of a stored procedure. This part of the query inserts values into some columns of TableA. The stored procedure is very lengthy which has several insert statements to fill out the different columns in TableA.
INSERT INTO TableA (ID, Event, Date, Amount, Status_, Country)
(SELECT DISTINCT ID, Event, Date, Amount, c.Status, b.Country
FROM TableA1 a
JOIN TableB1 b ON b.employeeID = a.ID
JOIN TableC1 c ON c.Status = ‘Active’)
Usually, a join condition consists of two columns, for example (a.Status_ = c.Status). But here, it's replaced with a filter condition (JOIN TableC1 c ON c.Status = ‘Active’).
The select query alone executes well and returns results. I'm trying to understand the effect made by this filter condition.
Can you explain, please?
Thanks
It's the same as this...
SELECT DISTINCT
ID, Event, Date, Amount, c.Status, b.Country
FROM
(
TableA1 a
INNER JOIN
TableB1 b
ON b.employeeID = a.ID
)
CROSS JOIN
(
SELECT * FROM TableC1 WHERE Status = 'Active'
)
c
In effect, the INNER JOIN is resolved, and then each row from that is joined to every row from TableC1 WHERE Status = 'Active'
For example
TableA1
ID
Event
Date
Amount
1
e1
2022-01-01
11
2
e2
2022-02-02
22
TableB1
EmployeeID
Country
1
c1
2
c2
TableC1
some_id
Status
1
Sleeping
2
Active
3
Active
4
Sleeping
Would yield...
ID
Event
Date
Amount
Country
Status
(some_id, added by me)
1
e1
2022-01-01
11
c1
Active
2
1
e1
2022-01-01
11
c1
Active
3
2
e2
2022-02-02
22
c2
Active
2
2
e2
2022-02-02
22
c2
Active
3
You probably should have...
INNER JOIN
TableC1 c
ON c.some_id = b.some_other_id
AND c.Status = 'Active'

Multiple table joins in Oracle SQL with same column names

Currently I have 3 tables like below
Master
ID_NUMBER
ZIPCODE
1
12341
2
12342
3
12343
4
12344
Table1
ID_NUMBER
CITYNAME
COUNTYNAME
1
NEW YORK
QUEENS
3
DETROIT
SUFFOLK
Table2
ID_NUMBER
CITYNAME
COUNTYNAME
2
ATLANTA
ROCKLAND
4
BOSTON
WINCHESTER
My desired output is like below. I want to filter based on the zipcode from master table
ID_NUMBER
ZIPCODE
CITYNAME
COUNTYNAME
2
12342
ATLANTA
ROCKLAND
How would i go about writing a query for this? Below is what i have tried but it's giving me null values if the ID_NUMBER is not found on that particular table.
SELECT mstr.id_number,
mstr.zipcode,
t1.cityname,
t1.countyname,
t2.cityname,
t2.countyname
FROM MASTER mstr
LEFT JOIN Table1 t1 ON mstr.id_number=t1.id_number
LEFT JOIN Table2 t2 ON mstr.id_number=t2.id_number
WHERE mstr.zipcode='12342'
Use COALESCE():
SELECT mstr.id_number,
mstr.zipcode,
COALESCE(t1.cityname, t2.cityname) as cityname
COALESCE(t1.countyname, t2.countyname) as countyname
FROM MASTER mstr LEFT JOIN
Table1 t1
ON mstr.id_number = t1.id_number LEFT JOIN
Table2 t2
ON mstr.id_number = t2.id_number
WHERE mstr.zipcode = '12342
'
Another approach you can try since your tables are identical is to join master with the union of the tables
with t as (
select Id_number, Cityname, Countyname
from t1
union all
select Id_number, Cityname, Countyname
from t2
)
select *
from Master m join t on m.Id_number=t.Id_Number
where m.zipcode='12342'

How to join table with both equal and Not equal on same column

I have two tables as below
TableA:
id Country
----------
1 US
----------
2 SG
----------
3 EU
----------
4 IN
TableB:
Report country
----------------
No NOT US
---------------
Yes US
Required output as below:
TableA.id TableA.Country TableB.country TableB.Report
--------------------------------------------------------
1 US US Yes
--------------------------------------------------------
2 SG NOT US NO
-------------------------------------------------------
3 EU NOT US NO
---------------------------------------------------------
4 IN NOT US NO
use left join
select id,a.Country,coalesce(b.country,'NOT US') as Bcountry,
coalesce(Report,'NO') as report
from tableA a left join tableB b on a.country=b.country
You can have complex join conditions:
select a.*, b.*
from a join
b
on (a.country = 'US' and b.country = 'US') or
(a.country <> 'US' and b.country = 'NOT US') ;
or in a query is usually a performance killer. Often, this type of query is used to match a default value. In such a case, one technique is two left joins:
select a.*,
coalesce(b.country, bdef.country) as b_country,
coalesce(b.report, bdef.report) as b_report
from a join
b
on a.country = b.country left join
b bdef
on b.country is null and
bdef.country = 'NOT US'

Find two employees having the same designation attribute - in SQL using self joins [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Display records having the same designation as "Peter" using inner join
CONDITION : without directly using the designation of Peter in the WHERE CLAUSE.
Try following:
SELECT t2.Name, t2.Designation
FROM table1 t1
INNER JOIN table1 t2
ON t1.Designation = t2.Designation
WHERE t1.Name = 'Peter'
FETCH NEXT 2 ROWS ONLY
It joins 2 tables (same table) on column Designation, filter the result for peter's designation and fetches first 2 rows only.
I guess technically since you have CONDITION : without directly using the designation of Peter in the WHERE CLAUSE. you could use:
SELECT *
FROM mytable t1
INNER JOIN mytable t2 ON t1.condition = t2.condition
AND t2.name = 'Peter'
You have records matching Peter's without using "Peter" in a WHERE clause.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table1 (name varchar(10), condition1 varchar(10));
INSERT INTO table1 (name, condition1)
SELECT 'Peter', 'c1' FROM dual UNION ALL
SELECT 'Paul', 'c2' FROM dual UNION ALL
SELECT 'Mary', 'c1' FROM dual UNION ALL
SELECT 'Jay', 'c2' FROM dual UNION ALL
SELECT 'SilentBob', 'c1' FROM dual UNION ALL
SELECT 'Bill', 'c1' FROM dual UNION ALL
SELECT 'Ted', 'c4' FROM dual UNION ALL
SELECT 'Rufus', 'c3' FROM dual
;
Query 1:
SELECT *
FROM table1 t1
INNER JOIN table1 t2 ON t1.condition1 = t2.condition1
AND t2.name = 'Peter'
Results:
| NAME | CONDITION1 | NAME | CONDITION1 |
|-----------|------------|-------|------------|
| Peter | c1 | Peter | c1 |
| Mary | c1 | Peter | c1 |
| SilentBob | c1 | Peter | c1 |
| Bill | c1 | Peter | c1 |
Assuming you have something like table1 table1_name,attribute1,attribute2 and a table like table2_name, attribute1,..., and the name attribute would be like a id (unqiue through the table)
then
SELECT * FROM table1 inner join table2 on table1_name = table2_name
Although this query gives result as per your criteria without where clouse please note that this query won't be good in terms of performance and I would not suggest you to use this on production.
Select * from employee e
Inner join designation d on (e.designationid=
d.designationid ) and (e.designation =(select
distinct designation from employee e1 inner
join designation d1 on (e1.designationid
=d1.designationid ) and e.name like 'peter' )
The inner join selects matching rows from both the tables. To understand the problem here, try the below SQL.
SELECT a.empname as a_empname, b.empname b_empname
FROM employee a
JOIN employee b ON(a.designation = b.designation);
I have three employees Adam, Peter and Smith in my table and Peter and Smith have the same designation. The above query returned the below records:
a_empname b_empname
Adam Adam
Smith Smith
Peter Smith
Smith Peter
Peter Peter
To get the required result if you select the column a.empname, you should filter on the column b.empname and vice versa.
so either of the following queries will work:
SELECT a.empname
FROM employee a
JOIN employee b ON(a.designation = b.designation)
WHERE b.empname="Peter";
SELECT b.empname
FROM employee a
JOIN employee b ON(a.designation = b.designation)
WHERE a.empname="Peter";

SQL | Left Join when 2nd Table Has No Matching Row?

I need to be able to show results for a row that doesn't actually exist in a second table. I have tried left join, but it doesn't seem to work for what I need to do. I have 2 tables, for example:
Table1
NAME | KEY
John 12345
Frank 23456
Table2
KEY | LIST | STATUS
12345 10001 1
12345 10003 0
23456 10001 1
23456 10002 1
I need to be able to show results like this :
NAME | KEY | LIST | STATUS
John 12345 10001 1
John 12345 10002 (null)
John 12345 10003 0
Frank 23456 10001 1
Frank 23456 10002 1
Frank 23456 10003 (null)
But I can't figure out how to do this because the records that would return a null value don't actually exist in the second table. If I run them one at a time, I can kind of get the results I need by doing a UNION ALL, but this is not efficient (I also had to re-order my results, which is making it harder as well)
SELECT b.list, a.name, a.key, b.status
FROM table1 a JOIN table2 b ON a.key = b.key
WHERE a.name = 'John'
UNION ALL
SELECT distinct(b.list), NULL AS "a.name", NULL AS "a.key", NULL AS "b.status"
FROM table2 b
This isn't an ideal solution either because I'm pulling the rest of the lists, but the other fields end up being null, so I have to paste them in manually when I move my results to excel.
Any ideas? I really thought I should be able to do this with a left join, but nothing I'm doing seems to work.
Use a cross join to get all the rows. Then use left join to bring in the existing values:
select t1.key, l.list, t2.status
from table1 t1 cross join
(select distinct list from table2) l left join
table2 t2
on t1.key = t2.key and t1.list = t2.list;
Try FULL OUTER JOIN
Example:
SELECT A.NAME, A.KEY, A.LIST, B.STATUS
FROM Table1 A
FULL OUTER JOIN Table2 B
ON A.KEY = B.KEY AND A.LIST = B.LIST
If don't want rows of the second table that they have not a reference in the first table add the condition:
WHERE A.KEY IS NOT NULL
Here is what I came up with. The first two queries are used to get all possible combinations of NAME, KEY and LIST together. The final query joins back to Table2 to get STATUS, returning NULL where STATUS does not exist.
;WITH Lists
AS
(
SELECT DISTINCT LIST
FROM Table2
),
KeyList AS
(
SELECT [NAME], [KEY], [LIST]
FROM Lists CROSS JOIN Table1
)
SELECT a.[NAME], a.[KEY],A.[LIST],b.[STATUS]
FROM KeyList a
LEFT JOIN Table2 b
ON a.[KEY] = b.[KEY]
AND a.[LIST] = b.[LIST]