I'm trying to get values in variables based on condition as below,
DECLARE #HP INT,#PP INT;
SELECT CASE COLUMN_1
WHEN 'VAL1' THEN SELECT #HP = COLUMN_CD
WHEN 'VAL2' THEN SELECT #PP = COLUMN_CD
END
FROM TBL
no success. how can i do this?
Note: here COLUMN_1 is UNIQUE
TheCASE..WHEN structure should return with a scalar value, not with a resultset. SELECT statement returns a resultset. (The SELECT #HP = COLUMN_CD parts)
You have to assign the values to the variables individually like this:
DECLARE #HP INT,#PP INT;
SELECT
#HP = CASE WHEN COLUMN_1 = 'VAL1' THEN COLUMN_CD ELSE #HP END
, #PP = CASE WHEN COLUMN_1 = 'VAL2' THEN COLUMN_CD ELSE #PP END
FROM
TBL
OR if you do not want to preserve the original value of the variables, you can replace the #HP and #PP in the ELSE part to NULL:
DECLARE #HP INT,#PP INT;
SELECT
#HP = CASE WHEN COLUMN_1 = 'VAL1' THEN COLUMN_CD ELSE NULL END
, #PP = CASE WHEN COLUMN_1 = 'VAL2' THEN COLUMN_CD ELSE NULL END
FROM
TBL
Related
Sample Code as follows : ALL or ANY operator is not working. I need to compare ALL the values of the array
CREATE OR REPLACE FUNCTION public.sample_function(
tt_sample_function text)
RETURNS TABLE (..... )
LANGUAGE 'plpgsql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
declare
e record;
v_cnt INTEGER:=0;
rec record;
str text;
a_v text [];
BEGIN
FOR rec IN ( SELECT * FROM json_populate_recordset(null::sample_function ,sample_function::json) )
LOOP
a_v:= array_append(a_v, ''''||rec.key || '#~#' || rec.value||'''');
END LOOP;
SELECT MAInfo.userid FROM
(SELECT DISTINCT i.userid,
CASE WHEN (i.settingKey || '#~#' || i.settingvalue) = ALL (a_v)
THEN i.settingKey || '#~#' || 'Y'
ELSE i.settingKey || '#~#' || 'N' END
AS MatchResult
FROM public.sample_table i
WHERE (i.settingKey || '#~#' || i.settingvalue) = ALL (a_v)
GROUP BY i.userid, MatchResult) AS MAInfo
GROUP BY MAInfo.userid
HAVING COUNT(MAInfo.userid) >= 1;
RETURN QUERY (....);
END;
$BODY$;
CREATE TYPE tt_sample_function AS
(
key character varying,
value character varying
)
Inputs are
SELECT public.sample_function(
'[{"key":"devicetype", "value":"TestType"},{"key":"ostype", "value":"TestType"}]'
)
Any suggestion, why my ALL operator is not working. I mean its always giving false, it should match with all the array elements...
Note: ofcourse data is there in table.
You are over complicating things. You don't need the FOR loop or the array to do the comparison. You can do that all in a single statement. No need for an extra TYPE or generating an array.
The parameter to the function should be declared as jsonb as you clearly want to pass valid JSON there.
I don't understand what you are trying to achieve with the CASE expression. The WHERE clause only returns rows that match the first condition in the CASE, so the second one will never be reached.
I also don't understand why you have the CASE at all, as you discard the result of that in the outer query completely.
But keeping the original structure as close as possible, I think you can simplify this to a single CREATE TABLE AS statement and get rid of all the array processing.
CREATE OR REPLACE FUNCTION public.sample_function(p_settings jsonb)
RETURNS TABLE (..... )
LANGUAGE plpgsql
AS $BODY$
declare
...
begin
CREATE TEMP TABLE hold_userID AS
SELECT MAInfo.userid
FROM (
-- the distinct is useless as the GROUP BY already does that
SELECT i.userid,
CASE
-- this checks if the parameter contains the settings key/value from sample_table
-- but the WHERE clause already makes sure of that???
WHEN p_settings #> jsonb_build_object('key', i.settingKey, 'value', i.settingvalue)
THEN i.settingKey || '#~#' || 'Y'
ELSE i.settingKey || '#~#' || 'N'
END AS MatchResult
FROM public.sample_table i
WHERE (i.settingKey, i.settingvalue) = IN (select t.element ->> 'key' as key,
t.element ->> 'value' as value
from jsonb_array_elements(p_settings) as t(element))
GROUP BY i.userid, MatchResult
) AS MAInfo
GROUP BY MAInfo.userid
HAVING COUNT(MAInfo.userid) >= 1;
return query ...;
end;
$body$
If you want to check if certain users have all the settings passed to the function, you don't really need a CASE expression, just a proper having condition
So maybe you want this instead:
CREATE TEMP TABLE hold_userID AS
SELECT i.userid,
FROM public.sample_table i
WHERE (i.settingKey, i.settingvalue) = IN (select t.element ->> 'key' as key,
t.element ->> 'value' as value
from jsonb_array_elements(p_settings) as t(element))
GROUP BY i.userid
HAVING COUNT(*) = jsonb_array_length(p_settings);
Or alternatively:
SELECT i.userid
FROM (
select userid, settingkey as key, settingvalue as value
from public.sample_table
) i
group by i.userid
HAVING jsonb_object_agg(key, value) = p_settings
this is my function:
CREATE OR REPLACE FUNCTION SANDBOX.DAILYVERIFY_DATE(TABLE_NAME regclass, DATE_DIFF INTEGER)
RETURNS void AS $$
DECLARE
RESULT BOOLEAN;
DATE DATE;
BEGIN
EXECUTE 'SELECT VORHANDENES_DATUM AS DATE, CASE WHEN DATUM IS NULL THEN FALSE ELSE TRUE END AS UPDATED FROM
(SELECT DISTINCT DATE VORHANDENES_DATUM FROM ' || TABLE_NAME ||
' WHERE DATE > CURRENT_DATE -14-'||DATE_DIFF|| '
) A
RIGHT JOIN
(
WITH compras AS (
SELECT ( NOW() + (s::TEXT || '' day'')::INTERVAL )::TIMESTAMP(0) AS DATUM
FROM generate_series(-14, -1, 1) AS s
)
SELECT DATUM::DATE
FROM compras)
B
ON DATUM = VORHANDENES_DATUM'
INTO date,result;
RAISE NOTICE '%', result;
INSERT INTO SANDBOX.UPDATED_TODAY VALUES (TABLE_NAME, DATE, RESULT);
END;
$$ LANGUAGE plpgsql;
It is supposed to upload rows into the table SANDBOX.UPDATED_TODAY, which contains table name, a date and a boolean.
The boolean shows, whether there was an entry for that date in the table. The whole part, which is inside of EXECUTE ... INTO works fine and gives me those days.
However, this code only inserts the first row of the query's result. What I want is that all 14 rows get inserted. Obviously, I need to change it into something like a loop or something completely different, but how exactly would that work?
Side note: I removed some unnecessary parts regarding those 2 parameters you can see. It does not have to do with that at all.
Put the INSERT statement inside the EXECUTE. You don't need the result of the SELECT for anything other than inserting it into that table, right? So just insert it directly as part of the same query:
CREATE OR REPLACE FUNCTION SANDBOX.DAILYVERIFY_DATE(TABLE_NAME regclass, DATE_DIFF INTEGER)
RETURNS void AS
$$
BEGIN
EXECUTE
'INSERT INTO SANDBOX.UPDATED_TODAY
SELECT ' || QUOTE_LITERAL(TABLE_NAME) || ', VORHANDENES_DATUM, CASE WHEN DATUM IS NULL THEN FALSE ELSE TRUE END
FROM (
SELECT DISTINCT DATE VORHANDENES_DATUM FROM ' || TABLE_NAME ||
' WHERE DATE > CURRENT_DATE -14-'||DATE_DIFF|| '
) A
RIGHT JOIN (
WITH compras AS (
SELECT ( NOW() + (s::TEXT || '' day'')::INTERVAL )::TIMESTAMP(0) AS DATUM
FROM generate_series(-14, -1, 1) AS s
)
SELECT DATUM::DATE
FROM compras
) B
ON DATUM = VORHANDENES_DATUM';
END;
$$ LANGUAGE plpgsql;
The idiomatic way to loop through dynamic query results would be
FOR date, result IN
EXECUTE 'SELECT ...'
LOOP
INSERT INTO ...
END LOOP;
The update and insert statements work when i run them alone and without a transaction...
But i like to execute both in the given order in the transaction and also get the RETURNING value every time - no matter if it inserts or updates - how do i do this`?
BEGIN;
UPDATE globaldata SET valuetext=(SELECT (CAST(coalesce(valuetext, '0') AS integer) + 1) FROM globaldata WHERE keyname='bb') WHERE keyname='bb' RETURNING valuetext;
INSERT INTO globaldata (keyname, valuetext)SELECT 'bb', '1' WHERE NOT EXISTS (SELECT 1 FROM globaldata WHERE keyname='bb') RETURNING valuetext;
COMMIT;
I tried to wrap the update and insert statements by CASE WHEN THEN...but i didnt succeed...
I like to do something like:
BEGIN;
CASE
WHEN (select count(id) from globaldata where keyname='bb') > 0 THEN
UPDATE globaldata SET valuetext=(SELECT (CAST(coalesce(valuetext, '0') AS integer) + 1) FROM globaldata WHERE keyname='bb') WHERE keyname='bb' RETURNING valuetext;
ELSE
INSERT INTO globaldata (keyname, valuetext)SELECT 'bb', '1' WHERE NOT EXISTS (SELECT 1 FROM globaldata WHERE keyname='bb') RETURNING valuetext;
END;
COMMIT;
I have been wanting to do this as well, after looking into it and a little trial and error I came up with this working solution.
use the with statement
with
u as (
update my_table
set some_value = $2
where
id = $1
returning *
)
,
i as (
insert into my_table (id, some_value)
select $1, $2
where
not exists(select * from u)
returning *
)
select * from u
union
select * from i;
Try the update first returning the row updated, if there is no row returned from the update, then insert the row returning the inserted row. Then select a union of the returned values form the update and the insert, since only one will happen you will only get one row returned.
Hope this helps
try using DO
Updated
do
$$
declare _valuetext text;
BEGIN
if
(select count(id) from globaldata where keyname='bb') > 0 THEN
UPDATE globaldata SET valuetext=(SELECT (CAST(coalesce(valuetext, '0') AS integer) + 1) FROM globaldata WHERE keyname='bb') WHERE keyname='bb' RETURNING valuetext into _valuetext
;
raise info '%','_valuetext is '||_valuetext;
ELSE
INSERT INTO globaldata (keyname, valuetext)SELECT 'bb', '1' WHERE NOT EXISTS (SELECT 1 FROM globaldata WHERE keyname='bb')
RETURNING valuetext into _valuetext
;
raise info '%','_valuetext is '||_valuetext;
end if;
END;
$$
;
I have two tables:
CREATE TABLE arapply
(
arapply_id serial NOT NULL,
arapply_postdate date,
arapply_source_docnumber text,
arapply_target_docnumber text,
arapply_target_paid numeric
);
CREATE TABLE aropenbal
(
ar_id integer,
doc_number text,
doc_type text,
doc_date date,
base_amount numeric,
paid_amount numeric,
open_balance numeric
);
For each entry in aropenbal, I want to SUM arapply.arapply_target_paid values where arapply.arapply_source_docnumber = aropenbal.doc_number (if aropenbal.doctype is C or R) or arapply.arapply_target_docnumber = aropenbal.doc_number (if aropenbal.doctype is not C or R) AND also arapply_postdate <= aropenbal.doc_date. The result should be stored to aropenbal.paid_amount.
I then wish to update aropenbal.open_balance with aropenbal.base_amount + aropenbal.paid_amount.
The function should return the total (SUM) of aropenbal.open_balance.
I'm having problems with the code below. The SELECT statements inside the FOR loop don't work, unless I manually assign a value say '362' in place of r.docnumber. Otherwise, the result is zero.
Seems to be a formatting problem.
Any insights?
CREATE OR REPLACE FUNCTION testit() RETURNS NUMERIC AS
$BODY$
DECLARE
r RECORD;
BEGIN
FOR r IN
SELECT * FROM aropenbal ORDER BY doc_date
LOOP
UPDATE aropenbal SET paid_amount = (
CASE WHEN (doc_type IN ('C', 'R')) THEN
(SELECT COALESCE (SUM (arapply_target_paid)* -1, 0)
FROM arapply
WHERE arapply_source_docnumber = r.doc_number
AND arapply_postdate <= r.doc_date)
ELSE
(SELECT COALESCE(SUM (arapply_target_paid),0)
FROM arapply
WHERE arapply_target_docnumber = r.doc_number
AND arapply_postdate <= r.doc_date)
END) WHERE ar_id = r.ar_id;
UPDATE aropenbal SET open_balance = (base_amount - paid_amount)
WHERE ar_id = r.ar_id;
END LOOP;
RETURN (SELECT SUM(open_balance) FROM aropenbal);
END;
$BODY$
LANGUAGE plpgsql;
I have a code:
DECLARE #a char(4)
Select #a=field_name
FROM table_name
where field='abc'
CASE #a
WHEN '2016' THEN
SELECT 'YES'
ELSE
SELECT 'No'
END CASE
The error is:
Incorrect syntax near keyword 'CASE'
What is the problem?
This works with MSSQL:
DECLARE #a char(4)
Select #a=field_name
FROM table_name
where field='abc'
IF #a = '2016'
SELECT 'YES'
ELSE
SELECT 'No'
Or use this:
SELECT
CASE WHEN field_name = '2016' THEN 'YES' ELSE 'No' END
FROM table_name
WHERE field='abc'