某事一直在困扰着我这个问题......你为什么需要每行的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关联这两个表,那么就不会像下面的代码更有意义(假设你有一个类似于上面的表结构):
我会假设$ 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.
}
现在,当你需要的用户的设置,你可以做一个加入一个SELECT把所有的设置和用户信息一起,原谅我,如果我虱子这一点,因为我远远不是一个MySQL(我)专家,所以我不确定你是否需要做任何特别的事情,因为设置表中有多个条目,用户表中有单个条目,但是我确定有人可以让我们两个都挺直,如果我搞砸:
$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(我)的专家和有可能的方式,以简化的东西,我可能犯了一些错误与信达x在我的JOIN语句上,或者只是使用多余的claus(es),比如GROUP BY。我从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,并且只在执行INSERT时执行$ mysqli-> insert_id == 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) |
+--------------------------------------------------+
如果您的time
默认的CURRENT_TIMESTAMP或刚插入日期(“YMD G:我:S” )添加到该字段中,然后您可以通过在创建或更改新设置时插入日志来跟踪对设置的更改。
要做INSERTS如果UPDATE没有改变任何东西,你可以使用两个单独的语句。也可以通过“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,但最终的结果是一样的。 INSERT语句只有在UPDATE没有改变表中的任何内容时才被调用(这将表明该设置和该用户没有记录)。
我很抱歉,这是一个非常冗长的答复,它偏离了你的原始问题,但我希望它是相对于你的真正目的/目标。我期待着您的回应,以及关于如何从真正的SQL高手改进我的SQL语句的意见。
我不确定关于第2点。如果是我,我会看看创建一个临时表,将每个last_insert_id添加到它,然后返回。或者更好的是,用另一种方式选择刚才发生的事情(用户并说一个datelastchanged时间戳) – 2013-05-14 10:45:50
简单的答案no。它不健壮,尽管任何单独的last_insert_id()都可能依赖于连接,但它并不提供*保证*,所有插入都将位于并发块中,而不会与来自另一个并发进程的插入交织。在编程方面,依靠强大的工程设计比认为应该是好的感觉要好得多。 – Anigel 2013-05-14 10:50:46
我同意上述问题。但是,可能会在要插入的表上添加一个额外的字段,并将其放入该唯一标识符中。然后,您可以读取该表以查找具有该唯一标识符的所有记录,以获取插入的id的列表。我仍然会担心哪个id引用的是你插入的数据集是未定义的。 – Kickstart 2013-05-14 12:51:49