开发者

Update values in each row based on foreign_key value

开发者 https://www.devze.com 2023-03-05 17:31 出处:网络
Downloads table: id (primary key) user_id item_id created_at updated_at The user_id and item_id in this case are both incorrect, however, they\'re properly stored in the users and items table, resp

Downloads table:

id (primary key)
user_id
item_id
created_at
updated_at

The user_id and item_id in this case are both incorrect, however, they're properly stored in the users and items table, respectively (import_id for in each table). Here's what I'开发者_C百科m trying to script:

downloads.each do |download|
    user = User.find_by_import_id(download.user_id)
    item = item.find_by_import_id(download.item_id)

   if user && item
    download.update_attributes(:user_id => user.id, :item.id => item.id)
   end
end

So,

  1. look up the user and item based on their respective "import_id"'s. Then
  2. update those values in the download record

This takes forever with a ton of rows. Anyway to do this in SQL?


If I understand you correctly, you simply need to add two sub-querys in your SELECT statement to lookup the correct IDs. For example:

SELECT id, 
   (SELECT correct_id FROM User WHERE import_id=user_id) AS UserID,
   (SELECT correct_id FROM Item WHERE import_id=item_id) AS ItemID,
   created_at,
   updated_at
FROM Downloads

This will translate your incorrect user_ids to whatever ID you want to come from the User table and it will do the same for your item_ids. The information coming from SQL will now be correct.

If, however, you want to update the tables with the correct information, you could write this like so:

UPDATE Downloads
SET user_id = User.user_id,
    item_id = Item.item_id
FROM Downloads
INNER JOIN User ON Downloads.user_id = User.import_id
INNER JOIN Item ON Downloads.item_id = Item.import_id
WHERE ...

Make sure to put something in the WHERE clause so you don't update every record in the Downloads table (unless that is the plan). I rewrote the above statement to be a bit more optimized since the original version had two SELECT statements per row, which is a bit intense.

Edit: Since this is PostgreSQL, you can't have the table name in both the UPDATE and the FROM section. Instead, the tables in the FROM section are joined to the table being updated. Here is a quote about this from the PostgreSQL website:

When a FROM clause is present, what essentially happens is that the target table is joined to the tables mentioned in the fromlist, and each output row of the join represents an update operation for the target table. When using FROM you should ensure that the join produces at most one output row for each row to be modified. In other words, a target row shouldn't join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.

http://www.postgresql.org/docs/8.1/static/sql-update.html

With this in mind, here is an example that I think should work (can't test it, sorry):

UPDATE Downloads
SET user_id = User.user_id,
    item_id = Item.item_id
FROM User, Item 
WHERE Downloads.user_id = User.import_id AND
      Downloads.item_id = Item.import_id

That is the basic idea. Don't forget you will still need to add extra criteria to the WHERE section to limit the rows that are updated.


i'm totally guessing from your question, but you have some kind of lookup table that will match an import user_id with the real user_id, and similarly from items. i.e. the assumption is your line of code:

User.find_by_import_id(download.user_id)

hits the database to do the lookup. the import_users / import_items tables are just the names i've given to the lookup tables to do this.

UPDATE downloads
SET downloads.user_id = users.user_id
, downloads.item_id = items.items_id
FROM downloads
INNER JOIN import_users ON downloads.user_id = import_users.import_user_id
INNER JOIN import_items ON downloads.item_id = import_items.import_item_id

Either way (lookup is in DB, or it's derived from code), would it not just be easier to insert the information correctly in the first place? this would mean you can't have any FK's on your table since sometimes they point to one table, and others they point to another. seems a bit odd.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号