MySQL:使用UNIQUE约束的SELECT ... INSERT INTO重复输入错误

时间:2009-05-22 09:18:57

标签: mysql select insert duplicates

我有下表:

CREATE TABLE `products_quantity` (
  `id` int(11) NOT NULL auto_increment,
  `product_id` varchar(100) NOT NULL,
  `stock_id` int(11) NOT NULL,
  `quantity` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `product_id` (`product_id`,`stock_id`),
  KEY `products_quantity_product_id` (`product_id`),
  KEY `products_quantity_stock_id` (`stock_id`)
) ENGINE=MyISAM

product_id是另一个表的外键,stock_id也是。

此表目前有10 000+行,所有行都具有相同的stock_id(1)。我要做的是将它的所有行复制两次,两次都使用新的stock_id(2和3),以及'quantity'的随机值。

这是SQL:

INSERT INTO `products_quantity` (product_id, stock_id, quantity)
    SELECT product_id, 2 AS stock_id, FLOOR(-1 + (RAND() * 15)) AS random_quantity FROM products_quantity;

工作正常。它使用另一个stock_id创建了10 000多个新行,因此尽管每行的product_id已经存在,但不会违反唯一性约束。

此时表中行的示例,按product_id排序(VARCHAR,丑陋但必要),请原谅格式:

22      0032705090062   1   1
10783   0032705090062   2   13
21      0032705090345   1   6
10784   0032705090345   2   0
...

这是每个product_id两次,每个stock_id一次。现在,如果我想以类似的方式创建第三个股票,使用与上次完全相同的查询但是替换为“3 AS stock_id”,我会在第一个产品行中收到此错误:

“密钥2”的重复条目'0032705090062-3'

突然,虽然product_id 0032705090062和stock_id 3的组合与stock_id 1和2一样独特,但是假设违反了唯一性约束,没有?

有趣的是,单行IS已创建,因此有一个新行:

21563    0032705090062  3   5

...但这是我试图插入的10 000+中唯一的一个。

我在这里缺少什么?为什么第一个SELECT ... INSERT INTO工作,但第二个不工作?

2 个答案:

答案 0 :(得分:2)

您正在从插入的同一个表中进行选择,因此第一次抓取

22      0032705090062   1       1
21      0032705090345   1       6

然后插入

10783   0032705090062   2       13
10784   0032705090345   2       0

但是当你再次运行时它会:

GET     22      0032705090062   1       1
INSERT  21563   0032705090062   3       5
GET     10783   0032705090062   2       13
INSERT          0032705090062   3   <-- oops, already exists

您只需将WHERE stock_id = 1添加到SELECT

即可

答案 1 :(得分:1)

简单:

INSERT INTO `products_quantity` (product_id, stock_id, quantity)
    SELECT 
      product_id, 
      3 AS stock_id, 
      FLOOR(-1 + (RAND() * 15)) AS random_quantity 
    FROM 
      products_quantity;
    WHERE
      stock_id = 1  /* !!!!! */

您的第二次插入失败,因为现在有20,000行(不是10.000,就像您想象的那样)。添加where子句可确保只插入10.000。