0

我在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 桌面程序不断收到错误消息,说我的查询中有错误:(

非常感谢任何帮助!

4

2 回答 2

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 ... FROMUPDATE并添加一个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 内联视图的目的是获取分配给这些行的序列号,以便我们可以将它们相互匹配。

连接到ab是返回到原始表中的行,这就是我们想要更新的内容。

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

但这是我将如何进行您想要执行的 UPDATE 的一个示例(据我所知)。


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

于 2012-07-26T22:21:11.693 回答
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) 
于 2012-07-26T20:31:31.077 回答