How to INSERT INTO…SELECT with ON DUPLICATE KEY

2019-07-24 19:37发布

问题:

I have two tables with identical structure. Table A contains all the current ads, Table B contains the archived ads. Column 1 (ad_id) is Primary Key, AI, INT. Table engine is MyISAM.

I need to copy all the table A ads preceding a certain date to the archive, table B. My goal is that all fields except ad_id are duplicated, ad_id should get auto-incremented. Here is what I have attempted:

INSERT INTO B`(`ad_id`, `ad_advertiser`, `ad_ln`, `ad_expire`) 
    SELECT *
    FROM A
    WHERE YEAR( ad_expire ) <= 2012

Table B has many thousands of ads, Table A gets flushed often enough that the unique id field has low numbers that often duplicate the id's in Table B. So MySQL chucks a wobbly and tells me I have a Duplicate entry '8577' for key 'PRIMARY'.

So I made several attempts to get past that:

First I tried selecting the individual columns to insert, setting ad_id to NULL:

INSERT INTO B(`ad_id`, `ad_advertiser`, `ad_ln`, `ad_expire`) 
    SELECT (NULL, `ad_advertiser`, `ad_ln`, `ad_expire`)
    FROM A
    WHERE YEAR( ad_expire ) <= 2012 

That results in the error #1241 - Operand should contain 1 column(s), which goes away if I use the wildcard * selector, but then I get the duplicate error.

Next I tried SELECT LAST_INSERT_ID(), which always returns 0.

Then I tried a few using ON DUPLICATE KEY UPDATE, but I can't seem to get that to work.

I even tried to grab the highest id with:

SELECT @max := max(ad_id) FROM B;

INSERT INTO B`(`ad_id`, `ad_advertiser`, `ad_ln`, `ad_expire`) 
  SELECT *
  FROM A
  WHERE YEAR( ad_expire ) <= 2012

ON DUPLICATE KEY UPDATE ad_id = @max + 1

This works for exactly one row, then results in a duplicate entry again (since @max is a static variable).

What am I doing wrong here? Am I making this way too difficult?

回答1:

in your case why not use ?

INSERT INTO B(`ad_advertiser`, `ad_ln`, `ad_expire`) 
    SELECT (`ad_advertiser`, `ad_ln`, `ad_expire`)
    FROM A
    WHERE YEAR( ad_expire ) <= 2012 


回答2:

you may drop the primary key constraint on your ad_id of your table B using th following command.

ALTER TABLE B DROP PRIMARY KEY

Then try your usual query i.e.

INSERT INTO B`(`ad_id`, `ad_advertiser`, `ad_ln`, `ad_expire`) 
    SELECT *
    FROM A
    WHERE YEAR( ad_expire ) <= 2012

UPDATE 1

if you dont want to have multiple ad_id then you may directly try this query

   INSERT INTO `B`(`ad_id`, `ad_advertiser`, `ad_ln`, `ad_expire`) 
    SELECT *
    FROM A
    WHERE YEAR( ad_expire ) <= 2012
   ON DUPLICATE KEY UPDATE
    ad_advertiser = VALUES(ad_advertiser), 
    ad_ln = VALUES(ad_ln), 
    ad_expire = VALUES(ad_expire);

Here is the SQL Fiddle