簡體   English   中英

UPDATE語句:在每個SET之后重新計算子查詢

[英]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} 它正確地替換了第二個26 ,但第二個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; 給出與上述查詢相同的結果。

使用預先計算的ID的解決方案,繞過查詢re_evaluation

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的解決方案,使用查詢re_evaluation

仍然沒有找到,問題仍然沒有答案。

嘗試使用以下語句。 您的表不允許標識行,例如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
          )

SQLFiddle演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM