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.
Related
I have a question about subqueries and I am uncertain how to google it effectively;
This feels hacky, but it works:
It uses a temporary table (#OrderProcessDates) which I preload with all Ordernr and Processdata data from a LinkedServer MySQL database
SELECT Ordernr
, CASE WHEN OrderStartDate IS NULL THEN (SELECT MIN(x.ProcessDate) from (SELECT * FROM #OrderProcessDates WHERE #OrderProcessDates.Ordernummer = Ordernr) as x)
ELSE OrderStartDate
END as OrderStartDate
, CASE WHEN OrderStopDate IS NULL AND OrderFinished = 1 THEN (SELECT MAX(x.ProcessDate) from (SELECT * FROM #OrderProcessDates WHERE #OrderProcessDates.Ordernummer = Ordernr) as x)
ELSE OrderStopDate
END as OrderStopDate
FROM (
SELECT Ordernummer as Ordernr
, OrderStartDate
, OrderStopDate
, OrderFinished
FROM OPENQUERY([LinkedServer],
'SELECT Ordernummer,Table2.DateCreated as OrderStartDate, Table2.DateFinished as OrderStopDate, Table2.Afgemeld as OrderFinished
FROM Database.Table1
JOIN Database.Table2 as ordernummers ON Table2.idordernummers = Table1.ordernummer '
) as sourcedata
) as fixedata
Is there a better way to use "ordernr" in a subquery; or are you always forced to use a query around the query for the values that are unknown?
Edit: removed earlier question; that contained non-working SQL; this works but need to know if this is "the way"
Image_1 is "table_1:-Product"
Image 2 is "table_2:-User_detail"
Now,
i want to select data from table_1 (p_name,p_amount) with use of particular "p_id" with "prompt" and insert into table_2 (purchased_item,amount_total,due_date) at particular select "u_id"
p_name-> purchased_item
p_amount->amount_total
due_date is sysdate
Expected output:-
If i am select "p_id=101" from table_1 and "u_id=3676" from table_2 then
i get this update in table_2 ---
"row-1"
u_id:-3676
u_name:-Rv
email:-rv#gmail.com
purchased_item:-LED
amount_total:-5000
due_date:-sysdate
please help me out,how this is possible? with procedure or with trigger?
thanx in advanced.
I am new pl/sql learner.
how this is possible? with procedure or with trigger?
Neither, I guess. UPDATE will do.
update user_detail d set
(d.purchased_item, d.amount_Total, d.due_Date) =
(select p.p_name, p.p_amount, sysdate
from product p
where p.p_id = :par_p_id
)
where d.u_id = :par_u_id;
If it has to be a procedure, then
create or replace procedure p_iud (par_p_id in product.p_id%type,
par_u_id in user_detail.u_id%type
)
as
begin
update user_detail d set
(d.purchased_item, d.amount_Total, d.due_Date) =
(select p.p_name, p.p_amount, sysdate
from product p
where p.p_id = par_p_id
)
where d.u_id = par_u_id;
end;
/
Call it as
begin
p_iud(101, 3676);
end;
/
If you'd want to pass several products at the same time, one option is to pass them as a string with comma-separated values. The procedure would then be
create or replace procedure p_iud (par_p_id in varchar2,
par_u_id in user_detail.u_id%type
)
as
begin
update user_detail d set
(d.purchased_item, d.amount_total, d.due_Date) =
(select listagg(p.p_name, ',') within group (order by p.p_name),
sum(p.p_amount),
sysdate
from product p
where p.p_id in (select to_number(regexp_substr(par_p_id, '[^,]+', 1, level))
from dual
connect by level <= regexp_count(par_p_id, ',') + 1
)
)
where d.u_id = par_u_id;
end;
/
and you'd call it as
begin
p_iud('101,301', 3676);
end;
/
Possible problem: as LISTAGG concatenates all those product names, it'll fail if such a "long" string is too long for PURCHASED_ITEM column (you could SUBSTR it, if that's an option)
When I try to execute the code below I receive this error here:
Error(9,4): PLS-00103: Encountered the symbol "SELECT" when expecting
one of the following: ( ) - + case mod new not null table continue avg count current exists max min prior sql
stddev sum variance execute multiset the both leading trailing
forall merge year month day hour minute second timezone_hour
timezone_minute timezone_region timezone_abbr time timestamp
interval date
CREATE OR REPLACE PROCEDURE PROC_LIST_SIMILAR_TVSERIES
(seriesName IN SERIES.NAME%TYPE)
AS
CURSOR series IS (SELECT IDS FROM SERIES WHERE NAME = seriesName);
allSeries SERIES%ROWTYPE;
BEGIN
FOR series IN allSeries
(SELECT 2* ( SELECT COUNT(*)
FROM DICT d
WHERE d.idt IN ( SELECT DISTINCT IDT
FROM POSTING
WHERE IDS = series
INTERSECT
SELECT DISTINCT IDT
FROM POSTING
WHERE IDS = allSeries.IDS
)
)
/ ( ( SELECT DISTINCT COUNT(IDT)
FROM POSTING
WHERE IDS = series
) +
( SELECT DISTINCT COUNT(IDT)
FROM POSTING
WHERE IDS = allSeries.IDS )
)
INTO similarity
FROM SERIES s1
SERIES s2
WHERE s1.IDS = series
AND s2.IDS != series
);
IF similarity > 0.7 THEN
DBMS_OUTPUT.PUT_LINE('ok');
END LOOP;
END;
/
What the code does is take in a name, find it's ID, and compare it to other id's (and avoid comparing it to the same ID). I'm trying to print out "ok" whenever the similarity calculation is over 0.7 . No idea why this doesn't work.
First, if you have a cursor named the same as the table, what is the series%rowtype going to look like? The cursor or the table? Bad idea.
Second, you never execute the cursor to get the ID, so your subsequent cursor loop is looking for records that match allSeries.IDS which is null because you haven't populated it.
Try this as a starting point, although I'm guessing that you still will have work to do on your cursor query. Still, at least it points you to the right code structures...
CREATE OR REPLACE PROCEDURE PROC_LIST_SIMILAR_TVSERIES
(seriesName IN SERIES.NAME%TYPE)
AS
CURSOR seriesCur IS (SELECT IDS FROM SERIES WHERE NAME = seriesName);
allSeries seriesCur%ROWTYPE;
BEGIN
OPEN seriesCur;
FETCH seriesCur INTO allSeries;
IF seriesCur%NOTFOUND
THEN
CLOSE seriesCur;
raise_application_error(-20001,'Your SeriesName does not exist');
END IF;
CLOSE seriesCur;
FOR seriesRec IN
-- this query is a mess! Tried to fix up some aspects of it according to what I THINK you're trying to do.
(SELECT 2*
(SELECT COUNT(*) FROM DICT d WHERE d.idt IN (
SELECT DISTINCT IDT FROM POSTING WHERE IDS = allSeries.IDS
INTERSECT
SELECT DISTINCT IDT FROM POSTING WHERE IDS = allSeries.IDS))
/ ((SELECT DISTINCT COUNT(IDT) FROM POSTING WHERE IDS = allSeries.IDS) +
(SELECT DISTINCT COUNT(IDT) FROM POSTING WHERE IDS = allSeries.IDS) ) similarity
FROM SERIES s1, SERIES s2
WHERE s1.IDS = allSeries.IDS
AND s2.IDS != allSeries.IDS)
LOOP
IF seriesRec.similarity > 0.7 THEN
DBMS_OUTPUT.PUT_LINE('ok');
END IF;
END LOOP;
END;
/
I am still trying to understand the logic in the SQL statement. But i
have hopefully tried to remove the syntactical error. Hope it helps.
CREATE OR REPLACE PROCEDURE PROC_LIST_SIMILAR_TVSERIES(
seriesName IN SERIES.NAME%TYPE)
AS
similarity PLS_INTEGER;
BEGIN
FOR i IN
(SELECT IDS FROM SERIES WHERE NAME = seriesName
)
LOOP
--The logic i am still not able to understand
SELECT *,
(SELECT COUNT(*)
FROM DICT d
WHERE d.idt IN
( SELECT DISTINCT IDT FROM POSTING WHERE IDS = I.IDS
INTERSECT
SELECT DISTINCT IDT
FROM POSTING
WHERE IDS = allSeries.IDS
) / (
(SELECT DISTINCT COUNT(IDT) FROM POSTING WHERE IDS = i.IDS
) +
(SELECT DISTINCT COUNT(IDT) FROM POSTING WHERE IDS = I.IDS
) )
)
INTO similarity
FROM SERIES s1,
SERIES s2
WHERE s1.IDS = s2.IDS
AND s2.IDS != I.IDS;
IF similarity > 0.7 THEN
DBMS_OUTPUT.PUT_LINE('ok');
END IF;
END LOOP;
END;
/
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 )
...
I have a query like this:
select data_name
into v_name
from data_table
where data_table.type = v_t_id
Normally, this query should return exactly one row. When there's no match on v_t_id, the program fails with a "No data found" exception.
I know I could handle this in PL/SQL, but I was wondering if there's a way to do this only in a query. As a test, I've tried:
select case
when subq.data_name is null then
'UNKNOWN'
else
subq.data_name
end
from (select data_name
from data_table
where data_table.type = '53' /*53 does not exist, will result in 0 rows. Need fix this...*/
) subq;
...but this will obviously not work (because subq being empty is not the same as subq.data_name is null). Is this even possible or should I just check in my PL/SQL solution?
(oracle 10g)
There's ways to make this simpler and cleaner, but this basically spells out the technique:
SELECT data_name
FROM data_table
WHERE data_table.type = v_t_id
UNION ALL
SELECT NULL AS data_name
FROM dual
WHERE NOT EXISTS (
SELECT data_name
FROM data_table
WHERE data_table.type = v_t_id
)
When the first part of the union is empty the second will contain a row, when the first part is not empty, the second will contain no rows.
If the query is takes to much time, use this one:
SELECT * FROM (
SELECT data_name
FROM data_table
WHERE data_table.type = v_t_id
UNION ALL
SELECT NULL AS data_name
FROM dual
) WHERE data_name is not null or ROWNUM = 1
I would prefer to handle the exception. However, this would work as you specify:
select min(data_name) data_name
into v_name
from data_table
where data_table.type = v_t_id
Note that this also "works" if the query returns more than 1 row - i.e. TOO_MANY_ROWS is not raised.
select coalesce(data_table.data_name, d.data_name) data_name
into v_name
from
(SELECT 'UNKNOWN ' as data_name FROM DUAL) d
LEFT JOIN data_table
ON data_table.type = v_t_id
or a.data_table.data_name is null
Here is my simple solution using LEFT OUTER JOIN:
CREATE TABLE data_table(data_name VARCHAR2(20), data_type NUMBER(2));
INSERT INTO data_table(data_name, data_type) VALUES('fifty-one', 51);
SELECT coalesce(data_name, 'unknown')
FROM dual
LEFT OUTER JOIN (SELECT data_name FROM data_table WHERE data_type = 53) o
ON 1 = 1;
SELECT coalesce(data_name, 'unknown')
FROM dual
LEFT OUTER JOIN (SELECT data_name FROM data_table WHERE data_type = 51) o
ON 1 = 1;
https://stackoverflow.com/a/4683045/471149 answer is nice, but there is shorter solution
select * from my_table ce, (select 150 as id from dual) d
where d.id = ce.entry_id (+)
If you always expect zero or one row then you can use a group function i.e.:
select dump(max(dummy)) from dual
where dummy = 'Not Found'
You will always get at least one row and a value of NULL in the case where the record is not found.