【问题标题】:SQL insert with joins and values带有连接和值的 SQL 插入
【发布时间】:2020-09-27 09:34:52
【问题描述】:

这个问题已经有人问过了,但我找不到答案。我搜索了一段时间,发现了这些相关的问题,但它们并没有帮助我理解或回答我的问题。

SQL Insert Into with Inner Join

T-SQL INSERT INTO with LEFT JOIN

我的问题是如何使用联接在 2 个表中插入数据。例如(使用 php)用户可以输入他/她的姓名和他/她喜欢的食物。

我将它们存储在一个变量和一个数组中(数组的长度并不总是 3,如下所示):

$name = "Niels"
$foodsHeLikes = array("apple", "pear", "banana");

这就是我想要存储它们的方式:

USERS:

UserID   name
1        Niels


FOODS:

FoodID userID name     //userID is linked to UserID in users table
1      1      apple
2      1      pear
3      1      banana

我在上面粘贴的第一个问题的链接有一个带有连接的插入,但我看不到任何地方可以像使用普通插入一样将值放入?

来自该问题的查询:

 INSERT INTO orders (userid, timestamp) 
 SELECT o.userid, o.timestamp FROM users u INNER JOIN orders o ON  o.userid = u.id

【问题讨论】:

  • 你的底层数据库服务器是什么?
  • 我目前正在使用 xampp 来托管我的本地
  • 查询没有问题,它应该可以工作,检查表中的任何约束或者尝试在临时表上使用'with'和普通选择语句。
  • 我知道查询有效,它是从另一个问题复制而来的,但我不明白这个查询将如何插入值,因为查询中没有“VALUES('niels')”
  • 如果您要求使用 ONE 查询插入 TWO 不同的表,那么这是无法完成的。不过还有其他方法,参考:stackoverflow.com/questions/5178697/…

标签: php sql xampp


【解决方案1】:

从评论部分的情况来看,您要问的是您希望有一个更优化的查询过程。现在您正在使用两个不同的查询来填充您的两个表,并且您想知道是否可以更优化地完成。

首先,不可能用 ONE 查询填充 两个 不同的表。

但是,您可以做的是使用事务。

此答案的其余部分将假设您使用 PHP 作为后端脚本语言(如您自己标记的那样)。

此外,您是否在查询中使用准备好的语句本身并不明显。如果您不这样做,我强烈建议您使用准备好的语句。否则,您将面临 SQL 注入(SQLI 攻击)。

我将继续在此答案中使用 mysqli 准备好的语句

<?php
// Your input post variables
$name = $_POST['name'];
$foodArray = $_POST['foodArray'];

/*
I'm using a function to handle my queries,
simply because it makes large piles of code easier to read.
I now know that every time the function:
createUserAndFood($name, $foodArray);

is called, that it will populate my user and food table.
That way I don't have to worry about writing all the code multiple times.
*/
function createUserAndFood($name, $foodArray){
    // food array values
    $foodValues = array_values($foodArray);

    // DB variables
    $servername = "localhost";
    $username = "username";
    $password = "password";
    $dbname = "myDB";

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);

    // Check connection
    if($conn->connect_error){
      die("Connection failed: " . $conn->connect_error);
    }

    /*
    Stops the query from auto commiting,
    I'll explain later, you can "maybe" disregard this.
    */
    $conn->autocommit(FALSE);

    // Declare the query
    $sql = "INSERT INTO userTable(name) VALUES(?)";

    // Prepare and bind
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("s", $name);

    // Execute the query
    $stmt->execute();

    // Fetch last inserted id
    $lastID = $conn->insert_id;

    $sql = "INSERT INTO foodTable(userId, food) VALUES(?, ?)";
    $stmt = $conn->prepare($sql);

    for($i = 0; $length = count($foodValues) > $i; $i++){
        $stmt->bind_param("is", $lastID, $food);
        $food = $foodValues[$i];
        $stmt->execute();
    }
    // Commits the query / queries
    $conn->commit();

    // Close connection
    $stmt->close();
    $conn->close();
}
?>

由于您想优化查询,我们在这里使用的一般想法是,我们通过 PHP 使用 MySQL 函数 LAST_INSERT_ID(); 并将其存储到变量中。

现在,如果您使用自动递增的 id,这主要是相关的。如果你不是,你可以忽略这个特定的逻辑并使用其他东西。但如果你是,请继续阅读。

我们将最后一个 id 存储到变量中的原因是因为我们需要多次使用它(新用户可能有不止一种喜欢的食物)。如果您不将最后一个 id 存储到变量中,它将取而代之的是在初始插入后第二个表的自动递增值,这意味着在您的第三个插入语句和转发时,您将使用错误的 id。

现在,正如我承诺解释的那样,我使用$conn-&gt;autocommit(FALSE);$conn-&gt;commit(); 的原因是因为您可能不希望数据库中的数据集不完整。想象一下用户输入正在发生,但您的数据库在这一切中崩溃了。您将拥有不完整的数据集。如果这不是您真正关心的问题,那么您可以忽略它。

为了简化 MySQL 方面发生的事情,可以这样考虑:

BEGIN;
INSERT userTable SET name = '$name';
SET @lastID = LAST_INSERT_ID();
INSERT foodTable SET id = @lastID, food = '$food';
COMMIT;

【讨论】:

  • 是的,我的问题主要是为了避免不完整的数据集,感谢您的详尽和有用的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 2012-03-21
  • 2012-10-08
  • 2013-11-03
  • 1970-01-01
相关资源
最近更新 更多