Postgresql trigger function working but producing duplicates - postgresql

Three Postgresql tables (Windows V 9.1.3)
The table obx is a dynamic table that recieves data from several machines.
We want to produce an after insert trigger function
The table testcode is a fixed table, which contains values we are trying to match to the obx table. If testcode TestID an integer field is not null, we want to insert the data into a new table finaldata using an after insert trigger on the table obx.
The first trigger works, but it produces duplicate data. The trigger has to contain "LIMIT 3" as one of the machines send three results at a time.
Trying second option using SQL only but not working.
The fields marked XY in the table finaldata are for internal use.
CREATE TABLE "public"."obx" (
"obxID" serial primary key,
"Pid" varchar,
"Sid" varchar,
"SidOrig" varchar,
"Parameter" varchar,
"Result" varchar,
"ResultOrig" varchar,
"Units" varchar,
"RefRange" varchar,
"Flag" varchar,
"FlagOrig" varchar,
"OperatorID" varchar,
"ObsTime" char(14),
"MsgTime" char(14),
"UnixTime" int4,
"Analyzer" varchar,
"Segment" varchar
)
;
CREATE TABLE "public"."testcode" (
"TcodeID" serial primary key,
"Analyzer" varchar,
"Parameter" varchar,
"TestName" varchar,
"ShortTestName" varchar,
"TestID" int4
)
;
CREATE TABLE "public"."finaldata" (
"FdataID" serial primary key,
"Pid" varchar,
"Sid" varchar,
"SidOrig" varchar,
"Parameter" varchar,
"Result" varchar,
"ResultOrig" varchar,
"Units" varchar,
"OperatorID" varchar,
"ObsTime" varchar,
"MsgTime" varchar,
"Analyzer" varchar,
"TestName" varchar,
"ShortTestName" varchar,
"TestID" varchar,
"XYchar1" varchar,
"XYchar2" varchar,
"XYchar3" varchar,
"XYint1" int4,
"XYint2" int4,
"XYint3" int4,
"XYGuid" uuid
)
;
DECLARE
var INTEGER;
name text;
short text;
id integer;
BEGIN
SELECT count("TestID") from testcode WHERE "testcode"."Parameter" = NEW."Parameter" into var;
IF var > 0 THEN
SELECT "TestName", "ShortTestName", "TestID" from testcode where "Parameter" = NEW."Parameter" Limit 1 into name, short, id;
INSERT INTO finaldata ("Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units", "OperatorID", "ObsTime", "MsgTime", "Analyzer", "TestName", "ShortTestName", "TestID")
SELECT "Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units", "OperatorID", "ObsTime", "MsgTime", "Analyzer", name, short, id
from obx WHERE "obx"."Parameter" = NEW."Parameter"
LIMIT 3;
END if;
RETURN NEW;
END;
----------------------------
-- Triggers structure for table "public"."obx"
-- ----------------------------
CREATE TRIGGER finaldata_ins
AFTER INSERT ON obx
FOR EACH ROW
EXECUTE PROCEDURE testcode_matches()
;
CREATE FUNCTION testcode_matches()
RETURNS TRIGGER AS $meat$
BEGIN
INSERT INTO finaldata ("Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units", "OperatorID", "ObsTime", "MsgTime", "Analyzer", "TestName", "ShortTestName", "TestID")
SELECT "obx"."Pid", "obx"."Sid", "obx"."SidOrig", "obx"."Parameter", "obx"."Result", "obx"."ResultOrig", "obx"."Units", "obx"."OperatorID", "obx"."ObsTime", "obx"."MsgTime", "obx"."Analyzer", "TestName", "ShortTestName", "TestID"
FROM obx testcode
JOIN obx ON "obx"."Parameter" = "testcode"."Parameter"
WHERE "testcode"."Parameter" = NEW."Parameter"
AND "testcode"."TestID" = NEW."TestID"
;
RETURN NEW;
END;
$meat$
LANGUAGE plpgsql;
----------------------------
-- Triggers structure for table "public"."obx"
-- ----------------------------
CREATE TRIGGER finaldata_ins
AFTER INSERT ON obx
FOR EACH ROW
EXECUTE PROCEDURE testcode_matches()
;

It seems you were confusing yourself by giving obx the correlation name "testcode" :
TESTTABLES:
SET search_path='tmp';
DROP TABLE "obx" CASCADE;
CREATE TABLE "obx" (
"obxID" serial primary key,
"Pid" varchar,
"Sid" varchar,
"SidOrig" varchar,
"Parameter" varchar,
"Result" varchar,
"ResultOrig" varchar,
"Units" varchar,
"RefRange" varchar,
"Flag" varchar,
"FlagOrig" varchar,
"OperatorID" varchar,
"ObsTime" char(14),
"MsgTime" char(14),
"UnixTime" int4,
"Analyzer" varchar,
"Segment" varchar
);
DROP TABLE "testcode" CASCADE;
CREATE TABLE "testcode" (
"TcodeID" serial primary key,
"Analyzer" varchar,
"Parameter" varchar,
"TestName" varchar,
"ShortTestName" varchar,
"TestID" int4
) ;
DROP TABLE "finaldata" CASCADE;
CREATE TABLE "finaldata" (
"FdataID" serial primary key,
"Pid" varchar,
"Sid" varchar,
"SidOrig" varchar,
"Parameter" varchar,
"Result" varchar,
"ResultOrig" varchar,
"Units" varchar,
"OperatorID" varchar,
"ObsTime" varchar,
"MsgTime" varchar,
"Analyzer" varchar,
"TestName" varchar,
"ShortTestName" varchar,
"TestID" varchar,
"XYchar1" varchar,
"XYchar2" varchar,
"XYchar3" varchar,
"XYint1" int4,
"XYint2" int4,
"XYint3" int4,
"XYGuid" uuid
) ;
Function && trigger:
DROP FUNCTION testcode_matches() CASCADE;
CREATE FUNCTION testcode_matches()
RETURNS TRIGGER AS $meat$
BEGIN
INSERT INTO finaldata ("Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units"
, "OperatorID", "ObsTime", "MsgTime", "Analyzer", "TestName", "ShortTestName", "TestID")
SELECT ob."Pid", ob."Sid", ob."SidOrig", ob."Parameter", ob."Result", ob."ResultOrig", ob."Units"
, ob."OperatorID", ob."ObsTime", ob."MsgTime", ob."Analyzer"
, tc."TestName", tc."ShortTestName", tc."TestID"
FROM obx ob
JOIN testcode tc ON ob."Parameter" = tc."Parameter"
WHERE ob."Parameter" = NEW."Parameter"
-- AND ob."TestID" = NEW."TestID" -- Column does not exist
AND ob."obxID" = NEW."obxID" -- This appears to be the PK for obx
;
RETURN NEW;
END;
$meat$ LANGUAGE plpgsql;
CREATE TRIGGER finaldata_ins
AFTER INSERT ON obx
FOR EACH ROW
EXECUTE PROCEDURE testcode_matches()
;
TESTDATA:
INSERT INTO testcode ("TestID", "Parameter") VALUES ( 101, 'Fudge');
INSERT INTO obx -- i"obxID" serial primary key,
( "Pid", "Sid" , "Parameter" ) VALUES ('Foo', 'Bar' ,'Fudge' ) ;
SELECT * FROM finaldata;
Also: I am missing a few foreign key constraints. I would expect the testdata to have at least the same keyfields as obx as candidate key. (plus som version/date,Parameter keyfield) It seems your datamodel is not fit to support the data you feed into it.

Related

Syntax error when making psql Tables one-to-many relation

I`m trying to create some basic DB for my backend API.
I want a one-to many relation with order and order_products so there can be only one order(id) but there can be more rows in "order_products" with the same "order_id" but i get a syntax error:
syntax error at or near "order"
LINE 2: "order_id" int REFERENCES order(id),
^
and i dont know why (This is in the order_products table).
CREATE TABLE IF NOT EXISTS "customers" (
"id" SERIAL PRIMARY KEY,
"first_name" varchar,
"last_name" varchar,
"username" varchar,
"password" varchar,
"email" varchar UNIQUE,
"is_admin" boolean
);
CREATE TABLE IF NOT EXISTS "address" (
"customer_id" int REFERENCES customers(id),
"zipcode" int,
"country" varchar,
"city" varchar,
"street_name" varchar,
"stree_number" varchar,
"mobile_number" int
);
CREATE TABLE IF NOT EXISTS "products" (
"id" SERIAL PRIMARY KEY,
"item_name" varchar UNIQUE,
"description" text,
"image_url" varchar,
"price" float
);
CREATE TABLE IF NOT EXISTS "order" (
"customer_id" int REFERENCES customers(id),
"id" SERIAL PRIMARY KEY,
"date_of_purchase" date,
"total_price" int
);
CREATE TABLE IF NOT EXISTS "order_products" (
"order_id" int REFERENCES order(id),
"product_id" int REFERENCES products(id),
"quantity" int,
"total_price" int,
UNIQUE(order_id, product_id)
);
CREATE TABLE IF NOT EXISTS "cart" (
"customer_id" int REFERENCES customers(id),
"id" SERIAL PRIMARY KEY,
"date_of_purchase" date,
"total_price" int
);
CREATE TABLE IF NOT EXISTS "cart_products" (
"cart_id" int REFERENCES cart(id),
"product_id" int REFERENCES products(id),
"quantity" int,
"total_price" int,
UNIQUE(cart_id, product_id)
);
order is a reserved keyword, so you need to enclose it always in double quotes:
"order_id" int REFERENCES "order"(id),
In general I recommend to never use double quotes. For that you would need to find a different name for the order table that doesn't require quoting

Postgres EXECUTE is slower than Query

I am facing a problem, I have developed a function with dynamic whare clause.
When every I run the query separatly it returns the value much faster while running with EXECUTE it give allot of time. "cv."SessionId" = ''f0d1c0e1-b13c-4aff-b1f7-432183b06d10'' AND cv."CampusId" = ''4f4310a3-9c36-49c2-8456-5604cb7e9a62'' AND cv."ProgramId"=''e50efffa-40a3-4eb9-a65b-65106967add7'' AND cv."ShiftId"=''414de073-ca8b-4a84-80bc-52c2030b4eeb'' AND cv."ProgramDetailId"=''8d1ce321-d015-4336-ba92-dcd2c8b6443b'' AND cv."ClassId"=''8931d744-acc9-4776-a03a-2b705038ea48'' AND cv."SectionId"=''83c507d0-8f61-4a28-b221-88625482953f'' AND cv."CollectorId"=''e58d2fbf-839a-49a1-b1ce-92e7c26a305b'' AND cv."FeeHeadId"=''5721bc8f-4e9c-49d0-a992-6b846fafb9db'' AND cv."PaidDate" >= ''2020-07-01'' AND cv."PaidDate" <= ''2020-08-07'' ORDER BY cv."ChallanNo" ASC" this is where clause parameter which change every time. some time two some time four or five. the following is my function which i want to optimize.
declare feeheadrow record;
declare paiddate date;
declare rollno text;
declare admisformid uuid;
declare feeheadname text;
declare instNo int4;
declare stdname text;
declare fathername text;
declare refno text;
declare classid uuid;
declare campusprogid uuid;
declare stdid uuid;
declare challano text;
declare campusid uuid;
declare sessionid uuid;
declare progdetailid uuid;
declare campusname text;
declare descrip text;
declare shiftname text;
declare genderid uuid;
declare shiftid uuid;
declare remarks text;
declare sessionname text;
declare totalamount int4;
declare programid uuid;
declare collectorid uuid;
BEGIN
DROP TABLE IF EXISTS "FeeReport";
DROP TABLE IF EXISTS "FeeHeads";
create temp table "FeeReport"("NewID" uuid, "PaidDate" Date, "RollNo" text, "AdmissionFormId" uuid, "FeeHeadName" text, "InstallmentNo" int4, "StudentName" text, "FatherName" text, "RefferenceNo" text, "ClassId" uuid, "CampusProgramId" uuid, "FeeHeadId" uuid,
"FeeAmount" int4, "PayableAmount" int4, "StudentId" uuid, "ChallanNo" text, "CampusId" uuid, "SessionId" uuid,
"ProgramDetailId" uuid, "CampusName" text, "Description" text, "ShiftName" text, "GenderId" uuid,
"ShiftId" uuid,"Remarks" text, "ScholarshipCriteriaId" uuid, "ScholarshipCriteriaName" text, "SessionName" text, "TotalAmount" int4
, "ProgramId" uuid, "CollectorId" uuid
) on commit DROP;
create temp table "FeeHeads"("FeeHeadId" UUID, "FullName" TEXT) on commit drop;
insert into "FeeReport"
SELECT * FROM "Query"('cv.*', '"Fee"."VWFeeStatement2" AS cv', whereclause) AS
"FeeRecords" ("NewID" uuid, "PaidDate" date, "RollNo" text, "AdmissionFormId" uuid, "FeeHeadName" text, "InstallmentNo" int4, "StudentName" text, "FatherName" text, "RefferenceNo" text, "ClassId" uuid, "CampusProgramId" uuid, "FeeHeadId" uuid, "FeeAmount" int4, "PayableAmount" int4, "StudentId" uuid, "ChallanNo" text, "CampusId" uuid, "SessionId" uuid, "ProgramDetailId" uuid, "CampusName" text, "Description" text, "ShiftName" text, "GenderId" uuid, "ShiftId" uuid, "Remarks" text, "ScholarshipCriteriaId" uuid, "ScholarshipCriteriaName" text, "SessionName" text, "TotalAmount" int4,"ProgramId" uuid,"CollectorId" uuid);
insert into "FeeReport"
SELECT * FROM "Query"('cv.*', '"Fee"."VWFeeStatementOther2" AS cv', whereclause) AS
"FeeRecords" ("NewID" uuid, "PaidDate" date, "RollNo" text, "AdmissionFormId" uuid, "FeeHeadName" text, "InstallmentNo" int4, "StudentName" text, "FatherName" text, "RefferenceNo" text, "ClassId" uuid, "CampusProgramId" uuid, "FeeHeadId" uuid, "FeeAmount" int4, "PayableAmount" int4, "StudentId" uuid, "ChallanNo" text, "CampusId" uuid, "SessionId" uuid, "ProgramDetailId" uuid, "CampusName" text, "Description" text, "ShiftName" text, "GenderId" uuid, "ShiftId" uuid, "Remarks" text, "ScholarshipCriteriaId" uuid, "ScholarshipCriteriaName" text, "SessionName" text, "TotalAmount" int4,"ProgramId" uuid,"CollectorId" uuid);
insert into "FeeHeads"
SELECT DISTINCT fh."FeeHeadId", fh."FullName" FROM "Fee"."FeeHead" AS fh, "FeeReport" fr
WHERE fr."FeeHeadId" = fh."FeeHeadId";
FOR vwfeestatementrow in select distinct f."AdmissionFormId"
from "FeeReport" f
LOOP
select vw."PaidDate", vw."RollNo", vw."AdmissionFormId", vw."InstallmentNo", vw."StudentName", vw."FatherName" , vw."RefferenceNo", vw."ClassId",
vw."CampusProgramId", vw."StudentId", vw."ChallanNo", vw."CampusId" , vw."SessionId",
vw."ProgramDetailId", vw."CampusName", vw."Description", vw."ShiftName", vw."GenderId",vw."ShiftId", vw."SessionName", vw."TotalAmount",vw."ProgramId",vw."CollectorId"
INTO paiddate,rollno,
admisformid,instNo,stdname,fathername,refno,classid,
campusprogid,stdid,challano,campusid,sessionid,progdetailid,campusname,descrip,shiftname,genderid,shiftid,sessionname,totalamount,programid,collectorid
from "FeeReport" vw where vw."AdmissionFormId"=vwfeestatementrow."AdmissionFormId" limit 1;
FOR feeheadrow IN SELECT fh."FeeHeadId",fh."FullName" FROM "FeeHeads" fh WHERE (fh."FeeHeadId" NOT IN (
SELECT ins."FeeHeadId" FROM "FeeReport" AS ins WHERE ins."AdmissionFormId" = vwfeestatementrow."AdmissionFormId"))
LOOP
INSERT INTO "FeeReport"("NewID","PaidDate","RollNo","AdmissionFormId","FeeHeadName","InstallmentNo","StudentName",
"FatherName","RefferenceNo","ClassId", "CampusProgramId","FeeHeadId",
"FeeAmount", "PayableAmount", "StudentId", "ChallanNo", "CampusId", "SessionId",
"ProgramDetailId", "CampusName", "Description", "ShiftName", "GenderId",
"ShiftId","Remarks", "ScholarshipCriteriaId", "ScholarshipCriteriaName", "SessionName", "TotalAmount","ProgramId",
"CollectorId"
)
VALUES(uuid_generate_v1(),paiddate,rollno,vwfeestatementrow."AdmissionFormId",
feeheadrow."FullName",instNo,stdname,fathername
,refno,classid,campusprogid,feeheadrow.
"FeeHeadId",0,0,stdid,challano,campusid,
sessionid,progdetailid,campusname,descrip,shiftname,genderid,shiftid,'',null,'',
sessionname,totalamount,programid,collectorid
);
END LOOP;
END LOOP;
-- DELETE FROM "Student" AS st WHERE st."AdmissionFormId" IN (SELECT af."AdmissionFormId" FROM "Fee"."StudentFeeStructure" AS sf, "Admission"."AdmissionForm" AS af WHERE sf."AdmissionFormId" = af."AdmissionFormId" AND af."CampusProgramId" = campusprogramid AND sf."ConcessionDetailId" IS NOT NULL);
RETURN query Select fr.* from "FeeReport" as fr ORDER BY fr."ChallanNo", fr."FeeHeadName";
END```

