sqlfuction to django method - django

I have this postgresql function. Can I convert this function to django-method?
I have implemented these functions in sql, but I would like to implement these functions so that they can be used in django or may I ask if there is a way to use the raw-query function separately in django?
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
DO $$ BEGIN
CREATE DOMAIN SHORTKEY as varchar(11);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
CREATE OR REPLACE FUNCTION shortkey_generate()
RETURNS TRIGGER AS $$
DECLARE
gkey TEXT;
key SHORTKEY;
qry TEXT;
found TEXT;
user_id BOOLEAN;
BEGIN
qry := 'SELECT id FROM ' || quote_ident(TG_TABLE_NAME) || ' WHERE id=';
LOOP
IF NEW.id IS NOT NULL THEN
key := NEW.company_id;
user_id := TRUE;
IF length(key) <> 11 THEN
RAISE 'User defined key value % has invalid length. Expected 11, got %.', key,
length(key);
END IF;
ELSE
gkey := encode(gen_random_bytes(8), 'base64');
gkey := replace(gkey, '/', '_'); -- url safe replacement
gkey := replace(gkey, '+', '-'); -- url safe replacement
key := rtrim(gkey, '='); -- cut off padding
user_id := FALSE;
END IF;
EXECUTE qry || quote_literal(key) INTO found;
IF found IS NULL THEN
EXIT;
END IF;
IF user_id THEN
RAISE 'ID % already exists in table %', key, TG_TABLE_NAME;
END IF;
END LOOP;
NEW.id = key;
RETURN NEW;
END
$$ language 'plpgsql';

You can run SQL commands on objects like this:
MyModel.objects.raw(
"""
SQL-COMMANDS
"""
)
In migration files you can run:
migrations.RunSQL(
"""
SQL-COMMANDS
"""
)
But it's generally not recommended to do that. I would recommend to transform this SQL script to Python/Django code.

Related

Amazon Redshift: having issue at the END IF point

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;
$$;

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.

Passing an invalid user id, code should display message but the dbms_output is blank

This procedure should list all project IDs mapped to the active user, and on passing an invalid user id it should print "User is not valid". However, no message is getting displayed.
PROCEDURE get_pid_info (p_return_status_o OUT VARCHAR2,
p_error_message_o OUT VARCHAR2,
p_user_id IN VARCHAR2)
IS
CURSOR c_pid
IS
SELECT DISTINCT xpppa.project_id,
papf.person_type_id,
xpppp.end_date_active,
papf.person_id,
COUNT (DISTINCT xpppa.project_id) pid_count
FROM xxcas_prj_pa_projects_all xpppa,
xxcas_prj_pa_project_players xpppp,
per_all_people_f papf
WHERE xpppa.project_id = xpppp.project_id
AND xpppp.person_id = papf.person_id
AND papf.person_id = 61--p_user_id
AND xpppp.project_role_type = 'PROJECT MANAGER'
AND papf.person_type_id = 6
and sysdate between xpppa.start_date and nvl(xpppa.completion_date,sysdate+1)
and sysdate between xpppp.start_date_active and nvl(xpppp.end_date_active,sysdate+1)
AND EXISTS
(SELECT 1
FROM pa_lookups
WHERE lookup_type = 'XXCAS_PRJ_USER_DETAILS'
AND description=papf.email_address
AND enabled_flag = 'Y'
AND SYSDATE BETWEEN start_date_active
AND NVL (end_date_active,
SYSDATE + 1))
GROUP BY xpppa.project_id,
papf.person_type_id,
xpppp.end_date_active,
papf.person_id;
BEGIN
FOR l_rec IN c_pid
LOOP
IF l_rec.project_id IS NOT NULL
THEN
dbms_output.put_line (
'The Projects mapped to the active user ID are : '
|| l_rec.project_id);
ELSIF l_rec.end_date_active < SYSDATE
THEN
dbms_output.put_line (
'The user has been end dated in the system on : ' || l_rec.end_date_active);
ELSIF l_rec.pid_count = 0
THEN
dbms_output.put_line (
'There are no projects mapped to the user having PM role');
ELSE
dbms_output.put_line ('Please check the user ID passed');
END IF;
IF SQL%NOTFOUND
THEN
dbms_output.put_line('Entered user id is not valid');
end if;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
dbms_output.put_line ('Please provide valid user ID');
WHEN OTHERS
THEN
dbms_output.put_line ('Error in get_pid' || SQLERRM);
END get_pid_info;
Anonymous Block:
declare
status varchar2(30);
msg varchar2(30);
begin
--DBMS_OUTPUT.ENABLE('20000000');
XXCAS_PRJ_PROJECT_DTLS.GET_PID_INFO(status,msg,61);
end;
Firstly, if there are no rows to process then the loop is not entered and so any check inside it will not be executed.
Secondly, the SQL% cursor attributes apply to implicit cursors, not named ones like c_pid in your procedure. It would be simplest to declare a Boolean variable, initialise it to FALSE and set it to TRUE in the loop; then you can check its value after the loop. (Or if you want the actual number of rows, use c_pid%rowcount and initialise it to 0.)
I'm assuming this is a simplified version of your actual procedure, as dbms_output is not generally useful in production code unless the caller is set up to capture it.

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;

Exception handling in PostgreSQL function with Django

have write the following store procedure in Postgres. This SP simply accept the incoming parameters, insert it into the table and return current identity. More I have also declare an addition variable that will tell is the sp runs successfully or not.
I am new to Postgres and have not much knowledge about Postgres way to do this. I want some thing like BEGIN TRY, END TRY and BEGIN CATCH, END CATCH like we do in MSSQL.
CREATE OR REPLACE FUNCTION usp_save_message(msg_sub character varying(80), msg_content text, msg_type character(12), msg_category character(255),msg_created_by character(255),msg_updated_by character(255))
RETURNS msg_id character, success boolean AS
$BODY$
DECLARE
msg_id character;
success boolean;
BEGIN
BEGIN TRY:
set success = 0
set msg_id = INSERT INTO tbl_messages(
message_subject, message_content, message_type, message_category,
created_on, created_by, updated_on, updated_by)
VALUES (msg_sub, msg_cont, msg_type,msg_category, LOCALTIMESTAMP,
msg_created_by, LOCALTIMESTAMP, msg_updated_by) RETURNING message_id;
set success = 1
RETURN msg_id,success;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
I want something like this:
begin proc()
BEGIN
BEGIN TRY:
set success = 0
execute the query
set success = 1
END TRY
BEGIN CATCH:
set success = 0
END CATCH
set success = 1
END
More I have to catched both these return values in django views.
I have updated the question and it is as now;
Here is the table,
CREATE TABLE tbl_messages
(
message_subject character varying(80),
message_content text,
message_type character(12),
message_category character(255),
created_on timestamp without time zone,
created_by character(255),
updated_on timestamp without time zone,
updated_by character(255),
message_id serial NOT NULL,
CONSTRAINT tbl_messages_pkey PRIMARY KEY (message_id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE tbl_messages
OWNER TO gljsxdlvpgfvui;
Here is the function i created;
CREATE FUNCTION fn_save_message(IN msg_sub character varying, IN msg_cont text, IN msg_type character varying, IN msg_category character varying, IN msg_created_by character varying, IN msg_updated_by character varying, OUT success boolean, OUT msg_id integer) RETURNS integer AS
$BODY$BEGIN
BEGIN
INSERT INTO tbl_messages
(message_subject, message_content, message_type, message_category,
created_on, created_by, updated_on, updated_by)
VALUES
(msg_sub, msg_cont, msg_type, msg_category, LOCALTIMESTAMP,
msg_created_by, LOCALTIMESTAMP, msg_updated_by)
returning message_id
into msg_id;
success := true;
EXCEPTION
WHEN others then
success := false;
msg_id := null;
END;
return msg_id,success;
END;$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF
COST 100;
ALTER FUNCTION public.fn_save_message(IN character varying, IN text, IN character varying, IN character varying, IN character varying, IN character varying)
OWNER TO gljsxdlvpgfvui;
But it is not still working... i don't know what id have done wrong now, any django/postgres expert here kindly help me out.
There are several problems with your function:
Statements need to be terminated with a ; - always
Variable assignments are done using := (see: http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-ASSIGNMENT)
You can't return more than one value from a function (unless you create a set returning function, return an object or use out parameters)
Boolean values are true or false. Not 0 or 1 (those are numbers)
The result of an automatically generated ID value is better obtained using lastval() or `` INSERT ... RETURNING expressions INTO ...not through aSET` statement.
Exception handling is done using the exception clause as documented in the manual
So you need something like this:
DECLARE
....
BEGIN
BEGIN
INSERT INTO tbl_messages
(message_subject, message_content, message_type, message_category,
created_on, created_by, updated_on, updated_by)
VALUES
(msg_sub, msg_cont, msg_type,msg_category, LOCALTIMESTAMP,
msg_created_by, LOCALTIMESTAMP, msg_updated_by)
returning message_id
into msg_id;
success := true;
EXCEPTION
WHEN others then
success := false;
msg_id := null;
END;
return msg_id;
END;
But as I said: you can't return more than one value from a function. The only way to do this is to declare OUT parameters, but personally I find them a bit hard to handle in SQL clients.
You have the following options to report an error to the caller:
let the caller handle the exception/error that might arise (which is what I prefer)
define a new user defined data type that contains the message_id and the success flag and return that (but that means you lose the error message!)
return a NULL for the message_id to indicate that something went wrong (but that also means you lose the error information)
Use out parameters to pass both values. An example is available in the manual: http://www.postgresql.org/docs/current/static/xfunc-sql.html#XFUNC-OUTPUT-PARAMETERS
CREATE FUNCTION fn_save_message3(IN msg_sub character varying, IN msg_cont text, IN msg_type character varying, IN msg_category character varying, IN msg_created_by character varying, IN msg_updated_by character varying) RETURNS integer AS
$BODY$ DECLARE msg_id integer := 0;
BEGIN
INSERT INTO tbl_messages
(message_subject, message_content, message_type, message_category,
created_on, created_by, updated_on, updated_by)
VALUES
(msg_sub, msg_cont, msg_type, msg_category, LOCALTIMESTAMP,
msg_created_by, LOCALTIMESTAMP, msg_updated_by);
Select into msg_id currval('tbl_messages_message_id_seq');
return msg_id;
END;$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF
COST 100;
ALTER FUNCTION public.fn_save_message(IN character varying, IN text, IN character varying, IN character varying, IN character varying, IN character varying)
OWNER TO gljsxdlvpgfvui;
SELECT fn_save_message3('Test','fjaksdjflksadjflas','email','news','taqi#gmail.com','');