Updating item based on linking data in three tables - sql

Trying to update a field while needing to link three tables, and matching three fields in two of the tables.
I need to update TableB Options by linking the ID to the ID in TableA and matching the list from TableC by matching the Fname,Lname,address fields from TableA.
TableA: TableB: TableC:
ID ID
Fname Options Fname
Lname Lname
address address
I've tried joins and selects but can't figure out how to join on matching three fields between two tables. Considered adding an ID field to TableC and first updating the ID field from TableA and then updating TableB, but still can't figure out how to match the three fields. I don't get all the results returned.
select TableB.options, TableA.fname, TableA.lname from TableB inner join TableA on TableB.id = TableA.id inner join TableC on TableA.address = TableC.address where TableA.firstname=TableC.fname and TableA.lname=TableC.lname
It did not return the correct number of people (68 instead of 128).
Also tried this which returned the wrong list of people (using a zip field also):
Select * from TableB where ID in(Select ID from TableA where Address in(Select Address from TableC) and zip in (Select Zipcode from TableC))
Upon further investigation some records will not show because the data will not match, but for those that should match I'd like to update a new ID field in TableC. Tried the following but get an error message that I need an EXISTS:
update atblundeliverables set personid= (select id, firstname, lastname from tblpeople where firstname in (select firstname from atblundeliverables where street in (select addressline1 from atblundeliverables)))

This update should work. Try it as Select, with the Where to eliminate Nulls
--Update dbo.[Link3_TableB]
-- Set Options = 'doesMATCH'
Select Options
,dbo.[Link3_TableB].*
,dbo.[Link3_TableA].*
,dbo.[Link3_TableC].*
From dbo.[Link3_TableB]
Left Join dbo.[Link3_TableA]
On dbo.[Link3_TableB].ID = dbo.[Link3_TableA].ID
Left Join dbo.[Link3_TableC]
On dbo.[Link3_TableA].Fname = dbo.[Link3_TableC].Fname
and dbo.[Link3_TableA].Lname = dbo.[Link3_TableC].Lname
and dbo.[Link3_TableA].address = dbo.[Link3_TableC].address
Where Not dbo.[Link3_TableA].ID Is Null
And Not dbo.[Link3_TableC].Fname Is Null

Related

Will this left join on same table ever return data?

In SQL Server, on a re-engineering project, I'm walking through some old sprocs, and I've come across this bit. I've hopefully captured the essence in this example:
Example Table
SELECT * FROM People
Id | Name
-------------------------
1 | Bob Slydell
2 | Jim Halpert
3 | Pamela Landy
4 | Bob Wiley
5 | Jim Hawkins
Example Query
SELECT a.*
FROM (
SELECT DISTINCT Id, Name
FROM People
WHERE Id > 3
) a
LEFT JOIN People b
ON a.Name = b.Name
WHERE b.Name IS NULL
Please disregard formatting, style, and query efficiency issues here. This example is merely an attempt to capture the exact essence of the real query I'm working with.
After looking over the real, more complex version of the query, I burned it down to this above, and I cannot for the life of me see how it would ever return any data. The LEFT JOIN should always exclude everything that was just selected because of the b.Name IS NULL check, right? (and it being the same table). If a row from People was found where b.Name IS NULL evals to true, then shouldn't that mean that data found in People a was never found? (impossible?)
Just to be very clear, I'm not looking for a "solution". The code is what it is. I'm merely trying to understand its behavior for the purpose of re-engineering it.
If this code indeed never returns results, then I'll conclude it was written incorrectly and use that knowledge during the re-engineering.
If there is a valid data scenario where it would/could return results, then that will be news to me and I'll have to go back to the books on SQL Joins! #DrivenCrazy
Yes. There are circumstances where this query will retrieve rows.
The query
SELECT a.*
FROM (
SELECT DISTINCT Id, PName
FROM People
WHERE Id > 3
) a
LEFT JOIN People b
ON a.PName = b.PName
WHERE b.PName IS NULL;
is roughly (maybe even exactly) equivalent to...
select distinct Id, PName
from People
where Id > 3 and PName is null;
Why?
Tested it using this code (mysql).
create table People (Id int, PName varchar(50));
insert into People (Id, Pname)
values (1, 'Bob Slydell'),
(2, 'Jim Halpert'),
(3,'Pamela Landy'),
(4,'Bob Wiley'),
(5,'Jim Hawkins');
insert into People (Id, PName) values (6,null);
Now run the query. You get
6, Null
I don't know if your schema allows null Name.
What value can P.Name have such that a.PName = b.PName finds no match and b.PName is Null?
Well it's written right there. b.PName is Null.
Can we prove that there is no other case where a row is returned?
Suppose there is a value for (Id,PName) such that PName is not null and a row is returned.
In order to satisfy the condition...
where b.PName is null
...such a value must include a PName that does not match any PName in the People table.
All a.PName and all b.PName values are drawn from People.PName ...
So a.PName may not match itself.
The only scalar value in SQL that does not equal itself is Null.
Therefore if there are no rows with Null PName this query will not return a row.
That's my proposed casual proof.
This is very confusing code. So #DrivenCrazy is appropriate.
The meaning of the query is exactly "return people with id > 3 and a null as name", i.e. it may return data but only if there are null-values in the name:
SELECT DISTINCT Id, PName
FROM People
WHERE Id > 3 and PName is null
The proof for this is rather simple, if we consider the meaning of the left join condition ... LEFT JOIN People b ON a.PName = b.PName together with the (overall) condition where p.pname is null:
Generally, a condition where PName = PName is true if and only if PName is not null, and it has exactly the same meaning as where PName is not null. Hence, the left join will match only tuples where pname is not null, but any matching row will subsequently be filtered out by the overall condition where pname is null.
Hence, the left join cannot introduce any new rows in the query, and it cannot reduce the set of rows of the left hand side (as a left join never does). So the left join is superfluous, and the only effective condition is where PName is null.
LEFT JOIN ON returns the rows that INNER JOIN ON returns plus unmatched rows of the left table extended by NULL for the right table columns. If the ON condition does not allow a matched row to have NULL in some column (like b.NAME here being equal to something) then the only NULLs in that column in the result are from unmatched left hand rows. So keeping rows with NULL for that column as the result gives exactly the rows unmatched by the INNER JOIN ON. (This is an idiom. In some cases it can also be expressed via NOT IN or EXCEPT.)
In your case the left table has distinct People rows with a.Id > 3 and the right table has all People rows. So the only a rows unmatched in a.Name = b.Name are those where a.Name IS NULL. So the WHERE returns those rows extended by NULLs.
SELECT * FROM
(SELECT DISTINCT * FROM People WHERE Id > 3 AND Name IS NULL) a
LEFT JOIN People b ON 1=0;
But then you SELECT a.*. So the entire query is just
SELECT DISTINCT * FROM People WHERE Id > 3 AND Name IS NULL;
sure.left join will return data even if the join is done on the same table.
according to your query
"SELECT a.*
FROM (
SELECT DISTINCT Id, Name
FROM People
WHERE Id > 3
) a
LEFT JOIN People b
ON a.Name = b.Name
WHERE b.Name IS NULL"
it returns null because of the final filtering "b.Name IS NULL".without that filtering it will return 2 records with id > 3