PostgreSQL - How to merge data from multiple rows using join from other tables

I am using postgresql 9.6 and want to merge data from multiple rows into one. I'm using 4 tables(the table format and data cannot be changed)
Tables are-
"id" int4 DEFAULT nextval('product_a_seq'::regclass) NOT NULL,
"name" varchar(255) COLLATE "default",
"organization_id" int4,
"description" text COLLATE "default",
"image" varchar(255) COLLATE "default" DEFAULT 'https://abcd.com'::character varying,
"deleted" bool,
"price" float4,
"currency_id" int4,
CONSTRAINT "product_pkey" PRIMARY KEY ("id")
)
CREATE TABLE "public"."product_asset" (
"id" int4 DEFAULT nextval('product_asset_a_seq'::regclass) NOT NULL,
"product_id" int4,
"asset_type" varchar(255) COLLATE "default",
"asset_url" text COLLATE "default",
"asset_value" text COLLATE "default",
"asset_name" text COLLATE "default",
CONSTRAINT "product_asset_pkey" PRIMARY KEY ("id")
)
CREATE TABLE "public"."user" (
"id" int4 DEFAULT nextval('istar_user_a_seq'::regclass) NOT NULL,
"mobile" varchar COLLATE "default",
"name" varchar(255) COLLATE "default",
"organization_id" int4,
CONSTRAINT "istar_user_pkey" PRIMARY KEY ("id")
)
CREATE TABLE "public"."pipeline_product" (
"pipeline_id" int4 NOT NULL,
"product_id" int4 NOT NULL,
CONSTRAINT "uq_pipeline_product_pipeline_id_product_id" UNIQUE ("pipeline_id", "product_id")
)
For each product there can be multiple assets and pipelines
I want all data grouped according to product.id, here's my initial attempt
SELECT
product. ID AS pid,
product. NAME AS pname,
product.price,
product.currency_id,
product.description,
product_asset.asset_type,
product_asset.asset_url,
product_asset.asset_name,
product_asset.asset_value,
product_asset. ID AS asset_id,
String_agg ( pipeline_product.pipeline_id :: TEXT, ',' ) AS process_id
FROM
product
LEFT JOIN product_asset ON product_asset.product_id = product. ID
AND product_asset.is_active = TRUE
LEFT JOIN pipeline_product ON pipeline_product.product_id = product. ID
WHERE
organization_id IN (
SELECT
"user" .organization_id
FROM
"user"
WHERE
"user" . ID = 218915
)
AND deleted = FALSE
GROUP BY
pid,
product_asset. ID,
product_asset.asset_type,
product_asset.asset_name,
product_asset.asset_url,
product_asset.asset_value
and i get output as:
I need only one entry for the product.id and everything else should be in a single column,
I am using string_agg() function. What am I missing?
I see three issues in your query:
product_asset.asset_url is not unique, use max(product_asset.asset_url)
product_asset.ID is not unique, so you cannot group it. Use min(product_asset.ID) or max(product_asset. ID)
String_agg(pipeline_product.pipeline_id :: TEXT, ',') does not return always the same value, because they are not sorted, You should add ORDER BY pipeline_product.product_id, pipeline_product.pipeline_id.

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

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?..

Oracle database error ORA-00936: missing expression

This query shows error on execution:
SELECT City,Company
FROM invoicelist
WHERE Company='Filmfare'
AND City='Ahmedabad' AND size= 20;
I created this table using this create statement:
create table invoicelist(
"city" varchar(20),
"company" varchar(20),
"month" varchar(20),
"size" varchar(20),
"des" varchar(500)
);
If you quote identifiers with " they become case sensitive.
So either you
select "city" ....
or you create your table without "
create table invoicelist(
city varchar(20),
company varchar(20),
month varchar(20),
size varchar(20),
des varchar(500)
);
BTW, may I recommend you use varchar2 instead of varchar?