3

I've just tried to convert this update command, which is Oracle sql, to MySQL with SQLWays and it failed with the following error:

You can't specify target table 'animal_table' for update in FROM clause

source command (Oracle):

UPDATE animal_table
     SET (animal_info1, 
          animal_info2, 
          animal_info3) = (SELECT animal_nbr, animal_amount, '00'
                           FROM animal_table t2
                           WHERE t2.category_id = animal_table.category_id
                             AND t2.sumary_id = animal_table.summary_id
                             AND t2.animal_type = 'special'
                          )
  WHERE animal_type = 'cats'
    AND category_id = 'foo';

suggested target command (MySQL):

UPDATE animal_table
SET 
    animal_info1 = (SELECT animal_nbr FROM animal_table t2 
                    WHERE t2.category_id = animal_table.category_id
                    AND t2.sumary_id = animal_table.summary_id
                    AND t2.animal_type = 'special'),
    animal_info2 = (SELECT animal_amount FROM animal_table t2 
                    WHERE t2.category_id = animal_table.category_id
                    AND t2.sumary_id = animal_table.summary_id
                    AND t2.animal_type = 'special'),
    animal_info3 = (SELECT '00' FROM animal_table t2 
                    WHERE t2.category_id = animal_table.category_id
                    AND t2.sumary_id = animal_table.summary_id
                    AND t2.animal_type = 'special')
    WHERE animal_type = 'cats'
    AND category_id = 'foo';

can anyone help me out here?

Derek Downey
  • 23,568
  • 11
  • 79
  • 104
Ed Michel
  • 133
  • 3

3 Answers3

3

Try using an UPDATE JOIN of the table against itself

UPDATE
    animal_table A
INNER JOIN
(
    SELECT
        category_id,summary_id,
        animal_nbr,animal_amount,'00' info3
    FROM animal_table
    WHERE animal_type = 'special'
) B USING (category_id,summary_id)
SET
    A.animal_info1 = B.animal_nbr,
    A.animal_info2 = B.animal_amount,
    A.animal_info3 = B.info3
WHERE
    A.animal_type = 'cats' AND
    A.category_id = 'foo';

Make sure that animal_table has a compound index on category_id and summary_id. If you do not have such an index, please run this:

ALTER TABLE animal_table ADD INDEX (category_id,summary_id);

UPDATE 2011-09-27 13:10 EDT

I just noticed that categrory_id 'foo' limits the dataset. Here is an updated refactoring of my answer ( I moved category_id = foo into the subquery )

UPDATE
    animal_table A
INNER JOIN
(
    SELECT
        category_id,summary_id,
        animal_nbr,animal_amount,'00' info3
    FROM animal_table
    WHERE animal_type = 'special'
    AND category_id = 'foo'
) B USING (category_id,summary_id)
SET
    A.animal_info1 = B.animal_nbr,
    A.animal_info2 = B.animal_amount,
    A.animal_info3 = B.info3
WHERE
    A.animal_type = 'cats';

I also recommend adding this additional index to accommodate the subquery

ALTER TABLE animal_table ADD INDEX (animal_type,category_id);
RolandoMySQLDBA
  • 185,223
  • 33
  • 326
  • 536
1

Unfortunately, in MySQL, you cannot update a table that you've listed in a subquery. From the docs (at the end):

Currently, you cannot update a table and select from the same table in a subquery.

You can nest the subqueries like so (untested):

UPDATE animal_table
SET 
animal_info1 = (SELECT animal_nbr FROM (SELECT animal_nbr FROM animal_table t2 
                WHERE t2.category_id = animal_table.category_id
                AND t2.sumary_id = animal_table.summary_id
                AND t2.animal_type = 'special') as X),
animal_info2 = (SELECT animal_amount FROM (SELECT animal_amount FROM animal_table t2 
                WHERE t2.category_id = animal_table.category_id
                AND t2.sumary_id = animal_table.summary_id
                AND t2.animal_type = 'special') AS Y),
animal_info3 = (SELECT '00' FROM (SELECT '00' FROM animal_table t2 
                WHERE t2.category_id = animal_table.category_id
                AND t2.sumary_id = animal_table.summary_id
                AND t2.animal_type = 'special')AS Z)
WHERE animal_type = 'cats'
AND category_id = 'foo';

But I think Rolando's is cleaner, since it doesn't duplicate the subqueries.

Derek Downey
  • 23,568
  • 11
  • 79
  • 104
1

I would suggest this, but please test it before running on some sample data:

UPDATE animal_table t1 inner join animal_table t2
ON t2.category_id = t1.category_id 
AND t2.sumary_id = t1.summary_id 
AND t2.animal_type = 'special'
SET t1.animal_info1 = t2.animal_nbr, 
t1.animal_info2 = t2.animal_amount, 
t1.animal_info3 = '00'
where t1.animal_type = 'cats'
and t1.category_id = 'foo'; 
Jonathan
  • 1,017
  • 9
  • 9