MYSQL: UPDATE FROM INNER JOIN syntax error - mysql

I am trying to update TableA with values from TableB, matched by the unique id field and add a WHERE condition.
Searched the web and found the code below. For some reason MYSQL states that there's as syntax error.
UPDATE
TableA
SET
TableA.field1 = TableB.field1
FROM
TableA
INNER JOIN
TableB
ON
TableA.id = TableB.id
WHERE
TableA.field1 <> ''
LIMIT 100;

The correct syntax in MySQL is:
UPDATE TableA INNER JOIN
TableB
ON TableA.id = TableB.id
SET TableA.field1 = TableB.field1
WHERE TableA.field1 <> '';
As a note: you cannot use LIMIT with a JOIN.
If you want to use LIMIT, you can do:
UPDATE TableA
SET TableA.field1 = (SELECT TableB.field1 FROM TableB WHERE TableA.id = TableB.id)
WHERE TableA.field1 <> '' AND
EXISTS (SELECT 1 FROM TableB WHERE TableA.id = TableB.id)
LIMIT 100;
(You can leave out the EXISTS expression if you know there is always a match in TableB. You can add LIMIT 1 to the subquery if more than one match is possible.)
I would advise you to always use ORDER BY with LIMIT as well. That way, you can control which rows are being updated.

Related

How to remove this subquery from this SQL statement?

I have a SQL statement that does left join with a table:
select a.id, b.col1 from tableA a
left join (select col1 from tableB where date = 'xxx') b on a.id = b.id
For some application constraint (I need to use Spring JPQL query that does not permit subquery), I need to "flatten" this query to remove the subquery without changing the meaning of the query: I want to enrich tableA with a subset of tableB.
I have tried a few queries such as:
select a.id, b.col1 from tableA a
left join tableB b on a.id = b.id
where (date = 'xxx' or date is null)
But that gave me different set of answer from previous query.
How do I remove this subquery?
It can be done in multiple different ways - using cte, using joins
Using join it can be implemented as -
select a.id, b.col1 from tableA a left join tableB b on a.id = b.id and b.date = 'xxx'
using CTE it can be implemented as -
with t as
(
select col1, id from tableB where date = 'xxx'
)
select a.id, b.col1 from tableA a
left join t on a.id = t.id

MySQL: How to Join to first row

I have 3 tables, Master with other two TableA and TableB, and Master has both one to many relationship with the other two tables.
What I want is to get all master records associated with only the latest record from both TableA and TableB, so I use left joins as below,
SELECT
*
FROM
Master master
LEFT JOIN (SELECT ta.* FROM TableA ta WHERE ta.masterId = master.id LIMIT 1 ORDER BY ta.id DESC ) as tableA
LEFT JOIN (SELECT tb.* FROM TableB tb WHERE tb.masterId = master.id LIMIT 1 ORDER BY tb.id DESC ) as tableB
WHERE master.status = 1
However above sql statement hit an error,
Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'ta' from one of the SELECTs cannot be used in global ORDER clause
; bad SQL grammar ... Table 'ta' from one of the SELECTs cannot be used in global ORDER clause
It complains .. in global ORDER clause, but it doesn't seem like that, all order clauses are used in the subquery?
Where is wrong with my sql, it might be naive but is there a better way to achieve my requirement?
Loads of thanks.
You should fetch last record of tablea, tableb for each masterId first, then left join tablea and tableb to get all the records:
select m.*, ta.*, tb.*
from master m
left join (
select tablea.*
from tablea
join (select max(id) as id from tablea group by masterId) tmp
on tablea.id = tmp.id
) ta on ta.masterId = m.id
left join (
select tableb.*
from tableb
join (select max(id) as id from tableb group by masterId) tmp
on tableb.id = tmp.id
) tb on tb.masterId = m.id
The LIMIT 1 AND ORDER BY clauses should switch places

how can I update a table but needing to get the update value from another select of the same table and other one?

