简体   繁体   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);

I want to make the numbers in test unique (like {1,2,3,4,5,6,7} - ie remove doubles) using this query: 我想使用此查询使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
    ); 

The above query updates the table to {1,2,3,4,5,6,6} . 上面的查询将表更新为{1,2,3,4,5,6,6} It replaces the second 2 to 6 correctly, but the second 4 becomes 6 also, which should be 7 . 它正确地替换了第二个26 ,但第二个4也变为6 ,应该是7 Existing non-duplicates should not be replaced, but only the second-onward duplicates. 不应替换现有的非重复项,而只应替换第二项重复项。

The problem with the above update statement is that (SELECT max(nn.id) FROM test nn) is evaluated once and cached, but it actually depends on what is updated. 上面的更新语句的问题是(SELECT max(nn.id) FROM test nn)被评估一次并缓存,但它实际上取决于更新的内容。 Is it possible to force re-evaluation of (SELECT max(nn.id) FROM test nn) after each SET? 是否有可能在每个SET之后强制重新评估(SELECT max(nn.id) FROM test nn) I tried some hints like /*+NOCACHE*/ without success. 我尝试了一些类似/*+NOCACHE*/提示,但没有成功。

In other words, during update, you need to take into account the fields that already have been updated. 换句话说,在更新期间,您需要考虑已更新的字段。

Anyone ideas? 任何想法?

I assume this could be solved with NON-DETERMINISTIC function, but I don't want to make functions. 我假设这可以通过NON-DETERMINISTIC函数来解决,但我不想创建函数。 EDIT: if I try to compute the id with a function i get ORA-04091: table TEST is mutating, trigger/function may not see it . 编辑:如果我尝试使用函数计算id我得到ORA-04091:表TEST正在变异,触发器/函数可能看不到它 Using PRAGMA AUTONOMOUS_TRANSACTION; 使用PRAGMA AUTONOMOUS_TRANSACTION; gives the same result as the above query. 给出与上述查询相同的结果。

Solution with precalculated ids, bypassing query re_evaluation 使用预先计算的ID的解决方案,绕过查询re_evaluation

AudriyM solved this (cf. comments) for MS SQL Server 2008 using CTEs. AudriyM使用CTE为MS SQL Server 2008解决了这个问题(参见注释)。 There is no alternative in Oracle for CTEs as far as I know, but because AudriyM's solution was based on precalculated values for ids, I though I could translate it in Oracle with subqueries. 据我所知,Oracle中没有替代CTE的替代方案,但由于AudriyM的解决方案基于id的预先计算值,我可以在Oracle中使用子查询进行翻译。 And here it is: 这是:

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 );

Solution without precalculated ids, using query re_evaluation 没有预先计算的id的解决方案,使用查询re_evaluation

Still not found and the question remains unanswered. 仍然没有找到,问题仍然没有答案。

Try to use the following statement. 尝试使用以下语句。 Your table doesn't allow to identify a row for example with ID=2 so to link table with ROW_NUMBER you can use ROWID 您的表不允许标识行,例如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 demo SQLFiddle演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM