1

Please see the Updated section of this question that follows after the initial question.

I have two tables, one for videos that contains a id, users_id, image, pcimagename, and video URL columns; and another for images that contains a id, users_id, file_name, user_file_name, and usage_count columns.

The primary key of both tables are the id columns, which are auto-incrementing, but the two id values are not related to each other. The images table also has a unique key on the file_name column. The usage_count column has 1 for its default value.

The phpMyAdmin shows the following information about the mySQL database that I'm using:

Database server
  Server:           Localhost via UNIX socket
  Server type:      MariaDB
  Server version:   5.5.52-MariaDB - MariaDB Server
  Protocol version: 10
  Server charset:   UTF-8 Unicode (utf8)

My goal is that whenever a row is to be deleted from the videos table, I want to first copy the image information from the videos table into the images table, and if the image (specifically the file_name column value) doesn't already exist in the images table, set the usage_count to 1, but, if the image does exist, I want to increment the usage_count by 1 and perform an update. I searched for "mySQL INSERT or UPDATE" and came up with with the INSERT ... ON DUPLCATE KEY UPDATE variant, which appears to be what I'm trying to do.

However, I've never used the INSERT ... ON DUPLICATE KEY UPDATE ... statement before. Looking at the MySQL INSERT ON DUPLICATE KEY UPDATE and Insert into a MySQL table or update if exists pages, I came up with the following; unfortunately, I'm able to connect to my database at this time, so I'm unable to determine if it is correct:

INSERT
  INTO `photos`
        ( `users_id`, `file_name`, `user_file_name` )
SELECT `users_id`, `image`, `pcimagename`
FROM `videos`
WHERE `status` = \'Deleted\'
   AND `last_updated_on` <= DATE_SUB( NOW(), INTERVAL 1 DAY )
   AND `tracks_id` = 0
ON DUPLICATE KEY UPDATE usage_count = VALUES( usage_count ) + 1;

My questions are:

  1. Is the syntax correct, specifically:

    1a) Is the placement of the ON DUPLICATE phrase correct?

    1b) Do I need to enclose the SELECT statement in parenthesizes, I've seen examples which did and others that didn't.

  2. Will the UPDATE usage_count = VALUES( usage_count ) + 1 phrase cause each row inserted into the image table to add 1 to the row's pre-insert usage_count value, or will all of the rows coming from the SELECT FROM videos be given the same value? I didn't see very much about how this part of the ON DUPLICAT statement actually worked. Most examples just assigned a fixed value.

Update

While working with the dbFiddle that Anina provided, I noticed that running the following INSERT statement didn't increment as I expected:

After several INSERT ... ON DUPLICATE KEY UPDATE ... statements the test 
table contains:

id  val test    action  comment
1   1   2       update  
2   2   2       update  
3   3   1       insert  

Perform another INSERT ... ON DUPLICATE KEY UPDATE ... statement,
this time to increment val 1, expecting that the test column should increment to 3.

INSERT INTO test (val ) 
VALUES ( 1 )
ON DUPLICATE KEY UPDATE test = VALUES( test ) + 1,
                        action = 'update',
                        comment = 'Why isn''t test 3?';

 However ....

 id val test    action  comment
 1  1   2       update  Why isn't test 3?
 2  2   2       update  
 3  3   1       insert  

The table was created as follows:

CREATE TABLE test ( id      INT NOT NULL AUTO_INCREMENT, PRIMARY KEY( ID ),
                    val     INT NOT NULL, UNIQUE( val ),
                    test    INT DEFAULT 1,
                    action  VARCHAR( 10 ) DEFAULT 'insert',
                    comment VARCHAR( 30 ) );

