我在mysql中有两个这样的表
a.cardnumber (unique)
a.position (numerical 3 digits or null)
a.serial
b.serial (unique)
b.lastused
我想更新位置大于600的“a”中的任何行,并且“a.serial”为空白,其中“b.serial”中的任何序列为“b.lastused”为null或超过30天前。当序列被复制到“a.serial”时,我想用今天的日期更新“b.lastused”,所以我知道今天已经使用了相关的“b.serial”。
除了序列之外,两个表没有任何关系,b中的任何序列都可以与a中的任何卡号一起使用。
我使用我对mysql的有限知识尝试了这一点,但我不断从我的mysql桌面程序中收到错误,说我的查询中有错误:(
非常感谢任何帮助!
答案 0 :(得分:2)
我在此假设您要在b.serial
中为每行使用单独的a
。 (这没有具体说明,但在我看来最有可能;如果错误,请随意纠正我的假设。)
我设置了一个小例子。目前还不清楚每个列的数据类型是什么,所以我使用了INT,我不确定。我使用了DATE数据类型(而不是DATETIME)用于lastused。
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
子句以为表分配新值。
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
您可以单独运行内联视图的查询(ia,jb),以验证这些查询是否获得了要更新的行。
从ia到a,从jb到b的连接应该在主键唯一键上。
ia和jb内联视图的目的是为这些行分配序列号,以便我们可以将它们相互匹配。
a
和b
的联接是返回原始表格中的行,这是我们想要更新的内容。
(显然,如果serial
不是INT,或者lastused
是DATETIME而不是DATE,则需要进行一些调整。)
但这是我想要做的更新的一个例子(我最了解它。)
注意:此方法适用于支持子查询的MySQL版本。对于MySQL 4.0,您需要分步运行,将“ia”和“jb”内联视图(子查询)的结果存储到实际表中。然后在查询中引用这些表来代替内联视图。可以删除ii和jj子查询,并在执行引用这些变量的查询之前用单独的SELECT @i := 0, @j := 0
语句替换。
答案 1 :(得分:1)
让我知道这是否有效
Update table_a
set serial =
(
select b.serial from table_b b
where b.lastused = NULL
OR b.lastused < (current date - 30) limit 1
)
where cardnumber in
(
select a.cardnumber
from table_a a
where a.position > 600
and a.serial = NULL
)
update table_b b
set b.lastused = current date
where b.lastused = NULL
OR b.lastused < (current date - 30)