#1 ON DUPLICATE KEY UPDATE用法
如果您指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则执行旧行UPDATE。例如,如果列a被定义为UNIQUE,并且包含值1,则以下两个语句具有相同的效果:
mysql>INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
mysql>UPDATE table SET c=c+1 WHERE a=1;
如果行作为新记录被插入,则受影响行的值为1;如果原有的记录被更新,则受影响行的值为2。
注释:如果列b也是唯一列,则INSERT与此UPDATE语句相当:
mysql>UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
如果a=1 OR b=2与多个行向匹配,则只有一个行被更新。通常,您应该尽量避免对带有多个唯一关键字的表使用ON DUPLICATE KEY子句。
您可以在UPDATE子句中使用VALUES(col_name)函数从INSERT...UPDATE语句的INSERT部分引用列值。换句话说,如果没有发生重复关键字冲突,则UPDATE子句中的VALUES(col_name)可以引用被插入的col_name的值。本函数特别适用于多行插入。VALUES()函数只在INSERT...UPDATE语句中有意义,其它时候会返回NULL。
mysql>INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
->ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
本语句与以下两个语句作用相同:
mysql>INSERT INTO table (a,b,c) VALUES (1,2,3)
->ON DUPLICATE KEY UPDATE c=3;
mysql>INSERT INTO table (a,b,c) VALUES (4,5,6)
->ON DUPLICATE KEY UPDATE c=9;
当您使用ON DUPLICATE KEY UPDATE时,DELAYED选项被忽略。
#2 要出发价格库存表结构
CREATE TABLE `ycf_sale_infos` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`product_id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '产品编号',
`date` date NOT NULL COMMENT '库存日期',
`price` decimal(8,2) unsigned NOT NULL COMMENT '售卖价格#两位小数,30.00(单位:元)',
`settlementPrice` decimal(8,2) unsigned DEFAULT NULL COMMENT '结算价格#底价模式时该字段必填,为结算价格',
`priceType` tinyint(3) unsigned NOT NULL COMMENT '价格类型#0:售价模式 1:底价模式',
`stock` int(10) unsigned NOT NULL COMMENT '库存#可购买产品的份数',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ycf_sale_infos_product_id_index` (`product_id`,`date`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1243705 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='要出发:产品库存表';
#3 model基类添加新方法
//BaseModel添加新方法
/**
* Mass (bulk) insert or update on duplicate
*
* insertOrUpdate([
* ['id'=>1,'value'=>10],
* ['id'=>2,'value'=>60]
* ]);
*
* @param array $rows
* @return bool
*/
function insertOrUpdate(array $rows)
{
$table = DB::getTablePrefix().with(new static())->getTable();
$first = reset($rows);
$columns = implode( ',',
array_map( function( $value ) { return "$value"; } , array_keys($first) )
);
$values = implode( ',', array_map( function( $row ) {
return '('.implode( ',',
array_map( function( $value ) { return '"'.str_replace('"', '""', $value).'"'; } , $row )
).')';
} , $rows )
);
$updates = implode( ',',
array_map( function( $value ) { return "$value = VALUES($value)"; } , array_keys($first) )
);
$sql = "INSERT INTO {$table}({$columns}) VALUES {$values} ON DUPLICATE KEY UPDATE {$updates}";
return DB::statement( $sql );
}
#4使用
//...
//对 `要出发`发起post请求
$req = $this->fetch("/OTA/StockPriceRequest", $data);
$productID = data_get($req, "data.productID");
if ($productID) {
//获取可批量更新的属性array
$fillAbles = app(SaleInfo::class)->getFillable();
$attributes = collect(data_get($req, "data.saleInfos"))
->map(function ($item, $key) use ($productID, $fillAbles) {
$item['product_id'] = $productID;
//只取可更新的信息段
$item = collect($item)->only($fillAbles)->toArray();
return $item;
})
->toArray();
//用批量语句更新
app(SaleInfo::class)->insertOrUpdate($attributes);
}
//...