Why select statement inside stored procedure in PostgreSQL throws error 'column does not exist..? - postgresql

I have this stored procedure in PostgreSQL where I want to make an insert in a table. I get some parameters from the procedure and using them I have tried to select other attributes on other tables.
This is my stored procedure:
CREATE OR REPLACE FUNCTION "public"."prc_sales_invoice_header_insert"("customercode" varchar, "sales_note" varchar, "automatic_payment_id" int4, "cash_register_code" varchar,...etc)
RETURNS "pg_catalog"."void" AS $BODY$
--declaring variables to store data from the tables
DECLARE
salesdate date;
salesdocumentserial varchar;
currencycode varchar;
currencycode2 varchar;
customername varchar;
warehousecode varchar;
......etc.
BEGIN
--getting values from tables and storing to variables
SELECT "name" into customername from public."customers" where "customer_code" = customercode;
SELECT CURRENT_DATE into salesdate;
SELECT max(sales_invoice_header_id) into salesdocumentserial from public."sales_invoice_header";
.....
--inserting values
INSERT INTO public."sales_invoice_header"("sales_date",
"sales_document_serial",
"currency_code",
"currency_code2",
"customer_code",
....
VALUES(
salesdate,
salesdocumentserial,
currencycode,
currencycode2,
customer_code,
.....)
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
When I try to execute it throws an error saying:
"ERROR: column "customer_code" does not exist", "HINT: There is a column named "customer_code" in table "sales_invoice_header", but it cannot be referenced from this part of the query."
Table customers exists and there is a column named costomer_code but I don't understand why it cannot reference it.
Table customers:
-- ----------------------------
-- Table structure for customers
-- ----------------------------
DROP TABLE IF EXISTS "public"."customers";
CREATE TABLE "public"."customers" (
"customer_id" int4 NOT NULL DEFAULT nextval('"Customers_CustomerId_seq"'::regclass),
"customer_code" varchar COLLATE "pg_catalog"."default",
"barcode" varchar COLLATE "pg_catalog"."default",
"qr_code" varchar COLLATE "pg_catalog"."default",
"tax_id" varchar COLLATE "pg_catalog"."default",
"business_id" varchar COLLATE "pg_catalog"."default",
"city_id" int8,
"mobile" varchar COLLATE "pg_catalog"."default",
"accounting_number" varchar COLLATE "pg_catalog"."default",
"name" varchar COLLATE "pg_catalog"."default"
);
Can anyone help me with this, what I am doing wrong? Or is this the correct way of doing things?
Thanks in advance.

INSERT INTO public."sales_invoice_header"("sales_date",
"sales_document_serial",
"currency_code",
"currency_code2",
"customer_code",
....
VALUES(
salesdate,
salesdocumentserial,
currencycode,
currencycode2,
customer_code,
here customer_code is not a variable, nor literal - it is a column name. yet you don't select it form table - you try to use it in VALUES - won't work. either use
insert into ... select ...,customer_code from sales_invoice_header
or
insert into ... values(..., VAR_customer_code)
or
insert into ... values(..., 'value_customer_code')
edit:
as a_horse_with_no_name noticed my VAR_customer_code, must be your customercode first argument?..

Related

i want insert a userid in another table , there is primary key uid in users table and its foreign key in cardtable

Create OR REPLACE PROCEDURE adduser(
fname varchar , lname varchar , pass varchar , uname varchar ,
cnumber integer, cname varchar
)
language SQL
BEGIN ATOMIC
insert into users(firstname , lastname , password , username ) Values (fname , lname , pass , uname);
select * from users AS uids;
insert into users_card (cardnumber , cardname , userid) values (cnumber , cname , uids);
END ;
If I understand you correctly, you want to firstly insert data into user table, after then get userid(uuid) of inserted data and insert this to another table.
Sample:
do
$body$
declare
vuserid uuid;
begin
insert into users (first_name, last_name)
values ('Jon', 'Smith')
returning uids into vuserid;
insert into users_card(card_number, card_name, userid)
values (123, 'test', vuserid);
end;
$body$
language 'plpgsql';

Postgresql aggregate related values using triggers

I have a database representing a payroll system.
Each Payroll is related to several PayrollRows (1 to M relationship), and includes a field summarizing its related payrollRows fields.
Simply said, Payroll includes a field called "amountEurToPay" which is the sum of the "paybackEur" fields of its related PayrollRow records.
I am trying to create a trigger function that automatically completes the amountEurToPay field when a Payroll is created. (indeed it will be created directly with its payrollRow)
I have done this :
-- Generate the trigger function
CREATE OR REPLACE TRIGGER new_payroll_creation
AFTER INSERT
ON "Payroll"
FOR EACH ROW
EXECUTE PROCEDURE populate_payroll_amountEur();
For the function, I tried this, but without any success.
CREATE OR REPLACE FUNCTION populate_payroll_amounteur()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
UPDATE "Payroll"
SET "amountEurToPay" = ( SELECT SUM("paybackEur")
FROM "PayrollRow"
WHERE "payrollId" = NEW."id")
WHERE ("id" = NEW."id");
RETURN NEW;
END;
$$
For extra information, my schema looks like this
model PayrollRow {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
paybackEur Decimal #default(0) #db.Decimal(10, 2)
payroll Payroll #relation(fields: [payrollId], references: [id])
payrollId Int
}
model Payroll {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
amountEurToPay Decimal #default(0) #db.Decimal(10, 2)
payrollRow PayrollRow[]
}
Could you please provide me some support to achieve that? :)
UPDATE--
It seems that that this works (with a preexisting payroll with id 2) for example, I am a bit confused :
CREATE OR REPLACE FUNCTION populate_payroll_amounteur()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
UPDATE "Payroll"
SET "amountEurToPay" = ( SELECT SUM("paybackEur")
FROM "PayrollRow"
WHERE "payrollId" = 2)
WHERE ("id" = NEW."id");
RETURN NEW;
END;
$$
---- UPDATE for MiTKo
If you request the schema definition , actually I use prisma.io ORM , which simplified for me the creation of the schema.
Some reverse engineering would give something like this :
-- CreateTable
CREATE TABLE "Payroll" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"amountEurToPay" DECIMAL(10,2) NOT NULL DEFAULT 0,
CONSTRAINT "Payroll_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "PayrollRow" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"paybackEur" DECIMAL(10,2) NOT NULL DEFAULT 0,
"payrollId" INTEGER NOT NULL,
CONSTRAINT "PayrollRow_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "PayrollRow" ADD CONSTRAINT "PayrollRow_payrollId_fkey" FOREIGN KEY ("payrollId") REFERENCES "Payroll"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Try this (it's working for update and delete as well)
-- Generate the trigger function
CREATE OR REPLACE TRIGGER new_payroll_creation
AFTER INSERT or UPDATE or delete
ON "PayrollRow"
FOR EACH ROW
EXECUTE PROCEDURE populate_payroll_amountEur();
CREATE OR REPLACE FUNCTION populate_payroll_amounteur()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
UPDATE "Payroll"
SET "amountEurToPay" =
(
SELECT COALESCE(SUM("paybackEur") ,0)
FROM "PayrollRow"
WHERE "payrollId" = COALESCE( NEW."payrollId",OLD."payrollId")
)
WHERE ("id" = (COALESCE( NEW."payrollId",OLD."payrollId")));
RETURN NEW;
END;
$$

CREATE TABLE is not allowed in a non-volatile function

I have the following three tables :
create table drugs(
id integer,
name varchar(20),
primary key(id)
);
create table prescription(
id integer,
drug_id integer,
primary key(id),
foreign key(drug_id) references drugs(id)
);
create table visits(
patient_id varchar(10),
prescription_id integer,
primary key( patient_id , prescription_id),
foreign key(prescription_id) references prescription(id)
);
I wrote the following function on these tables to show me a patient's drugs list(the patient id is parameter):
CREATE OR REPLACE FUNCTION public.patients_drugs(
patientid character varying)
RETURNS TABLE(drug_id integer, drug_name character varying)
LANGUAGE 'plpgsql'
COST 100
STABLE STRICT
ROWS 1000
AS $BODY$
begin
create temporary table result_table(
drug_id integer,
drug_name varchar(20)
);
return query select distinct drug.id , drug.name
from visits join prescription
on visits.patient_id = patientID;
end;
$BODY$;
However, it gives me this error:
CREATE TABLE is not allowed in a non-volatile function
You don't need to create a table in order to be able to "return a table". Just get rid of the CREATE TABLE statement.
But your query isn't correct either, as you are selecting columns from the drug table, but you never include that in the FROM clause. You can also get rid of the distinct clause if you don't use a join, but an EXISTS condition:
CREATE OR REPLACE FUNCTION public.patients_drugs(p_patientid character varying)
RETURNS TABLE(drug_id integer, drug_name character varying)
LANGUAGE plpgsql
AS $BODY$
begin
return query
select d.*
from drugs d
where exists (select *
from prescription p
join visits v on v.prescription_id = p.id
where d.id = p.drug_id
and v.patientid = p_patientid);
end;
$BODY$;
Or better, use a simple SQL function:
CREATE OR REPLACE FUNCTION public.patients_drugs(p_patientid character varying)
RETURNS TABLE(drug_id integer, drug_name character varying)
LANGUAGE sql
AS
$BODY$
select d.*
from drugs d
where exists (select *
from prescription p
join visits v on v.prescription_id = p.id
where d.id = p.drug_id
and v.patientid = p_patientid);
$BODY$;

I'm having an issue with this code when I try to input values into the transactions table

So I'm setting up a schema in which I can input transactions of a journal entry independent of each other but also that rely on each other (mainly to ensure that debits = credits). I set up the tables, function, and trigger. Then, when I try to input values into the transactions table, I get the error below. I'm doing all of this in pgAdmin4.
CREATE TABLE transactions (
transactions_id UUID PRIMARY KEY DEFAULT uuid_generate_v1(),
entry_id INTEGER NOT NULL,
post_date DATE NOT NULL,
account_id INTEGER NOT NULL,
contact_id INTEGER NULL,
description TEXT NOT NULL,
reference_id UUID NULL,
document_id UUID NULL,
amount NUMERIC(12,2) NOT NULL
);
CREATE TABLE entries (
id UUID PRIMARY KEY,
test_date DATE NOT NULL,
balance NUMERIC(12,2)
CHECK (balance = 0.00)
);
CREATE OR REPLACE FUNCTION transactions_biut()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
EXECUTE 'INSERT INTO entries (id,test_date,balance)
SELECT
entry_id,
post_date,
SUM(amount) AS ''balance''
FROM
transactions
GROUP BY
entry_id;';
END;
$$;
CREATE TRIGGER transactions_biut
BEFORE INSERT OR UPDATE ON transactions
FOR EACH ROW EXECUTE PROCEDURE transactions_biut();
INSERT INTO transactions (
entry_id,
post_date,
account_id,
description,
amount
)
VALUES
(
'1',
'2019-10-01',
'101',
'MISC DEBIT: PAID FOR FACEBOOK ADS',
-200.00
),
(
'1',
'2019-10-01',
'505',
'MISC DEBIT: PAID FOR FACEBOOK ADS',
200.00
);
After I execute this input, I get the following error:
ERROR: column "id" of relation "entries" does not exist
LINE 1: INSERT INTO entries (id,test_date,balance)
^
QUERY: INSERT INTO entries (id,test_date,balance)
SELECT
entry_id,
post_date,
SUM(amount) AS "balance"
FROM
transactions
GROUP BY
entry_id;
CONTEXT: PL/pgSQL function transactions_biut() line 2 at EXECUTE
SQL state: 42703
There are a few problems here:
You're not returning anything from the trigger function => should probably be return NEW or return OLD since you're not modifying anything
Since you're executing the trigger before each row, it's bound to fail for any transaction that isn't 0 => maybe you want a deferred constraint trigger?
You're not grouping by post_date, so your select should fail
You've defined entry_id as INTEGER, but entries.id is of type UUID
Also note that this isn't really going to scale (you're summing up all transactions of all days, so this will get slower and slower...)
#chirs I was able to figure out how to create a functioning solution using statement-level triggers:
CREATE TABLE transactions (
transactions_id UUID PRIMARY KEY DEFAULT uuid_generate_v1(),
entry_id INTEGER NOT NULL,
post_date DATE NOT NULL,
account_id INTEGER NOT NULL,
contact_id INTEGER NULL,
description TEXT NOT NULL,
reference_id UUID NULL,
document_id UUID NULL,
amount NUMERIC(12,2) NOT NULL
);
CREATE TABLE entries (
entry_id INTEGER PRIMARY KEY,
post_date DATE NOT NULL,
balance NUMERIC(12,2),
CHECK (balance = 0.00)
);
CREATE OR REPLACE FUNCTION transactions_entries() RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
INSERT INTO entries
SELECT o.entry_id, o.post_date, SUM(o.amount) FROM old_table o GROUP BY o.entry_id, o.post_date;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO entries
SELECT o.entry_id, n.post_date, SUM(n.amount) FROM new_table n, old_table o GROUP BY o.entry_id, n.post_date;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO entries
SELECT n.entry_id,n.post_date, SUM(n.amount) FROM new_table n GROUP BY n.entry_id, n.post_date;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER transactions_ins
AFTER INSERT ON transactions
REFERENCING NEW TABLE AS new_table
FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();
CREATE TRIGGER transactions_upd
AFTER UPDATE ON transactions
REFERENCING OLD TABLE AS old_table NEW TABLE AS new_table
FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();
CREATE TRIGGER transactions_del
AFTER DELETE ON transactions
REFERENCING OLD TABLE AS old_table
FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();
Any thoughts on optimization?

column does not exist is postgresql

Here is my sql data.
When I execute this query in postgresql getting some error.
Please help me to correct this. I have no experience in this database.
-- ----------------------------
-- Sequence structure for tuning_id_seq
-- ----------------------------
DROP SEQUENCE IF EXISTS "mainpage"."tuning_id_seq";
CREATE SEQUENCE "mainpage"."tuning_id_seq" INCREMENT 1 START 4000 MAXVALUE 9223372036854775807 MINVALUE 1 CACHE 1;
ALTER TABLE "mainpage"."tuning_id_seq" OWNER TO "postgres";
-- ----------------------------
-- Table structure for tuning
-- ----------------------------
DROP TABLE IF EXISTS "mainpage"."tuning";
CREATE TABLE "mainpage"."tuning" (
"id" int4 NOT NULL DEFAULT nextval("tuning_id_seq"::regclass),
"motor_id" int4,
"speed" int4,
"freetext" varchar(200) COLLATE "default",
"date_create" varchar(30) COLLATE "default",
"date_change" varchar(30) COLLATE "default"
)
WITH (OIDS=FALSE);
ALTER TABLE "mainpage"."tuning" OWNER TO "postgres";
-- ----------------------------
-- Records of tuning
-- ----------------------------
BEGIN;
INSERT INTO "mainpage"."tuning" VALUES ('1', '1', '0', null, null, null);
INSERT INTO "mainpage"."tuning" VALUES ('2', '2', '0', null, null, null);
INSERT INTO "mainpage"."tuning" VALUES ('3', '3', '0', null, null, null);
COMMIT;
Error
NOTICE: table "tuning" does not exist, skipping
ERROR: column "tuning_id_seq" does not exist
********** Error **********
ERROR: column "tuning_id_seq" does not exist
SQL state: 42703
I think the issue is you need to schema-qualify your sequence name.
e.g.:
CREATE TABLE "mainpage"."tuning" (
"id" int4 NOT NULL DEFAULT nextval("mainpage"."tuning_id_seq"::regclass),
"motor_id" int4,
"speed" int4,
"freetext" varchar(200) COLLATE "default",
"date_create" varchar(30) COLLATE "default",
"date_change" varchar(30) COLLATE "default"
)
WITH (OIDS=FALSE);
ALTER TABLE "mainpage"."tuning" OWNER TO "postgres";
Without the qualification, Postgres will look for the sequence in the public (e.g. unqualified) schema. (Since you could, in theory, have a sequence by the same name in each schema).