How to run many inserts related data into PostgreSQL functions? - sql

Im asking for help in this case:
I want to create function for insert data into 3 tables.
CREATE TABLE "public"."loads" (
"id" int4 NOT NULL DEFAULT nextval('loads_id_seq'::regclass),
"user_id" int4 NOT NULL,
"name" varchar(60) COLLATE "pg_catalog"."default",
"weight" float4 NOT NULL,
"capacity" float4,
"packing_type" int4,
"price_request" bool
)
CREATE TABLE "public"."load_loading" (
"load_id" int4 NOT NULL,
"date_from" date,
"date_to" date,
"addr" varchar(120) COLLATE "pg_catalog"."default",
"time_min" varchar(6) COLLATE "pg_catalog"."default",
"time_max" varchar(6) COLLATE "pg_catalog"."default"
)
CREATE TABLE "public"."load_unloading" (
"load_id" int4 NOT NULL,
"date_from" date NOT NULL,
"date_to" date,
"addr" varchar(120) COLLATE "pg_catalog"."default",
"time_min" varchar(6) COLLATE "pg_catalog"."default",
"time_max" varchar(6) COLLATE "pg_catalog"."default"
)
I wrote a function, but cant get any results.
CREATE OR REPLACE FUNCTION "public"."add_load"("load_date_from" date, "loading_addr" varchar, "unloading_date_from" date, "unloading_addr" varchar, "_user_id" int4, "_name" varchar, "_weight" float4, "_capacity" float4, "_packing_type" int4, "_price_request" bool)
RETURNS TABLE("_load" "public"."loads", "_load_load" "public"."load_loading", "_load_unload" "public"."load_unloading") AS $BODY$
BEGIN
RETURN QUERY
WITH _load AS (
INSERT INTO loads(user_id, name, weight, capacity, packing_type, price_request)
VALUES(_user_id, _name, _weight, _capacity, _packing_type, _price_request) RETURNING *)
, _load_load AS (INSERT INTO load_loading (load_id, date_from, addr)
VALUES ((select id from _load), load_date_from, loading_addr) RETURNING *)
, _load_unload AS (INSERT INTO load_unloading(load_id, date_from, addr)
VALUES ((SELECT id FROM _load), unloading_date_from, unloading_addr) RETURNING *)
TABLE _load;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000
When i call she i have this error:
select * from add_load('10-10-2019', 'addr1', '10-11-2019', 'addr2', 123, 'name', 55, 55, 1, true)
> ERROR: structure of query does not match function result type
DETAIL: Returned type integer does not match expected type loads in column 1.
CONTEXT: PL/pgSQL function add_load(date,character varying,date,character varying,integer,character varying,real,real,integer,boolean) line 3 at RETURN QUERY
I expect from my function see result like all columns from 3 tables;
And another question, is there a way to get the result like this:
id, user_id, name, weight, capacity, packing_type, price_request, {load_loading data}, {load_unloading_data}

The error above is because the function returns :
RETURNS TABLE(_load loads, _load_load load_loading, _load_unload load_unloading) AS $BODY$
and your query returns:
| id | user_id | name | weight | capacity | packing_type | price_request |
If you remove this part:
, _load_load load_loading, _load_unload load_unloading
The function will work as in my DEMO
And for your second question:
You should name every column by it's own to do that.
Here is the DEMO for that result.
And here is the function:
CREATE OR REPLACE FUNCTION add_load(load_date_from date
, loading_addr varchar(140)
, unloading_date_from date
, unloading_addr varchar(140)
, _user_id int4
, _name varchar(140)
, _weight float4
, _capacity float4
, _packing_type int4
, _price_request bool)
RETURNS TABLE( id int4, user_id1 int4, name varchar(60), weight float4, capacity float4,
packing_type int4, price_request bool, load_id1 int4, date_from1 date,
date_to1 date, addr1 varchar(120), time_min1 varchar(6),
time_max1 varchar(6), load_id2 int4, date_from2 date, date_to2 date,
addr2 varchar(120), time_min2 varchar(6), time_max2 varchar(6)
) AS $BODY$
BEGIN
RETURN QUERY
WITH _load AS (
INSERT INTO loads(user_id, name, weight, capacity, packing_type, price_request)
VALUES(_user_id::int, _name::varchar, _weight::float, _capacity::float, _packing_type::int, _price_request::bool) RETURNING *)
, _load_load AS (INSERT INTO load_loading (load_id, date_from, addr)
VALUES ((select user_id::int from loads), load_date_from::date, loading_addr::varchar) RETURNING *)
, _load_unload AS (INSERT INTO load_unloading(load_id, date_from, addr)
VALUES ((SELECT user_id::int FROM loads), unloading_date_from::date, unloading_addr::varchar) RETURNING *)
select * from _load, _load_load, _load_unload;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000

