PostgreSQL if else syntax error - postgresql

i try a query that runs on mssql however does not run postgreSQL...
SQL Query is..
IF EXISTS (SELECT * FROM Kategoriler WHERE KategoriId = 119)
BEGIN
SELECT * FROM Kategoriler
END
ELSE
SELECT * FROM Adminler
i searched it and i found in stackoverflow
DO
$BODY$
BEGIN
IF EXISTS (SELECT 1 FROM orders) THEN
DELETE from orders;
ELSE
INSERT INTO orders VALUES (1,2,3);
END IF;
END;
$BODY$
but i do not want to use DO or, $body etc... I do not want to write any function or other etc...
i want to write only if else statement in postgreSQL... Please help me...

T-SQL supports some procedural statement like IF. PostgreSQL doesn't support it, so you cannot rewrite your query to postgres simply. Sometime you can use Igor's solution, sometime you can use plpgsql (functions) and sometime you have to modify your application and move procedural code from server to client.

Try something like
SELECT *
FROM Kategoriler
UNION ALL
SELECT *
FROM Adminler
WHERE NOT EXIST (SELECT * FROM Kategoriler WHERE KategoriId = 119)
Will only work if Kategoriler and Adminler have same structure. Otherwise you need to specify list of fields instead of *

In my case I needed to know if a record existed.
I had to write a function
CREATE OR REPLACE FUNCTION public.pro_device_exists(vdn character varying)
RETURNS boolean
LANGUAGE plpgsql
AS $function$
BEGIN
IF EXISTS (SELECT 1 FROM tags WHERE device_name = upper(vdn)) THEN
return true;
ELSE
return false;
END IF;
END; $function$
Then I was able to call this function in my code ... just a portion of my code
if pro_device_exists(vdn) then
update tags
set device_id = 11 where device_id = pro_device_id(vdn) and tag_type=10;
update tags
set device_id = pro_device_id(vdn) where tag_id = vtag_id;
vmsg = (select 'Device Now set to ' || first_name || ' ' || last_name from tags where tag_id=vtag_id);
vaction = 'Refresh Device Data';
else
vmsg = 'Device is not registered on this system';
vaction = 'No Nothing';
end if;

Related

POSTGRES - Query has no destination for result data with trimmed mean

I'm new at postgresql and i'm trying to make a function that will return the trimmed mean about all table data. When i try to run this query i get the error message:
ERROR: query has no destination for result data
This is the function:
CREATE OR REPLACE FUNCTION media_truncada(
coluna TEXT,
percentualTruncado NUMERIC)
RETURNS REAL AS $$
BEGIN
IF coluna = 'tempo_ciclo' THEN
WITH limites AS
(SELECT
(AVG(evento_tempo_ciclo.tempo_ciclo) - STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo) * percentualTruncado) as limite_inferior,
(AVG(evento_tempo_ciclo.tempo_ciclo) + STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo) * percentualTruncado) as limite_superior
FROM evento_tempo_ciclo)
SELECT
AVG(evento_tempo_ciclo.tempo_ciclo) as media
FROM evento_tempo_ciclo
WHERE tempo_ciclo BETWEEN (SELECT limite_inferior FROM limites) AND (SELECT limite_superior FROM limites);
ELSE
WITH limites AS
(SELECT
(AVG(evento_tempo_ciclo.tempo_ciclo_liquido) - STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo_liquido) * percentualTruncado) as limite_inferior,
(AVG(evento_tempo_ciclo.tempo_ciclo_liquido) + STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo_liquido) * percentualTruncado) as limite_superior
FROM evento_tempo_ciclo)
SELECT
AVG(evento_tempo_ciclo.tempo_ciclo_liquido) as media
FROM evento_tempo_ciclo
WHERE tempo_ciclo BETWEEN (SELECT limite_inferior FROM limites) AND (SELECT limite_superior FROM limites);
END IF;
RETURN media;
END;
$$ LANGUAGE plpgsql;
You are getting this error message because you execute a query in your function, but nothing happens with the output. RETURN media doesn't actually return anything because media isn't defined, it's only the alias of the column in your query, which is unknown after the query ends.
You will either need to:
Assign the result to a variable:
DECLARE media REAL;
BEGIN
WITH (...) SELECT AVG(evento_tempo_ciclo.tempo_ciclo_liquido) INTO media ...
RETURN media;
END ...
Or return the query as the result:
RETURN QUERY AS WITH (...) SELECT ...
Or just use an SQL function rather than plpgsql:
CREATE OR REPLACE FUNCTION media_truncada(
coluna TEXT,
percentualTruncado NUMERIC)
RETURNS REAL AS $$
...
$$ LANGUAGE sql;
If you aren't 100% certain that your query will never return more than 1 result, you will need to add a LIMIT 1 to your query.

