Pregunta

Primero, soy realmente nuevo en pl/pgsql.Lo necesito para un proyecto.

Estoy atrapado con este problema (simplificado).

Mi esquema de base de datos tiene una relación n a m (autor, libros, autor_libros)

Ahora quiero tener una función pl/psgsql insert_book.(Sé que definitivamente todos los autores ya están en la tabla de autores, por lo que solo quiero pasar sus claves principales).

Este esquema de función es lo que tengo en mente.

 create or replace function insert_book(book_to_insert book, authors integer[])
  returns void as $$
begin
    -- insert book into table books
    -- for each author add an entry to author_books table
end;
 $$ language plpgsql;

Como argumentos pensé en pasar un registro del tipo libro y de los autores que lo escribieron.Pero, ¿cómo funcionaría esto exactamente?Busqué bastante en Google y parece que no puedo resolver esto...

Pregunta 1:¿El esquema de la función es "correcto"/tiene sentido?

Pregunta 2:¿Cómo insertar un libro de registro en un libro de mesa?¿Tengo que revisar todos los campos del libro (título, isbn, editorial,...) y agregarlos a una declaración INSERT INTO o existe una forma "más inteligente"?

Pregunta 3:¿Cómo llamaría a mi función insert_book?Encontré este ejemplo aquí (http://dbaspot.com/postgresql/206142-passing-record-function-argument-pl-pgsql.html), pero eso realmente no me ayuda.Para propósitos de prueba estoy usando el shell, pero más adelante usaremos Java con JDBC.

Muchas gracias por su ayuda.

¿Fue útil?

Solución

Usando unnest() y un CTE de modificación de datos (requiere Postgres 9.1 o posterior), esta puede ser una consulta SQL simple:

WITH x AS (SELECT '(1,foo_book)'::book AS _book
                , '{1,2,3}'::int[]     AS _authors)
   , y AS (
   INSERT INTO book  -- no column list, correct due to composite type
   SELECT (x._book).*
   FROM   x
   RETURNING book_id
   )
INSERT INTO author_book (book_id, author_id)
SELECT y.book_id, unnest(x._authors)
FROM   x,y;  -- CROSS JOIN ok, only 1 row for x and y

El primer CTE x es solo para entrada de datos simplificada y no es estrictamente necesario.

Violín SQL.

En cuanto a tus preguntas:

Pregunta 1:¿El esquema de la función es "correcto"/tiene sentido?

Podría ser más fácil pasar tipos base en lugar del tipo compuesto book, pero es un enfoque perfectamente válido.Sin embargo, debes conocer la sintaxis de tipos complejos.Por ejemplo, observe el paréntesis alrededor del nombre en mi ejemplo: (x._book).*.

A función plpgsql podría verse así:

CREATE OR REPLACE FUNCTION f_insert_book(_book book, _authors integer[])
   RETURNS void AS 
$func$
BEGIN
    WITH y AS (
        INSERT INTO book b
        SELECT (_book).*
        RETURNING b.book_id
        )
    INSERT INTO author_book (book_id, author_id)
    SELECT y.book_id, unnest(_authors)
    FROM   y;
END
$func$ LANGUAGE plpgsql;

Pregunta 2:¿Cómo insertar un libro de registro en un libro de mesa?(...) ¿o existe una forma "más inteligente"?

La forma más inteligente es descomponer el tipo compuesto con (variable_name).*.

como el tipo está garantizado que coincida con el table (derivado de él), este es uno de los raros casos en los que está perfectamente bien, no para proporcionar una lista de columnas para el INSERT comando en código persistente.

Pregunta 3:¿Cómo llamaría a mi función insert_book?...

SELECT f_insert_book('(1,foo_book)'::book, '{1,2,3}'::int[]);

Dentro de otras funciones plpgsql, use PERFORM en lugar de SELECT si no proporciona un objetivo (INTO foo) para los resultados (inexistentes).

Otros consejos

Pasando JSON DataType (PostgreSQL 9.2 o superior):

CREATE OR REPLACE FUNCTION f_insert_book(_book json, _authors json)
   RETURNS void AS 
$$
BEGIN
-- insert book into table books
Insert into books values select * from json_populate_recordset(null:book, _book);
    -- for each author add an entry to author_books table
Insert into authors values select * from json_populate_recordset(null:authors, _authors);
end;
$$ language plpgsql;

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top