Why this Join-Update query update all value? - sql

I made some mistake and all values of a column are updated.
I did this in SQL Server 2008 R2.
I should have run some query like this:
UPDATE TABLE_A
SET FEEL = 'HAPPY'
FROM TABLE_A A
INNER JOIN TABLE_B B ON A.SN = B.SN
WHERE B.WEATHER = 'SUNNY';
However, I made a mistake and ran this:
UPDATE TABLE_A
SET FEEL = 'HAPPY'
FROM TABLE_C A
INNER JOIN TABLE_B B ON A.SN = B.SN
WHERE B.WEATHER = 'SUNNY';
and even TABLE_C has column of [SN].
I expected that this query update FEEL of TABLE_A as 'HAPPY' where WEATHER of TABLE_B is 'SUNNY' with inner join between two tables, but every value of column FEEL is updated to 'HAPPY'.
What means Update A set ~ from c in SQL Server and when it should be used? And why "inner-join" updates all values?

This query:
UPDATE TABLE_A
SET FEEL = 'HAPPY'
FROM TABLE_C A INNER JOIN
TABLE_B B
ON A.SN = B.SN
WHERE B.WEATHER = 'SUNNY';
is saying to update all rows in TABLE_A that match the conditions in the ON and WHERE clauses. But, none of those conditions involve TABLE_A. So, nothing is being filtered. Actually, what you are doing is equivalent to:
UPDATE AA
SET FEEL = 'HAPPY'
FROM TABLE AA CROSS JOIN
TABLE_C A INNER JOIN
TABLE_B B
ON A.SN = B.SN
WHERE B.WEATHER = 'SUNNY';
This is a bit of weirdness in the UPDATE.
When you do:
UPDATE TABLE_A
SET FEEL = 'HAPPY'
FROM TABLE_A A INNER JOIN
TABLE_B B
ON A.SN = B.SN
WHERE B.WEATHER = 'SUNNY';
SQL Server makes an exception to the rule that an alias always replaces the table reference. It still allows TABLE_A in the UPDATE to refer to A. So, there is no CROSS JOIN.
Personally, I consider this broken-ness, because a table alias should always replace the table reference. The developers at Microsoft think otherwise. And there is no standard that guides this syntax.
If you have a FROM clause, I recommend that always use table aliases.
UPDATE A
SET FEEL = 'HAPPY'
FROM TABLE_A A INNER JOIN
TABLE_B B
ON A.SN = B.SN
WHERE B.WEATHER = 'SUNNY';

Related

Re-Writing a SQL Statement with a Subquery to Have a Join

I have to re-write a SQL statement with a subquery so that it has a join for my job. So far, this is what I have.
SELECT * FROM Table_A
WHERE TABLE_A.A_ID NOT IN
(SELECT LK.A_ID FROM Link_Table LK
LEFT JOIN Table_B B
ON B.B_ID = LK.B_ID)
I am really having a hard time with this. I feel like this is because of the link tables though. Can anyone give me advice on altering this query?
Seems like you want a LEFT JOin with a IS NULL in the where:
SELECT {Column list} --Don't use *
FROM dbo.Table_A A
LEFT JOIN dbo.Link_Table LK ON A.A_ID = LK.A_ID
WHERE LK.A_ID IS NULL;
You don't need the reference to Table_B at all here.
Personally, however, I would prefer an EXISTS, but that is a subquery again:
SELECT {Column List}
FROM dbo.Table_A A
WHERE NOT EXISTS (SELECT 1
FROM dbo.Link_Table LK
WHERE A.A_ID = LK.A_ID);

Pulling values from IBM DB2 lookup table based on relationship between 3 tables

I sincerely hope what I entered in the Title is not confusing. I also hope I explain this properly. In a nutshell, I have 3 tables as follows:
TABLE_A
id *
value
TABLE_B
id *
other_id
TABLE_C
other_id *
name_of_product
I want to pull multiple values from TABLE_A and one value from TABLE_C based on matching IDs between TABLE_A and TABLE_B, as well as matching ID between TABLE_B and TABLE_C. I have tried searching this, but haven't as yet found anything directly related to my problem. I have tried this SQL code, but I know it is wrong:
SELECT
TRIM(id) primary_key_value,
a.value name,
c.name_of_product product
FROM TABLE_A a, TABLE_C c
JOIN TABLE_A t1 ON t1.id = a.id
JOIN TABLE_B t2 ON t2.other_id = c.other_id
WHERE c.name_of_product = 'widget'
Any help would be greatly appreciated. If it isn't obvious by the code above, I should state that I am somewhat of an SQL newbie. Thank you.
It seems you need two joins:
SELECT TRIM(a.id) as primary_key_value,
a.value as name,
c.name_of_product as product
FROM TABLE_A a JOIN
TABLE_B b
ON b.id = a.id JOIN
TABLE_C c
ON c.other_id = b.other_id
WHERE c.name_of_product = 'widget'

