Returning query/table into a variable - sql

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;

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;

How to run many inserts related data into PostgreSQL functions?

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

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.

I'm creating a stored procedure in PostgreSQL, but I get an error 'syntax error at or near "UPDATE"'

I'm creating a stored procedure that changes email address, but I keep getting an error.
ERROR: syntax error at or near "UPDATE"
CREATE FUNCTION change(
IN oldAddr VARCHAR(50),
IN newAddr VARCHAR(50)
) AS
UPDATE accounts
SET a_email = newAddr
WHERE a_email = oldAddr;
I copied this from the textbook, but I don't think it works on PostgreSQL.
Please teach me how to correct it!
Thank you!
CREATE TABLE accounts (
a_id int NOT NULL PRIMARY KEY,
a_first_name varchar(25) NOT NULL,
a_last_name varchar(25) NOT NULL,
a_email varchar(50) NOT NULL,
a_password varchar(16) NOT NULL
);
Try it this way
CREATE OR REPLACE FUNCTION change_account_email(
IN oldAddr VARCHAR(50),
IN newAddr VARCHAR(50))
RETURNS INTEGER AS
$$
DECLARE
rcount INTEGER DEFAULT 0;
BEGIN
UPDATE accounts
SET a_email = newAddr
WHERE a_email = oldAddr;
GET DIAGNOSTICS rcount = ROW_COUNT;
RETURN rcount;
END;
$$
LANGUAGE plpgsql;
Sample usage:
SELECT change_account_email('djohn#example.com', 'new#example.com');
Let's try it:
# INSERT INTO accounts VALUES(1, 'John', 'Doe', 'djohn#example.com', '*********');
INSERT 0 1
# SELECT change_account_email('djohn#example.com', 'new#example.com');
change_account_email
----------------------
1
(1 row)
# SELECT * FROM accounts;
a_id | a_first_name | a_last_name | a_email | a_password
------+--------------+-------------+-----------------+------------
1 | John | Doe | new#example.com | *********
(1 row)
Here is SQLFiddle demo

i am trying to execute the before insert trigger , but i m getting the sql errors

what i want to achieve is i have a table called orders.
i want to perform the before insert trigger on my orders table.i want to capture the
username of person performing INSERT into table.
one table called info which contain the user.
this is my code
create table orders
(
order_id int,
quantity int,
cost int,
total_cost int,
created_date datetime,
created_by varchar(20)
)
create trigger beforeInsertdata
before insert
on orders
for each row
declare
v_username varchar2(10);
begin
-- Find username of person performing INSERT into table
SELECT user INTO v_username
FROM info;
-- Update create_date field to current system date
:new.create_date := sysdate;
-- Update created_by field to the username of the person performing the INSERT
:new.created_by := v_username;
END;
--user information--
create table info
(
userid int ,
user_name varchar(10)
)
insert into info values(1,'vivek')
select * from info
Basically, triggers are classified into two main types:-
1)After Triggers (For Triggers)
2)Instead Of Triggers
and the syntax for trigger is
CREATE TRIGGER trigger_name ON table_name
[FOR|AFTER|INSTEAD OF] [INSERT|UPDATE|DELETE]
AS
//your code goes here
GO
NOTE : FOR keyword used for INSERT |UPDATE Command where as AFTER USED FOR DELETE Command.
It's hard to tell what you're really trying to do. I've modified your code sample so that it will work on SQL2K5 and made some assumptions about how you're wanting to use the connected user account.
CREATE TABLE orders (
order_id int,
quantity int,
cost int,
total_cost int,
created_date datetime,
created_by varchar(20)
);
CREATE TABLE info (
userid int,
user_name varchar(10)
);
INSERT INTO info
VALUES (1, 'vivek');
SELECT *
FROM info;
CREATE TRIGGER orders_InsteadOfInsert ON orders
INSTEAD OF INSERT AS BEGIN
SET NOCOUNT ON;
-- varchar(10) is to match your table, but probably should be larger
DECLARE #CurrentUser VarChar(10);
SELECT #CurrentUser = SYSTEM_USER;
IF (#CurrentUser NOT IN (SELECT user_name FROM info)) BEGIN
-- consider using an identity column for the key instead of this
INSERT INTO info (userid, user_name)
SELECT
ISNULL((SELECT MAX(userid) FROM info), 0) + 1,
#CurrentUser;
END;
INSERT INTO orders (order_id, quantity, cost, total_cost, created_date, created_by)
SELECT
INS.order_id,
INS.quantity,
INS.cost,
INS.total_cost,
GETDATE(),
#CurrentUser
FROM INSERTED INS;
END;