I am trying to update table based on a select query using this:
UPDATE branches SET name =
(SELECT CONCAT(comp.name," ",bra.subsurb) as newname
FROM companies comp
RIGHT JOIN branches bra
ON comp.id = bra.company_id)
Which, according to this question, should work
but this produces an error: You can't specify target table 'branches' for update in FROM clause
Not sure what I am doing wrong.
EDIT:
Eventually this query did what I'm after:
UPDATE branches bra LEFT JOIN companies comp
ON comp.id = bra.company_id
SET bra.name = CONCAT(comp.name," ",bra.subsurb)
The error itself is pretty self explanatory, you are selecting from the table you are updating. Instead, you can use JOIN in the update statement. Try this:
UPDATE branches b
LEFT JOIN companies c ON c.id = b.company_id
SET b.name = CONCAT(c.name, " ", b.subsurb);
Note that because you're using a left join here to select all branches, regardless of whether or not they have a company, you may get null values for some names, so be careful about that.
In MySQL, you can't modify the same table which you use in the SELECT part.
This behaviour is documented at: http://dev.mysql.com/doc/refman/5.6/en/update.html
You will need to stop using the nested subquery and execute the operation in two parts, or alternatively use a simple where clause.
For more information please go through the following link
MySQL Error 1093 - Can't specify target table for update in FROM clause
The error you are getting is a restriction in MySQL.
To approach this problem, first write a SELECT statement that returns both the existing column value, and the new value you want to assign to the column:
e.g.
SELECT b.company_id
, b.name AS old_name
, CONCAT(c.name,' ',b.subsurb) AS new_name
FROM branches b
LEFT
JOIN companies c
ON c.id = b.company_id
NOTE: beware of NULL values returned for c.name (possible because of the outer join). CONCAT including a NULL may return NULL.
Once that is returning the rows you want to update, convert that to an UPDATE by replacing the SELECT ... FROM with the keyword UPDATE, and add a SET clause immediately before the WHERE clause:
UPDATE branches b
LEFT
JOIN companies c
ON c.id = b.company_id
SET b.name = CONCAT(c.name,' ',b.subsurb)
Related
I need to retrieve all default settings from the settings table but also grab the character setting if exists for x character.
But this query is only retrieving those settings where character is = 1, not the default settings if the user havent setted anyone.
SELECT `settings`.*, `character_settings`.`value`
FROM (`settings`)
LEFT JOIN `character_settings`
ON `character_settings`.`setting_id` = `settings`.`id`
WHERE `character_settings`.`character_id` = '1'
So i should need something like this:
array(
'0' => array('somekey' => 'keyname', 'value' => 'thevalue'),
'1' => array('somekey2' => 'keyname2'),
'2' => array('somekey3' => 'keyname3')
)
Where key 1 and 2 are the default values when key 0 contains the default value with the character value.
The where clause is filtering away rows where the left join doesn't succeed. Move it to the join:
SELECT `settings`.*, `character_settings`.`value`
FROM `settings`
LEFT JOIN
`character_settings`
ON `character_settings`.`setting_id` = `settings`.`id`
AND `character_settings`.`character_id` = '1'
When making OUTER JOINs (ANSI-89 or ANSI-92), filtration location matters because criteria specified in the ON clause is applied before the JOIN is made. Criteria against an OUTER JOINed table provided in the WHERE clause is applied after the JOIN is made. This can produce very different result sets. In comparison, it doesn't matter for INNER JOINs if the criteria is provided in the ON or WHERE clauses -- the result will be the same.
SELECT s.*,
cs.`value`
FROM SETTINGS s
LEFT JOIN CHARACTER_SETTINGS cs ON cs.setting_id = s.id
AND cs.character_id = 1
If I understand your question correctly you want records from the settings database if they don't have a join accross to the character_settings table or if that joined record has character_id = 1.
You should therefore do
SELECT `settings`.*, `character_settings`.`value`
FROM (`settings`)
LEFT OUTER JOIN `character_settings`
ON `character_settings`.`setting_id` = `settings`.`id`
WHERE `character_settings`.`character_id` = '1' OR
`character_settings`.character_id is NULL
You might find it easier to understand by using a simple subquery
SELECT `settings`.*, (
SELECT `value` FROM `character_settings`
WHERE `character_settings`.`setting_id` = `settings`.`id`
AND `character_settings`.`character_id` = '1') AS cv_value
FROM `settings`
The subquery is allowed to return null, so you don't have to worry about JOIN/WHERE in the main query.
Sometimes, this works faster in MySQL, but compare it against the LEFT JOIN form to see what works best for you.
SELECT s.*, c.value
FROM settings s
LEFT JOIN character_settings c ON c.setting_id = s.id AND c.character_id = '1'
For this problem, as for many others involving non-trivial left joins such as left-joining on inner-joined tables, I find it convenient and somewhat more readable to split the query with a with clause. In your example,
with settings_for_char as (
select setting_id, value from character_settings where character_id = 1
)
select
settings.*,
settings_for_char.value
from
settings
left join settings_for_char on settings_for_char.setting_id = settings.id;
The way I finally understand the top answer is realising (following the Order Of Execution of the SQL query ) that the WHERE clause is applied to the joined table thereby filtering out rows that do not satisfy the WHERE condition from the joined (or output) table. However, moving the WHERE condition to the ON clause applies it to the individual tables prior to joining. This enables the left join to retain rows from the left table even though some column entries of those rows (entries from the right tables) do not satisfy the WHERE condition.
The result is correct based on the SQL statement. Left join returns all values from the right table, and only matching values from the left table.
ID and NAME columns are from the right side table, so are returned.
Score is from the left table, and 30 is returned, as this value relates to Name "Flow". The other Names are NULL as they do not relate to Name "Flow".
The below would return the result you were expecting:
SELECT a.*, b.Score
FROM #Table1 a
LEFT JOIN #Table2 b
ON a.ID = b.T1_ID
WHERE 1=1
AND a.Name = 'Flow'
The SQL applies a filter on the right hand table.
I am working on a query with the following format:
I require all the columns from the Database 'A', while I only require the summed amount (sum(amount)) from the Database 'B'.
SELECT A.*, sum(B.CURTRXAM) as 'Current Transaction Amt'
FROM A
LEFT JOIN C
ON A.Schedule_Number = C.Schedule_Number
LEFT JOIN B
ON A.DOCNUMBR = B.DOCNUMBR
ON A.CUSTNMBR = B.CUSTNMBR
GROUP BY A
ORDER BY A.CUSTNMBR
My question is regarding the grouping statement, database A has about 12 columns and to group by each individually is tedious, is there a cleaner way to do this such as:
GROUP BY A
I am not sure if a simpler way exists as I am new to SQL, I have previously investigated GROUPING_ID statements but thats about it.
Any help on lumped methods of grouping would be helpful
Since the docnumber is the primary key - just use the following SQL:
SELECT A.*, sum(B.CURTRXAM) as 'Current Transaction Amt'
FROM A
LEFT JOIN C
ON A.Schedule_Number = C.Schedule_Number
LEFT JOIN B
ON A.DOCNUMBR = B.DOCNUMBR
ORDER BY RM20401.CUSTNMBR
GROUP BY A.DOCNUMBR
I have the following query which selects personal messages (PM) from "ac_pms" table. Additional info is fetching from other table - "ac_accounts" using LEFT JOIN. There is "pm_read" column in "ac_pms" table which define a PM is read or not. I need to set that field (pm_read) to "1" while selecting PMs.
SELECT p.*, a.seller_id, a.winner_id
FROM `ac_pms` AS p
LEFT JOIN `ac_accounts` AS a ON p.pm_for_lot = a.id
WHERE (p.pm_from=[user_id] OR p.pm_to=[user_id])
AND p.pm_for_lot=[account_id]
ORDER BY p.pm_date DESC;
I cannot imagine where to insert UPDATE expression to SET pm_read = 1.
You can't SELECT with UPDATE in the same SQL statement.
However, you can UPDATE with JOIN like this:
UPDATE ac_pms AS p
LEFT JOIN ac_accounts AS a ON p.pm_for_lot = a.id
SET p.pm_read = 1
WHERE (p.pm_from=[user_id] OR p.pm_to=[user_id])
AND p.pm_for_lot = [account_id];
Then you can make another SELECT after that.
The following query returns 2303 rows:
SELECT a.*
FROM cur_analises a
INNER JOIN cur_materias_subsidiarias ms
ON ms.materia_id = a.materia_id
AND ms.subsidiaria_id IN(SELECT id FROM cur_subsidiarias WHERE cliente_id = 134)
INNER JOIN cur_materias m
ON m.id = a.materia_id
INNER JOIN cur_clientes c
ON c.carga_id = ms.subsidiaria_id
WHERE a.cliente_id = 134;
I need to update the cliente_id field of all those 2303 rows from table cur_analises with the value from cur_clientes.id. However, when I try to turn that SELECT query into the following UPDATE, it only affects 2297 rows, according to MySQL Workbench:
UPDATE cur_analises a
INNER JOIN cur_materias_subsidiarias ms
ON ms.materia_id = a.materia_id
AND ms.subsidiaria_id IN(SELECT id FROM cur_subsidiarias WHERE cliente_id = 134)
INNER JOIN cur_materias m
ON m.id = a.materia_id
INNER JOIN cur_clientes c
ON c.carga_id = ms.subsidiaria_id
SET a.cliente_id = c.id
WHERE a.cliente_id = 134;
I have no idea why it's missing 6 rows. What am I doing wrong?
You are probably not joining on a unique value or set of values at some point in the query causing denormalization of your result set. Then when you do the update it only updates the rows that actually meet the criteria of the joins for the table aliased as a. Only you can know what are truly non denormalizing joins in your query and fix them.
We had a similar case, the issue was with mysql partitioning. Once we revert partitioning everything is ok again.
I am trying to update a field in my table based on if it exists in two join tables.
update quotes
inner join collection_records ON quotes.id <> collection_records.record_id
inner join subcollection_records ON quotes.id <> subcollection_records.record_id
set quotes.status_id = 1
where collection_records.type = 'Quote'
or subcollection_records.type = 'Quote'
this query runs, but hangs. If I remove on inner join it works, but I need to check both join tables for the existance of the quote id.
Have to be careful, because using JOINs risks duplicated data for the sake of the unique supporting data. I re-wrote your query as:
UPDATE QUOTES
SET status_id = 1
WHERE id NOT IN (SELECT cr.record_id
FROM COLLECTION_RECORDS cr
WHERE cr.type = 'Quote')
AND id NOT IN (SELECT sr.record_id
FROM SUBCOLLECTION_RECORDS sr
WHERE sr.type = 'Quote')
Using LEFT JOIN/IS NULL:
UPDATE QUOTES
LEFT JOIN COLLECTION_RECORDS cr ON cr.record_id = id
AND cr.type = 'Quote'
LEFT JOIN SUBCOLLECTION_RECORDS sr ON sr.record_id = id
AND sr.type = 'Quote'
SET status_id = 1
WHERE cr.record_id IS NULL
AND sr.record_id IS NULL
My guess is that it's mainly due to the <> (NOT EQUALS) operator. Is that really what you're looking for here?
Also, if you have a Quote record in both the joinging tables....you will get 2 records back. Seems that taking one of the joins out returns only one record to you. Try doing a select instead of the update on a certain Quote that exists in both tables and see if you get two records back. You will have to modify the joins down in order to get one quote record returned.