sql >> Base de Datos >  >> RDS >> PostgreSQL

plpgsql:uso del nombre de la tabla dinámica en la declaración de declaración

Es importante comprender la naturaleza principal de estos cinco diferentes tipos de datos/símbolos :

1. 'my_tbl'

Un literal de cadena de unknown tipo . Cuando se usa en SQL (incrustado en el código plpgsql o no), se fuerza a un tipo derivado del contexto . Si no se puede determinar el tipo, es posible que se requiera una conversión explícita. Como:'my_tbl'::text .

2. 'my_tbl'::text

La misma conversión literal de cadena a escriba text . Puede contener el nombre de una tabla, pero en realidad es solo texto.

3. 'my_tbl'::regclass

Un identificador de objeto (OID) para una clase registrada . Se muestra y se puede ingresar como una cadena que representa un nombre de objeto válido ('my_tbl' ). La salida se califica automáticamente según el esquema ('my_schema.my_tbl' ) y/o entre comillas dobles ('"mY_TbL"' ) si fuera ambiguo o ilegal de otro modo. Puede ser una mesa normal , secuencia , ver , vista materializada , tipo compuesto etc. Detalles en esta respuesta relacionada:

4. my_tbl_var my_tbl (abreviatura de my_tbl_var my_tbl%ROWTYPE )

En el DECLARE sección de un bloque de código plpgsql que es una declaración de variable con un bien conocido tipo de fila (también conocido como tipo compuesto). El tipo tiene que estar registrado en la tabla del sistema pg_class (igual que con una regclass variable). No es el OID del objeto al que se hace referencia, sino su tipo de fila real. my_tbl_var y my_tbl ambos son identificadores aquí y no se puede parametrizar. También puede emitir cualquier fila o registro directamente:(123, 'foo')::my_tbl

5. my_tbl_var record

En el DECLARE sección de un bloque de código plpgsql que es la declaración de un anónimo registro . Básicamente, un marcador de posición para un tipo de fila aún desconocido/con una estructura aún no definida. Se puede utilizar en la mayoría de los lugares se puede utilizar un tipo de fila. Pero no puede acceder a los campos antes de que se asigne la variable de registro.

Estabas confundiendo 1. , 3. y 4. y lo resolvió usando 5. en cambio.
Pero hay más cosas que van mal aquí:

  • Está seleccionando una tabla completa, pero una variable de fila (registro) solo puede contener una fila a la vez. Así que solo se asigna y se devuelve el primero. Mientras no haya ORDER BY cláusula, el resultado es arbitrario y puede cambiar en cualquier momento. Trampa del mal.

  • Dado que ahora está utilizando un record type, debe asegurarse de que se haya asignado antes de poder ejecutar pruebas en sus campos, o obtendrá excepciones para las tablas vacías. En su caso, la verificación record_var IS NULL casi hace el mismo trabajo. Pero hay un caso de esquina para filas con NULL en todos los campos:entonces record_var IS NULL se evalúa como verdadero. Aún más complicado para la prueba IS NOT NULL . Detalles aquí:

    Agregué una demostración al SQL fiddle a continuación.

  • La función devuelve un solo escalar (boolean ) valor. Usar:

    RETURN false;
    

    En lugar de:

    RETURN QUERY SELECT false;

Función

CREATE FUNCTION check_valid(_tbl regclass)
  RETURNS bool AS
$func$
DECLARE
   r record;
   _row_ct int;
BEGIN
   EXECUTE '
   SELECT is_valid, hit_count, hit_limit
   FROM  ' || _tbl || '
   ORDER  <whatever>
   LIMIT  1'            -- replace <whatever> with your sort criteria
   INTO r;              -- only needed columns

   GET DIAGNOSTICS _row_ct = ROW_COUNT;

   IF _row_ct = 0 THEN  -- necessary, because r may not be assigned
      RETURN false;
   ELSIF NOT r.is_valid OR r.hit_count > r.hit_limit THEN
      RETURN false;
   END IF;

   RETURN true;
END
$func$  LANGUAGE plpgsql;

SQL Fiddle (con dos variantes de la función y una demostración para la fila IS NULL).

Puntos principales

  • Utilice GET DIAGNOSTICS para averiguar si se encontraron filas en una instrucción dinámica con EXECUTE .

  • El IF la expresión se puede simplificar.

  • El parámetro es de tipo regclass , no solo un nombre de tabla. No usaría el nombre engañoso "tablename" para este parámetro. Eso solo se suma a su confusión inicial. Llamándolo _tbl en su lugar.

Si quieres también regresar un conjunto de tipo de fila variable: