这个问题一直困扰着我……你为什么需要每行的 insert_id?在我看来,如果您要插入设置表然后将设置与用户相关联,最好在表中添加某种用户密钥。我可能只是没有看到全貌,但这是我得到的想法:
+---------------------------------------+
| `settings` |
+------+--------+-----------+-----------+
| id | user | setting | value |
+------+--------+-----------+-----------+
| `id` INT(11) PRIMARY AUTO_INCREMENT |
+---------------------------------------+
| `user` INT(11) |
+---------------------------------------+
| `setting` VARCHAR(15) |
+---------------------------------------+
| `value` VARCHAR(25) |
+---------------------------------------+
+---------------------------------------+
| `users` |
+------+--------+--------+--------------+
| id | name | email | etc |
+------+--------+--------+--------------+
| `id` INT(11) PRIMARY AUTO_INCREMENT |
+---------------------------------------+
| `name` VARCHAR(32) |
+---------------------------------------+
| `email` VARCHAR(64) |
+---------------------------------------+
| `etc` VARCHAR(64) |
+---------------------------------------+
我在这里的基本想法是,您对 insert_id(s) 所做的事情就是如何尝试在用户和设置之间创建引用,以便您知道谁设置了什么,然后您将他们的设置返回给他们。
如果我完全失去了重点,请引导我回到主题上,我会尝试提出另一个解决方案,但是如果我在接近你想要去的地方找到任何地方:
如果您确实尝试使用 insert_id(s) 关联这两个表,那么类似下面的代码不会更有意义(假设您有一个类似于上面的表结构):
我假设 $user 是对特定用户 (users.id) 的引用。
我还假设您有一个名为 $settings 的关联数组,您正尝试将其放入数据库中。
$mysqli = new mysqli('host', 'username', 'password', 'database') or trigger_error('[MYSQLI]: Could not connect.');
if ($mysqli)
{
foreach ($settings AS $setting_name=>$setting_value)
{
// I'll do individual queries here so error checking between is easy, but you could join them into a single query string and use a $mysqli->multi_query();
// I'll give two examples of how to make the multi_query string below.
$sql = "INSERT INTO `settings` (`id`, `user`, `setting`, `value`) VALUES ('', $user, '$setting_name', '$setting_value')";
$mysqli->query($sql) or trigger_error('[MYSQLI]: ' . $mysqli->error . '['.$sql.']';
}
$mysqli->close() // Since we know in this scope that $mysqli was created we need to close it when we are finished with it.
}
现在,当您需要用户设置时,您可以使用 JOIN 执行 SELECT 以将所有设置和用户信息放在一起,如果我对此感到不满,请原谅我,因为我目前还不是 mysql(i) 专家,所以我不确定你是否需要做任何特别的事情,因为设置表中有多个条目,而用户表中有一个条目,但我敢肯定,如果我搞砸了,有人可以让我们俩都直截了当:
$mysqli = new mysqli('host', 'username', 'password', 'database') or trigger_error('[MYSQLI]: Unable to connect.');
if ($mysqli)
{
$sql = "SELECT `users`.`name`, `users`.`email`, `users`.`id`, `users`.`etc`, `settings`.`setting`, `settings`.`value` FROM `settings` JOIN (`users`) ON (`users`.`id`=`settings`.`user`) WHERE `settings`.`user`=$user GROUP BY `settings`.`user` ORDER BY `settings`.`user` ASC";
if ($result=$mysqli->query($sql))
{
if ($result->num_rows == 0)
echo "Uh oh! $user has no settings or doesn't exist!";
else
{
// Not sure if my sql would get multiple results or if it would get it all in one row like I want so I'll assume multiple which will work either way.
while ($row=$result->fetch_array())
print_r($row); // Just print the array of settings to see that it worked.
}
$result->free(); // We are done with our results so we release it back into the wild.
} else trigger_error('[MYSQLI]: '.$mysqli->error . '['.$sql.']');
$mysqli->close(); // Our if ($mysqli) tells us that in this scope $mysqli exists, so we need to close it since we are finished.
}
正如我之前所说,我目前还不是 mysql(i) 专家,可能有一些方法可以简化事情,我可能在我的 JOIN 语句的语法上犯了一些错误,或者只是使用了多余的子句,比如分组依据。我将 SELECT 从settings 中提取出来,并将users 加入其中,因为我不确定将设置加入用户是否会生成一个包含用户以及与我们的 WHERE 子句匹配的设置中的所有可能值的单一结果。我只加入过A 和B,每个都有 1 个结果,但我确信 JOIN 是在正确的一般区域。
除了多个查询之外,我说过我会给出为 multi_query 构建单个查询字符串的示例,所以:
$arr = array();
foreach($settings AS $setting_name=>$setting_value)
{
$arr[] = "INSERT INTO `settings` (`id`, `user`, `setting`, `value`) VALUES ('', $user, '$setting_name', '$setting_value')";
}
$sql = join('; ', $arr);
或
foreach($settings AS $setting_name=>$setting_value)
{
$sql = ( isset($sql) ) ? $sql.'; '."INSERT INTO `settings` (`id`, `user`, `setting`, `value`) VALUES ('', $user, '$setting_name', '$setting_value')" : "INSERT INTO `settings` (`id`, `user`, `setting`, `value`) VALUES ('', $user, '$setting_name', '$setting_value')";
}
我要注意的最后一件事:除非您特别需要用户具有相同设置的多个条目,否则您可以在 INSERT 查询之前执行 UPDATE 并且仅在结果 $mysqli->insert_id = 时才执行 INSERT = 0。如果您尝试为用户保留设置更改的历史记录,这就是您需要多个条目的原因,那么我建议创建一个单独的表,其中包含如下表结构的日志:
+--------------------------------------------------+
| `logs` |
+------+--------+--------+-----------+-------------+
| id | time | user | setting | new_value |
+------+--------+--------+-----------+-------------+
| `id` INT(11) PRIMARY AUTO_INCREMENT |
+--------------------------------------------------+
| `time` TIMESTAMP |
+--------------------------------------------------+
| `user` INT(11) |
+--------------------------------------------------+
| `setting` INT(11) |
+--------------------------------------------------+
| `new_value` VARCHAR(25) |
+--------------------------------------------------+
如果您将 CURRENT_TIMESTAMP 设为默认值 time 或仅将 date('Ymd G:i:s') 插入该字段,则您可以通过在创建新设置时插入日志来跟踪设置更改或更改。
如果 UPDATE 没有更改任何内容,则要执行 INSERTS,您可以使用两个单独的语句。也可以使用“INSERT VALUES() ON DUPLICATE KEY UPDATE ...”来执行此操作,但显然不建议在具有多个 UNIQUE 字段的表上使用此方法。使用后一种方法意味着单个查询,但您必须组合 user 和 setting UNIQUE(或者可能是 DISTINCT?)。如果您创建了setting UNIQUE,那么除非我弄错了,否则您将只能在表中拥有一个setting='foo'。要使用两个语句来做到这一点,您可以执行以下操作:
$sql = "UPDATE `settings` SET `value`='bar' WHERE `user`=$user AND `setting`='foo' LIMIT 1";
$mysqli->query() or trigger_error('[MYSQLI]: ' . $mysqli->error . '['.$sql.']');
if ( $mysqli->affected_rows == 0 )
{
$sql = "INSERT INTO `settings` (`id`, `user`, `setting`, `value`) VALUES ('', $user, 'foo', 'bar')";
$mysqli->query($sql) or trigger_error('[MYSQLI]: ' . $mysqli->error . '['.$sql.']');
}
在上面的代码中,如果你愿意,你可以用 $mysqli->insert_id 代替 $mysqli->affected_rows,但最终结果是一样的。仅当 UPDATE 未更改表中的任何内容(这表明该设置和该用户没有记录)时才调用 INSERT 语句。
很抱歉,这是一个非常冗长的回复,并且偏离了您最初的问题,但我希望它与您的真正目的/目标相关。我期待您的回复和 cmet 关于如何从真正的 SQL 大师那里改进我的 SQL 语句的方法。