I have this problem:
I have tableA and tableB
tableB needs to get the tableA's ID in a certain field.
tableB and tableA have a common field 'email'
Ive tried with this
Update tableB SET tableB.reference = (Select a.id from tableA a, tableB b where a.email = b.email)
Unfortunately when I run the query it says that I cant specify target 'tableB' for updates in FROM clause.
Any idea how to solve this or run a query like this?
UPDATE tableA, tableB
SET tableB.id = tableA.id
WHERE tableA.email = tableB.email
Or another one:
UPDATE tableB
INNER JOIN tableA USING (email)
SET tableB.id = tableA.id
Your query is also possible, but need to fix it:
Update tableB SET tableB.id = (Select a.id from tableA a, tableB b where a.email = b.email)
Update tableB SET tableB.id = (Select a.id from tableA a, tableB b where a.email = b.email)
You're trying to update tableA when you should update tableB, and also you don't need tableB in your sub-select:
UPDATE tableB SET reference = (SELECT id FROM tableA WHERE email = tableB.email)

MySQL with IF or EXISTS in WHERE

I have a problem with the following query for id’s not present in tableC. Despite the LEFT JOIN, an id in tableA and tableB is not in the results if the id is absent from tableC. And that is because the tableC.name doesn’t exist for these id’s. I imagined MySQL would then ignore the last part considering the clause to be true….but no.
SELECT
tableA.id, tableA.name
FROM
tableA
LEFT JOIN tableB ON tableA.id = tableB.id
LEFT JOIN tableC ON tableA.id = tableC.id
WHERE
tableA.latin = 'whatever'
AND RIGHT(tableC.name,2) != 'y'
I imagine there is a solution using either IF, CASE or EXISTS on the second part of the WHERE clause, but I don’t get the result I want with the following three attempts (I only show the last line):
WHERE
tableA.latin = 'whatever'
AND IF(tableC.name <> 0, RIGHT(tableC.name,2) != 'y', ' ');
This doesn’t give error either, but not the expected result:
WHERE
tableA.latin = 'whatever'
AND IF(tableC.name = true, RIGHT(tableC.name,2)!= 'y', ' ');
Trying the following with EXISTS gives me error in the MySQL Wordbench editor:
WHERE
tableA.latin = 'whatever'
AND if(EXISTS tableC.name, RIGHT(tableC.name,2) != 'y', ' ');
Any time you reference a column (tableC.name in your case) from a left-joined table in the where clause, you force the join to behave as if it were an inner join. Instead, move the test into the join condition.
SELECT tableA.id, tableA.name
FROM tableA
LEFT JOIN tableB
ON tableA.id = tableB.id
LEFT JOIN tableC
ON tableA.id = tableC.id
AND RIGHT(tableC.name,2) != 'y'
WHERE tableA.latin = 'whatever'
There is a much easier solution. Your where condition is turning the outer joins into inner joins. Just move the condition into the on clause:
SELECT tableA.id, tableA.name FROM tableA
LEFT JOIN tableB ON tableA.id = tableB.id
LEFT JOIN tableC ON tableA.id = tableC.id AND RIGHT(tableC.name, 2) <> 'y'
WHERE tableA.latin = 'whatever';
Of course, the expression RIGHT(tableC.name,2) != 'y' should always be true almost always, because you are looking for two characters and comparing to one. Perhaps you mean:
SELECT tableA.id, tableA.name FROM tableA
LEFT JOIN tableB ON tableA.id = tableB.id
LEFT JOIN tableC ON tableA.id = tableC.id AND tableC.name not like '%y'
WHERE tableA.latin = 'whatever';
How about this (untested but I think it should work):
SELECT tableA.id, tableA.name FROM tableA
LEFT JOIN tableB ON tableA.id = tableB.id
LEFT JOIN tableC ON (tableA.id = tableC.id AND RIGHT(tableC.name,2) != 'y')
WHERE tableA.latin = 'whatever'
It makes table c only include the ones you want but doesn't interfere with the left outer join.

Mysql Update table1 from table2 values with CASE

I have table A & Table B . I need to update TableA.custid , with values (1 - 8 ) so I can reflect TableB.names
To make it more clear
TableA.custid = 1 , when TableB.name = 'Allen Gray'
TableA.custid = 2 , when TableB.name = 'Alex Watt'
TableA and TableB got the same number of records. And the relation between the 2 would be TableA.id = TableB.id
What would be the syntax for this?
Update tableA as t1 inner join TableB as t2
on t1.id=t2.id
set t1.name=t2.name