Mysql INSERT INTO ... SELECT .... ON DUPLICATE KEY UPDATE

时间:2015-08-07 22:34:48

标签: php mysql

我有这个insert into select duplicate key update查询但在执行两次后,行数会加倍。堆栈溢出要我添加文本,所以我现在只是写东西,因为我不认为你们需要更多的解释,因为这个查询是非常自我解释的。

编辑1:澄清:它不应该加倍,我希望数据得到更新。

编辑2:表格信息

CREATE TABLE `Distance` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `distanceType_myId` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
   `common_id` int(11) NOT NULL,
   `distance` double NOT NULL,
    PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=786421 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

编辑3:更新了表格信息

CREATE TABLE `Distance` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `distanceType_myId` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
   `common_id` int(11) NOT NULL,
   `distance` double NOT NULL,
   PRIMARY KEY (`id`),
   KEY `uniqueId` (`distanceType_myId`,`common_id`)
  ) ENGINE=InnoDB AUTO_INCREMENT=786421 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

实际查询:

INSERT INTO Distance (common_id, distance, distanceType_myId)
SELECT 
c.id, 
AVG(
  ROUND(
    (
      6371 * acos(
        cos(
          radians(p.lat)
        ) * cos(
          radians(a.lat)
        ) * cos(
          radians(a.lng) - radians(p.lng)
        ) + sin(
          radians(p.lat)
        ) * sin(
          radians(a.lat)
        )
      )
    )* 1000
  )
) AS distance, 
'culturel' AS distanceType 
FROM 
immobilier_ad_blank AS c 
LEFT JOIN Adresse AS a ON c.adresse_id = a.id 
JOIN POI AS p on p.discr = 'Culturel' 
AND p.lat IS NOT NULL 
AND p.lng IS NOT NULL 
AND p.lat != '' 
AND p.lng != '' 
AND p.lat != 'Latitude' 
AND p.lng != 'Longitude' 
WHERE 
ROUND(
  (
    6371 * acos(
      cos(
        radians(p.lat)
      ) * cos(
        radians(a.lat)
      ) * cos(
        radians(a.lng) - radians(p.lng)
      ) + sin(
        radians(p.lat)
      ) * sin(
        radians(a.lat)
      )
    )
  )* 1000
)< 5000 
AND a.lat IS NOT NULL 
AND a.lng IS NOT NULL 
AND a.lat != '' 
AND a.lng != '' 
AND a.lat != 'Latitude' 
AND a.lng != 'Longitude' 
GROUP BY 
c.id 
ON DUPLICATE KEY 
UPDATE 
common_id = VALUES(common_id),
distanceType_myId = VALUES(distanceType_myId)

2 个答案:

答案 0 :(得分:2)

您错过了唯一索引 - 由于表格中唯一唯一的关键字是自动递增id字段,因此您需要添加UNIQUE约束。由您的INSERT声明触发。

答案 1 :(得分:2)

很简单,你没有唯一的密钥。在您的表中,您需要一个唯一的标识符或自然键,而不是代理项(主键)。

主键与数据无关,它们是代理键。例如,你不能看一行并知道它的主键是没有主键的那个。

自然键就像只有名称的数据库中的名称,或者电话号码数据库中的电话号码,它可以是状态数据库中的状态。你不会有密歇根州或俄亥俄州的两个条目,例如它们本身就是独一无二的。

代理键很适合关系或用作外键,因为它们与数据无关。一个不好的例子是,如果突然美国决定在该州的缩写中添加一封信。您必须更新所有关系。换句话说,您可以更改状态记录,而不必更改数据库中的任何其他数据,因为代理键与数据无关。 (一个更好的例子是制作北密歇根州和南密歇根州)

所以每个人都有自己的使用和存在理由。

<强> 更新

INSERT INTO
    Distance (common_id, distance, distanceType_myId)
    VALUES ( 1,20.0,'culturel' ) 
    ON DUPLICATE KEY UPDATE 
    id = LAST_INSERT_ID( id ),
    common_id = VALUES( common_id ),
    distance = VALUES( distance ),
    distanceType_myId = VALUES( distanceType_myId )

这是我过去阅读一些旧代码的方法,然后它也更新了插入ID。

<强> UPDATE1.1 但是,我在测试中发现,如果你使用带有异常的PDO,你可以通过忽略错误来提高插入性能。也就是说,如果您实际上不想更新行,或者需要id。例如,如果您只是插入并且不想要重复。(例如,代码仅未经过测试)

 try{
     $PDO->query( "INSERT INTO
    Distance (common_id, distance, distanceType_myId)
    VALUES ( 1,20.0,'culturel' )" );
 }catch( PDOException $e){
     if($e->getCode() != 24000 ){ //not 100% sure of the code number
        //rethrow if not duplicate key
        throw new PDOException( $e->getMessage(), $e->getCode(), $e );
     }
 }