我在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 的目的是获取分配给这些行的连续编号,以便我们可以将它们相互匹配。
与a
和b
的连接是为了返回原始表中的行,这就是我们要更新的行。
(显然,如果 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/