Related

Function not giving a response

I have created a database for an airline that currently has 3 tables: Table1: FLIGHTS, Table2: Clients, Table3: Reservation, and I want to create a function that returns the time left in the month from the reservation made till the flights date inside a function. After I run it, nothing is returning. Any tips?
DROP DATABASE if exists Chartered_Airlines;
CREATE DATABASE Chartered_Airlines;
USE Chartered_Airlines;
CREATE TABLE FLIGHTS(FLIGHT_NO INT(5) NOT NULL, DEPARTURE VARCHAR(15), ARRIVAL VARCHAR(15), TYPEFL VARCHAR(15), SEATS INT(4) NOT NULL, FREE_SEATS INT(4), FLIGHT_DATE DATE,
PRIMARY KEY(FLIGHT_NO));
CREATE TABLE CUSTOMERS(CL_NO INT(5) NOT NULL, LAST_NAME VARCHAR(15) NOT NULL, FIRST_NAME VARCHAR(15) NOT NULL, CITIZENSHIP VARCHAR(15) NOT NULL, B_DATE DATE,
PRIMARY KEY(CL_NO));
CREATE TABLE RESERVATIONS(RES_NO INT(5) NOT NULL, CL_NO INT(5) NOT NULL, FLIGHT_NO INT(5), COST FLOAT(15), RES_DATE DATE,
PRIMARY KEY(RES_NO),
FOREIGN KEY(FLIGHT_NO) REFERENCES FLIGHTS(FLIGHT_NO),
FOREIGN KEY(CL_NO) REFERENCES CUSTOMERS(CL_NO));
SHOW TABLES;
INSERT INTO FLIGHTS VALUES(10,'ATHENS','LONDON','EXTERNAL',310,34, '2023/10/04');
INSERT INTO FLIGHTS VALUES(20,'ATHENS','MYKONOS','INTERNAL',100,5, '2022/12/12');
INSERT INTO FLIGHTS VALUES(30,'ATHENS','PARIS','EXTERNAL',256,16, '2022/09/07');
INSERT INTO CUSTOMERS VALUES(5472,'ALEKSANDRAKIS','GEORGIOS','GREECE','1989/01/01');
INSERT INTO CUSTOMERS VALUES(1354,'STAVROU','ANTREAS','GREECE','1977/07/07');
INSERT INTO CUSTOMERS VALUES(6598,'AMALFIO','ROBERTO','ITALY','1995/05/02');
INSERT INTO CUSTOMERS VALUES(1953,'EUSTATHIOU','NIKOS','GREECE','2001/06/03');
INSERT INTO CUSTOMERS VALUES(1387,'STAKAS','VASILLIS','GREECE','1990/01/07');
INSERT INTO RESERVATIONS VALUES(3174,5472,10,6482, '2020/03/02');
INSERT INTO RESERVATIONS VALUES(3143,1354,10,6482, '2021/05/09');
INSERT INTO RESERVATIONS VALUES(1286,6598,20,662, '2022/10/12');
INSERT INTO RESERVATIONS VALUES(3275,1953,20,662, '2022/09/08');
INSERT INTO RESERVATIONS VALUES(7654,1387,30,264, '2022/09/06');
SELECT * FROM FLIGHTS;
SELECT * FROM CUSTOMERS;
SELECT * FROM RESERVATIONS;
DESC FLIGHTS;
DESC RESERVATIONS;
DESC CUSTOMERS;
DELIMITER //
CREATE FUNCTION TIME_LEFT(RES_NO INT) RETURNS INT
DETERMINISTIC
BEGIN
DECLARE TIME_LEFT INT DEFAULT 0;
SELECT TIMESTAMPDIFF(MONTH,RESERVATIONS.RES_DATE,FLIGHTS.FLIGHT_DATE) INTO TIME_LEFT FROM RESERVATIONS
WHERE RES_NO = RES_NO AND RESERVATIONS.FLIGHT_NO = FLIGHTS.FLIGHT_NO ;
RETURN TIME_LEFT;
END;
//
SELECT TIME_LEFT(3143);
I was expecting that it returns the date difference between reservation made date and flight date
Your forgot to use join and also use a variable name for holding the value passed in function:
DELIMITER //
CREATE FUNCTION TIME_LEFT(VAR_RES_NO INT) RETURNS INT
DETERMINISTIC
BEGIN
DECLARE TIME_LEFT INT DEFAULT 0;
SELECT TIMESTAMPDIFF(MONTH,RESERVATIONS.RES_DATE,FLIGHTS.FLIGHT_DATE) INTO TIME_LEFT FROM RESERVATIONS join FLIGHTS
WHERE RES_NO = VAR_RES_NO AND RESERVATIONS.FLIGHT_NO = FLIGHTS.FLIGHT_NO ;
RETURN TIME_LEFT;
END;
//
I think you need to include the table Flights in the SELECT statement, as well as specify the difference between RES_NO in the input vs reservations e.g.,
CREATE FUNCTION TIME_LEFT(RES_NO_in INT) RETURNS INT
DETERMINISTIC
BEGIN
DECLARE TIME_LEFT INT DEFAULT 0;
SELECT TIMESTAMPDIFF(MONTH,RESERVATIONS.RES_DATE,FLIGHTS.FLIGHT_DATE) INTO TIME_LEFT
FROM RESERVATIONS, FLIGHTS
WHERE RESERVATIONS.RES_NO = RES_NO_in AND RESERVATIONS.FLIGHT_NO = FLIGHTS.FLIGHT_NO;
RETURN TIME_LEFT;
END;
or
CREATE FUNCTION TIME_LEFT(RES_NO_in INT) RETURNS INT
DETERMINISTIC
BEGIN
DECLARE TIME_LEFT INT DEFAULT 0;
SELECT TIMESTAMPDIFF(MONTH,RESERVATIONS.RES_DATE,FLIGHTS.FLIGHT_DATE) INTO TIME_LEFT
FROM RESERVATIONS
INNER JOIN FLIGHTS ON RESERVATIONS.FLIGHT_NO = FLIGHTS.FLIGHT_NO
WHERE RESERVATIONS.RES_NO = RES_NO_in;
RETURN TIME_LEFT;
END;

