does LEFT JOIN return same row count as left table? - sql

SELECT *
FROM t1
LEFT JOIN t2 ON t1.fk = t2.id;
Will it always return the same row count as that of t1 ?

The contract of a left join states that, in the absence of a WHERE clause which might remove records from the result set, all records which appear in the left side of the join will appear at least once. Consider the following data set:
t1
id | fk
1 | 1
2 | 2
t2
id | value
1 | 1
1 | 2
Your query would return this result set:
id | fk | id | value
1 | 1 | 1 | 1
1 | 1 | 1 | 2
2 | 2 | NULL | NULL
Note carefully that the first table's fk = 2 did not match anything to the second table. This record still appears in the result set, but all columns coming from the second table are NULL. Also, note that fk = 1 records appear twice, because that single record in the first table matched twice to the second table.

If t2.id has a unique constraint, the row count will always be the same as if the join isn't there. If it's not unique, you will get multiple duplicates of the same t1 row, each with its own corresponding t2 row. Whether that's good enough for you depends on your database design.

Will it always return the same row count as that of t1?
No.
A LEFT JOIN is a join and as such will match one row from one table to multiple rows of another table. The result set may have the same number of rows or more rows.

Not necessarily:
CREATE TABLE t1(id int, fk int);
INSERT INTO t1 VALUES (1,1);
CREATE TABLE t2(id int, value int);
INSERT INTO t2 VALUES(1,1),(1,2);
SELECT *
FROM t1
LEFT JOIN t2 ON t1.fk = t2.id;
returns 2 rows:
id fk id value
1 1 1 1
1 1 1 2

Related

Count rows from left table without corresponding value in the right table

I want to count rows from left table (of a 1-to-many relation between two tables) that do not have PK-FK representative in right table
Left table
id | value
-----------
1 | a
2 | b
3 | c
Right table
id | id-left | value
--------------------
.. | 1 | ....
the expected result is 2 as rows with id 1 and 3 in left table have no counterpart in right table.
You can use a not exists anti-semi-join:
select count(*)
from l
where not exists (
select * from r where r.id_left = l.id
);

SQL Join On Columns of Different Length

I'm trying to join two tables together in SQL where the columns contain a different number of unique entries.
When I use a full join the additional entries in the column joined on are missing.
The code I'm using is (in a SAS proc SQL):
proc sql;
create table table3 as
select table1.*, table2.*
from table1 full join table2
on table1.id = table2.id;
quit;
Visual example of problem (can't show actual tables as contain sensitive data)
Table 1
id | count1
1 | 2
2 | 3
3 | 2
Table 2
id | count2
1 | 4
2 | 5
3 | 6
4 | 2
Table 3
id | counta | countb
1 | 2 | 4
2 | 3 | 5
3 | 2 | 6
- | - | 2 <----- I want don't want the id column to be blank in this row
I hope I've explained my problem clearly enough, thanks in advance for your help.
The id from table 1 is blank because the row from table2 has no match in table 1. Try looking at the output from this query:
select coalesce(table1.id, table2.id) as id, table1.count1, table2.count2
from table1 full join table2
on table1.id = table2.id;
Coalesce works from left to right returning the first non null value (it can take more than 2 arguments). If the id in table 1 is null it uses the id from table 2 instead
I recommend also to alias all tables in queries, so I’d have written this:
SELECT
COALESCE(t1.id, t2.id) as id,
t1.count1,
t2.count2
FROM
table1 t1
FULL OUTER JOIN
table2 t2
ON
t1.id = t2.id;
Simply select coalesce(t1.id, t2.id), will return the first non-null id value.

Update a table based on a condition

I have a column Table1.Tradedate and another column Table2.SettlementDate.
Based on the comparison between these 2, I want to update a column in table 2
IF (Table1.TradeDate <= Table2.SettlementDate)
BEGIN
UPDATE Table2 SET Status='Y'
END
This is what I have tried but I know its wrong, since the table will obviously contain more than 1 records. So, I believe what I should do is
use a join on 2 tables based on some #id to pick a particular record
check the IF condition for that particular record
update the Status column in table2.
I hope my approach is correct but I am writing it incorrectly.
Table1:
SKacc | Name | TradeDate | Othercolumns....
1 | xxx | 01/07/2019 |
2 | xxx | 01/06/2019 |
Table2:
SKAcc | Name | SettlementDate | Status |Other Columns....
1 | xxx | 01/08/2019 | NULL |
2 | xxx | 01/08/2019 | NULL |
Try below
update t2 set Status = 'Y'
from table2 t2
join table1 t1 on t1.id = t2.id
where t1.tradeDate <= t2.settlementDate
Try joining the two tables with the related column and then update the table you want to update with the value. Using inner join in the example but can change depending on the usecase
UPDATE Table2
SET Status = 'Y'
FROM Table2
INNER JOIN Table1 ON Table1.id = Table2.table1_id
WHERE Table1.TradeDate <= Table2.SettlementDate
I would not recommend a JOIN for this purpose. Instead:
update table2
set Status = 'Y'
where exists (select 1
from table1 t1
where t1.id = t2.id and
t1.tradeDate <= t2.settlementDate
);
The reason I recommend this version is because you have not specified that id is unique in table1. In general, you only want to use JOIN in UPDATE when you can guarantee that there is only one matching row.

Finding field value pairs using SQL

I have difficulties summarizing the issue into a nice, neat title, so the title may be misleading. Here is the situation
Table 1 has an ID, an Issue, and a resolution date, so it is expected that some dates will be null. ID's can be assigned to multiple issues as well.
Table_1:
ID | Issue | Date
1 | a | 1/1
2 | a | 1/1
3 | b |
4 | c | 1/2
I use another table to update this table, so for this example, the data in table_2 looks like:
ID | Issue | Date
3 | b | 1/3
1 | b | 1/3
Now, I have one query which will update table_1 dates using table_2 information, based on the ID/Issue pairing, using something like this:
Update Table_1 tab1
left outer join Table_2 tab2
on tab1.id = tab2.id and tab1.issue = tab2.issue
set tab1.date = tab2.date
However, there will be times where table 2 has ID/Issue pairs that are not in table_1. I would like to instead insert those rows into table_1, but I'm not sure how to do this.
If it was just one single field, say ID, i could just do something like:
insert into table_1 (ID, Issue, Date)
select ID, Issue, Date
from table_2 where table_2.ID not in (select ID from table_1)
How would I do this for an ID/Issue pairing?
Using the above example, I would want to insert the following row from table_2 into table_1:
1 | b | 1/3
since an ID/Issue pair of 1/b exists in table 2 but not table 1.
How would I go about selecting from table 2 the id/issue pairs that do not exist in table 1?
You can use a left outer join to do this:
insert into table_1 (ID, Issue, Date)
select ID, Issue, Date
from table_2 t2
left outer join table_1 t1 on t1.ID = t2.ID and
t1.Issue = t2.Issue
where t1.ID is null
This guarantees you to get every row in table_2 and then limit the rows in table two if there isn't a match in table_1.
One method is to use not exists:
insert into table_1 (ID, Issue, Date)
select ID, Issue, Date
from table_2
where not exists (select 1
from table_1
where table_2.ID = table_1.ID and table_2.issue = table_1.issue
);

Return another value when row is inexistent

In a database table with a structure like this :
Table 1
Name | Id
A 1
B 2
Table 2
Table1's ID | IntValue
1 11
2 66
now, there is a query which joins the 2 tables and outputs something like
A | 11
B | 66
but the problem is that when, let's say row (A,1) gets deleted from table1 the query outputs
| 11
B | 66
so instead of writing A it leaves it null because the row doesn't exist.
My question is: Instead of leaving it null, is there any option to make it write "Item Inexistent" or smth?
My database is Firebird 2.1.2
SELECT COALESCE(t1.name, 'Item nonexistent'), t2.intValue
FROM table2 t2
LEFT OUTER JOIN
table1 t1
ON t1.id = t2.id