从带有WHERE的SELECT中插入 - 如果存在?

时间:2011-04-06 16:39:31

标签: mysql sql select insert where

我有以下INSERT

INSERT INTO `tbl_productcategorylink` 
(`pcl_p_id`, `pcl_cat_id`, `pcl_orderby`) 
    SELECT 
     `p_id` AS pcl_p_id,
     (SELECT `cat_id` FROM `tbl_categories` WHERE 
       CASE
          WHEN `tbl_products`.`p_gender` = 'female' THEN
               `cat_url_tag` = 'womens' 
          ELSE
           `cat_url_tag` = 'mens'
       END
     LIMIT 1) AS pcl_cat_id,
     1 AS pcl_orderby
FROM `tbl_products` 
WHERE `tbl_products`.`p_gender` = 'female' OR `tbl_products`.`p_gender` = 'male';

这是为了在类别和产品之间添加链接,将p_gender设置为“男性”的任何产品都添加到“男性”类别,类似地添加到“女性”类别。

如果给定产品的行还不存在,我该怎么做呢?

我基本上需要在WHERE子句中添加一些内容来确定行是否已存在:

 AND `exists` IS NULL

我试图在查询的exists部分创建此SELECT列,但这会使列数混乱并导致INSERT失败。

有任何建议要实现这个目标吗?

感谢。

4 个答案:

答案 0 :(得分:3)

INSERT 
  tbl_productcategorylink 
  (pcl_p_id, pcl_cat_id, pcl_orderby) 
SELECT 
  p.p_id, c.cat_id, 1
FROM 
  tbl_products p
  INNER JOIN tbl_categories c ON c.cat_url_tag = CASE p.p_gender 
                                                 WHEN 'female' THEN 'womens' 
                                                 ELSE 'mens' END
WHERE 
  p.p_gender IN ('female', 'male')
  AND NOT EXISTS (
    SELECT 1 FROM tbl_productcategorylink WHERE pcl_p_id = p.p_id
  )

答案 1 :(得分:1)

在WHERE子句中尝试NOT EXISTS:

INSERT INTO `tbl_productcategorylink` 
(`pcl_p_id`, `pcl_cat_id`, `pcl_orderby`) 
    SELECT 
     `p_id` AS pcl_p_id,
     (SELECT `cat_id` FROM `tbl_categories` WHERE 
       CASE
          WHEN `tbl_products`.`p_gender` = 'female' THEN
               `cat_url_tag` = 'womens' 
          ELSE
           `cat_url_tag` = 'mens'
       END
     LIMIT 1) AS pcl_cat_id,
     1 AS pcl_orderby
FROM `tbl_products` 
WHERE `tbl_products`.`p_gender` = 'female' OR `tbl_products`.`p_gender` = 'male'
     AND NOT EXISTS (SELECT * FROM `tbl_productcategorylink` WHERE `pcl_p_id` = `tbl_products`.`p_id`);

答案 2 :(得分:1)

如果密钥存在,您可以使用INSERT IGNORE继续。假设列上有唯一键。

答案 3 :(得分:0)

“插入忽略”在以后重新执行相同的SQL时效率不高,因为它将尝试重新插入所有记录。为了获得最佳系统性能,您必须将插入次数限制为尽可能少的数量。

使用子选择查询也是低效的,在使用大型数据集时,“LEFT JOIN”几乎总是更快。子选择查询在SELECT子句中变得很糟糕。在LEFT JOINed表中的字段周围的SELECT子句中使用'IFNULL()',为缺失/ NULL记录提供默认值。

Tomalak的答案有效,但这里有一个纯粹的“LEFT JOIN”示例。

INSERT INTO tbl_productcategorylink (p_pid, pcl_cat_id, pcl_orderby )
SELECT prod.p_pid, IFNULL( cat.cat_id,0 ), 1 AS pcl_orderby
  FROM tbl_products                  AS prod 
  LEFT JOIN tbl_categories           AS cat  ON cat.cat_url_tag = IF(prod.p_gender='female','womans','mens')
  LEFT JOIN tbl_productcategorylink  AS pcl  ON pcl.pcl_p_id = prod.p_id
 WHERE prod.p_gender IN ('female','male')
   AND pcl.pcl_p_id IS NULL -- Optimizes to faster "NOT EXISTS IN (Select ... From pcl )"

这次重写假设tbl_categories有2个特定记录:'womans'和'mens'。 请注意'where'子句包含“pcl_p_pid IS NULL”,当处理非常大的数据集时,它会优化为“NOT EXISTS IN(Select * From tbl_productcategorylink ...)”的更快版本。

子选择查询执行以下两项操作之一:
a)创建一个临时表 b)当数据库遍历主要的“From”表时,对可能存在的EACH记录的子选择表执行“查找”。当子选择在'SELECT'子句中时,这被夸大为可怕的性能。

LEFT JOIN使用数据库提供的已经高效的JOIN逻辑,允许丢失记录。

- J Jorgenson -