Oracle Object-Relational - Is there a way to declare a nested table of a subtype?

Type declaration:
CREATE TYPE DIPENDENTE_TY AS OBJECT(
NOME VARCHAR2(20),
CF CHAR(16),
DATAN DATE
) NOT FINAL;
/
CREATE TYPE AMMINISTRATORE_TY UNDER DIPENDENTE_TY(
);
/
CREATE TYPE MEDICO_TY UNDER DIPENDENTE_TY(
SPECIALITA VARCHAR2(20),
REPARTO VARCHAR2(20),
MEMBER PROCEDURE INSERISCI_VISITA(PAZIENTE VARCHAR,
DATAV DATE,
TIPOV VARCHAR2,
TICKET INTEGER)
);
/
CREATE TYPE PAZIENTE_TY AS OBJECT(
CF CHAR(16),
NOME VARCHAR2(20),
COGNOME VARCHAR2(20)
);
/
CREATE TYPE VISITA_TY AS OBJECT(
DATA DATE,
TIPO VARCHAR2(20),
TICKET INTEGER
);
/
CREATE TYPE COLL_REF_VISITA_TY AS TABLE OF REF VISITA_TY;
/
ALTER TYPE MEDICO_TY ADD ATTRIBUTE VISITATO COLL_REF_VISITA_TY;
/
ALTER TYPE PAZIENTE_TY ADD ATTRIBUTE FA_VISITA COLL_REF_VISITA_TY;
/
ALTER TYPE VISITA_TY ADD ATTRIBUTE DIP REF PAZIENTE_TY CASCADE;
/
ALTER TYPE VISITA_TY ADD ATTRIBUTE DIM REF MEDICO_TY CASCADE;
/
CREATE TABLE PAZIENTE_TAB OF PAZIENTE_TY
NESTED TABLE FA_VISITA STORE AS VISITE_PAZIENTE_TAB;
/
CREATE TABLE DIPENDENTE_TAB OF DIPENDENTE_TY;
/
CREATE TABLE VISITA_TAB OF VISITA_TY;
--(
--DIP SCOPE IS PAZIENTE_TAB,
--DIM SCOPE IS DIPENDENTE_TAB
--);
/
I need to declare the VISITATO nested table of Medico_ty, but it is a subtype of Dipendente_ty and so I only have the table for instances of type Dipendente_ty. How can I declare the nested table only for the Medico_ty instances?
EDIT
I get the following error when I try to define the table for Dipendente_ty:
ORA-02320: failure in creating storage table for nested table column TREAT(SYS_NC_ROWINFO$ AS "SQL_PFOHOKUIIIAMJALHSUZHUBDGJ"."MEDICO_TY")."VISITATO" ORA-06512: at "SYS.DBCLOUD_SYS_SEC", line 1404
ORA-06512: at "SYS.DBCLOUD_SYS_SEC", line 2224
ORA-06512: at line 2
You do not need to declare a nested table for the sub-type (and can use forward declaration of the types to get rid of all of your ALTER statements):
CREATE TYPE DIPENDENTE_TY AS OBJECT(
NOME VARCHAR2(20),
CF CHAR(16),
DATAN DATE
) NOT FINAL;
CREATE TYPE AMMINISTRATORE_TY UNDER DIPENDENTE_TY();
CREATE TYPE MEDICO_TY;
CREATE TYPE PAZIENTE_TY;
CREATE TYPE VISITA_TY AS OBJECT(
DATA DATE,
TIPO VARCHAR2(20),
TICKET INTEGER,
DIP REF PAZIENTE_TY,
DIM REF MEDICO_TY
);
CREATE TYPE COLL_REF_VISITA_TY AS TABLE OF REF VISITA_TY;
CREATE TYPE MEDICO_TY UNDER DIPENDENTE_TY(
SPECIALITA VARCHAR2(20),
REPARTO VARCHAR2(20),
VISITATO COLL_REF_VISITA_TY,
MEMBER PROCEDURE INSERISCI_VISITA(
PAZIENTE VARCHAR,
DATAV DATE,
TIPOV VARCHAR2,
TICKET INTEGER
)
);
CREATE TYPE PAZIENTE_TY AS OBJECT(
CF CHAR(16),
NOME VARCHAR2(20),
COGNOME VARCHAR2(20),
FA_VISITA COLL_REF_VISITA_TY
);
CREATE TABLE DIPENDENTE_TAB OF DIPENDENTE_TY;
CREATE TABLE PAZIENTE_TAB OF PAZIENTE_TY
NESTED TABLE FA_VISITA STORE AS VISITE_PAZIENTE_TAB;
CREATE TABLE VISITA_TAB OF VISITA_TY(
DIP SCOPE IS PAZIENTE_TAB,
DIM SCOPE IS DIPENDENTE_TAB
);
ALTER TABLE VISITE_PAZIENTE_TAB
ADD SCOPE FOR ( COLUMN_VALUE ) IS VISITA_TAB;
Then you can create the data:
INSERT INTO visita_tab VALUES ( VISITA_TY( SYSDATE, 'tipo1', 1, NULL, NULL ) );
INSERT INTO visita_tab VALUES ( VISITA_TY( SYSDATE, 'tipo2', 2, NULL, NULL ) );
INSERT INTO visita_tab VALUES ( VISITA_TY( SYSDATE, 'tipo3', 3, NULL, NULL ) );
INSERT INTO DIPENDENTE_TAB VALUES (
MEDICO_TY(
'nome',
'cf______________',
SYSDATE,
'specialita',
'reparto',
COLL_REF_VISITA_TY(
( SELECT REF(v) FROM visita_tab v WHERE ticket = 1 ),
( SELECT REF(v) FROM visita_tab v WHERE ticket = 2 )
)
)
);
INSERT INTO visita_tab VALUES (
VISITA_TY(
SYSDATE,
'tipo4',
4,
NULL,
( SELECT TREAT(REF(m) AS REF MEDICO_TY)
FROM dipendente_tab m
WHERE nome = 'nome'
AND VALUE(m) IS OF ( MEDICO_TY )
)
)
);
The MEDICO_TY value is stored in the DIPENDENTE_TAB without the need for a nested table for the collection defined in the sub-type.
You can get the data out using:
SELECT data,
tipo,
ticket,
v.dim.nome,
v.dim.cf,
v.dim.datan,
v.dim.specialita,
v.dim.reparto,
dv.column_value.tipo
FROM visita_tab v
OUTER APPLY v.dim.VISITATO dv;
db<>fiddle here

Returning query/table into a variable

Following the instructions from here, I am trying to return the results of a query into a variable like so
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
\c test
CREATE TABLE staff(
id BIGSERIAL PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
age SMALLINT
);
CREATE FUNCTION get_contacts(
p_id_min BIGINT,
p_id_max BIGINT,
p_age_min BIGINT,
p_age_max BIGINT
)
RETURNS #contacts TABLE (
first_name VARCHAR(50),
last_name VARCHAR(50)
)
AS
BEGIN
INSERT INTO #contacts
SELECT
first_name,
last_name
FROM
staff
WHERE
id >= p_id_min
AND
id <= p_id_max;
INSERT INTO #contacts
SELECT
first_name,
last_name
FROM
staff
WHERE
age >= p_age_min
AND
age <= p_age_max;
RETURN;
END;
But I am getting the following error
DROP DATABASE
CREATE DATABASE
You are now connected to database "test" as user "postgres".
CREATE TABLE
psql:test.sql:31: ERROR: syntax error at or near "#"
LINE 5: RETURNS #contacts TABLE (
^
psql:test.sql:33: ERROR: syntax error at or near "RETURN"
LINE 1: RETURN;
^
psql:test.sql:34: WARNING: there is no transaction in progress
COMMIT
I have 2 questions:
Why am I getting the syntax error at or near "#" and how do I fix thix?
What is the significance of # at the beginning of a variable name?
Turns out, in Postgres, the RETURN command can be used multiple times, so I just did the following
CREATE FUNCTION get_contacts(
p_id_min BIGINT,
p_id_max BIGINT,
p_age_min BIGINT,
p_age_max BIGINT
)
RETURNS TABLE(
id BIGINT,
first_name VARCHAR(50),
last_name VARCHAR(50),
age SMALLINT
)
AS $$
BEGIN
--RETURN FIRST QUERY
RETURN QUERY
SELECT * FROM staff
WHERE id >=p_id_min AND id<=p_id_max;
--DO OTHER WORK
...
--RETURN SECOND QUERY
RETURN QUERY
SELECT * FROM staff
WHERE age >=p_age_min AND age<=p_age_max;
END $$ LAnguage 'plpgsql';
Author was initially using # for parameters. For code you might also try this
CREATE FUNCTION get_contacts(
p_id_min BIGINT,
p_id_max BIGINT,
p_age_min BIGINT,
p_age_max BIGINT
)
RETURNS TABLE (
first_name VARCHAR(50),
last_name VARCHAR(50)
)
AS $$
BEGIN
INSERT INTO #contacts
SELECT
first_name,
last_name
FROM
staff
WHERE
id >= p_id_min
AND
id <= p_id_max;
INSERT INTO #contacts
SELECT
first_name,
last_name
FROM
staff
WHERE
age >= p_age_min
AND
age <= p_age_max;
RETURN;
END;

