tags:

views:

280

answers:

2

I have the following query:

UPDATE lessonstatus
INNER JOIN user ON lessonstatus.user_id = user.user_id
SET user_id = (SELECT user_id FROM user WHERE username = 'too_many_accounts')
WHERE last_name = 'stupid' 
AND first_name = 'user'
AND username != 'too_many_accounts'
AND lessonstatus.lesson_id NOT IN (SELECT lesson_id FROM lessonstatus WHERE user_id = 1);

However, I get the following error when trying to execute it:

Error Code : 1093
You can't specify target table 'lessonstatus_rtab' for update in FROM clause

How would I fix this query so that it works?

A: 

There are more errors ("user" table and "user_rtab" alias do not match, use of non-qualified field names is not recommended), but UPDATE syntax itself should be similar:

UPDATE lessonstatus
SET user_id = (SELECT TOP 1 user_id FROM user WHERE username = 'too_many_accounts')
FROM lessonstatus
    INNER JOIN user ON lessonstatus.user_id = user_rtab.user_id
WHERE last_name = 'stupid' 
    AND first_name = 'user'
    AND username != 'too_many_accounts'
    AND lessonstatus.lesson_id NOT IN (
        SELECT lesson_id FROM lessonstatus WHERE user_id = 1
    );
Arvo
This might work in MSSQL Server or another engine, but it does not work in MySQL.
Noah Goodrich
"TOP" is a Microsoft/Sybase extension to SQL and it is not supported by MySQL. And even if it did, this has nothing to do with the error in the original query.
Bill Karwin
I somehow did read subject as "MSSQL Query", sorry. Will try better next time :)
Arvo
+3  A: 

You can't SELECT from a table (even in a subquery) that you're updating in the same query. That's what the error "can't specify target table" means.

But you can join user and lessonstatus multiple times in the UPDATE statement, and use the join criteria creatively to pick out the individual row you want.

The way to simulate NOT IN with a join is to do a LEFT OUTER JOIN. Where the right side of that join is not matched, that's where NOT IN would be true.

UPDATE lessonstatus l1
  INNER JOIN user u1 ON (l1.user_id = u1.user_id)
  INNER JOIN user u2 ON (u2.username = 'too_many_accounts')
  LEFT OUTER JOIN lessonstatus l2 
    ON (l1.lesson_id = l2.lesson_id AND l2.user_id = 1)
SET l1.user_id = u2.user_id
WHERE u1.last_name = 'stupid' AND u1.first_name = 'user'
  AND u1.username != 'too_many_accounts'
  AND l2.lesson_id IS NULL; -- equivalent to "l NOT IN l2"

nb: I have tested this query for syntax, but not with real data. Anyway, it should get you started.

Bill Karwin