If field like 'something' clause in void function - Postgresql - sql

I need makes this function to load teams from pl_raw to new table named game.
In pl_raw to be all data. Now.. this function in order to order data for tables...
CREATE OR REPLACE FUNCTION loadGames() RETURNS void AS $$
BEGIN
IF (SELECT * from pldata.pl_raw where venue = 'Away') THEN
INSERT INTO definitiu.game (date_game, home_team, away_team)
SELECT game_date, opposition_id,team_id from pldata.pl_raw;
ELSIF (SELECT * from pldata.pl_raw where venue = 'Home') THEN
INSERT INTO definitiu.game (date_game, home_team, away_team)
SELECT game_date, team_id, opposition_id from pldata.pl_raw;
END IF;
END; $$
LANGUAGE PLPGSQL;
The function compile, but, Postgres return this error when I execute this function:
ERROR: subquery must return only one column
LINE 1: SELECT (SELECT * from pldata.pl_raw where venue = 'Away')
^
QUERY: SELECT (SELECT * from pldata.pl_raw where venue = 'Away')
CONTEXT: PL/pgSQL function loadgames() line 4 at IF
********** Error **********
ERROR: subquery must return only one column
SQL state: 42601
Context: PL/pgSQL function loadgames() line 4 at IF

Use EXISTS:
IF EXISTS (SELECT * from pldata.pl_raw where venue = 'Away') THEN

Related

How to return result of two SELECT statement from a postgres fuunction?

I have this postgresql function:
CREATE OR REPLACE FUNCTION public.test_q1()
RETURNS TABLE(schemaname text)
LANGUAGE plpgsql
AS $function$
BEGIN
return Query (select "content" from public.post where id='863550630468626253');
-- return Query (select count(*) from public.comments WHERE post_id='863550630468626253');
END
$function$
;
How can I return both select statement result from this function?
Is it possible to return the result set of two select statement from function such that when i call public.test_q1 it will return two values first resultset will be the values of content and other columns inside first Select and second return value will be the count ?
Return two values in one query?
select p."content",
(select count(*)
from public.comments c
where c.post_id = '863550630468626253'
) as num_comments
from public.post p
where p.id = '863550630468626253'
);
EDIT:
I don't think you can guarantee the order of results in the returned set of a function, but you can use union all to return the two values. Presumably, content is not a number. So, one method is to cast the values:
select p."content"
from public.post p
where p.id = '863550630468626253'
union all
select count(*)::text
from public.comments c
where c.post_id = '863550630468626253';
I believe in practice this will return the content first and the count second. However, I don't think Postgres guarantees the ordering.

Postgres - If not exists not working in postgresql?

I'm currently building a query and apparently, it doesn't work. This is my current query (this is the full one)
IF NOT EXISTS(SELECT * FROM invite WHERE uid=$1::uuid)
BEGIN
INSERT INTO invite (uid, link) VALUES ($1::uuid, $2::text);
END
ELSE
BEGIN
SELECT * FROM invite WHERE uid=$1::uuid;
END
In my console, i'm getting syntax error at or near "IF"
Many errors in your code:
plpgsql code can return result only from function (not from DO)
IF clause must have THEN
you do not need BEGIN / END in each statement inside IF ... THEN ... ELSE ... END (not error also has no sense)
Probably is better to do this by pure SQL:
WITH q AS (
SELECT *
FROM invite
WHERE uid=$1::uuid
), i AS (
INSERT INTO invite (uid, link)
SELECT $1::uuid, $2::text
WHERE (SELECT count(*) = 0 FROM q)
RETURNING *
) SELECT * FROM q
UNION SELECT * FROM i

SQL state: 42601 when try to create view inside a function PostgreSQL

I am getting sql state 42601 when executing following function. Can someone please help to resolve this error. I used this stackoverflow question to create the view from function. My function code is as below. I am trying to execute this function using select * from Test('DEPTA_');. I am getting error
SQL state: 42601
Context: PL/pgSQL function test(text) line 3 at EXECUTE statement
Function code :
create or replace function Test(authority text) returns void
as $$
BEGIN
EXECUTE
'create materialized view '||authority ||' as
WITH FINDUNDERSCORE as
(select '||authority ||' as role, position(''_'' in '||authority||') as pos ),
DISTINCT_ROLE as
( select substring('||authority ||', 0, pos) as distinctRoles from FINDUNDERSCORE where position(''_'' in '||authority ||') > 1 and ''authority '' not like ''ROLE%''
union select substring('||authority ||', pos+1, length('||authority ||')) as distinctRoles from FINDUNDERSCORE where position(''_'' in '||authority ||') > 1 and '||authority ||' not like ''ROLE%''
union select '||authority ||' from FINDUNDERSCORE
),
ORIGINAL_ID as
(select ROW_NUMBER() over(order by distinctRoles asc) as id, distinctRoles from DISTINCT_ROLE order by distinctRoles asc),
mapped_Id as
( select (case when oi.distinctroles ~ asid.sid then asid.id end ) as newId, oi.id,oi.distinctroles,asid.sid, asid.id from original_id oi,acl_sid asid ),
AGGREGATE_NEWID as
(select mi.newid,max(sid) sid, max(distinctroles) distinctroles, array_to_string(array_agg(mi.distinctroles),',') as aggregatedroles from mapped_id mi where mi.newid is not null group by mi.newid ),
MATCH_ACL_ENTRY as
(select * from acl_entry ae join AGGREGATE_NEWID asid on ae.sid = asid.newid and granting is true and bitand(cast(ae.mask as bit(32)), cast(1 as bit(32)) ) = cast(1 as bit(32)) ) ,
MATCH_ACL_OBJECT_IDENTITY as
(select * from ACL_OBJECT_IDENTITY acl join MATCH_ACL_ENTRY asid on acl.id = asid.acl_object_identity),
MATCH_ACL_PLATE as
(select p.id, p.plate_barcode, p.plate_size, p.plate_id, acl.aggregatedroles, substring(acl.aggregatedroles,0,position(',' in acl.aggregatedroles)) as parentrole,
substring(acl.aggregatedroles,position(',' in acl.aggregatedroles)+1, length(acl.aggregatedroles)) as childrole from plate p join MATCH_ACL_OBJECT_IDENTITY acl on acl.object_id_identity = p.id)
select id,plate_barcode,plate_size,plate_id from MATCH_ACL_PLATE';
END;
$$ LANGUAGE plpgsql;
You've messed up at least three times while concatenating strings for EXECUTE statement. The SQL used to create view does not seem to be a valid one due to incorrect concatenation again.
My recommendation to you:
1st build a valid sql for view creation
2nd carefully replace required parts with variable concatenation
3rd you can always check log file to find out more information about errors you get
Good luck!
If anyone runs across same situation i solved this problem by adding three single quotes around parameter name which i want to consider as single quoted string
EXECUTE
'create materialized view '||authority||' as
WITH FINDUNDERSCORE as
(select position(''_'' in '''||authority||''') as pos )
...

PostgreSQL: CASE: SELECT FROM two different tables

