2011-09-06 44 views
7

Estoy tratando de actualizar una tabla en Oracle y estoy teniendo dificultades. Estoy portando mi código desde MySQL y algunos de los comandos que permite MySQL no son compatibles con Oracle.LIMIT/OFFSET en Oracle 11G

Aquí está el código de MySQL:

update table1 t1 set c5 = (select ContractID from table2 t2 where t1.assetid = 
t2.assetid and t1.lastdate >= t2.lastdate and t1.firstdate= t2.firstdate 
order by lastdate asc limit 1 offset 4); 

La sentencia devuelve una lista de ContractIDS, ordenados por últimofecha y sólo quieren una en particular, por lo tanto, el comando de desplazamiento X 1 límite.

El problema es el siguiente. Oracle no admite los comandos "límite" o "desplazamiento". Hay soluciones para el problema límite utilizando rownum y consultas anidadas, pero al analizador Oracle 11G no le gustan en un comando UPDATE.

Tuve un problema similar antes donde necesitaba un límite dentro de un comando de actualización, pero no un desplazamiento. Fue resuelto aquí: MySQL to Oracle Syntax Error (Limit/Offset/Update)

Hay una solución temporal que Florin Ghita encontró utilizando funciones analíticas.

update table1 alf 
    set nextcontractid = 
     (SELECT min(contractid) keep (dense_rank first order by lasttradedate asc) 
     FROM table1copy alf2 
     WHERE alf2.assetid  = alf.assetid 
     AND alf2.lasttradedate > alf.lasttradedate 
    ) 
    where alf.complete = 0 

Esta solución permite que consiga la entrada superior o inferior (mediante el uso de ASC o DESC en el comando DENSE_RANK), pero no soy capaz de encontrar un sustituto para el comando de desplazamiento, si quería el segundo o tercera fila.

Otra solución que he probado utilizaba una consulta anidada. El primero obtuvo las primeras 5 filas usando el comando rownum, las ordenó en el sentido opuesto, el MINUS-ed en las últimas cuatro filas. Esta solución falló porque el analizador de Oracle no entendía la referencia a una tabla en el comando más externo al que se hacía referencia dentro de una de las consultas anidadas.

(mismo problema que yo tenía antes: MySQL to Oracle Syntax Error (Limit/Offset/Update))

El reto no es simplemente para ejecutar una instrucción de selección en el oráculo con un límite y offset, como ya puedo hacerlo a través de consultas anidadas. El desafío es hacer que la instrucción select funcione en una declaración de actualización, porque aunque la declaración es sintácticamente correcta, el analizador de Oracle no puede decodificarlas. Hasta ahora, las consultas anidadas (y Google) me han fallado.

¿Alguien más ha tenido problemas similares?

+1

Si actualiza a 12c, que podría ser capaz de hacer algo como 'actualización tabla1 conjunto t1 c5 = (seleccionar ContractID de t2 tabla2 donde t1.assetid = t2.assetid y t1.lastdate> = t2.lastdate y t1.firstdate = t2.firstdate order por lastdate asc offset 4 buscar next 1 row solamente); ' – beldaz

+0

Relacionado, y probablemente útil si tiene Oracle 12cR1 (o superior): http://stackoverflow.com/a/26051830/1461424 – Krumia

Respuesta

0

eliminados respuesta original, no es viable

me siento esto debería ser factible en una sola instrucción SQL, pero hasta ahora la combinación de la necesidad de una consulta correlacionada y la necesidad de algún tipo de función analítica tiene hizo que todo lo que intenté fallara.

Aquí es un método de procedimiento que creo que va a hacer lo que quiera:

DECLARE 
    CURSOR t IS 
    SELECT LEAD(contractid,4) OVER (PARTITION BY assetid ORDER BY lasttradedate ASC) lead_contractid 
    FROM table1 
    FOR UPDATE; 
BEGIN 
    FOR r IN t LOOP 
    UPDATE table1 SET nextcontractid = r.lead_contractid 
     WHERE CURRENT OF t; 
    END LOOP; 
END; 
+0

No. las consultas anidadas tienen el problema exacto que mencioné anteriormente. La consulta más interna no comprende qué es ALF, aunque esté especificada en la consulta más externa. Error de SQL: ORA-00904: "ALF"."ASSETID": identificador no válido – Brian

+0

@Brian: lo siento, por supuesto que tienes razón. Parece que siempre me olvido de ese problema hasta que me encuentro con él. –

+0

No estoy exactamente seguro de lo que hace el código, pero he encontrado una solución utilizando los conceptos que ha mostrado. (Función LEAD y utilizando un procedimiento almacenado) Básicamente, utilicé un procedimiento almacenado que itera a través de cada entrada en mi tabla, usando rownumber como índice. Busca assetid = el assetID de esa fila lo ordena y obtiene el siguiente contrato utilizando la función principal. Supongo que la solución es usar un procedimiento almacenado. – Brian

Cuestiones relacionadas