0

私はmysqlにこのような2つのテーブルを持っています

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

b.serial (unique)
b.lastused

位置が600を超え、「a.serial」が空白で、「b.lastused」がnullまたは30日以上前の「b.serial」からのシリアルである「a」の行を更新したい。シリアルが「a.serial」にコピーされたら、「b.lastused」を今日の日付で更新したいので、関連する「b.serial」が今日使用されていることがわかります。

シリアル以外の2つのテーブルとの関係はなく、bのシリアルはaの任意のカード番号で使用できます。

mysqlに関する限られた知識を使用してこれを試しましたが、クエリにエラーがあるというエラーがmysqlデスクトッププログラムから発生し続けます:(

どんな助けでも大歓迎です!

4

2 に答える 2

2

b.serialここでは、 で更新する行ごとに個別の を使用することを想定していますa。(これは特に述べられていませんが、私には最も可能性が高いと思われます。間違っている場合は、お気軽に私の仮定を修正してください。)

小さな例をセットアップします。各列のデータ型が明確ではなかったため、不明な場合は INT を使用しました。lastused には (DATETIME ではなく) DATE データ型を使用しました。

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」の行は更新され、他の 2 つの行は更新されません (位置 <= 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 でない場合、またはlastusedDATE ではなく DATETIME である場合は、いくつかの調整を行う必要があります。)

しかし、これは、実行したい 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 に答える