2011-01-13 20 views
7

tengo una consulta como esta:Oracle: Obtenga una consulta para devolver siempre exactamente una fila, incluso cuando no hay datos que se encuentran

select data_name 
    into v_name 
    from data_table 
    where data_table.type = v_t_id 

Normalmente, esta consulta debe devolver exactamente una fila. Cuando no hay coincidencia en v_t_id, el programa falla con una excepción "No se encontraron datos".

Sé que podría manejar esto en PL/SQL, pero me preguntaba si hay una manera de hacer esto solo en una consulta. Como prueba, he intentado:

select case 
      when subq.data_name is null then 
      'UNKNOWN' 
      else 
      subq.data_name 
     end 
from (select data_name 
     from data_table 
     where data_table.type = '53' /*53 does not exist, will result in 0 rows. Need fix this...*/ 
     ) subq; 

... pero esto, evidentemente, no va a funcionar (porque subq estar vacía no es lo mismo que subq.data_name is null). ¿Es esto posible o debería simplemente verificar mi solución PL/SQL?

(Oracle 10g)

+1

¿Qué valor se puede esperar/quiere DATA_NAME a tener si la consulta no devuelve ninguna fila? Este es el desafío de lidiar con una condición sin datos encontrados. –

+0

@Thomas: la cadena "DESCONOCIDO" funcionaría bien en este escenario. – FrustratedWithFormsDesigner

Respuesta

18

Hay maneras de hacer esto más simple y más limpio, pero esto básicamente explica la técnica:

SELECT data_name 
FROM data_table 
WHERE data_table.type = v_t_id 

UNION ALL 

SELECT NULL AS data_name 
FROM dual 
WHERE NOT EXISTS (
    SELECT data_name 
    FROM data_table 
    WHERE data_table.type = v_t_id 
) 

Cuando la primera parte de la unión está vacía el segundo contendrá una fila, cuando la primera la parte no está vacía, la segunda no contendrá filas.

Si la consulta es toma mucho tiempo, utilizar éste:

SELECT * FROM ( 
    SELECT data_name 
    FROM data_table 
    WHERE data_table.type = v_t_id 

    UNION ALL 

    SELECT NULL AS data_name 
    FROM dual 
) WHERE data_name is not null or ROWNUM = 1 
+0

Me gusta esta, el 'NOT EXISTS' hace que el significado de todo el asunto sea muy claro. – FrustratedWithFormsDesigner

0

Si siempre esperas cero o una fila, se puede utilizar una función de grupo, es decir:

select dump(max(dummy)) from dual 
where dummy = 'Not Found' 

Usted siempre obtendrá al menos una fila y un valor de NULL en el caso donde no se encuentra el registro.

9

Preferiría manejar la excepción. Sin embargo, esto funcionaría como se especifica:

select min(data_name) data_name 
into v_name 
from data_table 
where data_table.type = v_t_id 

Tenga en cuenta que esto también "funciona" si la consulta devuelve más de 1 fila - es decir, TOO_MANY_ROWS no se eleva.

+0

¡Truco inteligente con 'min'! – FrustratedWithFormsDesigner

1
select coalesce(data_table.data_name, d.data_name) data_name 
    into v_name 
    from 
    (SELECT 'UNKNOWN ' as data_name FROM DUAL) d 
    LEFT JOIN data_table 
    ON data_table.type = v_t_id 
      or a.data_table.data_name is null 
1

Aquí está mi solución sencilla utilizando LEFT OUTER JOIN :

CREATE TABLE data_table(data_name VARCHAR2(20), data_type NUMBER(2)); 

INSERT INTO data_table(data_name, data_type) VALUES('fifty-one', 51); 

SELECT coalesce(data_name, 'unknown') 
    FROM dual 
    LEFT OUTER JOIN (SELECT data_name FROM data_table WHERE data_type = 53) o 
    ON 1 = 1; 

SELECT coalesce(data_name, 'unknown') 
    FROM dual 
    LEFT OUTER JOIN (SELECT data_name FROM data_table WHERE data_type = 51) o 
    ON 1 = 1; 
Cuestiones relacionadas