[英]UPDATE statement: re-evaluate subquery after each SET
CREATE TABLE test (id NUMBER(3));
INSERT INTO test VALUES (1);
INSERT INTO test VALUES (2);
INSERT INTO test VALUES (2);
INSERT INTO test VALUES (3);
INSERT INTO test VALUES (4);
INSERT INTO test VALUES (4);
INSERT INTO test VALUES (5);
我想使用此查詢使test
的數字唯一(如{1,2,3,4,5,6,7}
- 即刪除雙打):
UPDATE test u SET u.id = (SELECT max(nn.id) FROM test nn) + 1
WHERE 1 < (
SELECT tt.rown
FROM (SELECT rowid, row_number() over ( partition by t.id order by t.id) AS rown FROM test t) tt
WHERE tt.rowid = u.rowid
);
上面的查詢將表更新為{1,2,3,4,5,6,6}
。 它正確地替換了第二個2
到6
,但第二個4
也變為6
,應該是7
。 不應替換現有的非重復項,而只應替換第二項重復項。
上面的更新語句的問題是(SELECT max(nn.id) FROM test nn)
被評估一次並緩存,但它實際上取決於更新的內容。 是否有可能在每個SET之后強制重新評估(SELECT max(nn.id) FROM test nn)
? 我嘗試了一些類似/*+NOCACHE*/
提示,但沒有成功。
換句話說,在更新期間,您需要考慮已更新的字段。
任何想法?
我假設這可以通過NON-DETERMINISTIC函數來解決,但我不想創建函數。 編輯:如果我嘗試使用函數計算id我得到ORA-04091:表TEST正在變異,觸發器/函數可能看不到它 。 使用PRAGMA AUTONOMOUS_TRANSACTION;
給出與上述查詢相同的結果。
AudriyM使用CTE為MS SQL Server 2008解決了這個問題(參見注釋)。 據我所知,Oracle中沒有替代CTE的替代方案,但由於AudriyM的解決方案基於id的預先計算值,我可以在Oracle中使用子查詢進行翻譯。 這是:
UPDATE test u SET u.id = ( SELECT newIDs.newID
FROM ( SELECT ranked.rowid,
ranked.m + row_number() over (order by ranked.id, ranked.r) as newID
FROM ( SELECT t.rowid, t.id, row_number() over ( partition by t.id order by t.id) AS r, max(id) over() AS m
FROM test t ) ranked
WHERE ranked.r > 1 ) newIDs
WHERE u.rowid = newIDs.rowid )
WHERE u.rowid IN ( SELECT ranked.rowid
FROM ( SELECT t.rowid, t.id, row_number() over ( partition by t.id order by t.id) AS r, max(id) over() AS m
FROM test t ) ranked
WHERE ranked.r > 1 );
仍然沒有找到,問題仍然沒有答案。
嘗試使用以下語句。 您的表不允許標識行,例如ID = 2,因此要將表與ROW_NUMBER鏈接,您可以使用ROWID
UPDATE
Test
SET id = (SELECT RN FROM
(SELECT ROW_NUMBER()
OVER (ORDER BY ID) as RN
FROM Test
) T1
WHERE T1.RowID=Test.RowID
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.