我有三张桌子(我在这个问题中对其进行了简化):
Table 1
id | Name
-----------
1 | John
2 | Smith
Table 2
id | Title
-----------
1 | Developer
2 | Web Developer
3 | A New Title
Table 3 (links between 1 and 2)
idName | idTitle
-----------
1 | 1
1 | 2
2 | 1
我的问题在于更新页面。我的HTML为<select multiple> ... options ... </select>
,我使用chosen来选择和取消选择选项。我只想用PHP做这件事。
假设我们有以下情况:
管理员想要删除'John'的'Developer'标题,并为'John'添加'New Title'。
他/她将取消选择标题ID 1并选择标识3.当他/她提交表单时,我将获得两个选择值:id 1(他选择的那个)和id 2(已经存在的那个)。但我不会得到身份3,因为他取消了它。
我正在努力的是:当用户发布新选择的值时,取消选择的值未随表单一起提交。我没办法跟踪取消选择的那些,所以我可以从我的表中删除它们。您如何使用新更改更新表格?您是否删除该表中已存在的内容并再次添加ID?有更好的选择吗?
更新: 似乎@wander的答案比其他答案的破坏性小。但是,@ wonder没有解释如何在他的答案中计算第4步。在新选择的选项,已存在的选定选项和取消选择的选项之间进行分组。
答案 0 :(得分:4)
没有必要提交取消选择的那个。 e.g。
答案 1 :(得分:3)
您可以在选择菜单之前添加隐藏字段,这样也会导致0
/ falsey
值发送给PHP。
<input type="hidden" name="stuff[]" value="0" />
<input type="hidden" name="stuff[]" value="0" />
<input type="hidden" name="stuff[]" value="0" />
<select multiple name="stuff[]">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
这类似于将未经检查的复选框发送到服务器的方式:
https://stackoverflow.com/a/1992745/268074(注意没有JS的答案)
答案 2 :(得分:3)
您可以将旧值转储到隐藏的选择中,以便在处理表单时获取它们。
<!-- Invisible select field -->
<select multiple name="oldData[]" style="display:none;" aria-hidden="true">
<option value="1">1</option>
<option value="2" selected>2</option>
<option value="3" selected>3</option>
</select>
<!-- Real select field -->
<select multiple name="data[]">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
注意:@ Petah的回答让我受到启发,不要忘记向他投票: - )。
答案 3 :(得分:3)
假设我们有$old_titles
列表,其中包含来自db的标题,以及来自提交的$new_titles
个标题。
$add = array_diff($new_titles, $old_titles);
$delete = array_diff($old_titles, $new_titles);
$add
- 要添加的标题列表,$delete
- 要删除的标题列表。
添加操作:
$dbh->prepare('INSERT INTO table3(idName, idTitle) VALUES (:idName, :idTitle)');
foreach($add as $titleId) {
$dbh->execute(['idName' => $userId, 'idTitle' => $titleId]);
}
删除操作:
$dbh->prepare('DELETE FROM table3 WHERE idName = :idName AND idTitle = :idTitle');
foreach($delete as $titleId) {
$dbh->execute(['idName' => $userId, 'idTitle' => $titleId]);
}
答案 4 :(得分:1)
唯一更好的方法是最简单的方法,记住 KIS
在更新时你只需要执行以下操作
DELETE FROM table3 WHERE idName=??
然后在table3中再次插入所有选定的idTitles
答案 5 :(得分:1)
这可以在两个SQL语句中完成,而不知道取消选择了哪个值。遵循这两个步骤
1)在PHP中,创建一个逗号分隔的所有选定选项列表。例如:2, 3
。
2)然后执行以下语句:
DELETE FROM tblLink WHERE idName = $id AND idTitle NOT IN ($list);
INSERT IGNORE tblLink (idName, idTitle)
SELECT $id, id FROM tblTitle WHERE id IN ($list);
注意:为了简化,我在我的示例中使用了$id
和$list
。当您打算使用它时,您应该正确地准备和绑定参数。确保idName和idTitle是使其工作的主键。
答案 6 :(得分:1)
不确定为什么每个人都在使用隐藏的输入字段来跟踪现有数据。当您POST
表单时,您只需从数据库中检索原始值即可。根据用户输入,这样更安全,因为即使隐藏的字段也可以更改。我知道在这种特殊情况下这并不重要,但我认为最好始终使用最佳实践。
现在PHP
你有两种选择。第一个是删除所有关系,然后添加新关系。第二种方法是删除所有未发布的内容,并添加/更新其中的关系。
虽然第二种选择可能看起来像你说的“破坏性最小”,但它是最容易且最不容易出错的方式。我放弃这种策略的唯一原因是我会在关系表中存储额外的数据。 EG:添加日期(当某人进入某个功能时)或由用户添加。
你会怎么做(方法2)?
请记住,我使用的方法会尽可能地继续尝试。另一种方法是在发布虚假数据时暂停。
<?php
if (array_key_exists("relations",$_POST) && is_array($_POST["relations"])) {
//no duplicates, you dont want to store the same function twice
//only integers
$list = array_unique(array_filter($_POST["relations"], "is_int"));
$csv = implode(',', $list);
//get the userid hoewever you normally would
$userId = 1
//Delete existing
$query = "DELETE FROM Table3 WHERE idname=".$userId
//insert all posted functions
//I select the id's from the actual table so it will never inserted a none existing ID.
//this approach never has duplicates, so the duplicate check in the beginning is redundant now, but I leave it incase I change this.
$query = "INSERT INTO Table3 (idName, idTitle) SELECT ".$userId.", Id FROM Table2 WHERE id IN (".$csv.")".
//execute queries
} else {
//nothing posted, delete all relations
}
?>
现在,如果您只想插入新数据并删除不存在的
<?php
if (array_key_exists("relations",$_POST) && is_array($_POST["relations"])) {
//no duplicates, you dont want to store the same function twice
//only integers
$list = array_unique(array_filter($_POST["relations"], "is_int"));
$csv = implode(',', $list);
//get the userid hoewever you normally would
$userId = 1
//Delete existing
$query = "DELETE FROM Table3 WHERE idname=".$userId." AND idTitle NOT IN (".$csv.")"
//only insert new functions
//I select the id's from the actual table so it will never inserted a none existing ID.
//this approach never has duplicates, so the duplicate check in the beginning is redundant now, but I leave it incase I change this.
$query = "INSERT INTO Table3 (idName, idTitle) SELECT ".$userId.", Id FROM Table2 WHERE id IN (".$csv.") AND id NOT IN (SELECT idTitle FROM table3 WHERE idName=".$userId.")".
//execute queries
} else {
//nothing posted, delete all relations
}
?>
答案 7 :(得分:1)
我认为您必须先检查应该执行哪些操作。这是一个可以在http://sandbox.onlinephpfunctions.com/code/0fa11b3c9f846e344c912f5a3e994eea5e9cac34运行的小例子。 首先在表3上运行select for idName = 1,输出将是idTitle的数组(1,2)。在下面的示例中,$ array1是这样的select语句的输出,$ array2是必须更新,删除或插入的相同idName的新idTitle的数组。例如,如果用户的新idTitles比以前的idTitles更多或更少,那么你应该对它进行某种控制,以便决定你将运行到数据库的查询。
$array1 = array(1,7,3,5);// initial idTitles try it on the above link (php sandbox) with more or less values
$array2 = array(1,4,3,6);//new idTitles try it on the above link (php sandbox) with more or less values
$count1=count($array1);
$count2=count($array2);
$diff=$count1-$count2;
if ($diff==0) {
$result1=array_values(array_diff_assoc($array2,$array1));
$result2=array_values(array_diff_assoc($array1,$array2));
$countr=count($result1);// or $result2 it is the same since they have the same length
$cr=0;
while($cr < $countr) {
print_r("update tblname set val=$result1[$cr] where id=theid and val=$result2[$cr]\n");
$cr++;
}
}
if ($diff!=0) {
$result1=array_diff($array2,$array1);
$result2=array_diff($array1,$array2);
if(count($result2)>0) {
foreach($result2 as $r2) {
print_r("delete from tblname where id=theid and val=$r2\n");
}
}
foreach($result1 as $r1) {
print_r("insert into tblname where id=theid and val=$r1\n");
}
}
答案 8 :(得分:0)
我怎么做会扩展第一张表
1 |约翰| 1,2
2 |史密斯| 1,3
每次更新行时,我只需更换title_ids字段即可完成。