I have a table with IDs and domains(T1). Another with Names and domains(T2). A third with names and IDs (T3).
In its simplified form, my query goes as follows :
SELECT *
FROM T2
LEFT JOIN T1
ON T2.domain = T1.domain
)
LEFT JOIN T3
ON T1.name = T3.name
The output I'm looking for is a list with columns : "ID", "Name" and "Domain" where either domains or Names match in order to get the IDs. The challenge I face is that one domain can match with two names, and this creates a set of false positives (because the name matches, the wrong ID is also attributed).
Any best practices I should follow when doing these kind of joins would be most helpful.
Thanks
S
I think you want:
SELECT t2.name, t2.domain, coalesce(t1.id, t2.id)
FROM T2 LEFT JOIN
T1
ON T2.domain = T1.domain LEFT JOIN
T3
ON T2.name = T3.name AND
t1.domain IS NULL; -- no match on T1
This matches on domain first. Then if there is no domain-match, it uses name.
Related
I work with DB / SQL almost on a daily basis and the more I work with sql, the more I'm the opinion that there is no reason to use a right join or a full outer join.
Let's assume we have two tables: table1 and table2. Either I want to receive additional information for the rows in table1 so I can use an inner join on table2 and if I want to keep the original rows if there is no match, I use the left join then:
In case I have to add additional information to table 2, I can do the same and left join table 2 to table on. So I do not see a reason why I should ever use a right join. Is there any use case where you can not use a left join for a right join?
I also wondered if I would ever need a full outer join. Why would you join two tables and keep the rows that do not match of BOTH tables? We you could also achieve this by using two left joins.
Why would you join two tables and keep the rows that do not match of BOTH tables?
The full join has cases where it is useful.One of them is comparing two tables for differences like XOR between tables:
SELECT *
FROM t1
FULL JOIN t2
ON t1.id = t2.id
WHERE t1.id IS NULL
OR t2.id IS NULL;
Example:
t1.id ... t2.id
1 NULL
NULL 2
you could also achieve this by using two left joins.
Yes you could:
SELECT t1.*, t2.*
FROM t1
LEFT JOIN t2
ON t1.id = t2.id
WHERE t2.id IS NULL
UNION ALL
SELECT t1.*, t2.*
FROM t2
LEFT JOIN t1
ON t1.id = t2.id
WHERE t1.id IS NULL;
Some SQL dialects does not support FULL OUTER JOIN and we emulate it that way.
Related: How to do a FULL OUTER JOIN in MySQL?
On the other hand RIGHT JOIN is useful when you have to join more than 2 tables:
SELECT *
FROM t1
JOIN t2
...
RIGHT JOIN t3
...
Of course you could argue that you could rewrite it to correspodning form either by changing join order or using subqueries(inline views). From developer perspective it is always good to have tools(even if you don't have to use them)
As I am not very practical with SQL I am dealing with what is very likely a simple problem.
I have two tables t1 and t2 and I need to find observations in t2 that are not already in t1. The two tables contain lists of people by name, last name, email address...
The problem is that I can match some people via email address while some others with name + last name and so on...
For those in t1 that figure in t2 I need to set a value to 1 and then I need a list of the others in t2 that are unmatched.
So I've done:
UPDATE t1, t2 SET t1.value = "1"
WHERE (t1.Mail In t2.Mail);
which seems to have worked, but then when I try using name + last name it does not work:
UPDATE t1, t2 SET t1.value = "1"
WHERE (t1.Name AND t1.Surname In t2.Name AND t2.Surname);
Then for a list of unmatched observation I can find people that have no match using email and people that have no match using name + last name but I would like to find the people that have no match for name+last name of those who have no match for email address.
What I've done:
SELECT t2.*
FROM t2 LEFT JOIN t1 ON t2.Mail = t1.Mail
WHERE (t1.Mail Is Null);
and
SELECT t2.*
FROM t2
LEFT JOIN t1 ON t2.Surname = t1.Surname AND t2.Name = t1.Name
WHERE (t1.ID is Null);
Your current update queries are referencing the tables using a cross join or cartesian product, that is: for each record in the first table, the query is iterating over every record in the second table, with all matching occurring through the use of the where clause criteria.
This is generally considered bad practice when left/right/inner joins can be used, per your second set of examples using the left join.
As such, assuming I have correctly understood your data, I might suggest the following:
update t1 inner join t2 on t1.mail = t2.mail set t1.value = "1"
update t1 inner join t2 on t1.name = t2.name and t1.surname = t2.surname set t1.value = "1"
Regarding your second question:
...I would like to find the people that have no match for name+last name of those who have no match for email address.
You could use something along the lines of the following:
select q.*
from
(
select t2.* from t2 left join t1 on t2.mail = t1.mail
where t1.mail is null
) q
left join t1 on q.name = t1.name and q.surname = t1.surname
where
t1.name is null
This uses a subquery to obtain an initial set of records for which the email address does not match, and then left joins the results of this subquery with table t1 to obtain the records for which there is no matching first & last name.
I got a problem getting records out of two tables correctly.
I need to get a list in which every device and its software is linked.
Hard to explain what my goal is, but i hope you will understand my Example.
Example:
You need a join with multiple instances of table2
select b.name,c.name
from table1 a inner join table2 b on a.targetid=b.objectid
inner join table2 c on a.assignedid=c.objectid
JOIN the Table2 two times with Table1 and add the proper alias names will solve in your request.
The working query is:
SELECT T2.Name AS ComputerName, T3.Name AS SoftwareName
FROM Table1 T1
JOIN Table2 T2 T2.ObjectId = T1.TargetId
JOIN Table2 T3 T3.ObjectId = T1.AssignedId
I'm trying to construct a SQL query that I think requires multiple JOIN's, but I don't know the syntax.
Here is a rough example of the Tables (with column names) for each.
T1 (key, name)
T2 (key, fkeyT1)
T3 (key, fkeyT2)
I want to get all the rows from T3 that are linked to rows in T2 that are linked to rows in T1 with a given name.
I figure I'll need at least 2 JOIN's; I've got the first JOIN I think:
SELECT *
FROM T3 INNER JOIN T2
ON T3.fkeyT2 = T2.key
I figure I'll need to take these results and do another JOIN with T1 but I'm not sure of the syntax.
You probably want something like
SELECT *
FROM t3 INNER JOIN t2 ON (t3.fkeyT2 = t2.key)
INNER JOIN t1 ON (t2.fkeyT1 = t1.key)
WHERE t1.name = 'Foo'
I have a situation where I have one table of titles (t1) and another table with multiple links that reference these titles (t2) in a one to many relationship.
What I want is the full list of titles returned with a flag that indicates if there is a specific link associated with it.
Left Join and Group By:
SELECT
t1.id
, t1.title
, t2.link_id AS refId
FROM
t1
LEFT JOIN t2
ON (t1.id = t2.title_id)
GROUP BY t1.id;
This is close as it gives me either the first link_id or NULL in the refId column.
Now, how do I constrain the results if I have a specific link_id rather than allowing t2 run through the whole data set?
If I add a WHERE clause, for example:
WHERE t2.link_id = 123
I only get the few records where the link_id matches but I still need the full set of titles returned with NULL in the refId column unless link_id = 123.
Hope someone can help
Instead of in the WHERE clause, put your criteria in the LEFT JOIN clause:
SELECT
t1.id
, t1.title
, t2.link_id AS refId
FROM
t1
LEFT JOIN t2
ON t1.id = t2.title_id AND t2.link_id = 123
GROUP BY t1.id;
Put it in the join condition for the second table
SELECT t1.id, t1.title, t2.link_id as refId
FROM t1
LEFT JOIN t2 ON t1 = t2.title_id AND t2.link_id = 123
GROUP BY t1.id;