old_tokens really only has one column, because I moved this out of the users table so that the users table (which is used on virtually every website load) is not bearing any additional query load that isn't really necessary. I don't know if that is great db design, but it lowered queries on this table, so I thought it would be beneficial instead of having a monolithic users table.
The reason I said that it would require a "long series of loops and individual queries" is because the query above was fairly simplified. I am actually using a WHERE clause that dynamically selects a range of user_id 's (like a BETWEEN clause) and it varies from scenario to scenario. (In an actual query, I will usually be selecting all users who were created within a certain time range). I simplified it here, but I can now see that that may have made it not clear on why I want to do this with one query. In PHP I can put the range of the WHERE clause into an array, and look through each element of the array, run the query mentioned (so user_id is updated, and then the old token, which is remembered via php, is then put into another sql query where it is inserted into old_tokens.) So if I do this for 10000 users, that is 2 db queries per user, or 20k db queries. I was hoping to get this down to 1 query per user, or even better, 1 query overall, if possible.