2016-11-15 47 views
2

我想以相當複雜的方式更新一個表,並且決定將內表連接到它自己的表是有用的。 (爲了給出一些背景,表格存儲通過chain_id字段鏈接的記錄的短鏈,並且在鏈中通過日期字段進行排序。更新需要處理具有與日期不同的最近日期的符號。其他人在其鏈中,也可能需要將一些鏈分成多個單獨的鏈)。在MySQL中更新一個表內連接本身

這是我所看到的一個簡化版本:

CREATE TABLE t(
    `a` INT(3) NOT NULL, 
    `b` INT(3) 
    ); 

INSERT INTO t VALUES (3,4),(3,6); 

SELECT * FROM t; 

------------ 
| a | b | 
------------- 
| 3 | 4 | 
| 3 | 6 | as expected 


UPDATE t t1 
INNER JOIN t t2 
ON (t1.a = t2.a 
AND t1.b > t2.b) 
SET t1.b = t1.a 
AND t2.b = t1.a; 

SELECT * FROM t; 

------------ 
| a | b | 
------------- 
| 3 | 4 | 
| 3 | 0 | wat 

我本來希望得到是:

------------ 
| a | b | 
------------- 
| 3 | 3 | 
| 3 | 3 | 

所以很明顯,這是個不錯的計劃,但讓我有三個問題:

1.)這裏發生了什麼事?

2.)由於無論發生什麼事情都不太可能是預期的,MySQL爲什麼會允許它?

3)是否有另一種方式來實現類似我的本意(即實際更新的表內加入了與自身,不只是把一切都設置爲3 ...)

+1

更新與本身的內部連接的表是(在我看來)一個非常糟糕的主意。你很可能有深度未知的層次結構,因此最好的方法是(假設MySQL不支持遞歸查詢)實現一個簡單的遞歸函數,在每個**鏈**中找到合適的值,並且在遞歸完全倒回時,更新撥款記錄。 – FDavidov

回答

2

@CGritton解釋爲什麼只有1紀錄被更新,但沒有提供確切的信息,爲什麼b字段在第二次記錄的情況下設置爲0。

解決方案的第一條線索是,您得到set子句錯誤。如果要更新2個字段,則需要用逗號分隔兩個分配,而不要使用and運算符。正確的說法應該是:

UPDATE t t1 
INNER JOIN t t2 
ON (t1.a = t2.a 
AND t1.b > t2.b) 
SET t1.b = t1.a, t2.b = t1.a; 

如果我們分析原始set條款:

SET t1.b = t1.a AND t2.b = t1.a 

注意,即賦值運算符具有較低的優先級,那麼and運營商,因此上述表達式將被執行如:

SET t1.b = ((t1.a AND t2.b) = t1.a) 

如果我代替數字到位的字段名稱:

SET t1.b = ((3 AND 4) = 3) 

(3 AND 4)爲0,0 = 3是0,因此t1.b將被設置爲0

我不完全理解你想實現你的查詢是什麼,所以我不能提出一個最終版本給你。但第一個更正版本應該是你的一個很好的起點。只要確保你瞭解你的加入標準。

1

內的條件只能加入返回一行,所以只有一行正在更新。

> select * 
from t t1 
INNER JOIN t t2 
ON (t1.a = t2.a 
AND t1.b > t2.b) 

+ ------ + ------ + ------ + ------ + 
| a  | b  | a  | b  | 
+ ------ + ------ + ------ + ------ + 
| 3  | 6  | 3  | 4  | 
+ ------ + ------ + ------ + ------ + 

至於爲什麼0,檢查了這一點:

create table two_updates (a int(3)); 

insert into two_updates values (1); 

update two_updates set a = 99 and a = 99; 

select * from two_updates; 

+ ------ + 
| a  | 
+ ------ + 
| 0  | 
+ ------ + 

在您的查詢,你問的MySQL兩次更新同一領域,即使採用相同的價值,即使它有一個不同的別名。

你可以用這個替換你的更新語句並且靠近,但是行(3,4)不會被更新,因爲它不是內部連接的一部分。

UPDATE t t1 
INNER JOIN t t2 
ON (t1.a = t2.a 
AND t1.b > t2.b) 
SET t1.b = t1.a; 

+ ------ + ------ + 
| a  | b  | 
+ ------ + ------ + 
| 3  | 4  | 
| 3  | 3  | 
+ ------ + ------ +