2012-07-26 46 views
0

我在mysql中的兩個表這樣與無關表數據

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

b.serial (unique) 
b.lastused 

我想在更新任何行的MySQL更新列「一」,其中位置上方600和「a.serial」是空白的任何來自「b.serial」的序列,其中「b.lastused」爲null或超過30天前。當序列被複制到「a.serial」時,我想在今天的日期更新「b.lastused」,所以我知道相關的「b.serial」今天已經被使用。

除了串口之外,這兩個表格沒有任何關係,並且任何來自b的串口都可以用於a中的任何cardnumber。

我這個用我有限的MySQL的知識,但我不斷收到從我的MySQL桌面程序錯誤地說,我在我的查詢:(

任何幫助非常讚賞有一個錯誤嘗試!

+0

你可以發佈樣本表數據和預期的輸出嗎? – arunmoezhi 2012-07-26 20:22:34

+0

你能提供一個小的數據集嗎?我所關心的一個問題是,在a.serial和b.serial中會有很多NULL到NULL的值,所以你無法獲得唯一的更新。這會導致問題。 – Shawn 2012-07-26 20:26:04

回答

2

我假設這裏要使用一個單獨的b.serial的每一行中a更新。(這是不具體說明,但在我看來是最有可能的;請感覺fr ee糾正我的假設,如果它是錯誤的。)

我設置了一個小例子。目前還不清楚每個列的數據類型,所以我在我不確定的情況下使用了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; 

根據你給的條件下,用cardnumbers「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 

要轉換到更新,更換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 

您可以運行內嵌視圖的查詢seperately(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語句替換。

+0

嗨Spencer7593。我可以看到這是如何工作的,但是當我嘗試運行它時,我收到一條警告,說我的MySQL查詢中有一個錯誤,我已經將其跟蹤到創建序列號:「@ i:= @i + 1 AS i」,「JOIN(SELECT @i:= 0)ii」等。如果刪除這些行,我可以運行每個內嵌查詢,並返回期望的結果,但沒有得到一個連續的數字,沒有什麼可以加入這兩個查詢。我運行的數據庫是很舊的,我不能升級它,也許創建序列號的函數不可用?數據庫上的版本是4.0.22-nt – 2012-07-27 10:19:48

+0

我想我已經通過使用http://ronaldbradford.com/blog/a-need-trick-for-a-row-number-in-a-mysql-recordset -2008-09-13 /刪除「JOIN(SELECT @j:= 0)jj」並刪除「JOIN(SELECT @i:= 0)ii」。感謝您的查詢!我會仔細檢查並勾選右鍵回答如果d oes工作。 – 2012-07-27 10:52:18

+0

刪除「JOIN(SELECT @j:= 0)jj」並刪除「JOIN(SELECT @i:= 0)ii」爲每個內聯查詢工作,並且他們用一個附加列(i或j)成功返回正確的詳細信息序列號從1開始。但是,當我運行整個SELECT並加入兩個查詢時,它會給出錯誤。 – 2012-07-27 11:07:36

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) 
+0

但要小心。第二個查詢更新所有符合條件的記錄,而不是唯一用於更新第一個表的記錄。 – arunmoezhi 2012-07-26 20:40:51

+0

嗨Arunmoezhi,是的,我看到關於第二個查詢。我只需要更新所用的連續文件,因爲我可能有一批1m連續編號,我想每天自動使用這些連續文件。有沒有辦法只更新那些使用的連續劇?也許第二個查詢可以在之後運行,它將得到表a中的連續序列,然後在表b中查找它們,並使用今天的日期更新表b,以查找任何匹配的序列,該序列的最後一次使用爲null或超過30天前? – 2012-07-27 10:25:23

+0

我運行第一個查詢時也出現錯誤。我可以運行每個內嵌查詢並返回: 從... = 1中選擇b.serial未使用的序列 選擇a.cardnumber .... =所有位於600+的卡號,但尚未有一個序列號。 這些應該返回一個串行但很多卡號? – 2012-07-27 10:32:25