Why use left join at all - sql

I am looking at the following link Left Join
If left join uses all elements from table 1 and doesn't care about table 2, why not just write:
SELECT table1.column_name(s)
FROM table1
instead of writing
SELECT table1.column_name(s)
FROM table1
LEFT OUTER JOIN table2
ON table1.column_name=table2.column_name;

It isn't that one cares about the values in TABLE1 and, as you write, doesn't care about TABLE2. It is that one cares about the values in TABLE1 and also about the values in TABLE2 if they exist.
Suppose you want a report of employees and their managers. You wouldn't want to exclude the president of your company simply because he doesn't have a manager. So, you would write it as a LEFT OUTER JOIN.
SELECT e.employee_name, m.employee_name manager_name
FROM employees e
LEFT JOIN employees m ON m.employee_id = e.manager_id
That way, you will get a row with your president's name and a NULL manager name for the president. If you had written it as an INNER join, you wouldn't have gotten a row for the president at all.

A LEFT JOIN on another table without a WHERE clause is indeed quite unnessairy, when only columns from the first table are needed.
In fact, it could return more rows than expected.
For example:
First some sample data:
Table1:
Id Text1 SomeKey
1 Tralala 10
2 Joehoe 20
3 Trololo 30
Table2:
Id SomeKey Text2
1 10 Blah
2 20 Bleh
3 20 Blergh
A query only on Table1 would return 3 rows.
But a query with a left join on SomeKey would return 4 rows:
select t1.Text1
from Table1 t1
left join Table2 t2 on (t1.SomeKey = t2.SomeKey)
returns:
Text1
-------
Tralala
Joehoe
Joehoe
Trololo
A common reason why one would do such a left join, without selecting fields from the joined table, is to find records in Table1 that don't have a match in Table2. Or use criteria based on Table2 fields.
select t1.Text1, t1.SomeKey
from Table1 t1
left join Table2 t2 on (t1.SomeKey = t2.SomeKey)
where t2.Id is null;
returns:
Text1 SomeKey
-------- -------
Trololo 30

"If left join uses all elements from table 1 and doesn't care about table 2"
This statement is wrong and also the sample SQLs are not even similar.
LEFT JOIN means:
All the rows from "LEFT" table, regardless there is a match on "RIGHT" or not AND all the rows from "RIGHT" where there is a match. For example think of Customers and their Orders. You might have 100 Customers and not all of them yet have Orders.
select *
from Customers c
LEFT JOIN Orders o on c.CustomerID = o.CustomerID;
would retrieve all those 100 Customer rows, where those that do not have an Order have NULL for Orders' columns and if one has N Orders, its Customer row is repeated for each of those Orders. ie:
Customers: (CustomerId, CustomerName)
1, Customer1
2, Customer2
3, Customer3
Orders:(OrderId,CustomerId,OrderDate,...)
1, 1, 2000/1/1 10:00:00, ...
2, 1, 2000/1/5 11:00:00, ...
3, 2, 2000/1/6 18:00:00, ...
Result would be:
1, Customer1, 1, 1, 2000/1/1 10:00:00, ...
1, Customer1, 2, 1, 2000/1/5 11:00:00, ...
2, Customer2, 3, 2, 2000/1/6 18:00:00, ...
3, Customer3, NULL, NULL, NULL, ...
As you can see, it doesn't select "elements" only from LEFT table, it does from both. You can specify individual or all columns from either table:
select c.CustomerID, c.CustomerName, o.OrderDate, o.OrderID
from Customers c
LEFT JOIN Orders o on c.CustomerID = o.CustomerID;
select c.*
from Customers c
LEFT JOIN Orders o on c.CustomerID = o.CustomerID;
select c.*, o.OrderId, o.OrderDate
from Customers c
LEFT JOIN Orders o on c.CustomerID = o.CustomerID;
etc.

Related

SQL joining columns of the same table

