2012-02-02 9 views
11

Si tengo dos consultas, que llamaré horrible_query_1 y ugly_query_2, y quiero llevar a cabo las siguientes dos menos operaciones en ellos:¿Cómo reutilizar una consulta grande sin repetirla?

(horrible_query_1) minus (ugly_query_2) 
(ugly_query_2) minus (horrible_query_1) 

O tal vez tengo una terribly_large_and_useful_query, y establecer el resultado que se obtiene i desea utilizar como parte de varias consultas futuras.

¿Cómo puedo evitar copiar y pegar las mismas consultas en varios lugares? ¿Cómo puedo "no repetirme" y seguir los principios DRY? ¿Es esto posible en SQL?

Estoy usando Oracle SQL. Las soluciones de SQL portátiles son preferibles, pero si tengo que usar una característica específica de Oracle (incluyendo PL/SQL) está bien.

Respuesta

15

Entonces

(horrible_query_1_VIEW) minus (ugly_query_2_VIEW) 

(ugly_query_2_VIEW) minus (horrible_query_1_VIEW) 

O, tal vez, con un with clause:

with horrible_query_1 as (
    select .. .. .. 
    from .. .. .. 
) , 
ugly_query_2 as (
    select .. .. .. 
    .. .. .. 
) 
(select * from horrible_query_1 minus select * from ugly_query_2 ) union all 
(select * from ugly_query_2  minus select * from horrible_query_1) 
+0

Bueno, pero me gustaría manejar artículos únicos a horrible_query_1 diferente que yo manejo los elementos exclusivos de ugly_query_2. ¿Es posible decir con qué conjunto de elementos son únicos con esta consulta? EDITAR: las vistas pueden ser la mejor solución para SQL simple. – Buttons840

+2

Claro, ajuste sus operaciones de dos conjuntos en consultas externas con selecciones que incluyen columnas fijas llamadas Fuente, es decir, 'SELECT 'horrible_query_1' Fuente AS, *' y 'SELECT 'ugly_query_2' Fuente AS, *'. De esa forma, su UNION le dará todas las columnas de su consulta más el identificador de origen. – JamieSee

+1

El último ejemplo, utilizando las "cláusulas with" ha sido muy útil a lo largo de los años desde que originalmente hice esta pregunta. Estas "cláusulas con" a veces se denominan expresiones de tablas comunes (o CTE). Estos son algunos términos útiles que debe conocer al buscar más detalles. Las cláusulas with se agregaron al estándar SQL en 1999, por lo que la mayoría de las bases de datos deberían admitirlas, a excepción de MySQL, que aún no ha implementado esta parte del estándar de hace veinte años. – Buttons840

0

Si opera con los valores, se podría escribir funciones. Aquí encontrará información sobre cómo hacerlo. Básicamente funciona como escribir una función en cualquier idioma. Puede definir parámetros y devolver valores. que le da la gran posibilidad de escribir código solo una vez. Así es cómo se hace:

http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5009.htm

4

Si desea volver a utilizar el texto SQL de las consultas, a continuación, la definición de vistas es la mejor manera, como descriptor anterior.

Si desea volver a utilizar el resultado de las preguntas, entonces usted debería considerar tablas temporales globales. Estas tablas temporales almacenan datos para la duración de la sesión o transacción (cualquiera que elija). Estos son realmente útiles en caso de que necesite reutilizar datos calculados muchas veces, especialmente si sus consultas son de hecho "feas" y "horribles" (es decir, de larga ejecución). Consulte Temporary tables para obtener más información.

Si necesita mantener los datos durante más tiempo que una sesión, puede considerar vistas materializadas.

1

¿Ha intentado utilizar RESULT_CACHE sugerencia en sus consultas? Además, puede

ALTER SESSION SET RESULT_CACHE_MODE=FORCE 

y ver si esto ayuda.

+1

Eso puede ayudar con el rendimiento, pero creo que esta pregunta es más sobre el estilo de codificación. –

1

Dado que está utilizando Oracle, crearía las funciones de MESA Pipeline. La función toma parámetros y devuelve un objeto (que debe crear) y luego SELECCIONA * o incluso columnas específicas a partir de él utilizando la función TABLE() y puede usarlo con una cláusula WHERE o con JOINs. Si desea una unidad de reutilización (una función), no está limitado a devolver solo valores (es decir, una función escalar), puede escribir una función que devuelva filas o conjuntos de registros. algo como esto:

FUNCTION RETURN_MY_ROWS(Param1 IN type...ParamX IN Type) 
      RETURN PARENT_OBJECT PIPELINED 
      IS 
      local_curs cursor_alias; --you need a cursor alias if this function is in a Package 
      out_rec ROW_RECORD_OF_CUSTOM_OBJECT:=ROW_RECORD_OF_CUSTOM_OBJECT(NULL, NULL,NULL) --one NULL for each field in the record sub-object 
     BEGIN 
     OPEN local_curs FOR 
      --the SELECT query that you're trying to encapsulate goes here 
      -- and it can be very detailed/complex and even have WITH() etc.. 
     SELECT * FROM baseTable WHERE col1 = x; 

    -- now that you have captured the SELECT into a Cursor 
    -- here you put a LOOP to take what's in the cursor and put it in the 
    -- child object (that holds the individual records) 
      LOOP 
     FETCH local_curs --opening the ref-cursor 
      INTO out_rec.COL1, 
       out_rec.COL2, 
       out_rec.COL3; 
     EXIT WHEN local_curs%NOTFOUND; 
     PIPE ROW(out_rec); --piping out the Object 
     END LOOP; 
     CLOSE local_curs; -- always do this 
     RETURN; -- we're now done 
    END RETURN_MY_ROWS; 

después de que hayas hecho esto, se puede utilizar como tal

SELECT * FROM TABLE(RETURN_MY_ROWS(val1, val2)); 

puede insertar SELECT o incluso crear TABLA fuera de él, se puede tener en une .

dos más cosas que mencionar:

--ROW_RECORD_OF_CUSTOM_OBJECT is something along these lines 
CREATE or REPLACE TYPE ROW_RECORD_OF_CUSTOM_OBJECT AS OBJECT 
(
    col1 type; 
    col2 type; 
     ... 
    colx type; 
); 

y PARENT_OBJECT es una tabla del otro objeto (con las definiciones de campo) que acaba de hacer

create or replace TYPE PARENT_OBJECT IS TABLE OF ROW_RECORD_OF_CUSTOM_OBJECT; 

por lo que esta función necesita dos objetos para apoyar pero uno es un registro, el otro es una tabla de ese registro (primero debe crear el registro).

En pocas palabras, la función es fácil de escribir, necesita un objeto secundario (con campos) y un objeto principal que albergará ese objeto secundario que es del tipo TABLE del objeto secundario y abre el original tabla base que busca SQL en SYS_REFCURSOR (que puede necesitar alias) si está en un paquete y lee desde ese cursor desde un bucle en los registros individuales. La función devuelve un tipo de PARENT_OBJECT pero dentro de él empaqueta el subobjeto de registros con los valores del cursor.

Espero que esto funcione para usted (puede haber problemas de la concesión de permisos con su DBA si desea crear objetos y funciones de tabla) */

Cuestiones relacionadas