在写入规范化数据库时,我经常使用这样的逻辑。
在伪代码中:
is the thing I want in the table?:
yes - get it's ID
else
no - insert it, then get it's ID
在 PHP 中:
// is the useragent in the useragent table?
// if so, find the id, else, insert and find.
$useragentResult = $mysqli->query("SELECT id FROM useragent WHERE name = '".$useragent."' LIMIT 1");
if ($useragentResult->num_rows == 0) {
// It is not in there
$mysqli->query("INSERT INTO useragent (name) VALUES ('".$useragent."')");
$resultID_object = $mysqli->query("SELECT LAST_INSERT_ID() as id");
$row = $resultID_object->fetch_object();
$useragentID = $row->id;
} else {
// It is, so find it and set it
$useragentData = $useragentResult->fetch_object();
$useragentID = $useragentData->id;
}
这感觉很丑陋(不仅仅是因为PHP!),而且很常见,也许有更好的方法。
这样做的真正方法是什么,或者这是最好的方法?
使用 INSERT ... ON DUPLICATE KEY UPDATE
。
从 MySQL 5.5 开始:
如果表包含
AUTO_INCREMENT
列,并且INSERT ... ON DUPLICATE KEY UPDATE
插入或更新行,则LAST_INSERT_ID()
函数返回AUTO_INCREMENT
值。
或者在早期版本中:
如果表包含
AUTO_INCREMENT
列并且INSERT ... ON DUPLICATE KEY UPDATE
插入一行,则LAST_INSERT_ID()
函数返回AUTO_INCREMENT
值。如果语句改为更新行,则LAST_INSERT_ID()
没有意义。但是,您可以使用LAST_INSERT_ID(expr)
来解决此问题。假设id
是AUTO_INCREMENT
列。若要使LAST_INSERT_ID()
对更新有意义,请按如下所示插入行:INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;
只有当你使用一些基本的PHP而没有充分利用该语言时,它才是丑陋的。对于这样的操作,面向对象编程非常方便。将数据库访问重写为类将生成更如下所示的代码:
$userAgent = new UserAgent();
$userAgent->name = $useragent;
$results = $userAgent->find();
if (empty($results)) {
$userAgent->save();
}
$userAgentId = $userAgent->id;
在该示例中,UserAgent 类的 find 方法在后台执行所有 SQL 工作。如果 find 返回空,我们调用 save 方法,该方法根据填充的属性执行插入并自动填充 id 属性。所以现在在 if 语句之后,我知道 id 是由成功的 find() 或 save() 填充的。