How do I do an SQL query based on a foreign key field?

I have the following tables:
people:
id, name
parent:
id, people_id, name
I have tried the following:
SELECT * FROM people
LEFT JOIN parent ON people.id = parent.people_id
WHERE parent.name != 'Carol';
How do I find all the people whose parent's name is not Carol?
You can try below code
select people.name from people
inner join parent on people.id=parent.people_id
where parent.name not in ('Carol')
If the two tables are to be queried by using Foreign Key.
If you want to get all records from one table that have some related entry in a second table then use Inner join
Select * from People INNER JOIN parent ON people.id = parent.people_id
WHERE parent.name <> 'Carol'
Similarly LEFT JOIN will get all records from the LEFT linked table but if you have selected some columns from the RIGHT table, if there is no related records, these columns will contain NULL
First of all, why would you need two tables? why can't you have a single table named "Person" with ID,Name,ParentID columns
Where ParentID will be optional and reference the ID if it has got parent.
And run the following query
select * from PERSON where Name not like 'Carol%' and ParentID IS NOT NULL;
SELECT * FROM people WHERE EXISTS(SELECT 1 FROM parent WHERE people_id = id AND name <> 'Carol')
First of all the table structure you have taken restrict the future growth. Like in future if you want to add parents of your parents then it wont work in this table structure.
You can do like :
id | parent_id | people_name
Here you can make parent_id null for the parent and add parent_id as id for those who have parent. Here to retrieve you have to use SELF join(join in the same table)
`
Select * from people P
INNER JOIN parent PA ON PA.people_id = P._id
where PA.name not in ('Carol')
`
Difference between INNER JOIN and LEFT OUTER JOIN
is
1) INNER JOIN bring only similar data between two table
for ex if in people table parent_id table is nullable then it will not discard the complete row,but in case of LEFT OUTER JOIN it will bring all the rows from LEFT table as well as related table from right table.with all null in right joined row..

SQL: Combine result sets using common value?

