I have a base and I need to display if object is ready to work after delivery status "Delivered"
And I need to put it inside function
DO
$$
BEGIN
CASE
WHEN status IN ('In Transit','is going') THEN 'Not ready';
ELSE 'Ready';
end case;
end $$;
Table named Delivery and column status
Attempt with IF
CREATE OR REPLACE FUNCTION prepare_object
()
RETURNS SETOF delivery
LANGUAGE 'plpgsql'
AS
$$
DECLARE answer varchar;
DECLARE status varchar;
BEGIN
SELECT * FROM delivery
if status IN ('In Transit','is going');
THEN answer = ('Not ready');
ELSE answer = ('Ready');
END IF;
END;
RETURN;
$$
Delivery table looks like this
CREATE TABLE Delivery
(
Delivery_Code Serial PRIMARY KEY UNIQUE,
Status varchar(255) CHECK (Status = 'Delivered' OR Status = 'In Transit'
OR Status = 'is going'),
Composition_Delivery varchar(255),
Date_and_time timestamp,
Price money,
Supplier_code Serial REFERENCES Provider(Supplier_code),
Request_Code Serial REFERENCES Request(Request_Code),
Object_ID serial REFERENCES Object(Object_ID)
);
If you just want to have a column expression answer there is no need for a function or PL/pgSQL. This can be achieved using a CASE expression in SQL:
SELECT d.*,
case
when d.status IN ('In Transit','is going') then 'Not ready'
else 'Ready'
end as answer
FROM delivery d
If you don't want to type this every time you retrieve rows from the table, put it into a VIEW.
Related
If an entire row of null values is inserted into my table, I am wanting to execute a trigger to change all columns the newly inserted row to the average instead of null.
I have created the trigger function:
create or replace function teammate_null_check()
returns trigger as
$$
begin
if new.score is null then new.score = (select avg(score) from doubles.teammate);
elsif new.goals is null then new.goals = (select avg(goals) from doubles.teammate);
elsif new.assists is null then new.assists = (select avg(assists) from doubles.teammate);
elsif new.saves is null then new.saves = (select avg(saves) from doubles.teammate);
elsif new.shots is null then new.shots = (select avg(shots) from doubles.teammate);
end if;
return new;
end;
$$ language plpgsql
And the trigger event:
create trigger teammate_trigger
before insert on doubles.teammate
for each row
execute procedure teammate_null_check()
However when I insert a null value for all columns on my table, the trigger only sets the first column (score) to the average. I've tried using ifelse and a case statement and they both only update the first column.
This is what the table looks like after insert:
score
goals
assist
saves
shots
1234
1
2
3
4
1234
null
null
null
null
How can I update all columns if the entire row is inserted null?
ELsif for the alghorithm to choose only one column, but if ypu want all columns t be checked, you need to check eac column individually
create or replace function teammate_null_check()
returns trigger as
$$
begin
if new.score is null then
new.score = (select avg(score) from doubles.teammate);
end if;
if new.goals is null then new.goals = (select avg(goals) from doubles.teammate); end if;
if new.assists is null then new.assists = (select avg(assists) from doubles.teammate); end if;
if new.saves is null then new.saves = (select avg(saves) from doubles.teammate); end if;
if new.shots is null then new.shots = (select avg(shots) from doubles.teammate);
end if;
return new;
end;
$$ language plpgsql
I am using postgresql version 10.3
I am working with a Common Table Expressions inside a function. The function code is following:
CREATE OR REPLACE FUNCTION subscriptions.to_supply_patients(
character varying,
timestamp with time zone)
RETURNS void
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
declare
aws_sub_pro alias for $1; -- health professional aws_sub
tour_date alias for $2; -- tour date to manage patients covered accounts
number_cover int; -- the number of account to manage
sub_list integer[]; -- array list for subscribers covered
no_sub_list integer[];-- array list for no subscribers covered
date_tour timestamp with time zone;--tour date to manage patients covered accounts converted with time zone converted to 23:59:59
begin
select subscriptions.convert_date_to_datetime((select date(tour_date)),'23:59:59','0 days') into date_tour; -- function to convert time to 23:59:59
select count(*) from subscriptions.cover where aws_sub = aws_sub_pro into number_cover; -- global number of patient to cover
if number_cover > 0 then
begin
if tour_date >= current_timestamp then -- if tour date is later than today date
begin
with cover_list as (
select id_cover from subscriptions.cover where aws_sub = aws_sub_pro and cover_duration >0 and is_covered_auto = true
-- we selectionned here the patients list to cover for health pro with aws_sub = aws_sub_pro
),
sub_cover_list as (
select id_subs from subscriptions.subscribers_cover inner join cover_list on cover_list.id_cover = subscribers_cover.id_cover
-- list of subscribers covered
),
no_sub_cover_list as (
select id_free_trial from subscriptions.no_subscribers_cover inner join cover_list on cover_list.id_cover = no_subscribers_cover.id_cover
-- list of no subscribers covered
)
-----------------------------------------------------------------------------------------------------------------------------
select array( select id_subs from subscriptions.subscribers_cover inner join cover_list on cover_list.id_cover = subscribers_cover.id_cover
) into sub_list; -- convert list of subscribers covered into array list
if array_upper(sub_list,1) <>0 then -- if array list is not empty
begin
for i in 1 .. array_upper (sub_list,1) loop -- for every one in this list
if date_tour = (select sub_deadline_date from subscriptions.subscription where id_subs =sub_list[i] ) then -- if tour date is equals to
-- the deadline date
begin
update subscriptions.subscription
set
sub_expiration_date = sub_expiration_date + interval'30 days', -- add 30 days to the exp date
sub_deadline_date = sub_deadline_date + interval'30 days', -- add 30 date to deadline date
sub_source = aws_sub_pro, -- supply source is no the professional
is_sub_activ = false -- we turn off patients subscription
where id_subs = (select id_subs from subscriptions.subscription where id_subs =sub_list[i] );
end;
end if;
end loop;
end;
end if;
--------------------------------------------------------------------------------------------------------------------------------
select array(select id_free_trial from subscriptions.no_subscribers_cover inner join cover_list on cover_list.id_cover = no_subscribers_cover.id_cover
) into no_sub_list;
if array_upper(no_sub_list,1) <>0 then
begin
for i in 1 .. array_upper (no_sub_list,1) loop
if date_tour = (select expiration_date from subscriptions.free_trial where id_free_trial =no_sub_list[i] and is_free_trial_activ = true ) then
begin
update subscriptions.free_trial
set
expiration_date = expiration_date + interval'30 days'
where id_free_trial = (select id_free_trial from subscriptions.free_trial where id_free_trial =no_sub_list[i] );
end;
end if;
end loop;
end;
end if;
end;
else
raise 'tour date must be later than today''s date' using errcode='71';
end if;
end;
else
raise notice 'your cover list is empty. you don''t have any patient to cover' using errcode='70';
end if;
end;
$BODY$;
ALTER FUNCTION subscriptions.to_supply_patients(character varying, timestamp with time zone)
OWNER TO master_pgsql_hygeexv2;
When I run this function, I get the following error:
ERROR: ERREUR: la relation « cover_list » n'existe pas
LINE 1: ...rom subscriptions.no_subscribers_cover inner join cover_list...
Translated:
(the relation « cover_list » does not exist )
I tried to run only the CTE in a query window and I get the same error message.
Is there something I am missing?
The CTE is part of the SQL statement and not visible anywhere outside of it.
So you can use cover_list only in the SELECT statement with the WITH clause.
Either repeat the WITH clause in the second SELECT statement or refractor the code so you need only a single query.
An alternative would be to use a temporary table.
I am stuck at a place.
There is a procedure that checks for something and inserts into an table type upon successful determination of that condition.
But i can insert only once in the table type. Is there a way to insert again and again into the table type.
PROCEDURE "hello"."helloWorld.db::sampleException" (OUT TRACE_RECORD "hello"."LogTrace" )
LANGUAGE SQLSCRIPT AS
BEGIN
DECLARE i int;
select count(*) into i from "hello"."REGION";
IF :i > 1 then
TRACE_RECORD = SELECT '1' AS "LogID", '1' AS "TraceID" FROM DUMMY;
end if;
IF :i > 2 then
TRACE_RECORD = SELECT '2' AS "LogID", '2' AS "TraceID" FROM DUMMY;
end if;
END;
What i get on executing the procedure is only the last record "2,2".
How can i insert both the records 1,1 and 2,2.
Note: I do not want to use Temporary Tables.
Any help on this..
Thanks.!
Editing the Question a bit:
-I have to use Table TYPE (till the time there is no optimal way better than it)
-I have to insert more than 20-30 records in the table type.
Do you have to write this as a procedure? A table-valued function seems more suitable:
CREATE FUNCTION f_tables4 (in_id INTEGER)
RETURNS TABLE (
"LogID" VARCHAR(400),
"TraceID" VARCHAR(400)
)
LANGUAGE SQLSCRIPT
AS
BEGIN
RETURN
SELECT t."LogID", t."TraceID"
FROM (
SELECT 1 AS i, '1' AS "LogID", '1' AS "TraceID" FROM DUMMY
UNION ALL
SELECT 2 AS i, '2' AS "LogID", '2' AS "TraceID" FROM DUMMY
) t
JOIN (SELECT count(*) AS cnt FROM "hello"."REGION") c
ON c.cnt > t.i
END
I want to fill the value of product_id. If article_code is not in the table, it executes the insert, but if record exists I don't know how to select the id of that record and assign to product_id.
The table "core_product" looks like that:
id
article_code
Here the code (inside of a function):
DECLARE
product_id int;
BEGIN
INSERT INTO core_product(article_code)
SELECT NEW.article_code
WHERE NOT EXISTS (
SELECT id INTO product_id
FROM core_product
WHERE article_code = NEW.article_code
)
RETURNING id INTO product_id;
END
Use a special variable FOUND:
DECLARE
product_id int;
BEGIN
SELECT id INTO product_id
FROM core_product
WHERE article_code = NEW.article_code;
IF NOT FOUND THEN
INSERT INTO core_product(article_code)
SELECT NEW.article_code
RETURNING id INTO product_id;
END IF;
END
If there is an unique constraint on article_code, you can harden the function against a race condition using retry loop (as Craig suggested in a comment):
BEGIN
LOOP
SELECT id INTO product_id
FROM core_product
WHERE article_code = NEW.article_code;
IF FOUND THEN
EXIT; -- exit loop
END IF;
BEGIN
INSERT INTO core_product(article_code)
SELECT NEW.article_code
RETURNING id INTO product_id;
EXIT; -- exit loop
EXCEPTION WHEN unique_violation THEN
-- do nothing, go to the beginning of the loop
-- and check once more if article_code exists
END;
END LOOP;
-- do something with product_id
END;
Probably a really easy question but I created a record that has 3 columns. The third column I am going to assign a value later. The query selects 2 columns for the record. What am I missing? The error that is thrown is that there are "too many values" in my select statment.
create or replace Procedure Pledges3
(IDdonor In Int, flag Out Varchar)
as
type allPledges is record(iddonor dd_pledge.iddonor%type, idstatus dd_status.idstatus%type, flag Varchar(25));
allPledges2 allpledges;
Begin
Select dd_pledge.iddonor, dd_status.idstatus
into allpledges2
from dd_donor
join dd_pledge on dd_donor.iddonor=dd_pledge.iddonor
join dd_status on dd_pledge.idstatus=dd_status.idstatus
where dd_pledge.IDdonor=305;
if allpledges2.idstatus = '10' THEN
Flag := 'True';
elsif allpledges2.idstatus= '20' THEN
Flag := 'False';
End if;
dbms_output.put_line(flag);
End;
Check the below code, corrected:
create or replace Procedure Pledges3
(IDdonor In Int, flag Out Varchar)
as
type allPledges is record(iddonor dd_pledge.iddonor%type, idstatus dd_status.idstatus%type, flag Varchar(25));
allPledges2 allpledges;
Begin
Select dd_pledge.iddonor, dd_status.idstatus, null
into allpledges2
from dd_donor
join dd_pledge on dd_donor.iddonor=dd_pledge.iddonor
join dd_status on dd_pledge.idstatus=dd_status.idstatus
where dd_pledge.IDdonor=305;
if allpledges2.idstatus = '10' THEN
allPledges2.Flag := 'True';
elsif allpledges2.idstatus= '20' THEN
allPledges2.Flag := 'False';
End if;
dbms_output.put_line(allPledges2.flag);
End;