I need help on the following SQL query. Let's say we have table_1 with these columns:
number
Customer
list
321
4514
321
2
2
5321
2
5555
If there's a number in the list column, that indicates that is that there is a list of numbers that should refer to that list. Below is a snapshot of how the final table should look. When there's a null value in the customer field it indicates that there is a list, that list number you can find the customers on that list when the number = the list. I need to change the number to make reference to the number the list belongs to.
number
Customer
list
321
4514
321
5321
2
321
5555
2
I've tried with different joins but unsuccessful:
SELECT *
FROM table_1
OUTER JOIN
(SELECT *
FROM TABLE_1
WHERE list IS NOT NULL) AS table_2 ON TABLE_1.list = table_2.list
You say that this is guaranteed to be one level only. So you can have 321->2, but not, say, 321->2->1.
Then, well, let's join and show the joined result:
select
coalesce(ref.number, t1.number) as num,
t1.customer,
ref.list
from table_1 t1
left outer join table_1 ref on ref.list = t1.number
where t1.list is null;
I guess you need to change the data (DML). Here us an example:
DROP TABLE IF EXISTS customer_list
CREATE TABLE customer_list (
number INT,
Customer INT,
list INT
);
INSERT INTO customer_list (number, Customer, list)
VALUES
(321, 4514, NULL),
(321, NULL, 2),
(2, 5321, NULL),
(2, 5555, NULL);
UPDATE A
SET [number] = B.number
,[list] = b.list
FROM customer_list A
INNER JOIN customer_list B
ON A.number = B.list
WHERE B.Customer IS NULL
DELETE FROM customer_list
WHERE Customer IS NULL;
SELECT *
FROM customer_list
If you need only to get the records:
SELECT B.number
,A.customer
,B.List
FROM customer_list A
INNER JOIN customer_list B
ON A.number = B.list
WHERE B.Customer IS NULL

How to fix sql query problem with two or more position which have one ID

I have sql query where I have to join three tables. One of this is a table with data of invoice, it looks like this:
INVOICE
ID CUSTOMER_NAME TAXID NUMBER LABEL GUID
1 CUSTOMER1 8739281100 FV001/2019 1 04EABFB3-0B9D-4749-B99D-A4EBEE079633
POSITION OF INVOICE
ID ID_INV POSITION_NAME COUNT
1 1 NAME1 3
2 1 NAME2 2,5
TABLE WITH LABEL
ID NAME VALUE GUID_INV
1 LABEL1 true 04EABFB3-0B9D-4749-B99D-A4EBEE079633
When I want to run this query I have statement like this multiple rows in singleton select.
This is for Firebird 2.5.
SELECT
a.ID,
a.GUID,
a.NUMBER,
a.CUSTOMER_NAME,
b.COUNT,
(select usrd.LABEL from USER_FIELD_DEFS usrd
where usrd.GUID_INV=a.GUID and (usrd.ID=1 and usrb.VALUE='true')) as LABEL_NAME
FROM INVOICE a
join POSITION_INVOICE b ON a.ID=b.ID_INV
I want to get result like this
1 04EABFB3-0B9D-4749-B99D-A4EBEE079633 FV001/2019 CUSTOMER1 3 LABEL1
1 04EABFB3-0B9D-4749-B99D-A4EBEE079633 FV001/2019 CUSTOMER1 2,5 LABEL1
Please help with this. I know that solution maybe is very simple but I have some eclipse of the mind:)
This should give you the rows you want based on the 3 tables you provided. If there is a chance that an invoice has no position then simply replace the inner join with left join
SELECT
I.[Id]
,I.[GUID]
,I.[NUMBER]
,I.[CUSTOMER_NAME]
,IP.[POSITION_NAME]
,L.[NAME]
FROM [INVOICE] I
INNER JOIN [IN_P] IP ON IP.ID_INV = I.Id
LEFT JOIN [LABEL] L ON L.[GUID_INV] = I.[GUID]
You are just missing one more join here. Assuming USER_FIELD_DEFS is the same as TABLE WITH LABEL that you have mentioned here
SELECT
a.ID,
a.GUID,
a.NUMBER,
a.CUSTOMER_NAME,
b.COUNT,
c.NAME
FROM INVOICE a
JOIN POSITION_INVOICE b ON a.ID=b.ID_INV
JOIN USER_FIELD_DEFS c ON c.GUID_INV = a.GUID AND c.ID=1 and c.VALUE='true'

SQL Join left join or left outer join

I am having a question in SQL Joins. I have table employee with employeeid as primary key and some other columns for employee. And there is another table called employeeaddress where there can be multiple employeeid is a foreign key. One employee can have many employeeaddresses just to explain one to many relationship.
If I want to write a query which will fetch the following columns
employee.employeeid, employee.empname,
employeeaddress.employeeaddressid, employeeaddress.addr1,
employeeaddress.addr2
So there can be an employee with no employeeaddress. But anyway I wanted to fetch all the employees who may have zero or multiple addresses.
Do I need to apply left join or left outer join? I want the following result for a table that has 2 employees John and Michael where John has two employeeaddresses with employeeaddressid 21 and 22 and Michael has no employeeaddress
1, John, 21, addr1 for John, addr2 for John
1, John, 22, another addr1 for John, another addr2 for John
2, Michael, NULL , NULL , NULL
The above result is arranged in the following fashion
employee.employeeid, employee.empname, employeeaddress.employeeaddressid, employeeaddress.addr1, employeeaddress.addr2
Please help.
Based on your description it sounds like you're looking for a query as follows. If you also wanted the address details, you'll just have to add a left join to the outer query.
Also, as comments have eluded to, LEFT JOIN is shorthand for LEFT OUTER JOIN, they will produce the same results.
SELECT *
FROM employee
inner join
(
SELECT
employeeid,
count(*) as addresscount
FROM employee
left join employeeaddress ON employeeaddress.employeeaddressid = employee.employeeaddressid
group by employeeid
) counts on counts.employeeid = employee.employeeid
WHERE counts.addresscount = 0 -- Or 1, or 5 or > 1, etc.
LEFT JOIN should be all you need.
SQL Fiddle Example
SELECT e.employeeID ,
e.empName ,
ea.employeeAddressID ,
ea.addr1 ,
ea.addr2
FROM Employee e
LEFT JOIN EmployeeAddress ea ON ea.employeeID = e.employeeID

Selecting from table with categories of people

I created a database in ms sql , in the database I have three category of persons namely staff, customers, suppliers whom I stored in different tables create serial unique id for each.
Now these persons id are stored under person_id and a column names person type which stores whether its a staff, custimer or supplier in the transaction table, The problem lies in selecting the records from the transaction table like this pseudo code
Select t.*,s.na as staff,sp.name as supplier, c.name as customer
From Trans t
left join Staff s on s.id = t.pid
left join Suppliers sp on sp.id = t.pid
left join Customers c on c.id = t.pid
This returns one row, instead of at least 3 or more, How do I solve this problem
My trans table
person_id Person_type Trans_id
1 staff 1
1 customer 2
2 customer 3
3 suppler 4
1 staff 5
Expected output
person_name Trans_id
james 1
mark 2
dan 3
jude 4
james 5
Staff, Customers, and suppliers are stored in their different tables
That's what the Join does, combine data from multiple tables into one result row. If you want to "keep the rows", not combine them, you can use UNION
(
Select t.* From Trans t
left join Staff s on s.id = t.pid
)
UNION
(
Select t.* From Trans t
left join Suppliers sp on sp.id = t.pid
)
UNION
(
Select t.* From Trans t
left join Customers c on c.id = t.pid
)
This will get you the multiple rows you want BUT still not sure you have defined it right. I see you are only taking columns from Trans, so you're not getting any data from the other tables. And you're doing left outer joins so the other tables won't affect the selection. So I think it's just that same as selecting from just Trans.
If what you want is data from Trans where there is corresponding entry in the other tables, then do the UNION, but also change the outer joins to inner.

