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 );
仍然没有找到,问题仍然没有答案。
答案 0 :(得分:0)
尝试使用以下语句。您的表格不允许识别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
)