【问题标题】:SQL Update across 3 tables - Where clause issue(?)跨 3 个表的 SQL 更新 - Where 子句问题(?)
【发布时间】:2016-03-31 15:10:53
【问题描述】:

我们需要通过输入表单更新 3 个不同表中的各个列。其中大部分是功能性的,但是当我们尝试更新已连接的其他 2 个表(发布者和类别)时,它会更新该记录以及具有相同输入的所有其他记录。

(例如,如果我们将流派从金属更改为爵士,那么所有金属 CD 也会更改为爵士)

以下是我们目前的更新代码。

$sql = "UPDATE nmc_cd, nmc_category, nmc_publisher 
SET CDTitle ='$title', CDYear = '$year', nmc_publisher.pubID = '$publisherID', nmc_category.catID = '$categoryID', CDPrice = '$price', pubName ='$pubName', catDesc='$catDesc'
WHERE CDID = $id
AND nmc_category.catID = nmc_cd.catID
AND nmc_publisher.pubID = nmc_cd.pubID";

我对这个网站比较陌生,所以如果需要任何东西,例如代码、变量/函数的名称等,请说出来,我会编辑我的帖子或回复。

提前致谢!

【问题讨论】:

  • 您不能在 1 个语句中执行此操作,您必须为每个要更新的表将其拆分为 1 个更新语句。最好创建一个事务并在所有 3 次更新后提交它。您还可以编写一个存储过程并在其中执行语句(再次在事务中)。
  • 这可能属于 DBMS 特定的怪癖领域,而不是纯 SQL。请指定您的目标 DBMS,如果在一个查询中可以做到这一点,我们可以更具体。使用纯 SQL 可能不是。

标签: php sql join where clause


【解决方案1】:

一些建议。

1) 限定 SQL 语句中引用多个表的 all 列引用,即使列引用对 MySQL 而言并不模棱两可。 (还可以考虑为每个表分配一个简短的别名。)这有几个原因,但一个重要的原因是它让人类读者知道每个引用的列在哪个表中。

2) 抛弃旧式逗号运算符进行连接操作,并使用 JOIN 关键字。还将连接谓词从WHERE 子句移动到适当的ON 子句。

3) 对于多表更新,首先编写 SELECT 语句,使其工作和测试,然后将其转换为 UPDATE 语句

4) 避免 SQL 注入漏洞。首选模式是使用带有绑定占位符的准备好的语句。或者(不太理想)至少,SQL 文本中包含的所有可能不安全的值都必须正确转义。


忽略 SQL 注入漏洞(假设变量的内容已经被正确转义)...

我将首先编写一个 SELECT 语句,该语句返回我们计划更新的列的当前值,以及我们计划分配给这些列的新值。例如:

 SELECT cd.cdtitle      AS old_cd_cdtitle
      , '$title'        AS new_cd_cdtitle

      , cd.cdyear       AS old_cdyear
      , '$year'         AS new_cdyear

      , pub.pubid       AS old_pub_pubid
      , '$publisherID'  AS new_pub_pubid

      , cat.catid       AS old_cat_catid
      , '$categoryID'   AS new_cat_catid

      , cd.cdprice      AS old_cd_cdprice
      , '$price'        AS new_cd_cdprice

      , pub.pubName     AS old_pub_pubname
      , '$pubName'      AS new_pub_pubname

      , cat.catDesc     AS old_cat_catdesc
      , '$catDesc'      AS new_cat_catdesc

   FROM nmc_cd cd
   JOIN nmc_category cat
     ON cat.catID = cd.catid
   JOIN nmc_publisher pub
     ON pub.pubID = cd.pubid
  WHERE cd.cdid = $id

(这实际上只是一个猜测,我不确定您实际上想要实现什么。)

当在连接谓词中引用时,为catid 列分配一个新值似乎很奇怪。为了维护cdcat 中的行之间的关系,需要更新两个表中的列中的catid,除非我们依赖ON UPDATE CASCADE 规则来传播更改。

如果不了解此声明试图实现的目标,则无法推荐任何特定声明。

在将SELECT 转换为UPDATE 语句方面,将SELECT ... FROM 替换为关键字UPDATE

WHERE 子句之前,添加SET 语句。从 SELECT 列表中获取 old_cd_cdyear 和 new_cd_cdyear 的表达式,将其转换为 SET 子句,如下所示:

    SET cd.cdyear       = '$year'

后续赋值,使用逗号代替 SET 关键字,例如

      , cd.cdprice      = '$price'

【讨论】:

  • 将 SELECT 语句转换为 UPDATE 的“规则”是针对 MySQL 的。其他 RDBMS 对多表更新有不同的语法。没有说明语句应该实现什么的规范(更改前后的表内容,包括不应该更改的行),实际上不可能为它推荐适当的语法。)如果没有规范,我们'只是在墙上扔“试试这个”猜测,看看有什么坚持。我们可以尝试很多事情,但在不知道我们真正想要实现的目标的情况下,我们怎么知道我们是否“得到了它”?
  • 我们已经加入了表格。当用户在网站表单上输入信息时,我们要做的就是有一个更新语句来更新 3 个表中的信息。这是我们的加入,我们目前有$sql = "SELECT * FROM nmc_cd INNER JOIN nmc_category ON nmc_category.catID = nmc_cd.catID INNER JOIN nmc_publisher ON nmc_publisher.pubID = nmc_cd.pubID WHERE CDID = $id ORDER BY CDTitle"; 为格式化道歉。
  • @spesh:您需要更新哪些表中what行中的哪些列?规范“更新 3 个表中的信息”含糊不清。正如我在回答中指出的那样,如果您有引用 cat.catid 且带有 ON UPDATE CASCADE 的外键,那么当您为 cat.catid 分配新值时,引用旧值的那些外键列也将被更改。行之间的关系将保持不变。如果您还为cat.catname 分配了一个新值,那么所有这些相同的行(引用cat.catid)也将引用新的catname
  • @spesh:我建议您为需要更新的表中的每组行找出单独的更新语句。一旦你有了这些,你就可以将它们组合成一个多表更新。
猜你喜欢
  • 2018-09-11
  • 2013-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多