Oracle Statement does not count correctly

I've got a SQL-statement with a - for me not explainable - strange behaviour.
Perhaps you could find what's wrong:
When I use the statement
select count(*) from department
I got 2755 results
Using the following statement
select
building1.street, building1.streetno, building1.plz, building1.city, dept1.buildingid
from
department dept1
left join
supporter sup
on
dept.supporterid = sup.id
left join
building building1
on
sup.buildingid = building1.ibuildingid
where
dept.usepostaladresssupporter = 1
union all
select
building2.street, building2.streetno, building2.plz, building2.city, dept2.buildingid
from
building building2
right join
tueks_department dept2
on
dept2.buildingid = building2.ibuildingid
where
dept2.usepostaladresssupporter = 0
I got 2755 results too.
But when I want to combine the two statements with a left join:
select count(*) from department
left join
(
select
building1.street, building1.streetno, building1.plz, building1.city, dept1.buildingid
from
department dept1
left join
supporter sup
on
dept.supporterid = sup.id
left join
building building1
on
sup.buildingid = building1.ibuildingid
where
dept.usepostaladresssupporter = 1
union all
select
building2.street, building2.streetno, building2.plz, building2.city, dept2.buildingid
from
building building2
right join
tueks_department dept2
on
dept2.buildingid = building2.ibuildingid
where
dept2.usepostaladresssupporter = 0
) postadress
on
department.buildingid = postadress.buildingid;
I got 3648513 results.
My expectation was, that I get only 2755 results.
Where's the mistake?
Thanks for help!
I assume that buildingid is not unique (for my reasoning to hold true, it can't be unique)
Imagine following simple tables
TableA
create TableA (name VARCHAR(32));
insert into TableA values ('Lieven');
insert into TableA values ('Lieven');
TableB
create TableB (name VARCHAR(32));
insert into TableB values ('Lieven');
insert into TableB values ('Lieven');
insert into TableB values ('AnyOtherValue');
Select statement
select * from TableA a left outer join TableB b on a.name = b.name
As each record of TableA is matched with each record of TableB where the name is equal, this will result in 4 records (the AnyOtherValue is dissmissed as it doesn't match)
The first record of TableA is returned with two of three records of `TableB'
The second record of TableA is returned with two of three records of `TableB'
The query
select
building1.street, building1.streetno, building1.plz, building1.city, dept1.buildingid
from
department dept1
left join
supporter sup
on
dept.supporterid = sup.id
left join
building building1
on
sup.buildingid = building1.ibuildingid
where
dept.usepostaladresssupporter = 1
union all
select
building2.street, building2.streetno, building2.plz, building2.city, dept2.buildingid
from
building building2
right join
tueks_department dept2
on
dept2.buildingid = building2.ibuildingid
where
dept2.usepostaladresssupporter = 0
will return one row per department that has usepostaladresssupporter as either 0 or 1 (note that records with other values will not be included, this may or may not be a problem depending on the constrainst of this column).
The unique key of this query results is probably something like departmentid (you will need to include that column in your select criteria).
So the correct query should look something like this:
select * from department
left join
(
select
building1.street, building1.streetno, building1.plz, building1.city, dept1.departmentid
from
department dept1
left join
supporter sup
on
dept.supporterid = sup.id
left join
building building1
on
sup.buildingid = building1.ibuildingid
where
dept.usepostaladresssupporter = 1
union all
select
building2.street, building2.streetno, building2.plz, building2.city, dept2.departmentid
from
building building2
right join
tueks_department dept2
on
dept2.buildingid = building2.ibuildingid
where
dept2.usepostaladresssupporter = 0
) postadress
on
department.departmentid = postadress.departmentid;
Your query will go wrong on data something like this:
Departmentid BuildingId Name
1 1 Dept1
2 2 Dept2
3 2 Dept3
The multiplying effect is not quite equal to deptcount * deptcount, but rather it is buildingcount * buildingcount + deptcount - buildingcount