更新相互链接的三个表时出现问题
Posted
技术标签:
【中文标题】更新相互链接的三个表时出现问题【英文标题】:Problem updating three tables that are linked to eachother 【发布时间】:2019-05-23 05:11:58 【问题描述】:我正在尝试更新我的数据库中相互链接的三个表。
我的桌子是这样设置的:
模板
id
title
id_company
问号
id
title
ordering
tid (id of templates)
问题
id
question
catid (id of questioncat)
ordering
templates
包含我的问题列表的名称,questioncat
包含我列表中的所有类别,questions
包含属于某个类别的所有问题。
插入该数据工作正常,我这样做:
首先,我的 php 脚本得到一个数组,例如:
Array
(
[0] => Array
(
[name] => lijsttitle
[value] => Lijst nieuw
)
[1] => Array
(
[name] => category[]
[value] => cat1
)
[2] => Array
(
[name] => sortorder
[value] => 1
)
[3] => Array
(
[name] => question[]
[value] => q1
)
[4] => Array
(
[name] => category[]
[value] => cat2
)
[5] => Array
(
[name] => sortorder
[value] => 2
)
[6] => Array
(
[name] => question[]
[value] => q1
)
)
我会像这样检查列表是否已经存在:
$check = '
SELECT *
FROM templates
WHERE title = "'.$conn->real_escape_string($title["value"]).'"';
$checkcon = $conn->query($check);
$check = $checkcon->fetch_assoc();
// If there is more than 1 result, update data instead of inserting
if($checkcon->num_rows > 0)
// Else insert data as new list
else
// Insert template title and companyid
$inserttemplate = '
INSERT INTO templates (title, id_company) VALUES ("'.$conn->real_escape_string($title["value"]).'","'.$conn->real_escape_string($companyid).'")';
$inserttemplatecon = $conn->query($inserttemplate);
$lastinserted = $conn->inserted_id();
$currCat = '';
$sortorder = '';
foreach($arr as $a)
$val = $a['value'];
// handle category
if($a['name'] == 'category[]')
// save cat name
$currCat = $val;
// init questions array
$store[$currCat] = [];
else if($a['name'] == 'sortorder')
$sortorder = $val;
$store[$currCat]['sortorder'] = $val;
else
// add question to question array
$store[$currCat]['question'][] = $val;
array_shift($store);
// $key is de waarde van de categorie, $lijst is een array met alles onder de categorie
foreach($store as $keycat => $lijst)
$sortorder = $lijst['sortorder'];
$insertcats = '
INSERT INTO questioncat (title, tid, ordering) VALUES ("'.$conn->real_escape_string($keycat).'", "'.$conn->real_escape_string($lastinserted).'", "'.$conn->real_escape_string($sortorder).'")';
$insertcatscon = $conn->query($insertcats);
$lastinserted1 = $conn->inserted_id();
$questionarr = $lijst['question'];
foreach($questionarr as $q)
$insertquestions = '
INSERT INTO questions (question, catid) VALUES ("'.$conn->real_escape_string($q).'", "'.$conn->real_escape_string($lastinserted1).'")';
$insertquestionscon = $conn->query($insertquestions);
echo 'Uw lijst is toegevoegd';
如果有 0 个结果,则该列表不存在并添加到我的数据库中,这可以正常工作,但如果有超过 1 个结果,则表示该列表确实存在并需要更新。
这是我开始遇到问题的地方。
我可以在一个查询中更新所有三个表吗?
我首先尝试在我的 if 语句(我检查模板列表是否已经存在的那个)中使用以下代码仅更新类别名称:
foreach($arr as $a)
$val = $a['value'];
// handle category
if($a['name'] == 'category[]')
// save cat name
$currCat = $val;
// init questions array
$store[$currCat] = [];
else if($a['name'] == 'sortorder')
$sortorder = $val;
$store[$currCat]['sortorder'] = $val;
else
// add question to question array
$store[$currCat]['question'][] = $val;
$updatetemplate = '
UPDATE questioncat c
INNER JOIN templates t
ON c.tid = t.id
SET t.title = "'.$conn->real_escape_string($title["value"]).'",
c.title = "'.$conn->real_escape_string($currCat).'",
c.ordering = "'.$conn->real_escape_string($sortorder).'"
WHERE t.title = "'.$conn->real_escape_string($getcats['title']).'"
AND c.id = "'.$conn->real_escape_string($getcats["id"]).'"';
$updatetemplatecon = $conn->query($updatetemplate);
echo 'Uw lijst is gewijzigd.';
但是所有类别的标题都是一样的,顺序也是一样的。
是否可以在一个查询中更新三个表?它们基本上是三个级别,模板 - 模板下的类别 - 类别下的问题 有可能吗?如果有,怎么做?
【问题讨论】:
您使用的是哪个数据库 RDMS 以及哪个引擎?对于您的案例来说,提及它非常重要,因为解决方案可能会有所不同 @SergeyTelshevsky 我正在使用 mysql (SQL),我的数据库系统是 phpmyadmin。 为什么要在一个查询中进行更新?有什么特殊原因吗?为什么不更新与插入数据相同的方式(foreach over hirarchy)? @SteffenMächtel 我很难做到这一点,当我这样更新时,所有类别和问题都具有相同的价值。循环中的所有循环对我的代码的概述有点丢失,所以我想知道是否有更简单的方法来做到这一点。 @SteffenMächtel 另外,我插入到所有使用最后插入的 id 相互链接的表中,例如这一行:$lastinserted1 = $conn->inserted_id();
这不适用于更新查询。
【参考方案1】:
尝试使用单个查询进行更新不会使过程更简单。这将是一个非常复杂的更新查询。您仍然需要一种方法来以某种方式识别每个“父”(模板、类别)的“子”行(类别、问题)。
具有多个更新/插入查询的解决方案:
在您的示例中,每个表都有一个唯一的 ID。您可以使用此 id 更新特定行。在您的 php 数组(POST/GET?)中,每个项目都有名称和值,但没有 id。只需添加“id”即可。
如果 id 为空 => 插入一个新行(该项目不是来自数据库)
如果 id 已定义 => 更新具有特定 id 的行(此项已存在并且可能已更改)
Array
(
[0] => Array
(
[id] => 1
[name] => lijsttitle
[value] => Lijst nieuw
)
[1] => Array
(
[id] => 17
[name] => category[]
[value] => cat1
)
[2] => Array
(
[name] => sortorder
[value] => 1
)
[3] => Array
(
[id] => 35
[name] => question[]
[value] => q1
)
[4] => Array
(
[id] =>
[name] => category[]
[value] => cat2
)
[5] => Array
(
[name] => sortorder
[value] => 2
)
[6] => Array
(
[id] =>
[name] => question[]
[value] => q1
)
)
【讨论】:
【参考方案2】:要同时更新三个表,您应该在单个数据库事务中进行。
如果您在应该执行的表上有一些触发器(ON UPDATE/DELETE/INSERT),一些数据库引擎,如 PostgreSQL 允许defer execution moment of triggers。如果触发器被延迟,它将在提交事务后立即执行,并且由于它,您甚至可以更新所有键类型(主键、外键、唯一键、复杂键等)。
【讨论】:
【参考方案3】:您可能想开始寻找 PL/SQL 过程,它们可以节省您的编码并且非常安全。
简报:
当第一个表中发生事件时 可以在数据库上执行多个事件,事件可以是(ON DELETE、ON UPDATE 或 ON INSERT) 与 AFTER 和 BEFORE 条件。
PL/SQL 触发器:Source
定义
触发器是存储的程序,当某些事件发生时会自动执行或触发。
至于语法,它会根据您使用的 DBMS 有所不同。 我希望我的解释是好的。
【讨论】:
以上是关于更新相互链接的三个表时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
尝试使用 POJO 记录更新表时出现 Java jOOQ 问题
Access 2007,VBA:将 BLOB 插入链接表时出现奇怪的错误
从 Google Apps 脚本访问 GoogleSheet 链接的 BigQuery 表时出现“获取驱动器凭据时权限被拒绝”错误