愚かではあるが単純な例:受け取るアイテムの合計を保持するテーブル 'Item'があるとします。
Item_Name Items_In_Stock
ここではアイテム名が主キーです。数量XのアイテムAを受け取ったときに次のことを達成する方法.
アイテムが存在しない場合、アイテムAの新しい記録を挿入し、在庫のアイテムをXに設定し、在庫のアイテムがYであるレコードが存在する場合、在庫のアイテムの新しい値は(X + Y)
INSERT INTO `item`
(`item_name`, items_in_stock)
VALUES( 'A', 27)
ON DUPLICATE KEY UPDATE
`new_items_count` = 27 + (SELECT items_in_stock where item_name = 'A' )
私の問題は、実際のテーブルに複数の列があることです。更新部分に複数の選択ステートメントを書くことは良い考えですか?
もちろん、コードでそれを行うことができますが、より良い方法はありますか?
私のコメントで述べたように、ON DUPLICATE KEYを起動する原因となっている行を参照するために副選択を行う必要はありません。したがって、あなたの例では次のものを使用できます:
INSERT INTO `item`
(`item_name`, items_in_stock)
VALUES( 'A', 27)
ON DUPLICATE KEY UPDATE
`new_items_count` = `new_items_count` + 27
ほとんどのことは本当に単純であることに注意してください。単純でなければならないことを過度に複雑にしている場合は、おそらく間違った方法でやっている可能性が高いです:)
この例からアイデアを得ることができます:
ユーザーごとに7日間のデータを追加するとします。
Useridとdayに一意の値が必要です
UNIQUE KEY `seven_day` (`userid`,`day`)
こちらが表です
CREATE TABLE `table_name` (
`userid` char(4) NOT NULL,
`day` char(3) NOT NULL,
`open` char(5) NOT NULL,
`close` char(5) NOT NULL,
UNIQUE KEY `seven_day` (`userid`,`day`)
);
そして、あなたのクエリは
INSERT INTO table_name (userid,day,open,close)
VALUES ('val1', 'val2','val3','val4')
ON DUPLICATE KEY UPDATE open='val3', close='val4';
例:
<?php
//If your data is
$data= array(
'sat'=>array("userid"=>"1001", "open"=>"01.01", "close"=>"11.01"),
'Sun'=>array("userid"=>"1001", "open"=>"02.01", "close"=>"22.01"),
'sat'=>array("userid"=>"1001", "open"=>"03.01", "close"=>"33.01"),
'mon'=>array("userid"=>"1002", "open"=>"08.01", "close"=>"08.01"),
'mon'=>array("userid"=>"1002", "open"=>"07.01", "close"=>"07.01")
);
//If you query this in a loop
//$conn = mysql_connect("localhost","root","");
//mysql_select_db("test", $conn);
foreach($data as $day=>$info) {
$sql = "INSERT INTO table_name (userid,day,open,close)
VALUES ('$info[userid]', '$day','$info[open]','$info[close]')
ON DUPLICATE KEY UPDATE open='$info[open]', close='$info[close]'";
mysql_query($sql);
}
?>
データは表になります:
+--------+-----+-------+-------+
| userid | day | open | close |
+--------+-----+-------+-------+
| 1001 | sat | 03.01 | 33.01 |
| 1001 | Sun | 02.01 | 22.01 |
| 1002 | mon | 07.01 | 07.01 |
+--------+-----+-------+-------+
マイケルの答えは正しいものですが、プログラムでアップサートを行うにはもう少し知っておく必要があります。
まず、テーブルを作成し、一意のインデックスが必要な列を指定します。
CREATE TABLE IF NOT EXISTS Cell (
cellId BIGINT UNSIGNED,
attributeId BIGINT UNSIGNED,
entityRowId BIGINT UNSIGNED,
value DECIMAL(25,5),
UNIQUE KEY `id_ce` (`cellId`,`entityRowId`)
)
次に、いくつかの値を挿入します。
INSERT INTO Cell VALUES( 1, 6, 199, 1.0 );
同じことをもう一度試してください。cellId
とentityRowId
は同じであるため、重複キーエラーが発生します。
INSERT INTO Cell VALUES( 1, 6, 199, 1.0 );
キー「id_ce」のエントリ「1-199」が重複しています
そのため、upsertコマンドを使用します。
INSERT INTO Cell ( cellId, attributeId, entityRowId, value, s, l, p, t )
VALUES( 1, 6, 199, 300.0 )
ON DUPLICATE KEY UPDATE `value` = `value` + VALUES(`value`)
このコマンドは値1.0
既に値として存在し、value = value + 300.0
。
したがって、上記のコマンドを実行した後でも、テーブルには1行しかなく、値は302.0
。
PKカラムの値、またはユニシティを満たすカラムのユニークインデックスがある場合、INSERT IGNORE
、INSERT INTO ... ON DUPLICATE
、またはREPLACE
を使用できます。
INSERT IGNORE
の例
INSERT IGNORE INTO Table1
(ID, serverID, channelID, channelROLE)
VALUES
(....);
INSERT INTO .. ON DUPLICATE KEY UPDATE
の例
SET @id = 1,
@serverId = 123545,
@channelId = 512580,
@channelRole = 'john';
INSERT INTO Table1
(ID, serverID, channelID, channelROLE)
VALUES
(@id, @serverId, @channelId, @channelRole)
ON DUPLICATE KEY UPDATE
serverId = @serverId,
channelId = @channelId,
channelRole = @channelRole;
Replace
の例
REPLACE INTO table1
(ID, serverID, channelID, channelROLE)
VALUES
(...);
これはアップサートの構文です
INSERT INTO `{TABLE}` (`{PKCOLUMN}`, `{COLUMN}`) VALUES (:value)
ON DUPLICATE KEY UPDATE `{COLUMN}` = :value_dup';