2011-05-23 187 views
16

Quiero rellenar una columna de tabla con un número entero en ejecución, así que estoy pensando en usar ROWNUM. Sin embargo, necesito poblarlo según el orden de otras columnas, algo así como ORDER BY column1, column2. Esto es, por desgracia, no es posible ya que Oracle no se hace la siguiente declaración:Oracle: Actualización de una columna de tabla usando ROWNUM junto con la cláusula ORDER BY

UPDATE table_a SET sequence_column = rownum ORDER BY column1, column2; 

Tampoco la siguiente afirmación (un intento de utilizar la cláusula WITH):

WITH tmp AS (SELECT * FROM table_a ORDER BY column1, column2) 
UPDATE tmp SET sequence_column = rownum; 

Entonces, ¿cómo lo hago usando una instrucción SQL y sin recurrir al método de iteración del cursor en PL/SQL?

+2

Tan pronto a medida que se completa la instrucción y se produce otra operación DML, el 'sequence_col umn' será incorrecto/desactualizado. ¿Por qué no poner sequence_column (y la numeración) en una vista? Eso siempre será correcto. –

+0

@Damien_The_Unbeliever No estoy seguro si te entiendo, pero no hay ninguna preocupación con la futura inserción de registros en la tabla porque la columna tiene un índice único y el script que realiza la inserción está garantizado, coloca el siguiente número en ejecución en la columna. Es solo que a veces cuando se eliminan los registros, la columna ya no es secuencial y debe volver a secuenciarse. – Lukman

+0

@Lukman, estoy de acuerdo con Damien. Es mejor calcular 'ROWNUM' o' ROW_NUMBER() 'sobre la marcha –

Respuesta

26

Esto debería funcionar (funciona para mí)

update table_a outer 
set sequence_column = (
    select rnum from (

      -- evaluate row_number() for all rows ordered by your columns 
      -- BEFORE updating those values into table_a 
      select id, row_number() over (order by column1, column2) rnum 
      from table_a) inner 

    -- join on the primary key to be sure you'll only get one value 
    -- for rnum 
    where inner.id = outer.id); 

O se utiliza la instrucción MERGE. Algo como esto.

merge into table_a u 
using (
    select id, row_number() over (order by column1, column2) rnum 
    from table_a 
) s 
on (u.id = s.id) 
when matched then update set u.sequence_column = s.rnum 
+0

Oracle devuelve el error: 'ORA-30483: las funciones de ventana no están permitidas aquí' cuando lo uso en la cláusula' SET'> __ <.. – Lukman

+0

Ver mi actualización. Lo he intentado con una tabla más simple. Le dará una idea para una solución para su situación –

+0

Ejecuté la declaración y todavía está ejecutándose en este momento, casi 5 minutos. La tabla solo tiene unos 15K registros, así que la lentitud es extraña. – Lukman

2
UPDATE table_a 
    SET sequence_column = (select rn 
          from (
           select rowid, 
             row_number() over (order by col1, col2) 
           from table_a 
          ) x 
          where x.rowid = table_a.rowid) 

Pero eso no va a ser muy rápido y como Damien señaló, hay que volver a ejecutar esta declaración cada vez que cambie los datos de esa tabla.

2

En primer lugar crear una secuencia:

CREATE SEQUENCE SEQ_SLNO 
    START WITH 1 
    MAXVALUE 999999999999999999999999999 
    MINVALUE 1 
    NOCYCLE 
    NOCACHE 
    NOORDER; 

después de que actualizan la tabla usando la secuencia:

UPDATE table_name 
SET colun_name = SEQ_SLNO.NEXTVAL; 
+1

¿Qué pasa con la parte "PEDIR POR"? – Lukman

1

Una pequeña corrección sólo tiene que añadir AS RN:

UPDATE table_a 
    SET sequence_column = (select rn 
          from (
           select rowid, 
             row_number() over (order by col1, col2) AS RN 
           from table_a 
          ) x 
          where x.rowid = table_a.rowid) 
Cuestiones relacionadas