Thanks

  • `ON DUPLICATE KEY UPDATE photos set usage_count = usage_count + 1;` The manual pages are quite clear [see the manual](https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html) – RiggsFolly Dec 01 '20 at 19:43
  • *Will the `UPDATE usage_count = VALUES( usage_count ) + 1` phrase cause each row inserted into the image table to add 1 to the row's pre-insert `usage_count` value, or will all of the rows coming from the `SELECT FROM videos` be given the same value?* Neither first nor second. Read carefully the Reference Manual about VALUES() function action. – Akina Dec 01 '20 at 19:47
  • [fiddle](https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=82699c5d56ee24771c40495a8f3b0c4b) - investigate. – Akina Dec 01 '20 at 19:52
  • Thank you all. Anina, your fiddle was most helpful concerning my question about how the VALUES() expression in the ON DUPICATE KEY phase worked. –  Dec 02 '20 at 02:28
  • RiggsFolly, I didn't bring up the MySQL 5.6 Reference Manual page on for the INSERT ... ON DUPLICATE KEY UPDATE Statement because for v5.6, the earliest version of that page in the manual pages, and one past the version of mySQL that I'm using, it didn't answer all of my questions, or if it did, I didn't find it clear enough, so I missed what I asked about in the question posted, here. Not the manual's fault. Which is why I asked my question, here. However, thanks for adding the link for anyone who reads this question and want for information about the clause. –  Dec 02 '20 at 02:47

1 Answers1

0

Answer to the Update:

In order to make the test column beyond 2, I added the following UPDATE TRIGGER after creating the test table, before any inserts on existing rows:

CREATE TRIGGER before_test_update
BEFORE UPDATE ON test FOR EACH ROW
BEGIN
  SET new.test = old.test + 1;
END;

This causes the test column to increment its value in the existing row by 1, rather than the failed insert's test value (1) incremented by 1 (always 2).

See this dbLink for an example that shows how this works.

However, because the ON DUPLICATE KEY phrase just converts the INSERT to an UPDATE, which intern uses the above trigger to correct the test increment. Actual UPDATEs will also call the same trigger when any of the column in an existing row are updated, causing an incorrect test column value.

The mySQL manual says:

With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if the
row is inserted as a new row, 2 if an existing row is updated, and 0 if an
existing row is set to its current values. If you specify the
CLIENT_FOUND_ROWS flag to the mysql_real_connect() C API function when
connecting to mysqld, the affected-rows value is 1 (not 0) if an existing
row is set to its current values.

Is there a way to use the fact that the affected-rows value is 2 when the ON DUPLICARE KEY UPDATE phrase converts the INSERT to an UPDATE in the BEFORE UPDATE TRIGGER or an AFTER UPDATE TRIGGER or some other means to determine this happened, rather than when a direct UPDATE is made, where the affected-rows value is 1?

If so how do I get the affected-rows value from within a TRIGGER?

Note: In my code I'm using an INSERT from a sub-SELECT so multiple rows could be added before returning a value to my program. Therefore, I'm looking for a Purely-mySQL solution that runs when multiple rows are inserted.

  • None of the help you received indicated you needed to add a trigger. Why have you done so? All you needed to do was change your update statement to `ON DUPLICATE KEY UPDATE usage_count = usage_count + 1;` – gview Dec 02 '20 at 19:23
  • Thanks for your suggestion gview, but I'm already using that phrase. The BEFORE TRIGGER is a work-around needed because the usage_count/test column value stops incrementing past 2. –  Dec 03 '20 at 00:24
  • If you did look at the link to dbFiddle in the Updated section of my question, you would see that the inserts against the value 1 after it is initially added to the table all have a test value of 2. What I need, as stated in the initial question is for the test value to start at 1, using the default value for that column, then with each INSERT, changed to an UPDAT by the ON DUPLICATE ... phrase, increment by 1, going from 1 to 2, 2 to 3, 3 to 4, etc. This doesn't happen without the BEFORE INSERT trigger. The dbLink in my answer solves this problem by adding the BEFORE TRIGGER. –  Dec 03 '20 at 00:29
  • However, simply swopping INSERT to UPDATE due to the ON DUPLICATE ... phrase doesn't fully work because I when I change the value of any of column other than test with an explicit UPDATE statement the trigger fires and usage_count (or test) column's value is incremented. In my project code the column is usage_count. In the dbFiddle example the test column performs the same function. I need to somehow only call the BEFORE UPDATE TRIGGER when the ON DUPLICATE swops from INSERT to UPDATE. –  Dec 03 '20 at 00:36