How to copy values corresponding to the foreign key from another table to this table?

I have two tables tblA and tblX. In tblA, there is a foreign key FKX from tblX. I want to copy corresponding values of StringColumn to strColCopy column. It introduces redundancy but it's part of longer migrations process.
How can I access tblX.StringColumn cell for every single tblA.FKX cell?
You can use UPDATE using JOIN
Solution for SQL Server:
UPDATE A
SET A.strCol = X.StringColumn
FROM TblA A
JOIN (SELECT FKX, strCol FROM TxlX GROUP BY FKX, strCol) AS X ON A.FKX = X.ID
Syntax for general Update join for SQL Server:
UPDATE a
SET a.columnToUpdate = [something]
FROM TABLEA a
JOIN TABLEB b ON a.colA = b.colB
Solution for MySQL:
UPDATE TblA A
JOIN (SELECT FKX ,strCol FROM TxlX GROUP BY FKX ,strCol)AS X
ON A.FKX = X.ID
SET A.strCol = X.StringColumn
Syntax for general Update join for MySQL:
UPDATE TABLEA a
JOIN TABLEB b ON a.colA = b.colB
SET a.columnToUpdate = [something]

Remove Duplicate Code from UPDATE

I have the following query.
UPDATE A SET b = (SELECT b FROM B WHERE A.a_id = B.a_id AND B.value = ?)
This might fill A with NULL values if no a_id exists in B where value = ?. but this is okay, because before executing this query, it is certain that A.b contains only NULL values to begin with.
However, I need the number of updated columns to reflect the number of updates performed. So I changed it into this:
UPDATE A SET b = (SELECT b FROM B WHERE A.a_id = B.a_id AND B.value = ?)
WHERE EXISTS (SELECT b FROM B WHERE A.a_id = B.a_id AND B.value = ?)
I don't like this solution, because now I have duplicate code and have to fill the parameter multiple times. This gets even uglier when the where clause gets more complicated.
Is there a way to get rid of this duplicate code?
(BTW I'm on Oracle 10, but I prefer DB independent solutions)
Updat using an inner join
UPDATE A
INNER JOIN B ON A.a_id = B.a_id
SET A.b = B.b
WHERE B.value = ?
If that isn't allowed with your particular RDBMS, perhaps you could SELECT the old and new values into an aliased table expression and update using that. See Update statement with inner join on Oracle

SQL joining/unioning help - link table b and c to table a?

I have 3 tables in my database. Each of them has one column, "index" that links the fields across all 3.
Our starting point is table a, and the indexes inside it. If the index is not there, I don't need it.
Tables b and c are very similar, and every index listed in table a will be in b or c, or both. All I need to do is make sure that all the fields in table a are joined to fields in table b or c.
I started with:
SELECT *
FROM `table_a`
JOIN table_b ON table_a.index = table_b.index
Which works great. But it will exclude all the indexes in table a which don't match, which is why I believe, when I add:
UNION
FROM `table_a`
JOIN table_c ON table_a.index = table_c.index
I actually get LESS results, rather than more.
Can someone tell me how to say "if the index isn't in table b, then look in table c?"
I'm not sure this is what you're after, but it will give you all the results of a, and any possible matches from b OR c.
SELECT *
FROM table_a
LEFT OUTER JOIN table_b ON table_a.index = table_b.index
LEFT OUTER JOIN table_c ON table_a.index = table_c.index
Did you try a "Union All" ?
SELECT *
FROM `table_a`
JOIN table_b ON table_a.index = table_b.index
UNION ALL
SELECT *
FROM `table_a`
JOIN table_c ON table_a.index = table_c.index
First step:
SELECT * FROM
table_a
LEFT JOIN table_b ON table_a.index = table_b.index
LEFT JOIN table_c ON table_b.index = table_c.index
This will get you all indexes from all 3 tables.
If you want to have the first index which isn't NULL from the tables _a, _b, or _c you can do this like this in MySQL:
SELECT COALESCE(table_a.index, table_b.index, table_c.index) AS firstIndexFromABC
FROM
table_a
LEFT JOIN table_b ON table_a.index = table_b.index
LEFT JOIN table_c ON table_b.index = table_c.index
Or what DB are you using? Update: MySQL
Update after some comments:
Sorry, I still don't get it. That's what the COALESCE method does. You get in 1 column combined the value of a if it's there, if not you get b if it's there, if not you get c.
If you mean, that you want the information, from which table you took the index then try this:
SELECT COALESCE(table_a.index, table_b.index, table_c.index) AS firstIndexFromABC,
CASE WHEN table_a.index IS NULL AND table_b.index IS NULL THEN 'c'
WHEN table_a.index IS NULL AND table_b.index IS NOT NULL THEN 'b'
WHEN table_a.index IS NOT NULL THEN 'a'
END AS whichTable
FROM
table_a
LEFT JOIN table_b ON table_a.index = table_b.index
LEFT JOIN table_c ON table_b.index = table_c.index