MySQL 更新具有不相关表数据的列

标签 mysql sql

我在mysql中有两个这样的表

a.cardnumber (unique)
a.position (numerical 3 digits or null)
a.serial

b.serial (unique)
b.lastused

我想更新“a”中位置高于 600 且“a.serial”为空白且“b.serial”中的任何序列号为空的行,其中“b.lastused”为空或超过 30 天前。当序列号被复制到“a.serial”时,我想用今天的日期更新“b.lastused”,这样我就知道相关的“b.serial”今天已被使用。

除了序列号之外,这两个表没有任何关系,b 中的任何序列号都可以与 a 中的任何卡号一起使用。

我已经用我有限的 mysql 知识尝试过这个,但我不断从我的 mysql 桌面程序收到错误,说我的查询有错误:(

非常感谢任何帮助!

最佳答案

我在这里假设您希望对 a 中要更新的每一行使用单独的 b.serial。 (虽然没有具体说明,但在我看来这是最有可能的;如果我的假设有误,请随时纠正。)

我设置了一个小例子。不清楚每列的数据类型是什么,因此我在不确定的地方使用了 INT。我使用 DATE 数据类型(而不是 DATETIME)作为最后使用的数据。

CREATE TABLE a (`cardnumber` VARCHAR(10) NOT NULL PRIMARY KEY, `position` INT, `serial` INT);
CREATE TABLE b (`serial` INT NOT NULL PRIMARY KEY, lastused DATE);
INSERT INTO a VALUES ('x0000',555,NULL),('x0001',700,123),('a1111',601,NULL),('a2222',602,NULL);
INSERT INTO b VALUES (100,'2012-07-15'),(101,NULL),(102,'2010-01-01'),(103,NULL),(104,NULL);
SELECT * FROM a;
SELECT * FROM b;

根据您给出的条件,卡号为“a1111”和“a2222”的行应该更新,其他两行不应更新(位置 <= 600,序列号已分配)。

在运行 UPDATE 之前,我们希望首先运行 SELECT 来返回要更新的行以及将分配的值。一旦我们得到它,我们就可以将其转换为多表 UPDATE 语句。

SELECT a.cardnumber AS `a.cardnumber`
     , a.position   AS `a.position`
     , a.serial     AS `a.serial`
     , b.serial     AS `b.serial`
     , b.lastused   AS `b.lastused`
  FROM (
         SELECT @i := @i + 1 AS i
              , aa.*
           FROM a aa
           JOIN (SELECT @i := 0) ii
          WHERE aa.position > 600   /* assuming `position` is numeric datatype */
            AND aa.serial IS NULL   /* assuming 'blank' represented by NULL    */
          ORDER BY aa.cardnumber
       ) ia
  JOIN (
         SELECT @j := @j + 1 AS j
              , bb.serial
              , bb.lastused
           FROM b bb
           JOIN (SELECT @j := 0) jj
          WHERE bb.lastused IS NULL 
             OR bb.lastused < DATE_ADD(NOW(),INTERVAL -30 DAY)
          ORDER BY bb.serial
       ) jb
    ON ia.i = jb.j
  JOIN a ON a.cardnumber = ia.cardnumber
  JOIN b ON b.serial = jb.serial

要将其转换为 UPDATE,请将 SELECT ... FROM 替换为 UPDATE,并添加 SET 子句来分配新值到 table 上。

UPDATE (
         SELECT @i := @i + 1 AS i
              , aa.*
           FROM a aa
           JOIN (SELECT @i := 0) ii
          WHERE aa.position > 600
            AND aa.serial IS NULL
          ORDER BY aa.cardnumber
       ) ia
  JOIN (
         SELECT @j := @j + 1 AS j
              , bb.serial
              , bb.lastused
           FROM b bb
           JOIN (SELECT @j := 0) jj
          WHERE bb.lastused IS NULL 
             OR bb.lastused < DATE_ADD(NOW(),INTERVAL -30 DAY)
          ORDER BY bb.serial
       ) jb
    ON ia.i = jb.j 
  JOIN a ON a.cardnumber = ia.cardnumber
  JOIN b ON b.serial = jb.serial
   SET a.serial = b.serial
     , b.lastused = DATE(NOW())

-- 4 row(s) affected

您可以单独运行内联 View (ia、jb)的查询,以验证这些 View 是否获取了您想要更新的行。

从ia到a、从jb到b的连接应该在主键唯一键上。

ia 和 jb 内联 View 的目的是获取分配给这些行的连续编号,以便我们可以将它们相互匹配。

ab的连接是为了返回原始表中的行,这就是我们要更新的行。

(显然,如果 serial 不是 INT,或者 lastused 是 DATETIME 而不是 DATE,则需要进行一些调整。)

但这是我如何进行您想做的更新的示例(据我所知)。


注意:此方法适用于支持子查询的 MySQL 版本。对于 MySQL 4.0,您需要分步运行,将“ia”和“jb”内联 View (子查询)的结果存储到实际表中。然后在查询中引用这些表来代替内联 View 。在执行引用这些变量的查询之前,可以删除 ii 和 jj 子查询,并用单独的 SELECT @i := 0, @j := 0 语句替换。

关于MySQL 更新具有不相关表数据的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11677393/

相关文章:

c# - 在 ASP.Net 中将数据更新到 SQL Server 的最佳实践是什么

sql - 异步存储过程调用

php - 从关联数组中回显特定数据?

sql - 如何使用 PHPUnit 使用 SQL 文件设置和拆除数据库?

php - CodeIgniter 没有正确执行 sql 查询

sql - 从 Access 导入 Excel 无法正常工作

sql - 多个不同的数组,其中包含空值

php - SSH 隧道 - MySQL 服务器已消失

php - 防止 PHP 脚本同时运行多次的最佳方法?

sql - 对一系列值进行分组以进行相关计算