简体   繁体   中英

How to update rows based only on ROW_NUMBER()?

Such SQL query:

SELECT ROW_NUMBER() OVER (PARTITION BY ID, YEAR order by ID ), ID, YEAR
from table t

give me following query set:

1   1000415591  2012
1   1000415591  2013
2   1000415591  2013
1   1000415591  2014
2   1000415591  2014

How could I update records with ROW_NUMBER() equals to 2? Other fields of this records is identically ( select distinct from table where id = 1000415591 gives 3 records when there are 5 without distinct keyword), so I can depend only on ROW_NUMBER() value.

I need solution for Oracle, because I saw something similar for SQL-Server but it won't work with Oracle.

You could use a MERGE statement which is quite verbose and easy to understand.

For example,

MERGE INTO t s 
USING
(SELECT ROW_NUMBER() OVER (PARTITION BY ID, YEAR order by ID ) RN,
  ID,
  YEAR
FROM TABLE t
) u ON (s.id = u.id)
WHEN MATCHED THEN
  UPDATE SET YEAR = some_value WHERE u.RN = 2)
/

Note You cannot merge the same column which is used to join in the ON clause.

This is not the update statement but this is how to get the 2 rows you wanted to update:

SELECT * 
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY ID, YEAR order by ID ) as rn, ID, YEAR
from t )
where rn = 2

SQLFIDDLE

Try to use ROWID field:

UPDATE T
SET t.year = t.year*1000
WHERE (rowid,2) in (SELECT rowid,
                           ROW_NUMBER() 
                              OVER (PARTITION BY ID, t.YEAR order by ID ) 
                    FROM T)

SQLFiddle demo

If you need to delete range of ROWNUMBERS then :

UPDATE T
SET t.year = t.year*1000
WHERE rowid in ( SELECT rowid FROM
                 ( 
                   SELECT rowid,
                           ROW_NUMBER() 
                              OVER (PARTITION BY ID, t.YEAR order by ID ) as RN
                    FROM T
                  ) T2 WHERE RN >=2 AND RN <=10
                  )

SQLFiddle demo

When I've posted thq question, I've found that this could be wrong approach. I could modify table and add new fields. So better solution to create one more field IDENTITY and update it with numbers from the new sequence from 1 to total row numbers. Then I could update fields based on this IDENTIY field.

I'll keep this question opened if someone come up with solution based on ROW_NUMBER() analytic function.

update TABLE set NEW_ID = TABLE_SEQ.nextval 
where IDENTITY in (
    select IDENTITY from (
        select row_number() over(PARTITION BY ID, YEAR order by ID) as row_num, t.ID, t."YEAR", t.IDENTITY
        from TABLE t
    ) where row_num > 1
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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