In MS Access 2010 I've got (a) multiple tables with names (primary key) and ID numbers; and (b) a lookup table with all possible variations of names (primary key), as well as a last name for each. e.g.
tableA
name ID
"Jones, B" 1
"Smith, A" 2
tableB
name ID
"Jones" 4
"Smith, Abe" 5
lookupTable
name Lastname
"Smith, A" "Smith"
"Smith, Abe" "Smith"
What I want to end up with is a query that returns the IDs for each distinct value in lookupTable.Lastname, e.g.
Lastname tableA.ID tableB.ID
"Smith" 2 5
I can't wrap my head around how to do this. So far I have something like:
SELECT * FROM
(lookupTable LEFT JOIN tableA ON lookupTable.name = tableA.name)
LEFT JOIN tableB ON lookupTable.name = tableB.name
I hope this quick hint helps.
It's seems like you are in the right direction. I would think the same.
You may want to add to what you have
SELECT * FROM
(lookupTable LEFT JOIN tableA ON lookupTable.name = tableA.name)
LEFT JOIN tableB ON lookupTable.name = tableB.name
Something like
SELECT DISTINCT Statement
As shown in this page.
http://www.w3schools.com/sql/sql_distinct.asp
I hope this helps.
Thank you,

find duplicate pairs in sql table and update values for 1 of each duplicate pair

I have a table with 1800 entries. 900 entries are duplicates of the other 900 by values in a number of fields, example contactFirstName and contactLastName, however one of each duplicate pair contains data which the other does not, example PhoneNumber. The duplicates which contain the additional data, ie: phoneNumber, have a statusID=10 and the duplicates without the phoneNumber data have statusID=2.
How can I find the duplicate pairs by contactFirstName and ContactLastName, then for each pair (remember-there are 900 pairs) copy the phoneNumber data in the duplicate with statusID=2 into the phoneNumber field in the duplicate with statusID=10 (but only if the destination field value is 'NULL').
I hope my explanation is clear. I Would be very grateful of any help.
Join the table with itself, and update the one with status id 10.
Example (SQL Server syntax):
update
a
set
phoneNumber = b.phoneNumber
from
TheTable a
inner join TheTable b on b.contactFirstName = a.contactFirstName and b.contactLastName = a.contactLastName and b.statusID = 2
where
a.statusID = 10 and a.phoneNumber is null
Something like:
UPDATE table
SET PhoneNumber = (SELECT t2.PhoneNumber
FROM table t2
WHERE t2.StatusID = 2
AND t2.contactFirstName = table.contactFirstName
AND t2.ContactLastName = table.ContactLastName)
WHERE PhoneNumber IS NULL
AND StatusID = 10;

How to write the right SQL query statement using join condition?

There are three fields in a table, all of them refer the same field in another table, like this:
table1
-------
! a_term_id* ! b_term_id* ! c_term_id* !
! ! ! !
table2
-------
! term_id ! term_title ! term_description !
! ------- ! ! !
columns a_term_id, b_term_id, c_term_id all refer to term_id
How should I write the SQL statement to retrieve the three fields' info?
I think you need to know how Sql_Join works. Here on W3Schools you can find useful examples.
A simple example:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders
ON Persons.P_Id=Orders.P_Id
ORDER BY Persons.LastName
EDIT
You can try something like this:
SELECT * FROM tableA
inner join tableB on tableA.term_id = tableB.term_id
inner join tableC on tableA.term_id = tableC.term_id;
It an example you can modify as per your need.
Edit 2
SELECT * FROM tableB
JOIN tableA AS tableA1 ON tableB.term_id = tableA1.a_term_id
JOIN tableA AS tableA2 ON tableB.term_id = tableA2.b_term_id
JOIN tableA AS tableA3 ON tableB.term_id = tableA3.c_term_id
Here is an example. Suppose that we have two tables - Employees and Companies:
CREATE TABLE Employees(
Id int,
Name varchar(128),
CompanyId int);
CREATE TABLE Companies(
Id int,
Name varchar(128),
Address varchar(1024),
DateFounded datetime);
The following SQL query will join the tables:
SELECT * FROM Employees
INNER JOIN Companies
ON Employees.CompanyId = Companies.Id
Your question is a bit unclear, but I'll guess that you have a table A with three fields, each of which identifies a (possibly different) row from table B. You want to retrieve info from each of those rows of table B based on the field values of a single row of table A.
To do this, you will need to join table A to table B three times, once for each field of table A. Each join should be given an alias and then you can refer to the fields in the joined table by qualified field names.
SELECT b1.info, b2.info, b3.info
FROM A JOIN B AS b1 ON field1 = b1.field
JOIN B AS b2 ON field2 = b2.field
JOIN B AS b3 ON field3 = b2.field
WHERE ...
SELECT
t.a_term_id, a.term_title, a.term_description,
t.b_term_id, b.term_title, b.term_description,
t.c_term_id, c.term_title, c.term_description
FROM abc_terms t JOIN ( terms_info a, terms_info b, terms_info c )
ON ( t.a_term_id = a.term_id
AND t.b_term_id = b.term_id
AND t.c_term_id = c.term_id )