@ 2023-11-19T16:27:53Z <?php
/*----------------------------------------------------------------------
ユニークキーの値が既存ならIDを取得し, なければ保存してからIDを取得
という処理において早い方法はなにか?
以下メソッドを比較してテスト
bulkInsertAndIfDuplicateGetIds1()
bulkInsertAndIfDuplicateGetIds2()
bulkInsertAndIfDuplicateGetIds3()
----------------------------------------------------------------------*/
$testUser = new TestUser();
// 挿入データ
// initRows() でINSERTされるデータに対し2番目だけが新規なので
// 挿入を試みると ["1","5","3"] が返ることを期待するが, 結果は下記 echo の通り
$users = [
['name' => 'John', 'kind' => 'TypeA', 'age' => 25], // 既存
['name' => 'Bob', 'kind' => 'TypeC', 'age' => 22], // 新規
['name' => 'Alice', 'kind' => 'TypeB', 'age' => 30], // 既存
];
// 挿入実行
$testUser->initRows();
$result1 = $testUser->bulkInsertAndIfDuplicateGetIds1($users);
$testUser->initRows();
$result2 = $testUser->bulkInsertAndIfDuplicateGetIds2($users);
$testUser->initRows();
$result3 = $testUser->bulkInsertAndIfDuplicateGetIds3($users);
// 結果確認
echo '<p>result1</p>' . json_encode($result1); // ["1","5","3"]
echo '<p>result2</p>' . json_encode($result2); // ["4","4","4"]
echo '<p>result3</p>' . json_encode($result3); // ["4","4","4"]
// テストユーザークラス
final class TestUser
{
private \PDO $pdo;
public function __construct()
{
$host = 'localhost';
$dbname = 'database_name';
$user = 'username';
$password = 'password';
$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";
$this->pdo = new PDO($dsn, $user, $password);
}
// 初期状態として3レコード入れておく
final public function initRows(): void
{
try {
// テーブル作成
$this->pdo->query("
CREATE TABLE IF NOT EXISTS test_users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
kind VARCHAR(255),
age INT,
UNIQUE KEY unique_name_kind (name, kind)
)
");
// レコード削除
$this->pdo->query("
TRUNCATE TABLE test_users;
ALTER TABLE test_users AUTO_INCREMENT = 1;
");
// 3レコード入れておく
$this->pdo->query("
INSERT INTO test_users
(name, kind, age)
VALUES
('John', 'TypeA', 25),
('John', 'TypeB', 30),
('Alice', 'TypeB', 28)
");
} catch (\PDOException $e) {
echo $e->getMessage();
}
}
// 方法1
// execute() を複数回
// ON DUPLICATE KEY UPDATE は LAST_INSERT_ID を指定
final public function bulkInsertAndIfDuplicateGetIds1(array $users): array
{
// 返り値のID配列
$ids = [];
// INSERT文
$sql = 'INSERT INTO test_users (name, kind, age)
VALUES (:name, :kind, :age)
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id)';
try {
$stmt = $this->pdo->prepare($sql);
foreach ($users as $user) {
$stmt->execute($user);
$ids[] = $this->pdo->lastInsertId();
}
return $ids;
} catch (\PDOException $e) {
echo $e->getMessage();
}
}
// 方法2
// execute() を1回
// ON DUPLICATE KEY UPDATE は LAST_INSERT_ID を指定
final public function bulkInsertAndIfDuplicateGetIds2(array $users): array
{
// 返り値のID配列
$ids = [];
// INSERT文
$placeholders = implode(', ', array_fill(0, count($users), '(?, ?, ?)'));
$sql = 'INSERT INTO test_users (name, kind, age)
VALUES ' . $placeholders . '
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id)';
try {
$stmt = $this->pdo->prepare($sql);
$params = [];
foreach ($users as $user) {
$params = array_merge($params, array_values($user));
}
$stmt->execute($params);
for ($i = 0; $i < count($users); $i++) {
$ids[] = $this->pdo->lastInsertId();
}
return $ids;
} catch (\PDOException $e) {
echo $e->getMessage();
}
}
// 方法3
// execute() を1回
// ON DUPLICATE KEY UPDATE は ユニークキーを指定
final public function bulkInsertAndIfDuplicateGetIds3(array $users): array
{
// 返り値のID配列
$ids = [];
// INSERT文
$placeholders = implode(', ', array_fill(0, count($users), '(?, ?, ?)'));
$sql = 'INSERT INTO test_users (name, kind, age)
VALUES ' . $placeholders . '
ON DUPLICATE KEY UPDATE
name = VALUES(name),
kind = VALUES(kind)';
try {
$stmt = $this->pdo->prepare($sql);
$params = [];
foreach ($users as $user) {
$params = array_merge($params, array_values($user));
}
$stmt->execute($params);
for ($i = 0; $i < count($users); $i++) {
$ids[] = $this->pdo->lastInsertId();
}
return $ids;
} catch (\PDOException $e) {
echo $e->getMessage();
}
}
}
Enable javascript to submit You have javascript disabled. You will not be able to edit any code.
Output for 8.2.0 - 8.2.19 , 8.3.0 - 8.3.7 Fatal error: Uncaught PDOException: could not find driver in /in/pZvuD:50
Stack trace:
#0 /in/pZvuD(50): PDO->__construct('mysql:host=loca...', 'username', Object(SensitiveParameterValue))
#1 /in/pZvuD(14): TestUser->__construct()
#2 {main}
thrown in /in/pZvuD on line 50
Process exited with code 255 . Output for 8.0.1 - 8.0.30 , 8.1.0 - 8.1.28 Fatal error: Uncaught PDOException: could not find driver in /in/pZvuD:50
Stack trace:
#0 /in/pZvuD(50): PDO->__construct('mysql:host=loca...', 'username', 'password')
#1 /in/pZvuD(14): TestUser->__construct()
#2 {main}
thrown in /in/pZvuD on line 50
Process exited with code 255 . preferences:dark mode live preview
59.46 ms | 402 KiB | 91 Q