Teradata error SPL 1076 - The right parenthesis in parameter declaration is missing

I have created a blank table in Teradata called EMPLOYEE
CREATE MULTISET VOLATILE TABLE EMPLOYEE (
EmployeeNo INTEGER,
FirstName VARCHAR(30),
LastName VARCHAR(30),
DOB DATE FORMAT 'YYYY-MM-DD',
JoinedDate DATE FORMAT 'YYYY-MM-DD',
DepartmentNo BYTEINT
)
PRIMARY INDEX ( EmployeeNo ) On COMMIT PRESERVE ROWS;
Table is created.
Now i am trying to define a procedure to enter data into the table.
CREATE PROCEDURE InsertEmployee (
IN in_EmployeeNo INTEGER, IN in_FirstName VARCHAR(30),
IN in_LastName VARCHAR(30), IN in_DOB DATE FORMAT 'YYYY-MM-DD',
IN in_JoinedDate DATE FORMAT 'YYYY-MM-DD', IN in_DepartmentNo BYTEINT
)
BEGIN
INSERT INTO EMPLOYEE(
EmployeeNo,
FirstName,
LastName,
DOB,
JoinedDate,
DepartmentNo
)
VALUES (
:in_EmployeeNo,
:in_LastName,
:in_FirstName,
:in_DOB,
:in_JoinedDate,
:in_DepartmentNo
);
END;
This is where I repeatedly get 2 errors:
SPL1076:E(L3), The right parenthesis in parameter declaration is missing.
SPL1048:E(L3), Unexpected text ';' in place of SPL statement.

PgAdmin Function return type

I am creating a stored procedure in PgAdmin to insert data into a table from different tables. I have tried the following code but I am being asked for a return type. What do I need to add?
Also, how do I use this procedure to insert the data into the table from different tables?
CREATE OR REPLACE FUNCTION stager.ProductDimSP
(
cat_name character varying(25) ,
pr_name character varying(40) ,
pr_id character varying(6) ,
disc boolean
) RETURNS NULL ON NULL INPUT AS
$$
BEGIN
INSERT INTO stager."ProductDimTable"
(
category_name, product_name, product_id, discontinued
)
VALUES
(
cat_name, pr_name, pr_id, disc
)
END
$$
LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION stager.ProductDimSP
(
cat_name character varying(25) ,
pr_name character varying(40) ,
pr_id character varying(6) ,
disc boolean
)
RETURNS VOID -- this defines a function with no return value
AS
$$
BEGIN
INSERT INTO stager."ProductDimTable"
(
category_name, product_name, product_id, discontinued
)
VALUES
(
cat_name, pr_name, pr_id, disc
); -- this semicolon was also missing
END
$$
LANGUAGE plpgsql; -- do not put the language name in quotes