¿Hay una manera simple en PL / pgSQL para verificar si una consulta no arrojó ningún resultado?

16

Actualmente estoy experimentando un poco con PL / pgSQL y quiero saber si hay una manera más elegante de hacer algo como esto:

select c.data into data from doc c where c.doc_id = id and c.group_cur > group_cur order by c.id desc limit 1;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        select c.data into data from doc c where c.doc_id = id and c.global_cur > global_cur order by c.id desc limit 1;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                RETURN NULL;
icefex
fuente

Respuestas:

21

Los bloques de excepción están destinados a atrapar errores, no a verificar condiciones. En otras palabras, si alguna condición puede manejarse en tiempo de compilación, no debe quedar atrapada como error, sino que debe resolverse mediante la lógica ordinaria del programa.

En la sección Errores de captura de la documentación de PL / PgSQL puede encontrar este consejo:

Consejo: Un bloque que contiene una cláusula EXCEPTION es significativamente más costoso para entrar y salir que un bloque sin uno. Por lo tanto, no use EXCEPCIÓN sin necesidad.

En lugar de utilizar excepciones (malas) o IF / THEN / ELSIF (mejor), puede volver a escribir esto en una consulta:

SELECT c.data into data
FROM  doc c
WHERE c.doc_id = id
  and (
    c.group_cur > group_cur
    or
    c.global_cur > global_cur
  )
ORDER BY
  -- this will make group always preferred over global
  case when c.group_cur > group_cur then 1 else 2 end ASC,
  -- and this is your normal ordering
  c.id DESC
limit 1;

Si realmente desea dos consultas, puede usar una variable FOUND especial para probar si la consulta anterior dio algún resultado:

select c.data into data
from doc c
where c.doc_id = id and c.group_cur > group_cur
order by c.id desc limit 1;
if not found then
    select c.data into data
    from doc c
    where c.doc_id = id and c.global_cur > global_cur
    order by c.id desc limit 1;
    if not found then return null; end if;
end if;

Obligatorio RTFM enlaces folllow :-)

Vea esto para la descripción de la FOUNDvariable, y esto para IF/ THENblocks.

filiprem
fuente
13

Puede examinar una variable especial ENCONTRADA de un tipo booleano. De la documentación:

FOUND comienza falso dentro de cada llamada de función PL / pgSQL. Lo establece cada uno de los siguientes tipos de declaraciones:

Una instrucción SELECT INTO establece FOUND verdadero si se asigna una fila, falso si no se devuelve ninguna fila.

Una instrucción PERFORM establece FOUND verdadero si produce (y descarta) una o más filas, falso si no se produce ninguna fila.

Las instrucciones UPDATE, INSERT y DELETE establecen FOUND verdadero si al menos una fila se ve afectada, falso si ninguna fila se ve afectada.

Una instrucción FETCH establece FOUND verdadero si devuelve una fila, falso si no se devuelve ninguna fila.

Una instrucción MOVE establece FOUND verdadero si reposiciona con éxito el cursor, de lo contrario, falso.

Una instrucción FOR o FOREACH establece FOUND verdadero si itera una o más veces, de lo contrario es falso. FOUND se configura de esta manera cuando sale el bucle; dentro de la ejecución del bucle, FOUND no se modifica mediante la instrucción del bucle, aunque podría modificarse mediante la ejecución de otras instrucciones dentro del cuerpo del bucle.

Las declaraciones RETURN QUERY y RETURN QUERY EXECUTE establecen FOUND true si la consulta devuelve al menos una fila, false si no se devuelve ninguna fila.

Otras declaraciones PL / pgSQL no cambian el estado de FOUND. Tenga en cuenta en particular que EXECUTE cambia la salida de GET DIAGNOSTICS, pero no cambia FOUND.

FOUND es una variable local dentro de cada función PL / pgSQL; cualquier cambio en él afecta solo a la función actual.

alexk
fuente
pero un select intoque no devuelve datos aún generará una excepción, ¿verdad?
Jack dice que intente topanswers.xyz
3
generalmente no, genera excepciones solo si se especifica la cláusula STRICT, como SELECT * INTO STRICT my record ...
alexk
ah sí, mi mal, aunque eso no significa que el controlador de excepciones en el ejemplo de OP nunca se disparará? :-)
Jack dice que intente topanswers.xyz
1
@JackDouglas: los datos generalmente no son motivo de una excepción (excepto en casos especiales como el modificador STRICT anterior). El OP tuvo una idea errónea allí.
Erwin Brandstetter