I have a table in PostgreSQL (mixbest) with 73018 rows. The fields that I want to select are:
sample integer
m integer,
pciv double precision,
aggrec double precision
soil character(1)
I'm trying a SELECT but I get the following error SQLstate: 22003 numeric overflow. My select:
SELECT sample, m, 1-(EXP(SUM(LN(1-pciv)))) pciv, avg (aggrec) aggrec_avg, soil
FROM mixbest
GROUP BY sample, m, soil;
I know the problem is the EXP() due to I've tried the same select with the expression (SUM(LN(1-pciv)))) and I don't get the same error.
I tried to execute the select only in a few lines, and it works:
SELECT sample, m, 1-(EXP(SUM(LN(1-pciv)))) pciv, avg (aggrec) aggrec_avg, soil
FROM mixbest
WHERE sample< 4492 GROUP BY sample, m, soil;
Do you have any suggestion?
Something like this, I guess:
create or replace function mixbest_avg(out sample int, out m int, out pciv double precision, out aggrec_avg double precision, out soil character(1))
returns setof record as
$$
declare
rec record;
begin
for rec in
SELECT t.sample _sample, t.m _m, SUM(LN(1-t.pciv)) _pciv, avg(t.aggrec) _aggrec, t.soil _soil
FROM mixbest t
GROUP BY t.sample, t.m, t.soil
loop
begin
rec._pciv = 1 - exp(rec._pciv);
exception
when numeric_value_out_of_range then -- here we catch an exception
rec._pciv = 0; -- or other default value
end;
select rec._sample, rec._m, rec._pciv, rec._aggrec, rec._soil into sample, m, pciv, aggrec_avg, soil;
return next;
end loop;
end
$$ language plpgsql;
Can anyone help me with this procedure? It's a pretty simple one, just want to insert some data into a table, but pgAdmin is giving me some errors.
This is the procedure code:
CREATE OR REPLACE FUNCTION FILL_INVOICE2(IN_NUM integer)
RETURNS void AS
DECLARE
counter numeric := 0;
BEGIN
IF in_num > 1 THEN
WHILE counter < 10
LOOP
INSERT INTO INVOICE(ID,INVOICE_ID,SUBSCRIBER_ID,AMOUNT,INVOICE_DATE,RECORD_DATE,INVOICE_TYPE,REST_TO_PAY,DESCRIPTION,INVOICE_REFERENCE)
VALUES(counter,counter,counter,100,current_date,current_date,1,100,'Telco services',1111);
counter := counter + 1;
RAISE NOTICE 'The counter is %', counter;
END LOOP;
END IF;
RETURN;
END;
Error is:
ERROR: syntax error at or near "DECLARE counter numeric"
LINE 3: DECLARE
^
********** Error **********
ERROR: syntax error at or near "DECLARE counter numeric"
SQL state: 42601
Character: 75"
This would work:
CREATE OR REPLACE FUNCTION fill_invoice2(in_num integer)
RETURNS void AS
$func$
DECLARE
counter numeric := 0;
BEGIN
IF in_num > 1 THEN
WHILE counter < 10
LOOP
INSERT INTO invoice(ID,INVOICE_ID,SUBSCRIBER_ID,AMOUNT,INVOICE_DATE,RECORD_DATE
,INVOICE_TYPE,REST_TO_PAY,DESCRIPTION,INVOICE_REFERENCE)
VALUES(counter,counter,counter,100,current_date,current_date
,1,100,'Telco services',1111);
counter := counter + 1;
RAISE NOTICE 'The counter is %', counter;
END LOOP;
END IF;
END
$func$ LANGUAGE plpgsql;
Major points
Missing language declaration.
Missing quotes around function body. Preferrably, use dollar-quoting - like #Eelke advised. Details:
Insert text with single quotes in PostgreSQL
But the whole function looks needlessly expensive.
Use a single INSERT based on generate_series() to replace the expensive loop with inserts per row. Optionally, you can wrap it in a function. Example with simple SQL function:
CREATE OR REPLACE FUNCTION fill_invoice2(in_num integer)
RETURNS void AS
$func$
INSERT INTO invoice(ID,INVOICE_ID,SUBSCRIBER_ID,AMOUNT,INVOICE_DATE,RECORD_DATE
,INVOICE_TYPE,REST_TO_PAY,DESCRIPTION,INVOICE_REFERENCE)
SELECT g,g,g,100,current_date,current_date,1,100,'Telco services',1111
FROM generate_series(0,10) g
WHERE $1 > 1;
$func$ LANGUAGE sql;
Does the same as your original.
I would also consider column defaults for some of your columns. For instance:
ALTER TABLE invoice
ALTER COLUMN invoice_date SET DEFAULT current_date
, ALTER COLUMN record_date SET DEFAULT current_date;
Details:
converting mysql scripts to postgresql script
Then just don't mention those column in the INSERT statement and defaults are filled in automatically.
The body should be passed as a string
CREATE OR REPLACE FUNCTION FILL_INVOICE2(IN_NUM integer) RETURNS void AS
$$
DECLARE
counter numeric := 0;
BEGIN
IF in_num > 1 THEN
WHILE counter < 10 LOOP
INSERT INTOI NVOICE(ID,INVOICE_ID,SUBSCRIBER_ID,AMOUNT,INVOICE_DATE,
RECORD_DATE,INVOICE_TYPE,REST_TO_PAY,DESCRIPTION,INVOICE_REFERENCE)
VALUES(counter,counter,counter,100,current_date,current_date,1,100,
'Telco services',1111);
counter := counter + 1;
RAISE NOTICE 'The counter is %', counter;
END LOOP;
END IF;
RETURN;
END;
$$
You can use $$ to mark the beginning en end of a multiline string.
I am having trouble debugging some syntax issues with my postgresql function. The error doesn't indicate a line that the issue is on and I am too new to Postgres to recognize what's wrong. I am using SQLFiddle for testing. SQLFiddle link is http://sqlfiddle.com/#!15/266ef
Function I am using
CREATE OR REPLACE FUNCTION updateSalary() RETURNS VOID AS
$BODY$
DECLARE
sum INTEGER := 0;
dep CURSOR FOR SELECT Dno FROM Department;
dep_row Department%ROWTYPE;
emp CURSOR(dept_Dno) CURSOR FOR
SELECT Dno, Salary FROM Employee WHERE Dno = dept_Dno;
emp_row Employee%ROWTYPE;
BEGIN
open dep;
LOOP
FETCH dep into dep_row;
exit when NOT FOUND;
open emp(dep_row.Dno);
LOOP
FETCH emp into emp_row;
exit when NOT FOUND;
SET sum := sum + emp_row.salary;
END LOOP;
UPDATE department SET total_sal = sum WHERE department.dno = emp_row.dno;
close emp;
SET sum := 0;
END LOOP;
close dep;
END;
$BODY$
LANGUAGE plpgsql;
Error I am receiving
Schema Creation Failed: ERROR: missing data type declaration at or near ")":
Cursor argument must have a type declared (and remove second word 'cursor'):
...
emp CURSOR(dept_Dno integer) FOR
SELECT Dno, Salary FROM Employee WHERE Dno = dept_Dno;
...
Assignments without keyword 'set':
sum := sum + emp_row.salary;
Inside a postgresql function I'm trying to get two values selected from a table into two variables, but I get this error:
INTO specified more than once at or near "INTO"
This is the (pseudo)code:
CREATE OR REPLACE FUNCTION func() RETURNS TRIGGER AS
$$
DECLARE
a numeric;
b varchar(20);
c numeric;
BEGIN
IF ... THEN
...
SELECT x INTO a FROM t1 WHERE y = 1
IF a > 5 THEN
SELECT m, n INTO b, c FROM t2 WHERE ...;
...
END IF;
END IF;
END
$$ LANGUAGE plpgsql;
The problem is just (as always) a missing semicolon.
Just add the missing semicolon on the first SELECT statement
[...]
SELECT x INTO a FROM t1 WHERE y = 1; #missing semicolon
IF a > 5 THEN
SELECT m, n INTO b ...;
[...]
The INTO specified more than once error is generated from the second SELECT statement (when it finds a second INTO) and it doesn't suggest much about where to find the problem.
Let's say I've created a composite type in Postgresql:
CREATE TYPE custom_type AS
(x integer
y integer);
I need to use it in a function as an array:
...
DECLARE
customVar custom_type[];
BEGIN
....
My question is: how do I access custom_type's specific components?
For example, I want to (re)assign 'x' for the third element in custom_type array...
postgres=> create type pt as (x int, y int);
CREATE TYPE
postgres=> create or replace function fx()
returns void as $$
declare a pt[] = ARRAY[(10,20),(30,40)]; declare xx pt;
begin
for i in array_lower(a, 1) .. array_upper(a,1)
loop
xx = a[i]; xx.x := xx.x + 1; a[i] := xx; raise notice '%', a[i].x;
end loop;
end;
$$ language plpgsql;
CREATE FUNCTION
postgres=> select fx();
NOTICE: 11
NOTICE: 31
fx
────
(1 row)
Significant limit for target of assign statement is possibility to refer only one level nested properties. This limit can be bypassed by auxiliary variables - it is not too friendly - and internal implementation is too simple, but it is fast and enough for typical stored procedure usage although it is not strong in comparison with generic programming languages.
Given:
SELECT ARRAY[(1,2),(3,4)]::custom_type[];
Use an array subscript and then refer to the field by name.
regress=> SELECT (ARRAY[(1,2),(3,4)]::custom_type[])[1].x;
x
---
1
(1 row)