32

I'm not crazy familiar with WPDB or SQL in general but I have a custom table for my project and I'm trying to assign some metadata to it. What I'd "like" to happen is if a row exists, update it and if not insert it. I've read both Insert and Update in the WPDB Codex but neither really went into an "either or" situation. I thought i could work with update, so my code so far looks like this:

$wpdb->update(
    $wpdb->prepare(
        $wpdb->prefix.'item_info',
        array(
            'post_id'       => $post_id,
            'item_stock'    => $item_stock
        ),
        array('post_id' => $post_id)
    )
);

Does WordPress have anything like an "IF exists Update, ELSE Insert", or do I need to run custom SQL to achieve this, or do I need to query the database first to see if an ID exists in my table THEN decide whether to update it or insert it?

5 Answers 5

32

First, you are using prepare incorrectly. You seem to have $wpdb->update's arguments wrapped in $wpdb->prepare like that. That won't work. In effect, you are passing update a single argument-- the output of prepare. Try something simple like the following and you will see why that won't work:

$post_id = 123;
$item_stock = 567;
var_dump(
  $wpdb->prepare(
    $wpdb->prefix.'item_info',
    array(
        'post_id'       => $post_id,
        'item_stock'    => $item_stock
    ),
    array('post_id' => $post_id)
  )
);

And $wpdb->update() runs prepare for you.

Second, if this were me, I skip the helper function bloat and write a proper ON DUPLICATE KEY UPDATE query:

$sql = "INSERT INTO {$wpdb->prefix}item_info (post_id,item_stock) VALUES (%d,%s) ON DUPLICATE KEY UPDATE item_stock = %s";
// var_dump($sql); // debug
$sql = $wpdb->prepare($sql,$post_id,$item_stock,$item_stock);
// var_dump($sql); // debug
$wpdb->query($sql);

This assumes that post_id is a UNIQUE index or PRIMARY KEY. If your table structure is what I think it is, let the database handle it.

3
  • This was insanely useful... Thanks for your time s_ha_dum!
    – Jake
    Jul 30, 2014 at 15:01
  • Prepare returns false for me - no other db errors. If running the query manually in phpmyadmin it works as expected. Also checked that variables are what they should be .. Any ideas?
    – trainoasis
    Jan 25, 2016 at 8:37
  • 4
    What if post_id isn't the PRIMARY KEY? Nov 29, 2016 at 0:36
37

Have you tried $wpdb->replace. According to WP Codex:

Replace a row in a table if it exists or insert a new row in a table if the row did not already exist.

I have tried myself in some plugins and it does the work when trying to avoid unique IDs duplication errors, etc.

More info in the codex

6
  • This worked for me while custom query did not - thanks for mentioning replace()
    – trainoasis
    Jan 25, 2016 at 8:49
  • This is the correct answer to the question. Sep 20, 2016 at 9:19
  • 11
    it is worth noting that $wpdb->replace is a destructive overwrite of the entire record, whereas $wpdb->update only updates the specific fields included in the $data array
    – MatthewLee
    Dec 9, 2016 at 4:46
  • This function doesn't do the replacing for me at the moment. It duplicates the same rows. Can be a PRIMARY KEY (id) field the cause that prevents the replacement to happen? I can't see info on it in the Codex. May 14, 2020 at 16:54
  • I figured it out: To mitigate this replacement issue, it's also required to apply the UNIQUE constraint to specific columns at table creation, thus making unique rows possible. May 14, 2020 at 17:12
6

You can try and update the table using $wpdb->update, I am using the id in the following code, but you can use any criteria.

$result = $wpdb->update($tableName, $info, array('id' => $info["id"]));
//If nothing found to update, it will try and create the record.
if ($result === FALSE || $result < 1) {
    $wpdb->insert($tableName, $info);
}

Update() result output

  • $result === FALSE : Fail
  • $result === 0 : Success, but nothing updated
  • $result > 1: Success and updated
1
  • 3
    If the values are the same then MySQL will not update the row, so the affected row count will be 0.
    – Darrel K.
    Oct 8, 2021 at 6:28
0

use $wpdb->insert, $wpdb->insert can insert and update too.. IN 2023

EDIT $wpdb->insert not update the row , use $wpdb->replace

1
  • 1
    An important distinction to note is that wpdb::replace() does delete then insert if a duplicate is found - it does not perform a wpdb::update(), which needs to be considered per usecase.
    – Howdy_McGee
    Nov 20 at 19:29
-1

You should check if the row exists first.

Most likely you'll want to try to get the ID or primary key for the row you're trying to update, then $wpdb->update if it does or $wpdb->insert of it doesn't

1
  • 22
    An example of how to check if the ID or primary key exists would really make this a useful answer. This is almost like reiterating the question.
    – Jake
    Jul 30, 2014 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.