简体   繁体   English

添加和更新具有多个条目的Mysql子表

[英]Adding and updating Mysql child table with multiple number of entries

I have two tables in mysql: a master table called "grants" and a child table called "goals". 我在mysql中有两个表:一个称为“ grants”的主表和一个称为“ goals”的子表。 Grants has an id field as well as a bunch of others and goals has a goal name and a grant_id to link it to the grants table. Grants具有一个ID字段以及许多其他字段,目标具有一个目标名称和一个grant_id以将其链接到Grants表。

On the html form, the user can add or edit as many goals as they wish (I'm using Javascript to add new inputs). 在html表单上,用户可以根据需要添加或编辑任意数量的目标(我正在使用Javascript添加新输入)。 The form also gets any previous goals added and adds them to the form. 该表格还会添加之前的所有目标,并将它们添加到表格中。

<div id="goals">
        <?php
        $goals = getGoalsById($_GET['id']);
        if (empty($goals)) echo "<p>Goal 1: <input type='text' size='40' name='goals[]' /></p>";
        else {
            $i = 1;
            foreach($goals as $goal) {
                echo "<p>Goal {$i}: <input type='text' size='40' name=\"goals[{$goal['id']}]\" value=\"{$goal['goal']}\" /></p>";
            $i++;
            }

        }
        ?>
    </div>
<input type="button" value="Add goal" onClick="addInput('goals')" />

When I submit the form, I have the following statement to insert or update the goals: 提交表单时,我有以下声明可插入或更新目标:

foreach($goals as $key=>$goal) {

        $sql_goals_add[] = "INSERT INTO goals (id, goal, grant_id) VALUES ($key,:goalnew,$grant_id) ON DUPLICATE KEY UPDATE goal = :goalupdate";
        foreach ($sql_goals_add AS $sql_goal) {
            $stmt_goal = $DBH->prepare($sql_goal);
            $stmt_goal->bindValue(':goalnew', $goal, PDO::PARAM_STR);
            $stmt_goal->bindValue(':goalupdate', $goal, PDO::PARAM_STR);
        }
    $stmt_goal->execute();
    }

This works fine for updating existing goals as the key that is passed is the id that is in the goal table. 这对于更新现有目标非常有效,因为传递的键是目标表中的ID。 However, the problem I run into is when they have new goals, the $goals array that gets passed from the form always starts at 0 and therefore the insert query tries to use 0, 1, 2, etc as the insert id. 但是,我遇到的问题是当他们有新目标时,从表单传递的$ goals数组始终从0开始,因此insert查询尝试使用0、1、2等作为插入id。 I'd rather have it automatically choose the next available id in the goals table. 我希望它自动在目标表中选择下一个可用ID。

I have tried to auto-populate what I think could be the new goal id's, but this is a bad idea as multiple people may hit the site as once and it could overlap. 我试图自动填充我认为可能是新目标ID的内容,但这是一个坏主意,因为多个人可能一次访问该网站,而且可能会重叠。 Any help is appreciated! 任何帮助表示赞赏!

I'm going to make a few assumptions for this process to work for you. 我将对此过程进行一些假设。

  • The form in the case of a new entry is blank . 如果是新条目,则该表格为空白。
  • In the case of an update the form is populated from the database as it stands. 如果进行更新,则从数据库中直接填充表单。
  • On update the form is redisplayed from the database with a note at the top that says the update has happened. 更新后,将从数据库中重新显示该表单,并在顶部显示一条说明更新已发生的注释。
  • This is not bank data or hyper critical fault intolerant data. 这不是存储库数据或超关键容错数据。 Which for your application I don't think it is. 对于您的应用程序,我认为不是。 It is a form for processing administrative data. 它是处理管理数据的一种形式。

The Post process I suggest is a follows. 我建议的发布过程如下。 I suggest split up your insert process a little. 我建议您稍微简化一下插入过程。

  1. Insert/update into the master table. 插入/更新到主表中。 If it is an insert, grab the record Id from the crated row for use as your external key for the goals table. 如果是插入内容,请从创建的行中获取记录ID,以用作目标表的外键。

  2. Delete all entries from your goals table related to the external key. 从目标表中删除与外键有关的所有条目。 This will run even if there is no entry yet and will clear all goals should there be any. 即使没有条目,此命令也将运行,并在有目标的情况下清除所有目标。 Literally rip out all rows and do a fresh insert. 从字面上撕开所有行并重新插入。

  3. Loop through the goals part of the post array using the master table's record id as the external key for insertion. 使用主表的记录ID作为插入的外部键,循环遍历post数组的目标部分。 It is damn hard to keep track of the original goal record IDs for update. 很难跟踪要更新的原始目标记录ID。 Because you cleared the table you don't worry with it as that data is in the post also. 因为您清除了表格,所以您不必担心,因为该数据也在帖子中。 If the person edits the wording of a goal you don't need to detect that to see if the goal needs updating as they are all reentered at once. 如果此人编辑了目标的措词,则无需检测该目标的措辞即可查看目标是否需要更新,因为它们都可以立即重新输入。

  4. Display the form again with data pulled from the database. 再次显示该表单,其中包含从数据库中提取的数据。 If there is an error and you output the result back into the form the user can always update again if there is a fault in the update process after the data is cleared from the goals table. 如果存在错误,并且将结果输出回表格中,则在从目标表中清除数据后,如果更新过程中存在错误,则用户始终可以再次进行更新。 The user will see the problem and try again if data is lost. 用户将看到问题,如果数据丢失,请重试。

Again not how I handle bank data but for the form with an infinite number of goals that can be tacked on this is the easiest solution I have found. 同样,不是我要如何处理银行数据,而是要针对具有可实现的无限目标的表单,这是我找到的最简单的解决方案。
Best of luck 祝你好运

So, after having the discussion over in G+, I ended up splitting things out: 因此,在G +中进行了讨论之后,我最终将事情分解了:

1) Rename the arrays that are passed to goalsNew and goalsExisting 2) Changing the function to parse each array separately so it will perform an insert on new entries, but an update on existing entries. 1)重命名传递给GoalNew和GoalExisting的数组2)更改函数以分别解析每个数组,以便它将对新条目执行插入操作,但对现有条目进行更新。 Below is the completed code, in case anyone cares. 如果有人关心,下面是完整的代码。 :) :)

<div id="goals">
        <?php
        $goals = getGoalsById($_GET['id']);

        if (empty($goals)) echo "<p>Goal 1: <input type='text' size='40' name='goalsNew[]' /></p>";
        else {
            $i = 1;
            foreach($goals as $goal) {
                echo "<p>Goal {$i}: <input type='text' size='40' name=\"goalsExisting[{$goal['id']}]\" value=\"{$goal['goal']}\" /></p>";
            $i++;
            }
        }
        ?>
    </div>

And here is the function that does it all (and I renamed it dealingWithChildren from dealingWithGoals because this is going to be used for multiple child tables, but also because a new father should have a function called dealingWithChildren! 这是完成所有操作的函数(我从DealingWithGoals重命名为DealingWithChildren,因为这将用于多个子表,而且还因为新父亲应该具有一个名为DealingWithChildren的函数!

function dealWithChildren($childType, $childNew, $childExisting, $grant_id) {

$fieldName = substr($childType, 0, -1);

dbConnect();
global $DBH;

try {

// If there are no children at all, delete them all

if(empty($childNew) && empty($childExisting)) {
        $sql_child_delete = "DELETE FROM $childType WHERE grant_id = $grant_id";
        $stmt_child = $DBH->prepare($sql_child_delete);
        $stmt_child->execute();
    }

// If the user removed a child, delete those children
    if(!empty($childExisting)) {
        $sql_child_delete = "DELETE FROM $childType WHERE grant_id = $grant_id AND id NOT IN (";
        $i = 0;
        $len = sizeof($childExisting);
        foreach($childExisting as $key=>$child) {
            $sql_child_delete .= $key;
            if ($len > 1 && $i < $len-1) $sql_child_delete .= ",";
            $i++;
        }
        $sql_child_delete .= ")";
        $stmt_del_child = $DBH->prepare($sql_child_delete);
        $stmt_del_child->execute();
    }
// If a user added any children
    if(!empty($childNew)) {
        foreach($childNew as $key=>$child) {
            $sql_child_add[] = "INSERT INTO $childType ($fieldName, grant_id) VALUES (:childnew,$grant_id)";
            foreach ($sql_child_add AS $sql_child) {
                $stmt_child = $DBH->prepare($sql_child);
                $stmt_child->bindValue(':childnew', $child, PDO::PARAM_STR);
            }
        $stmt_child->execute();
        }
    }

// If a user updated any children
    if(!empty($childExisting)) {
        foreach($childExisting as $key=>$child) {
            $sql_child_update[] = "UPDATE $childType SET $fieldName = :childupdate WHERE id = $key";
            foreach ($sql_child_update AS $sql_child) {
                $stmt_child = $DBH->prepare($sql_child);
                $stmt_child->bindValue(':childupdate', $child, PDO::PARAM_STR);
            }
        $stmt_child->execute();
        }
    }


} catch (PDOException $f) {
    echo 'Database query failure: ' . $f->getMessage();
    //exit;
}

dbDisconnect();

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM