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

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 )
...

Related

Remove duplicate values from comma separated variable in Oracle

I have a variable (called: all_email_list) which contains 3 email address lists altogether. (I found some similar question but not the same with a proper solution)
Example: test#asd.com, test2#asd.com,test#asd.com,test3#asd.com, test4#asd.com,test2#asd.com (it can contain spaces between comas but not all the time)
The desired output: test#asd.com, test2#asd.com,test3#asd.com,test4#asd.com
declare
first_email_list varchar2(4000);
second_email_list varchar2(4000);
third_email_list varchar2(4000);
all_email_list varchar2(4000);
begin
select listagg(EMAIL,',') into first_email_list from UM_USER a left join UM_USERROLLE b on (a.mynetuser=b.NT_NAME) left join UM_RULES c on (c.id=b.RULEID) where RULEID = 902;
select listagg(EMAIL,',') into second_email_list from table2 where CFT_ID =:P25_CFT_TEAM;
select EMAIL into third_email_list from table3 WHERE :P25_ID = ID;
all_email_list:= first_email_list || ',' || second_email_list || ',' || third_email_list;
dbms_output.put_line(all_email_list);
end;
Any solution to solve this in a simple way? By regex maybe.
Solution description. Use CTE to first split up the list of emails into rows with 1 email address per row (testd_rows). Then select distinct rows (testd_rows_unique) from testd_rows and finally put them back together with listagg. From 19c onwards you can use LISTAGG with the DISTINCT keyword.
set serveroutput on size 999999
clear screen
declare
all_email_list varchar2(4000);
l_unique_email_list varchar2(4000);
begin
all_email_list := 'test#asd.com, test2#asd.com,test#asd.com,test3#asd.com, test4#asd.com,test2#asd.com';
WITH testd_rows(email) AS
(
select regexp_substr (all_email_list, '[^, ]+', 1, rownum) split
from dual
connect by level <= length (regexp_replace (all_email_list, '[^, ]+')) + 1
), testd_rows_unique(email) AS
(
SELECT distinct email FROM testd_rows
)
SELECT listagg(email, ',') WITHIN GROUP (ORDER BY email)
INTO l_unique_email_list
FROM testd_rows_unique;
dbms_output.put_line(l_unique_email_list);
end;
/
test2#asd.com,test3#asd.com,test4#asd.com,test#asd.com
But ... why are you converting rows to a comma separated string and then de-duping it ? Use UNION to take out the duplicate values in a single SELECT statement and do LISTAGG on the values. No regexp needed then. UNION will skip duplicates as opposed to UNION ALL which returns all the rows.
DECLARE
all_email_list varchar2(4000);
BEGIN
WITH all_email (email) AS
(
select email from UM_USER a left join UM_USERROLLE b on (a.mynetuser=b.NT_NAME) left join UM_RULES c on (c.id=b.RULEID) where RULEID = 902
UNION
select email from table2 where CFT_ID =:P25_CFT_TEAM
UNION
select email from table3 WHERE :P25_ID = ID
)
SELECT listagg(email, ',') WITHIN GROUP (ORDER BY email)
INTO all_email_list
FROM all_email;
dbms_output.put_line(all_email_list);
END;
/
You could leverage the apex_string.split table function to simplify the code.
12c+ makes it real clean
select listagg(distinct column_value,',') within group (order by null)
from apex_String.split(replace('test#asd.com, test2#asd.com,test#asd.com,test3#asd.com, test4#asd.com,test2#asd.com'
,' ')
,',')
11g needs a wrapping table() and listagg doesn't support distinct.
select listagg(email,',') within group (order by null)
from
(select distinct column_value email
from table(apex_String.split(replace('test#asd.com, test2#asd.com,test#asd.com,test3#asd.com, test4#asd.com,test2#asd.com',' '),','))
);

PL/SQL fetch records from JOIN clause problem

It's the second question I'm asking for the same issue, so I'll try to be more specific and brief as I can.
In my pl/sql script, i try to insert into a table some records from lots of different tables. I achieve that, except for a field that comes from a JOIN of 2 tables.
The INSERT statement is placed into the following loop:
FOR FST_DEMAND_rec IN (
SELECT *
FROM A
WHERE FK_DEPOSIT_ACCOACC = DEPOSIT_ACC_rec.ACCOUNT_NUMBER
AND TRX_DATE BETWEEN '01-JAN-2018' AND '31-DEC-2018'
ORDER BY TRANS_SER_NUM , ENTRY_SER_NUM ASC)
LOOP
This loop is placed into the following cursor loop :
FOR T IN MOF_CURSOR LOOP
So the INSERT statement, which actually lies in 2 loops, is the following :
INSERT INTO MOF_OUT
VALUES(
T.MOF_REQUEST_ID,
LOC_SERIAL_NUM,
'2B',
CAST(FST_DEMAND_rec.TRX_UNIT || TO_CHAR(FST_DEMAND_rec.TRX_DATE,'YYYYMMDD') || FST_DEMAND_rec.TRX_USR || FST_DEMAND_rec.TRX_SN AS CHAR(50) ),
TO_CHAR(FST_DEMAND_rec.TRX_DATE,'YYYY-MM-DD') ,
CAST(FST_DEMAND_rec.TRX_UNIT AS CHAR(4) ) ,
UNIT_rec.UNIT_NAME ,
CAST(FST_DEMAND_rec.ID_TRANSACT AS CHAR(6) ),
PRFT_TRANS_rec.DESCRIPTION,
-- 'MY PROBLEMATIC FIELD'
TO_CHAR(FST_DEMAND_rec.TIMESTAMP,'hh24miss'),
FST_DEMAND_rec.ENTRY_AMOUNT,
LOC_DC_FLAG,
LOC_PROGR_BALANCE,
LOC_PROGR_BAL_IND
) ;
This INSERT statement works fine, but I don't know how to fill a record which comes from the following SELECT statement with the JOIN clause:
SELECT A.ENTRY_COMMENTS || ' ' || B.DESCRIPTION
FROM FST_DEMAND_EXTRAIT A INNER JOIN JUSTIFIC B ON A.ID_JUSTIFIC = B.ID_JUSTIFIC
For example, the PRFT_TRANS_rec variable that I use in the INSERT, it's declared as PRFT_TRANSACTION%ROWTYPE; and I have the following SELECT statement for it which is within these 2 loops :
SELECT *
INTO PRFT_TRANS_rec
FROM PRFT_TRANSACTION PRFT_TRANS
WHERE PRFT_TRANS.ID_TRANSACT = FST_DEMAND_rec.ID_TRANSACT;

Previously Compiled P/L SQL Now Freezes in SQL Developer

I am at a complete loss as to where my issue is. Earlier on I wrote a procedure that compiled fine, however now I notice that if I take the exact code (even copy/paste from the procedure itself), and try to run it again, SQL Developer essentially freezes and it never compiles.
The SQL itself is certainly not the cleanest, and I am aware that I've made it a little more complex than a better programmer would, however if it compiled earlier it should compile again, no? Below is the P/L SQL in case that may help...
create or replace PROCEDURE insert_comments AS
v_blob BLOB; v_record number;
BEGIN
SELECT blob_content INTO v_blob from xlsx_files;
for x in
(select id into v_record from
(SELECT to_number(id) id, name FROM
(WITH xlsx AS
(SELECT
ROW_NR,
COL_NR,
CASE CELL_TYPE
WHEN 'S'
THEN STRING_VAL
WHEN 'N'
THEN TO_CLOB(NUMBER_VAL)
WHEN 'D'
THEN TO_CLOB(TO_CHAR(DATE_VAL, 'DD-MON-YYYY'))
ELSE
TO_CLOB(FORMULA)
END CELL_VAL
FROM
(SELECT * FROM
TABLE(as_read_xlsx_clob.read(v_blob ))
--as_read_xlsx_clob is a function from the As_read_XLSX_CLOB package
)
)
/*The below statement works as a roundabout way of pivoting
the table. Since the data in the file may contain CLOBs, you
can't use the PIVOT function since CLOBs do not support
aggregation. I have commented out the original SQL that used
PIVOT*/
SELECT id_table.id, name_table.name FROM
(SELECT row_nr, cell_val id FROM
(SELECT * FROM xlsx WHERE row_nr > 1) id_table
where id_table.col_nr=1
) id_table
inner join
(SELECT row_nr, cell_val name FROM
(SELECT *
FROM xlsx
--PIVOT (MAX(TO_CHAR(CELL_VAL))
FOR COL_NR IN (1 AS ROW_WID,2 AS NAME)
) ad
WHERE row_nr >1
) name_table
where name_table.col_nr = 2
) name_table
ON id_table.row_nr = name_table.row_nr
)
)
)
loop
v_record := x.id;
INSERT INTO comment_test(id, name)
(SELECT to_number(id) id, name
FROM
(WITH xlsx AS
(SELECT
ROW_NR,
COL_NR,
CASE CELL_TYPE
WHEN 'S'
THEN STRING_VAL
WHEN 'N'
THEN TO_CLOB(NUMBER_VAL)
WHEN 'D'
THEN TO_CLOB(TO_CHAR(DATE_VAL, 'DD-MON-YYYY'))
ELSE TO_CLOB(FORMULA)
END CELL_VAL
FROM
(SELECT * FROM
TABLE(as_read_xlsx_clob.read(v_blob ))
--as_read_xlsx_clob is a function from the As_read_XLSX_CLOB package
)
)
/*The below statement works as a roundabout way of
pivoting the table. Since the data in the file may
contain CLOBs, you can't use the PIVOT function since
CLOBs do not support aggregation. I have commented out
the original SQL that used PIVOT*/
SELECT id_table.id, name_table.name FROM
(SELECT row_nr, cell_val id FROM
(SELECT * FROM xlsx WHERE row_nr > 1) id_table
where id_table.col_nr=1
) id_table
inner join
(SELECT row_nr, cell_val name FROM
(SELECT *
xlsx
--PIVOT (MAX(TO_CHAR(CELL_VAL))
FOR COL_NR IN (1 AS ROW_WID,2 AS NAME)
) ad
WHERE row_nr >1
) name_table
where name_table.col_nr = 2
) name_table
ON id_table.row_nr = name_table.row_nr)
where to_number(id) = v_record
);
end loop;
delete from xlsx_files;
END;
Per William Robertson's comments, the issue was there was another session which was using the procedure. This session was killed and I was able to recompile.

Description of the following code?

I do have a situation where a programmer who has developed a stored procedure is absent and doesn't work anymore, so I have to make a little bit of update to the code. I should add 2 more variables in to the code and I know the place, but I don't know how to put it.. Could you please describe the following code, what it does in terms of sql? Cause I know what for this code stand inside the programm..
RAISE NOTICE 'STAT CARD: formid=%',formid;
DROP TABLE IF EXISTS tbl_aggregation;
-- execute
sql_ := 'CREATE TEMPORARY TABLE tbl_aggregation as ' --select programstageinstanceid,'|| dynamic_columns ||' from patientdatavalue'
||'
select OrgUnitID
, max(dateperiod) as dateperiod
, programstageinstanceid
, max("[DE:202062.202063.575]"::integer) as "[DE:202062.202063.575]"
, max(
(case when position(''-'' in "[DE:202062.202063.202095]")>0 then substring("[DE:202062.202063.202095]" from 0 for position(''-'' in "[DE:202062.202063.202095]"))
else "[DE:202062.202063.202095]" end)
) as "[DE:202062.202063.202095]"
, sum("[DE:202062.202063.202078]"::integer) as "[DE:202062.202063.202078]"
, max("[DE:202062.202063.202076]") as "[DE:202062.202063.202076]"
from
(
select psi.organisationunitid as OrgUnitID
, ou.name as OrgName, pdv.timestamp as DatePeriod
, pdv.programstageinstanceid
, pdv.dataelementid
, pdv.value,'
|| dynamic_columns ||'
from patientdatavalue pdv inner join programstageinstance psi
on pdv.programstageinstanceid = psi.programstageinstanceid
-- left join organisationunit ou
inner join tbl_org_list ou
on psi.organisationunitid = ou.organisationunitid
where psi.completed=''t'' and
psi.duedate >= '''||period_from ||''' and
psi.duedate <= '''||period_to ||'''
)as aggregation_
'||cCondition||'
group by programstageinstanceid, OrgUnitID
';
In this code there are hard-coded "variables" as [DE:202062.202063.575], and [DE:202062.202063.202078] and etc.. I do have 2 more different [DE:xxx,xxx,xx] which I should add here.
Because whenever I run this storing procedure it doesn't work and gives the error that those new [DE:xxx,xxx,xx] doesn't exist.. So I should make them exist in the code, but where to put them? TO do it I have to understand the sql syntax and what it does, and unfortunately I'm noob in sql.

Oracle Sort inline view by variable name not working in PL SQL

Thank you very much in advance for looking at my issue.
Summary:
I want to sort inline view by variable name, &pSortColumn.
In Query (see below), it works nicely. However, in PL SQL, no sorting is done!!!
Query below SORTED correctly
SELECT RUV2.*
FROM
(SELECT ROWNUM AS ROW_ID, RUV1.*
FROM
(SELECT
ru.ENTERPRISE_ID,
ru.LEGAL_NAME
FROM
TB_REPORTING_UNIT ru
WHERE ru.REFYEAR = 2012
ORDER BY &pSortColumn
) RUV1
) RUV2 ;
PL SQL below NOT SORTING at all
OPEN cur_ReportingUnit FOR
SELECT RUV2.*
FROM
(SELECT ROWNUM AS ROW_ID, RUV1.*
FROM
(SELECT
ru.ENTERPRISE_ID,
ru.LEGAL_NAME
FROM
TB_REPORTING_UNIT ru
WHERE ru.REFYEAR = 2012
ORDER BY pSortColumn
) RUV1
) RUV2 ;
LOOP
FETCH cur_ReportingUnit INTO mRow_Id, mEnterprise_ID, mLegal_Name ;
EXIT WHEN (cur_ReportingUnit%notfound) ;
DBMS_OUTPUT.PUT_LINE (mEnterprise_ID || ' --- ' || mLegal_Name ) ;
END LOOP;
Add the sorting clause to the most outer query
For paging with a "window", you can do something like this:
select e.*
from ( select e.*
, row_number()
over
(order by uur_id) ive$idx$
from bubs_uren_v e
where ( uur_id = :w1 )
) e
where ive$idx$ between (:start_index + 1) and (:start_index + :max_row_count)
We use this code in our project management suite which handles very large volumes of data. Don't ask me how Oracle did it, but it consistently fast. Remember to only include the columns you need, saves processing, memory and maybe even PL/SQL function calls.