Amazon Redshift: having issue at the END IF point - amazon-web-services

Working with Amazon Redshift having issue at the END IF point:
CREATE OR REPLACE PROCEDURE IF_CON()
AS $$
DECLARE
BEGIN
IF(SELECT EXISTS(SELECT clientid FROM ods_epremis.new_old_merge)) THEN
BEGIN
UPDATE ods_epremis.new_old_merge SET patientencounter_id=(SELECT max(patientencounter_id)
FROM ods_epremis.new_old_merge)+1
WHERE new_old_merge.clain_oid =(SELECT top 1 claim_oid from ods_epremis.new_old_merge)
INSERT INTO ods_epremis.CLM_REM_MAPPING_PATIENT_ENCOUNTER
SELECT * from ods_epremis.new_old_merge
where claim_oid=(select top 1 claim_oid from ods_epremis.new_old_merge order by claim_oid)
END IF
END
$$ LANGUAGE plpgsql;

Your nesting is: IF / BEGIN / END IF / END
It should probably be: IF / BEGIN / END / END IF
This keeps the BEGIN/END transaction inside the IF.
Also, based on examples from Structure of PL/pgSQL - Amazon Redshift, commands should end with semi-colons (;):
CREATE OR REPLACE PROCEDURE record_example()
LANGUAGE plpgsql
AS $$
DECLARE
rec RECORD;
BEGIN
FOR rec IN SELECT a FROM tbl_record
LOOP
RAISE INFO 'a = %', rec.a;
END LOOP;
END;
$$;

Related

posix regulation does not work with postgreSQL in trigger function

I am working on a trigger function, and I only want to insert the data when it satisfies specific format. So I tried to use posix regulation expressions. But none of it seems working.
if(new.tin ~ '\d{10}') then
if not exists(
select *
from taxcodes
where code = substr(new.tin, 1, 4)
) then return null;
end if;
end if;

Amazon Redshift stored procedure call

CREATE OR REPLACE PROCEDURE proc_test1(p_1 varchar)
LANGUAGE plpgsql
AS $$
DECLARE
V_TEST integer := 0;
BEGIN
select count(*)
from mytab
into V_TEST
WHERE X =P_1;
RAISE NOTICE 'COUNT IS:(%)',V_TEST;
EXCEPTION
WHEN OTHERS THEN
null;
END;
$$
;
In Amazon Redshift, can I not call this stored proc in this way ?
call proc_test1(p_1 => 'x')
also, why does RAISE with a semicolon fails ? the below error handler says RAISE; - the error i get is invalid operation: syntax error at or near ;
CREATE OR REPLACE PROCEDURE risk.proc_test1(p_1 varchar)
LANGUAGE plpgsql
AS $$
DECLARE
V_TEST integer := 0;
BEGIN
select count(*)
from risk.mytab
into V_TEST
WHERE X =P_1;
RAISE NOTICE 'COUNT IS:(%)',V_TEST;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
$$
;
call proc_test1(p_1 => 'x')
Are you asking about the syntax of calls, or are you asking about named parameters?
The doc doesn't mention it so no it isn't supported.
https://docs.aws.amazon.com/redshift/latest/dg/r_CALL_procedure.html
I guess with regards to the RAISE error, you are missing required parameters
https://docs.aws.amazon.com/redshift/latest/dg/c_PLpgSQL-statements.html#r_PLpgSQL-messages-errors
RAISE level 'format' [, variable [, ...]];
All of these things are in the documentation.

AWS Redshift create a stored procedure to perform a manual vaccum

My goal is to create a stored procedure that loops through a select statement that will identify tables requiring a vacuum. I will call it from Lambda if I can get it to work. These are my ideas and code so far.
CREATE OR REPLACE PROCEDURE vac_an (rs_out INOUT refcursor)
AS $$
BEGIN
OPEN rs_out FOR SELECT 'VACUUM FULL ' + "schema" + '.' + "table" + ';' AS command
FROM svv_table_info
WHERE (unsorted > 5 OR empty > 5)
AND size < 716800;
END;
$$ LANGUAGE plpgsql;
This is a start. It compiles, but it would not execute the actual command that the cursor builds, which is:
VACUUM FULL SCHEMA.TABLE;
I guess I could call it with this:
CALL sample_cursor_test ();
My second line of thinking was something like this:
CREATE PROCEDURE vac_an()
AS $$
DECLARE
tlist RECORD;
BEGIN
FOR tlist IN EXECUTE 'SELECT 'VACUUM FULL ' + "schema" + '.' + "table" + ';' AS command FROM svv_table_info WHERE (unsorted > 5 OR empty > 5) AND size < 716800;'
LOOP
EXECUTE tlist;
END LOOP;
END;
$$ LANGUAGE plpgsql;
However that gives me :
ERROR: missing "LOOP" at end of SQL expression
Where: compile of PL/pgSQL function "vac_an" near line 4
I feel like the code is almost there I just need to loop through this cursor:
SELECT 'VACUUM FULL ' + "schema" + '.' + "table" + ';' AS command
FROM svv_table_info
WHERE (unsorted > 5 OR empty > 5)
AND size < 716800;
And execute the output line by line.
Can you please help?
You cannot call VACUUM from within a transaction, which means you cannot call VACUUM from within a procedure, since a procedure is inherently a transaction.

Can you reference an aggregate function on a temporary row in an insert statement within a stored procedure in postgresql?

I am writing a postgres stored procedure that loops through the rows returned from a select statement. For each row it loops through, it inserts values from that select statement into a new table. One of the values I need to insert into the second table is the average of a column. However, when I call the stored procedure, I get an error that the temporary row has no attribute for the actual column that I am averaging. See stored procedure and error below.
Stored Procedure:
create or replace procedure sendToDataset(sentence int)
as $$
declare temprow peoplereviews%rowtype;
BEGIN
FOR temprow IN
select rulereviewid, avg(rulereview)
from peoplereviews
where sentenceid = sentence
group by rulereviewid
loop
insert into TrainingDataSet(sentenceId, sentence, ruleCorrectId, ruleCorrect, dateAdded)
values(sentence, getSentenceFromID(sentence), tempRow.rulereviewid, tempRow.avg(rulereview), current_timestamp);
END LOOP;
END
$$
LANGUAGE plpgsql;
Error:
ERROR: column "rulereview" does not exist
LINE 2: ...omID(sentence), tempRow.rulereviewid, tempRow.avg(rulereview...
^
QUERY: insert into TrainingDataSet(sentenceId, sentence, ruleCorrectId, ruleCorrect, dateAdded)
values(sentence, getSentenceFromID(sentence), tempRow.rulereviewid, tempRow.avg(rulereview), current_timestamp)
CONTEXT: PL/pgSQL function sendtodataset(integer) line 11 at SQL statement
SQL state: 42703
Basically, I am wondering if it's possible to use that aggregate function in the insert statement or not and if not, if there is another way around it.
you don't need to use a slow and inefficient loop for this:
insert into TrainingDataSet(sentenceId, sentence, ruleCorrectId, ruleCorrect, dateAdded)
select getSentenceId(sentence), sentence, rulereviewid, avg(rulereview), current_timestamp
from peoplereviews
where sentenceid = sentence
group by rulereviewid
To answer the original question: you need to provide a proper alias for the aggregate:
FOR temprow IN
select rulereviewid, avg(rulereview) as avg_views
from peoplereviews
where sentenceid = sentence
group by rulereviewid
loop
insert into TrainingDataSet(sentenceId, sentence, ruleCorrectId, ruleCorrect, dateAdded)
values(sentence, getSentenceFromID(sentence), tempRow.rulereviewid,
tempRow.avg_views, current_timestamp);
END LOOP;

Can i use REGEXP_LIKE as a condition with IF in a PL/SQL block

I'm trying to create a function designed to traverse a tree of organisational units filtering out some based on their level in the tree structure and weather they appear on our intranet page. The input to the function is the ORG_UNIT_ID of the starting unit, a flag to show if we should care about the intranet flag and a comma separated list of levels. For instance '2,3'. I'm trying to use REGEXP_LIKE in conjunction with an ELSEIF inside a loop to run up the tree until I hit the first eligible parent unit.
T_STOP is the control variable for the loop. R_ORG_UNIT_OVER is used to query meta-data on the above unit. During the loops first pass this will be the unit above the one passed as input to the function.
The cursor definition:
CURSOR C_ORG_UNIT_OVER(V_ORG_UNIT_ID ORG_UNIT.ORG_UNIT_ID%TYPE) IS
SELECT ORUI.ORG_UNIT_ID
, ORUI.ORG_LEVEL
, ORUI.SHOW_ON_INTRANET
FROM ORG_UNIT ORUI
JOIN ORG_UNIT_PARENT OUPA ON ORUI.ORG_UNIT_ID=OUPA.ORG_UNIT_ID_PARENT
WHERE OUPA.ORG_UNIT_ID = V_ORG_UNIT_ID;
The failing code segment in the loop:
IF R_ORG_UNIT_OVER.SHOW_ON_INTRANET = 'N' THEN
T_ORG_UNIT_ID := R_ORG_UNIT_OVER.ORG_UNIT_ID;
ELSEIF REGEXP_LIKE (P_SKIP_LEVEL, '(^|,)' || R_ORG_UNIT_OVER.ORG_LEVEL || '($|,)') THEN
T_ORG_UNIT_ID := R_ORG_UNIT_OVER.ORG_UNIT_ID;
ELSE
T_STOP := 'Y';
END IF;
However this code always throws a PLS-00103 error on the REGEXP_LIKE symbol. Is there some sort of limitation or alternate way in which REGEXP_LIKE works when used as a condition in a PL/SQL IF/ELSEIF block as opposed to in a regular query?
PL/SQL uses ELSIF, not ELSEIF. With your edit your code does get the error you described; with this it doesn't:
IF R_ORG_UNIT_OVER.SHOW_ON_INTRANET = 'N' THEN
T_ORG_UNIT_ID := R_ORG_UNIT_OVER.ORG_UNIT_ID;
ELSIF REGEXP_LIKE (P_SKIP_LEVEL, '(^|,)' || R_ORG_UNIT_OVER.ORG_LEVEL || '($|,)') THEN
T_ORG_UNIT_ID := R_ORG_UNIT_OVER.ORG_UNIT_ID;
ELSE
T_STOP := 'Y';
END IF;
Yes you can.
declare
testvar varchar2(20) := 'Kittens';
begin
if regexp_like(testvar, '^K') then
dbms_output.put_line(testvar || ' matches ''^K''');
end if;
end;
Kittens matches '^K'
PL/SQL procedure successfully completed.
Include some test data and I'll try to see what's not working as expected. For example,
declare
p_skip_level number := 2;
org_level number := 3;
begin
if regexp_like (p_skip_level, '(^|,)' || org_level || '($|,)')
then
dbms_output.put_line('Matched');
else
dbms_output.put_line('Not matched');
end if;
end;