这个问题一直困扰着我……为什么你需要每行的 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 语句的语法上犯了一些错误,或者只是使用了像 GROUP BY 这样的多余子句. 我让 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 == 0 时执行 INSERT。如果您尝试为用户保留设置更改的历史记录,这就是您需要多个条目的原因,那么我建议您创建一个单独的表,其中包含一个包含表结构的日志,例如:
+--------------------------------------------------+
| `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) |
+--------------------------------------------------+
如果您time
将 CURRENT_TIMESTAMP 设为默认值,或者只是将 date('Ymd G:i:s') 插入该字段,那么您可以通过在创建或更改新设置时插入日志来跟踪设置的更改。
如果 UPDATE 没有更改任何内容,则要执行 INSERTS,您可以使用两个单独的语句。也可以使用“INSERT VALUES() ON DUPLICATE KEY UPDATE ...”来执行此操作,但显然不建议在具有多个 UNIQUE 字段的表上使用此方法。使用后一种方法意味着单个查询,但是您必须将user
和setting
UNIQUE (或者可能是 DISTINCT?)结合起来。如果您设置了UNIQUE,那么除非我弄错了,否则setting
您将只能在表中有一个='foo'。setting
要使用两个语句来做到这一点,您可以执行以下操作:
$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 语句(这表明该设置和该用户没有记录)。
很抱歉,这是一个非常冗长的回复,并且偏离了您最初的问题,但我希望它与您的真正目的/目标相关。我期待着您的回复以及关于如何从真正的 SQL 大师那里改进我的 SQL 语句的评论。