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

¿Convertir rápidamente de arreglos de Python a PostgreSQL?

Configuración

Desea crear disparadores (¿repetidamente?) usando la misma función de disparador como se describe en mi respuesta relacionada en dba.SE . Debe pasar valores a la función de activación para crear múltiples filas con múltiples valores de columna, de ahí la matriz bidimensional. (Pero podemos trabajar con cualquier cadena claramente definida!)

La única forma de pasar valores a una función de activación PL/pgSQL (aparte de los valores de columna de la fila de activación) es text parámetros, a los que se puede acceder dentro de la función como 0- matriz de texto basada en la variable de matriz especial TG_ARGV[] . Puede pasar una cantidad variable de parámetros, pero anteriormente discutimos un literal de cadena única que representa su matriz bidimensional.

La entrada proviene de una matriz de Python bidimensional con entero con signo números, que encajan en el tipo de Postgres integer . Utilice el tipo de Postgres bigint para cubrir números enteros sin signo, como comentado .

La representación de texto en Python se ve así:

[[1,2],[3,4]]

Sintaxis para un literal de matriz de Postgres:

{{1,2},{3,4}}

Y desea automatizar el proceso.

Automatización completa

Puede concatenar la cadena para CREATE TRIGGER declaración en su cliente o puede persistir la lógica en una función del lado del servidor y simplemente pasar parámetros.

Demostración de una función de ejemplo que toma un nombre de tabla y la cadena que se pasa a la función de activación. La función de activación insaft_function() se define en su pregunta anterior en dba.SE .

CREATE OR REPLACE FUNCTION f_create_my_trigger(_tbl regclass, _arg0 text)
  RETURNS void
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format($$
      DROP TRIGGER IF EXISTS insaft_%1$s_ids ON %1$s;
      CREATE TRIGGER insaft_%1$s_ids
      AFTER INSERT ON %1$s
      FOR EACH ROW EXECUTE PROCEDURE insaft_function(%2$L)$$
                , _tbl
                , translate(_arg0, '[]', '{}')
      );
END 
$func$;

Llamar:

SELECT f_create_my_trigger('measurements', '[[1,2],[3,4]]');

O:

SELECT f_create_my_trigger('some_other_table', '{{5,6},{7,8}}');

db<>fiddle aquí
Antiguo sqlfiddle

Ahora puede pasar [[1,2],[3,4]] (entre corchetes) o {{1,2},{3,4}} (con llaves). Ambos funcionan igual. translate(_arg0, '[]', '{}' transforma la primera en la segunda forma.

Esta función descarta un disparador con el mismo nombre, si existe, antes de crear uno nuevo. Es posible que desee eliminar o conservar esta línea:

DROP TRIGGER IF EXISTS insaft_%1$s_ids ON %1$s;

Esto se ejecuta con los privilegios del rol de base de datos que llama. Puede hacer que se ejecute con privilegios de superusuario (o cualquier otro) si es necesario. Ver:

Hay muchas maneras de lograr esto. Depende de los requisitos exactos.

Explicando format()

format() y el tipo de datos regclass ayudar a concatenar de forma segura el comando DDL y hacer imposible la inyección de SQL. Ver:

El primer argumento es la "cadena de formato", seguida de los argumentos que se incrustarán en la cadena. Yo uso dollar-quoting , que no es estrictamente necesario para el ejemplo, pero generalmente es una buena idea para concatenar cadenas largas que contienen comillas simples:$$DROP TRIGGER ... $$

format() se modela a lo largo de la función C sprintf . %1$s es un especificador de formato del format() función. Significa que el primero (1$ ) después de insertar la cadena de formato como cadena sin comillas (%s ), por lo tanto:%1$s . El primer argumento para formatear es _tbl en el ejemplo - el regclass El parámetro se representa automáticamente como un identificador legal, entre comillas dobles si es necesario, por lo que format() no tiene que hacer más. Por lo tanto, solo %s , no %I (identificador). Lea la respuesta vinculada arriba para obtener más detalles.
El otro especificador de formato en uso es %2$L :Segundo argumento como literal de cadena entre comillas .

Si eres nuevo en format() , juega con estos sencillos ejemplos para entender:

SELECT format('input -->|%s|<-- here', '[1,2]')
     , format('input -->|%s|<-- here', translate('[1,2]', '[]', '{}'))
     , format('input -->|%L|<-- here', translate('[1,2]', '[]', '{}'))
     , format('input -->|%I|<-- here', translate('[1,2]', '[]', '{}'));

Y lea el manual .