Include IF.. ELSE condition in plpgsql and generating dynamic query

Hi all i have 2 tables dcrhd ( which holds current data) and dcrhd_arc(which holds historical data) and
I have created a function to get some data from theses tables.But this function satisfies only half of my requirement(it checking data from dcrhd table only) i will share my function here..
CREATE OR REPLACE FUNCTION dcr_report( --fin_year_flag,
finid integer, prdid integer, comp_cd CHARACTER varying, divid integer, fsid integer) RETURNS refcursor LANGUAGE 'plpgsql' AS $BODY$
DECLARE
ref refcursor;
BEGIN
open ref for SELECT hd.report_no,
hd.dcr_date,
coalesce(pr2.para_descr,' ') work_type,
coalesce(pr1.para_descr,' ') hq_type,
coalesce(rm.route_name,' ') route_name,
coalesce(hd.doctor_visits,0) doctor_visits,
coalesce(hd.stockist_visits,0) stockist_visits,
coalesce(hd.retailer_visits,0) retailer_visits,
hd.dcr_id,
fm.fs_name,
hd.fstaff_id,
CASE hd.status
WHEN 'A' THEN 'APPROVED'
WHEN 'D' THEN 'DISCARDED'
WHEN 'F' THEN 'FORWARDED'
WHEN 'E' THEN 'DRAFT'
END
status,
zsm.fs_name report1,
rsm.fs_name report2,
fm.geog_lvl1_hq,
fm.level_code,
coalesce(pm.para_descr,'SELF') joint_work,
fm.fs_code,
fm.emp_code,
coalesce(hd.doc_other,0) doc_other
FROM dcrhd hd
LEFT OUTER JOIN parameters pm ON hd.jfw = pm.para_code AND pm.para_type = 'JFW'
LEFT OUTER JOIN route_master rm ON rm.fstaff_id = hd.fstaff_id AND rm.route_id = hd.route_id AND rm.company_cd
= comp_cd
LEFT OUTER JOIN parameters pr1 ON pr1.para_code = hd.hq_exhq AND pr1.para_type = 'HQ_',
parameters pr2,
field_master fm,
field_master zsm,
field_master rsm
WHERE hd.period_id = prdid AND hd.fin_year_id = finid AND hd.fstaff_id = fm.fs_id AND fm.mgr_level4 =
zsm.fs_id AND fm.mgr_level3 = rsm.fs_id AND fm.fs_id =
CASE
WHEN fsid = 0 THEN fm.fs_id
ELSE fsid
END
AND fm.div_id =
CASE
WHEN divid = 0 THEN fm.div_id
ELSE divid
END
AND fm.fs_id = hd.fstaff_id AND fm.level_code = '005' AND pr2.para_code = hd.work_type AND pr2.
para_type = 'WTP' AND hd.company = comp_cd AND fm.company_cd = comp_cd
ORDER BY fm.fs_name,
dcr_date;
RETURN REF;
END;
$BODY$;
My requirement is I just want to add a new parameter called 'fin_year_flag'
and select the master table accordingly (like , if fin_year_flag='current'
then go to dcrhd else goto dcrhd_arc can I achive this???
Would you guys please share your ideas on this??? and is there any other way to full fill my requirement??I am new to PostgreSQL googled many times on internet but couldn't find anything helpful..
The code you have posted is huge, so let me demonstrate you how to use a table name dynamically and return a CURSOR for it by simplifying it.
I create the two tables with a sample row.
create table dcrhd as select 'CURRENT' ::TEXT as col;
create table dcrhd_arc as select 'ARCHIVED'::TEXT as col;
This is a function which uses OPEN <refcursor> FOR EXECUTE over the dynamically generated query. You need to escape the single quotes in your main SQL using another quote or use dollar quoting.
The table name is set using fin_year_flag from a CASE expression.
CREATE OR REPLACE FUNCTION dcr_report( fin_year_flag TEXT)
RETURNS refcursor LANGUAGE plpgsql
AS $BODY$
DECLARE
ref refcursor;
v_table_name TEXT := CASE fin_year_flag
WHEN 'current' THEN 'dcrhd'
ELSE 'dcrhd_arc' END;
v_sql text := format('select col from %s',v_table_name );
BEGIN
open ref for EXECUTE v_sql ;
RETURN REF;
END;
$BODY$;

POSTGRESQL - FUNCTION SELECT + UPDATE

I need execute update for each return of the select, but I don't know how I can do it.
In firebird I have this code:
BEGIN
FOR
SELECT data_cadastro || ' ' || hora_cadastro as data_hora_cadastro,codigo_alteracao_convenio
FROM CC_ALTERACAO_CONVENIO
INTO:data_hora_cadastro,codigo_alteracao_convenio
DO
BEGIN
update CC_ALTERACAO_CONVENIO
set data_hora_cadastro = :data_hora_cadastro
where codigo_alteracao_convenio = :codigo_alteracao_convenio;
suspend;
END
END
I want change to function in postgresql.
I tried this, but not work because I don't know the syntax of postgresql of how can I do it.
CREATE OR REPLACE FUNCTION sim.ajuste_alteracao_convenio(OUT data_hora_cadastro character varying, OUT codigo_alteracao_convenio integer)
RETURNS SETOF record AS
$BODY$
DECLARE
v_data_hora_cadastro character varying;
v_codigo_alteracao_convenio INTEGER;
BEGIN
RETURN QUERY
SELECT data_cadastro || ' ' || hora_cadastro as data_hora_cadastro,codigo_alteracao_convenio
FROM sim.CC_ALTERACAO_CONVENIO
--loop
BEGIN
update sim.CC_ALTERACAO_CONVENIO
set data_hora_cadastro = v_data_hora_cadastro
where codigo_alteracao_convenio = v_codigo_alteracao_convenio;
END
--END LOOP;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
Could someone give me a direction of how can I solved this?
SOLVED
create type foo as (
data_hora_cadastro timestamp,
codigo_alteracao_convenio integer
)
CREATE OR REPLACE FUNCTION sim.ajuste_alteracao_convenio3()
RETURNS SETOF foo AS
$BODY$
DECLARE
r foo%rowtype;
BEGIN
FOR r IN SELECT data_cadastro || ' ' || hora_cadastro as data_hora_cadastro,codigo_alteracao_convenio FROM sim.CC_ALTERACAO_CONVENIO
LOOP
update sim.CC_ALTERACAO_CONVENIO
set data_hora_cadastro = r.data_hora_cadastro
where codigo_alteracao_convenio = r.codigo_alteracao_convenio;
RETURN NEXT r; -- return current row of SELECT
END LOOP;
RETURN;
END
$BODY$
LANGUAGE 'plpgsql' ;
Thank you all
Information is missing in the question, but it looks like all you need is a simple UPDATE with RETURNING:
UPDATE sim.cc_alteracao_convenio a
SET data_hora_cadastro = a.data_cadastro + a.hora_cadastro
RETURNING a.data_hora_cadastro, a.codigo_alteracao_convenio;
Assuming data_cadastro is data type date and hora_cadastro is data type time. Currently, you convert both to text, concatenate and cast back to timestamp. That's much more expensive than it needs to be. Just add both together: data_cadastro + hora_cadastro
The UPDATE itself looks like you are storing functionally dependent values redundantly. Once you've updated data_hora_cadastro you can drop data_cadastro and hora_cadastrocan.
If you positively need a function:
CREATE OR REPLACE FUNCTION sim.ajuste_alteracao_convenio3()
RETURNS TABLE (data_hora_cadastro timestamp
, codigo_alteracao_convenio integer) AS
$func$
UPDATE sim.cc_alteracao_convenio a
SET data_hora_cadastro = a.data_cadastro + a.hora_cadastro
RETURNING a.data_hora_cadastro, a.codigo_alteracao_convenio;
$func$ LANGUAGE sql; -- never quote the language name
You don't need to create a composite type, just use RETURNS TABLE() instead.
Or, if you need pre-UPDATE values:
Return pre-UPDATE Column Values Using SQL Only - PostgreSQL Version
this is what I do, it's an idea but may be it inspires you:
WITH insusu AS (
SELECT data_cadastro || ' ' || hora_cadastro
as data_hora_cadastro,codigo_alteracao_convenio
FROM sim.CC_ALTERACAO_CONVENIO
RETURNING id
)
update sim.CC_ALTERACAO_CONVENIO
set data_hora_cadastro =:data_hora_cadastro
from insusu;
select *
from insusu;
The Objetive is uses a with to determine with what data need work.

Getting Results of Dynamic Query As A Table?

My company is going to start generating documents using data from our database and I am designing the function that will spit out the document text. These documents will need to contain data taken from multiple tables, with hundreds of columns and invariably some records will be missing data.
I am trying to make a function that will take null fields and replace them with a little error message that makes it clear to the end user that a piece of data is missing. Since the end user is totally unfamiliar with the backend, I want these messages to reference something intelligible to them.
My solution is pretty simple yet I for the life of me can't get it to work. The record identifier, table name are set as parameters in the function. The function then loops through names for each of the columns in the specified table, building a query that contains a bunch of case statements. Once the loop is complete, the identifier is appended and then the query is executed, returning the results to the calling function.
Despite reading around quite a bit, the best I can is a single column/row containing all the results - not useful to me at all, because I need to be able to easily reference specific pieces of data in the parent query. I am a beginner with Postgres and the documentation is too complex for me to understand, any help would be appreciated.
-- Function: data_handler(text, text)
-- DROP FUNCTION data_handler(text, text);
CREATE OR REPLACE FUNCTION data_handler(target_uri text, target_table TEXT)
RETURNS SETOF record AS
$BODY$
DECLARE
c text;
strSQL text;
site_only text;
result record;
BEGIN
--We need the schema for strSQL but the loop needs just the table name.
site_only = split_part(target_table, '.', 2);
FOR c IN
SELECT column_name
FROM information_schema.columns
WHERE table_name = site_only
LOOP
strSQL = concat(strSQL, chr(10), '(SELECT CASE WHEN ', c::text, '::text IS NULL THEN concat(', chr(39), '<Error:', chr(39), ', (SELECT lkp_value FROM alb_cr.lkp_field_values WHERE column_name = ', chr(39), c::text, chr(39), ')::text, ', chr(39), ' value not found>', chr(39), ')::text ELSE ',
c::text, '::text END AS ', c::text, '_convert) AS ', c::text, ',');
END LOOP;
strSQL = LEFT(strSQL, character_length(strSQL) - 1);
strSQL = concat('SELECT ', strSQL, ' FROM ', target_table, ' WHERE nm_site_id = ', chr(39), target_uri, chr(39));
RETURN QUERY EXECUTE strSQL;
RAISE NOTICE 'strSQL: %', strSQL;
--RETURN strSQL;
--RETURN QUERY EXECUTE format('SELECT ' || strSQL || 'FROM %s WHERE nm_site_id = $1', pg_typeof(target_table)) USING target_uri;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION data_handler(text, text)
OWNER TO inti;
You could create views for that as well, in the following example on a schema nullsbegone:
-- create the schema to hold the views
create schema if not exists nullsbegone;
-- create a function to create the views (any and all that you might need)
create or replace function nullsbegone.f_make_view_of(p_tablename text) returns void as $f$
begin
execute ($$
create or replace view nullsbegone.$$||(select relname from pg_class where oid = $1::regclass)||$$
returns void as
select $$||array_to_string(array(
select case when not attnotnull then 'COALESCE('||quote_ident(attname)||$$::text, (SELECT '<Error:'''||lkp_value||''' value not found>' FROM alb_cr.lkp_field_values
WHERE column_name = $$||quote_literal(attname)||$$)) AS $$
else '' end || quote_ident(attname)
from pg_attribute
where attrelid = $1::regclass and attnum > 0 order by attnum
), E', \n')||$$
from $$||$1);
end;$f$ language plpgsql;
-- create the view based on a given table
select nullsbegone.f_make_view_of('yourschema.yourtable');
-- select from your view as if you were selecting from the actual table
select * from nullsbegone.yourtable
where nm_site_id = 'yoursite';

PL/pgSQL variable percieved as column

I have a problem with my Postgres and it looks like a simple one. I have done my research but I have not seen anything similar online and would like some clarification:
This is done inside a function, here is the whole code:
BEGIN
IF($5 IS NOT NULL) THEN
BEGIN
INSERT INTO "PushDevice"("DeviceId","PushNotificationId", "pushId","deviceType",sound)
SELECT DISTINCT d.id, $4,d.pushid,d.type,d.sound FROM "Device" d inner join "DeviceLocation" dl ON d.id = dl."DeviceId"
WHERE dl."FIPScode" in (select "FIPScode" from "CountyFIPS" where "stateCode"=$5) AND dl."AppId"=$2 AND d.pushId is not null and d.pushId <>'' and d.pushId<>'1234-5678-9101-2345-3456' and d."isTest"=$3 and d."enableNotification"=TRUE and dl."isDeleted"=0
AND NOT EXISTS (SELECT 1 FROM "PushDevice" t where t."DeviceId"=d.id AND t."PushNotificationId"=$4);
END;
ELSE
DECLARE "epiCentre" VARCHAR := NULL;
magnitude FLOAT = NULL;
BEGIN
SELECT polygon INTO "epiCentre" from alert where id=$1 and "disablePush"=FALSE;
END;
IF("epiCentre" IS NOT NULL) THEN
BEGIN
INSERT INTO "PushDevice"("DeviceId","PushNotificationId", "pushId","deviceType","sound")
SELECT DISTINCT d.id, $4,d."pushId",d.type,d.sound FROM "Device" d inner join "DeviceLocation" dl ON d.id = dl."DeviceId"
WHERE dl."AppId"=$2 AND d."pushId" is not null and d."pushId" <>'' and d."pushId" <>'1234-5678-9101-2345-3456' and d."isTest" =$3 and ST_Distance_Sphere(ST_GeometryFromText("epiCentre"), ST_GeometryFromText(geoPoint))<=d.radius * 1609.344 and magnitude>= d.magnitude and d."enableNotification"=1 and dl."isDeleted"=0
AND NOT EXISTS (SELECT 1 FROM "PushDevice" t where t."DeviceId"=d.id AND t."PushNotificationId"=$4);
END;
END IF;
RETURN QUERY SELECT pd.* FROM "PushDevice" pd
WHERE pd."PushNotificationId" =$4 and pd."sentAt" is null;
END IF;
END;
The problem is here specifically:
DECLARE "epiCentre" VARCHAR := NULL;
magnitude FLOAT = NULL;
BEGIN
SELECT polygon INTO "epiCentre" from alert where id=$1 and "disablePush"=FALSE;
END;
IF("epiCentre" IS NOT NULL) THEN
With error:
Procedure execution failed
ERROR: column "epiCentre" does not exist
LINE 1: SELECT ("epiCentre" IS NOT NULL)
^
QUERY: SELECT ("epiCentre" IS NOT NULL)
CONTEXT: PL/pgSQL function "GetDevicesForPush... line 18 at IF.
So somehow the IF statement perceives epiCentre as column instead of value. And it does not even know it exists although I specifically declared it above.
Any thoughts?
I think you have to many BEGIN-END statements. The declaration of epiCentre is only valid to the first END. And the IF is after that. Therefore I would use on Block for the whole ELSE part.
http://www.postgresql.org/docs/8.3/static/plpgsql-structure.html
As you have found yourself already that DECLARE must be placed before BEGIN of a each block.
More importantly, you do not need multiple blocks here at all. And you don't need a variable either. Use this simpler, safer and faster form:
CREATE function foo(...)
RETURNS ... AS
$func$
BEGIN
IF($5 IS NOT NULL) THEN
-- no redundant BEGIN!
INSERT INTO ... ;
-- and no END!
ELSIF EXISTS (SELECT 1 FROM alert
WHERE id = $1
AND "disablePush" = FALSE
AND polygon IS NOT NULL -- only if polygon can be NULL
) THEN
INSERT INTO ... ;
...
END IF;
END
$func$ LANGUAGE plpgsql;
More Details:
PL/pgSQL checking if a row exists - SELECT INTO boolean