Is it possible to do something like the following with SQL, not PL/pgSQL (note if it's only possible with PL/pgSQL, then how)?
IF password = 'swordfish' THEN
SELECT a, b, c FROM users;
ELSE
SELECT -1; -- unauthorized error code
END IF;
Ideally, could I wrap the above in a function with TRUE being an argument?
Rather, is it possible to set the command status string to -1?
I'm asking this because I want the query to return an error code, like -1, if someone tries to get a list of all the users with the wrong password. This is for a web app with user accounts that each have a password. So, this is not something I want to manage with database roles/permissions.
Algorithm
Select 1 into a (authorized) if we find a user_id_1-session_id match.
Select 0, NULL, NULL into u (unauthorized) if we didn't find a match in step 1.
Select user_id, body, sent into s (select) if we did find a match in step 1.
Union u and s.
Code
-- List messages between two users with `user_id_1`, `session_id`, `user_id_2`
CREATE FUNCTION messages(bigint, uuid, bigint) RETURNS TABLE(i bigint, b text, s double precision) AS
$$
WITH a AS (
SELECT 1
FROM sessions
WHERE user_id = $1
AND id = $2
), u AS (
SELECT 0, NULL::text, NULL::double precision
WHERE NOT EXISTS (SELECT 1 FROM a)
), s AS (
SELECT user_id, body, trunc(EXTRACT(EPOCH FROM sent))
FROM messages
WHERE EXISTS (SELECT 1 FROM a)
AND chat_id = pair($1, $3)
LIMIT 20
)
SELECT * FROM u UNION ALL SELECT * FROM s;
$$
LANGUAGE SQL STABLE;
The PL/pgsql function below returns the messages sent between user_id & with_user_id if the user_id:key pair is authorized, as determined by the user-defined function (UDF) user_auth. Otherwise, it returns one row with from = -1 . The other UDF, pair, is a unique unordered pairing function that, given two user IDs, returns the chat_id to which the messages belong.
--- Arguments: user_id, key, with_user_id
CREATE FUNCTION messages(bigint, uuid, bigint)
RETURNS TABLE(from bigint, body text, sent double precision) AS $$
BEGIN
IF user_auth($1, $2) THEN
RETURN QUERY SELECT from, body, trunc(EXTRACT(EPOCH FROM sent))
FROM messages WHERE chat_id = pair($1, $3);
ELSE
i := -1;
RETURN NEXT;
END IF;
END;
$$ LANGUAGE plpgsql STABLE;
I don't know how to translate this to an SQL function or whether that would be better.
This will work, but it's not pretty:
WITH
u AS (SELECT * FROM user WHERE mail = '..'),
code AS (
SELECT
CASE (SELECT count(*) FROM u)
WHEN 0 THEN
'not found'
ELSE
CASE (SELECT count(*) FROM u WHERE password = '..')
WHEN 1 THEN
'right password'
ELSE
'wrong password'
END
END)
SELECT
code.*,
u.*
FROM code NATURAL LEFT OUTER JOIN u
I think you might want to look into creating a result set returning function instead.
There is a CASE expression in addition to the (pl/pgsql only) CASE control structure.
EDIT: CASE expression in sql context:
SELECT CASE
WHEN my_conditions_are_met THEN a
ELSE NULL
END AS a_or_null,
b,
c
FROM users;
EDIT 2: given your example that's how you can do it in pure SQL:
WITH params AS (
SELECT user_auth(:user_id, :key) AS user_auth,
pair(:user_id, :with_user_id) AS chat_id
), error_message AS (
SELECT -1 AS "from",
'auth error' AS "body",
EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) AS "sent"
)
SELECT from, body, trunc(EXTRACT(EPOCH FROM sent))
FROM messages
JOIN params ON messages.chat_id = params.chat_id AND params.user_auth
UNION ALL
SELECT error_message.*
FROM error_message
JOIN params ON NOT params.user_auth

plpgsql Error: RETURN cannot have a parameter in function returning void

I am trying to extract the count of records corresponding to a specific date and user_ids which do not have corresponding user_ids for the next later date in the database. This is the way I am trying to accomplish it (using plpgsql but not defining a function:
DO
$BODY$
DECLARE
a date[]:= array(select distinct start_of_period from monthly_rankings where balance_type=2);
res int[] = '{}';
BEGIN
FOR i IN array_lower(a,1) .. array_upper(a,1)-1
LOOP
res:=array_append(res,'SELECT COUNT(user_id) from (select user_id from monthly_rankings where start_of_period=a[i] except select user_id from monthly_rankings where start_of_period=a[i+1]) as b');
i:=i+1;
END LOOP;
RETURN res;
$BODY$ language plpgsql
I get an Error: could not Retrieve the result : ERROR: RETURN cannot have a parameter in function returning void
LINE 11: RETURN res;
I am new to this procedural language and cannot spot why the function is returning void. I do assign the values to variables , and I declared empty - not NULL - arrays. Is there a syntax or a more significant reasoning mistake?
1.) You cannot RETURN from a DO statement at all. You would have to CREATE FUNCTION instead.
2.) You don't need any of this. Use this query, which will be faster by an order of magnitude:
WITH x AS (
SELECT DISTINCT start_of_period
,rank() OVER (ORDER BY start_of_period) AS rn
FROM monthly_rankings
WHERE balance_type = 2
)
SELECT x.start_of_period, count(*) AS user_ct
FROM x
JOIN monthly_rankings m USING (start_of_period)
WHERE NOT EXISTS (
SELECT 1
FROM x x1
JOIN monthly_rankings m1 USING (start_of_period)
WHERE x1.rn = x.rn + 1
-- AND m1.balance_type = 2 -- only with matching criteria?
AND m1.user_id = m.user_id
)
-- AND balance_type = 2 -- all user_id from these dates?
GROUP BY x.start_of_period
ORDER BY x.start_of_period
This includes the last qualifying start_of_period, you may want to exclude it like in your plpgsql code.