How to use two columns with clause definescore oracle text - sql

I have this code:
declare
sName varchar(25);
iRank number := 0;
sDesc varchar(510);
cursor q is
SELECT *
FROM trec_topics ORDER BY num;
BEGIN
for ql in q
loop
sDesc := replace(replace(replace(ql.title, '?', '{?}'), ')', '{)}'), '(', '{(}');
--dbms_output.put_line(ql.num||'-'||sDesc);
declare
cursor c is
SELECT /*+ FIRST_ROWS(100) */ docno,
CASE
WHEN SCORE(10) >= SCORE(20) THEN SCORE(10)
ELSE SCORE(20)
END AS SCORE
FROM txt_search_docs WHERE CONTAINS(txt, 'DEFINESCORE(ql.title, OCCURRENCE)', 10) > 0 OR
CONTAINS(txt, 'DEFINESCORE(sDesc, OCCURRENCE)', 20) > 0
order by SCORE desc;
begin
iRank := 1;
for c1 in c
loop
dbms_output.put_line(ql.num||' Q0 '||c1.docno||' '||lpad(iRank,3, '0')||' '||lpad(c1.score, 2, '0')||' myUser');
iRank := iRank + 1;
exit when c%rowcount = 100;
end loop;
end;
end loop;
end;
As you can see I'm doing select on two different tables, however, I need to change the standard score, as it did not perform well. I'm trying to use the DEFINESCORE clause that has this 'DEFINESCORE (query_term, scoring_expression)' format.
How can I call the table columns within this clause? That is, I need to call my columns instead of "query_term", as there are several documents to do the search. Because the way I’m calling him, he’s looking for exactly the term ql.title
Anyone a suggestion to help me with this problem?

I finally managed to solve it.
It was about:
create a variable: topics varchar (525);
store the column value: topics := replace(replace(replace(ql.title, '?', '{?}'), ')', '{)}'), '(', '{(}');
and after calling it in the CONTAINS clause: FROM txt_search_docs WHERE CONTAINS(txt, 'DEFINESCORE(('''||topics||'''), OCCURRENCE)', 1) > 0

Related

Oracle SQL - table type in cursor causing ORA-21700: object does not exist or is marked for delete

I have problem with my function, I'm getting ORA-21700: object does not exist or is marked for delete error. It's caused by table type parameter in cursor, but I've no idea how to fix it.
I've read that table type part should be assigned to a variable, but it can't be done in cursor, right? I've marked the part which causing the issue
Can anyone help? Is there any other way I can do this?
My package looks something like this:
FUNCTION createCSV(DateFrom date
,DateTo date)
RETURN clob IS
CURSOR c_id (c_DateFrom date
,c_DateTo date) IS
SELECT id
FROM limits
WHERE utcDateFrom <= NVL(c_DateTo, utcDateFrom)
AND NVL(utcDateTo, c_DateFrom + 1) >= c_DateFrom + 1;
CURSOR c (c_DateFrom date
,c_DateTo date
,pc_tDatePeriods test_pkg.t_date_periods) IS -- this is table type (TYPE xx AS TABLE OF records)
SELECT l.id limit_id
,TO_CHAR(time_cond.utcDateFrom, og_domain.cm_yyyymmddhh24mi) time_stamp_from
,TO_CHAR(time_cond.utcDateTo, og_domain.cm_yyyymmddhh24mi) time_stamp_to
FROM limits l
JOIN (SELECT limit_id, utcDateFrom, utcDateTo FROM TABLE(pc_tDatePeriods) --This part is causing the issue
) time_cond
ON l.id = time_cond.limit_id
WHERE l.utcDateFrom <= NVL(c_DateTo, l.utcDateFrom)
AND NVL(l.utcDateTo, c_DateFrom + 1) >= c_DateFrom + 1;
CSV clob;
tDatePeriods test_pkg.t_date_periods := test_pkg.t_date_periods();
BEGIN
FOR r_id IN c_id(DateFrom, DateTo)
LOOP
tDatePeriods := test_pkg.includeTimeGaps(p_Id => r_id.id); --this loop is ok
FOR r IN c(DateFrom, DateTo, tDatePeriods) --here I'm getting error
LOOP
CSV := CSV || chr(13) || r.limit_id || ',' || r.time_stamp_from || ',' || r.time_stamp_to;
END LOOP;
END LOOP;
RETURN CSV;
END createCSV;
Your problem should be solved by declaring type test_pkg.t_date_periods on schema level instead of in package.
Similar answer can be found here but with more details.

How to generate a random, unique, alphanumeric ID of length N in Postgres 9.6+?

I've seen a bunch of different solutions on StackOverflow that span many years and many Postgres versions, but with some of the newer features like gen_random_bytes I want to ask again to see if there is a simpler solution in newer versions.
Given IDs which contain a-zA-Z0-9, and vary in size depending on where they're used, like...
bTFTxFDPPq
tcgHAdW3BD
IIo11r9J0D
FUW5I8iCiS
uXolWvg49Co5EfCo
LOscuAZu37yV84Sa
YyrbwLTRDb01TmyE
HoQk3a6atGWRMCSA
HwHSZgGRStDMwnNXHk3FmLDEbWAHE1Q9
qgpDcrNSMg87ngwcXTaZ9iImoUmXhSAv
RVZjqdKvtoafLi1O5HlvlpJoKzGeKJYS
3Rls4DjWxJaLfIJyXIEpcjWuh51aHHtK
(Like the IDs that Stripe uses.)
How can you generate them randomly and safely (as far as reducing collisions and reducing predictability goes) with an easy way to specify different lengths for different use cases, in Postgres 9.6+?
I'm thinking that ideally the solution has a signature similar to:
generate_uid(size integer) returns text
Where size is customizable depending on your own tradeoffs for lowering the chance of collisions vs. reducing the string size for usability.
From what I can tell, it must use gen_random_bytes() instead of random() for true randomness, to reduce the chance that they can be guessed.
Thanks!
I know there's gen_random_uuid() for UUIDs, but I don't want to use them in this case. I'm looking for something that gives me IDs similar to what Stripe (or others) use, that look like: "id": "ch_19iRv22eZvKYlo2CAxkjuHxZ" that are as short as possible while still containing only alphanumeric characters.
This requirement is also why encode(gen_random_bytes(), 'hex') isn't quite right for this case, since it reduces the character set and thus forces me to increase the length of the strings to avoid collisions.
I'm currently doing this in the application layer, but I'm looking to move it into the database layer to reduce interdependencies. Here's what the Node.js code for doing it in the application layer might look like:
var crypto = require('crypto');
var set = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
function generate(length) {
var bytes = crypto.randomBytes(length);
var chars = [];
for (var i = 0; i < bytes.length; i++) {
chars.push(set[bytes[i] % set.length]);
}
return chars.join('');
}
Figured this out, here's a function that does it:
CREATE OR REPLACE FUNCTION generate_uid(size INT) RETURNS TEXT AS $$
DECLARE
characters TEXT := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
bytes BYTEA := gen_random_bytes(size);
l INT := length(characters);
i INT := 0;
output TEXT := '';
BEGIN
WHILE i < size LOOP
output := output || substr(characters, get_byte(bytes, i) % l + 1, 1);
i := i + 1;
END LOOP;
RETURN output;
END;
$$ LANGUAGE plpgsql VOLATILE;
And then to run it simply do:
generate_uid(10)
-- '3Rls4DjWxJ'
Warning
When doing this you need to be sure that the length of the IDs you are creating is sufficient to avoid collisions over time as the number of objects you've created grows, which can be counter-intuitive because of the Birthday Paradox. So you will likely want a length greater (or much greater) than 10 for any reasonably commonly created object, I just used 10 as a simple example.
Usage
With the function defined, you can use it in a table definition, like so:
CREATE TABLE users (
id TEXT PRIMARY KEY DEFAULT generate_uid(10),
name TEXT NOT NULL,
...
);
And then when inserting data, like so:
INSERT INTO users (name) VALUES ('ian');
INSERT INTO users (name) VALUES ('victor');
SELECT * FROM users;
It will automatically generate the id values:
id | name | ...
-----------+--------+-----
owmCAx552Q | ian |
ZIofD6l3X9 | victor |
Usage with a Prefix
Or maybe you want to add a prefix for convenience when looking at a single ID in the logs or in your debugger (similar to how Stripe does it), like so:
CREATE TABLE users (
id TEXT PRIMARY KEY DEFAULT ('user_' || generate_uid(10)),
name TEXT NOT NULL,
...
);
INSERT INTO users (name) VALUES ('ian');
INSERT INTO users (name) VALUES ('victor');
SELECT * FROM users;
id | name | ...
---------------+--------+-----
user_wABNZRD5Zk | ian |
user_ISzGcTVj8f | victor |
I'm looking for something that gives me "shortcodes" (similar to what Youtube uses for video IDs) that are as short as possible while still containing only alphanumeric characters.
This is a fundamentally different question from what you first asked. What you want here then is to put a serial type on the table, and to use hashids.org code for PostgreSQL.
This returns 1:1 with the unique number (serial)
Never repeats or has a chance of collision.
Also base62 [a-zA-Z0-9]
Code looks like this,
SELECT id, hash_encode(foo.id)
FROM foo; -- Result: jNl for 1001
SELECT hash_decode('jNl') -- returns 1001
This module also supports salts.
Review,
26 characters in [a-z]
26 characters in [A-Z]
10 characters in [0-9]
62 characters in [a-zA-Z0-9] (base62)
The function substring(string [from int] [for int]) looks useful.
So it looks something like this. First we demonstrate that we can take the random-range and pull from it.
SELECT substring(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
1, -- 1 is 'a', 62 is '9'
1,
);
Now we need a range between 1 and 63
SELECT trunc(random()*62+1)::int+1
FROM generate_series(1,1e2) AS gs(x)
This gets us there.. Now we just have to join the two..
SELECT substring(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
trunc(random()*62)::int+1
1
)
FROM generate_series(1,1e2) AS gs(x);
Then we wrap it in an ARRAY constructor (because this is fast)
SELECT ARRAY(
SELECT substring(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
trunc(random()*62)::int+1,
1
)
FROM generate_series(1,1e2) AS gs(x)
);
And, we call array_to_string() to get a text.
SELECT array_to_string(
ARRAY(
SELECT substring(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
trunc(random()*62)::int+1,
1
)
FROM generate_series(1,1e2) AS gs(x)
)
, ''
);
From here we can even turn it into a function..
CREATE FUNCTION random_string(randomLength int)
RETURNS text AS $$
SELECT array_to_string(
ARRAY(
SELECT substring(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
trunc(random()*62)::int+1,
1
)
FROM generate_series(1,randomLength) AS gs(x)
)
, ''
)
$$ LANGUAGE SQL
RETURNS NULL ON NULL INPUT
VOLATILE LEAKPROOF;
and then
SELECT * FROM random_string(10);
Thanks to Evan Carroll answer, I took a look on hashids.org.
For Postgres you have to compile the extension or run some TSQL functions.
But for my needs, I created something simpler based on hashids ideas (short, unguessable, unique, custom alphabet, avoid curse words).
Shuffle alphabet:
CREATE OR REPLACE FUNCTION consistent_shuffle(alphabet TEXT, salt TEXT) RETURNS TEXT AS $$
DECLARE
SALT_LENGTH INT := length(salt);
integer INT = 0;
temp TEXT = '';
j INT = 0;
v INT := 0;
p INT := 0;
i INT := length(alphabet) - 1;
output TEXT := alphabet;
BEGIN
IF salt IS NULL OR length(LTRIM(RTRIM(salt))) = 0 THEN
RETURN alphabet;
END IF;
WHILE i > 0 LOOP
v := v % SALT_LENGTH;
integer := ASCII(substr(salt, v + 1, 1));
p := p + integer;
j := (integer + v + p) % i;
temp := substr(output, j + 1, 1);
output := substr(output, 1, j) || substr(output, i + 1, 1) || substr(output, j + 2);
output := substr(output, 1, i) || temp || substr(output, i + 2);
i := i - 1;
v := v + 1;
END LOOP;
RETURN output;
END;
$$ LANGUAGE plpgsql VOLATILE;
The main function:
CREATE OR REPLACE FUNCTION generate_uid(id INT, min_length INT, salt TEXT) RETURNS TEXT AS $$
DECLARE
clean_alphabet TEXT := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
curse_chars TEXT := 'csfhuit';
curse TEXT := curse_chars || UPPER(curse_chars);
alphabet TEXT := regexp_replace(clean_alphabet, '[' || curse || ']', '', 'gi');
shuffle_alphabet TEXT := consistent_shuffle(alphabet, salt);
char_length INT := length(alphabet);
output TEXT := '';
BEGIN
WHILE id != 0 LOOP
output := output || substr(shuffle_alphabet, (id % char_length) + 1, 1);
id := trunc(id / char_length);
END LOOP;
curse := consistent_shuffle(curse, output || salt);
output := RPAD(output, min_length, curse);
RETURN output;
END;
$$ LANGUAGE plpgsql VOLATILE;
How-to use examples:
-- 3: min-length
select generate_uid(123, 3, 'salt'); -- output: "0mH"
-- or as default value in a table
CREATE SEQUENCE IF NOT EXISTS my_id_serial START 1;
CREATE TABLE collections (
id TEXT PRIMARY KEY DEFAULT generate_uid(CAST (nextval('my_id_serial') AS INTEGER), 3, 'salt')
);
insert into collections DEFAULT VALUES ;
This query generate required string. Just change second parasmeter of generate_series to choose length of random string.
SELECT
string_agg(c, '')
FROM (
SELECT
chr(r + CASE WHEN r > 25 + 9 THEN 97 - 26 - 9 WHEN r > 9 THEN 64 - 9 ELSE 48 END) AS c
FROM (
SELECT
i,
(random() * 60)::int AS r
FROM
generate_series(0, 62) AS i
) AS a
ORDER BY i
) AS A;
So I had my own use-case for something like this. I am not proposing a solution to the top question, but if you are looking for something similar like I am, then try this out.
My use-case was that I needed to create a random external UUID (as a primary key) with as few characters as possible. Thankfully, the scenario did not have a requirement that a large amount of these would ever be needed (probably in the thousands only). Therefore a simple solution was a combination of using generate_uid() and checking to make sure that the next sequence was not already used.
Here is how I put it together:
CREATE OR REPLACE FUNCTION generate_id (
in length INT
, in for_table text
, in for_column text
, OUT next_id TEXT
) AS
$$
DECLARE
id_is_used BOOLEAN;
loop_count INT := 0;
characters TEXT := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
loop_length INT;
BEGIN
LOOP
next_id := '';
loop_length := 0;
WHILE loop_length < length LOOP
next_id := next_id || substr(characters, get_byte(gen_random_bytes(length), loop_length) % length(characters) + 1, 1);
loop_length := loop_length + 1;
END LOOP;
EXECUTE format('SELECT TRUE FROM %s WHERE %s = %s LIMIT 1', for_table, for_column, quote_literal(next_id)) into id_is_used;
EXIT WHEN id_is_used IS NULL;
loop_count := loop_count + 1;
IF loop_count > 100 THEN
RAISE EXCEPTION 'Too many loops. Might be reaching the practical limit for the given length.';
END IF;
END LOOP;
END
$$
LANGUAGE plpgsql
STABLE
;
here is an example table usage:
create table some_table (
id
TEXT
DEFAULT generate_id(6, 'some_table', 'id')
PRIMARY KEY
)
;
and a test to see how it breaks:
DO
$$
DECLARE
loop_count INT := 0;
BEGIN
-- WHILE LOOP
WHILE loop_count < 1000000
LOOP
INSERT INTO some_table VALUES (DEFAULT);
loop_count := loop_count + 1;
END LOOP;
END
$$ LANGUAGE plpgsql
;

Oracle : String Concatenation is too long

I have below SQL as a part of a view. In one of the schema I am getting "String Concatenation is too long" error and not able to execute the view.
Hence I tried the TO_CLOB() and now VIEW is not throwing ERROR, but it not returning the result as well it keep on running..
Please suggest....
Sql:
SELECT Iav.Item_Id Attr_Item_Id,
LISTAGG(La.Attribute_Name
||'|~|'
|| Lav.Attribute_Value
||' '
|| Lau.Attribute_Uom, '}~}') WITHIN GROUP (
ORDER BY ICA.DISP_SEQ,LA.ATTRIBUTE_NAME) AS ATTR
FROM Item_Attribute_Values Iav,
Loc_Attribute_Values Lav,
Loc_Attribute_Uoms Lau,
Loc_Attributes La,
(SELECT *
FROM Item_Classification Ic,
CATEGORY_ATTRIBUTES CA
WHERE IC.DEFAULT_CATEGORY='Y'
AND IC.TAXONOMY_TREE_ID =CA.TAXONOMY_TREE_ID
) ICA
WHERE IAV.ITEM_ID =ICA.ITEM_ID(+)
AND IAV.ATTRIBUTE_ID =ICA.ATTRIBUTE_ID(+)
AND Iav.Loc_Attribute_Id =La.Loc_Attribute_Id
AND La.Locale_Id =1
AND Iav.Loc_Attribute_Uom_Id =Lau.Loc_Attribute_Uom_Id(+)
AND Iav.Loc_Attribute_Value_Id=Lav.Loc_Attribute_Value_Id
GROUP BY Iav.Item_Id;
Error:
ORA-01489: result of string concatenation is too long
01489. 00000 - "result of string concatenation is too long"
*Cause: String concatenation result is more than the maximum size.
*Action: Make sure that the result is less than the maximum size.
You can use the COLLECT() function to aggregate the strings into a collection and then use a User-Defined function to concatenate the strings:
Oracle Setup:
CREATE TYPE stringlist IS TABLE OF VARCHAR2(4000);
/
CREATE FUNCTION concat_List(
strings IN stringlist,
delim IN VARCHAR2 DEFAULT ','
) RETURN CLOB DETERMINISTIC
IS
value CLOB;
i PLS_INTEGER;
BEGIN
IF strings IS NULL THEN
RETURN NULL;
END IF;
value := EMPTY_CLOB();
IF strings IS NOT EMPTY THEN
i := strings.FIRST;
LOOP
IF i > strings.FIRST AND delim IS NOT NULL THEN
value := value || delim;
END IF;
value := value || strings(i);
EXIT WHEN i = strings.LAST;
i := strings.NEXT(i);
END LOOP;
END IF;
RETURN value;
END;
/
Query:
SELECT Iav.Item_Id AS Attr_Item_Id,
CONCAT_LIST(
CAST(
COLLECT(
La.Attribute_Name || '|~|' || Lav.Attribute_Value ||' '|| Lau.Attribute_Uom
ORDER BY ICA.DISP_SEQ,LA.ATTRIBUTE_NAME
)
AS stringlist
),
'}~}'
) AS ATTR
FROM your_table
GROUP BY iav.item_id;
LISTAGG is limited to 4000 characters unfortunately. So you may want to use another approach to concatenate the values.
Anyway ...
It is strange to see LISTAGG which is a rather new feature combined with error-prone SQL1992 joins. I'd suggest you re-write this. Are the tables even properly joined? It looks strange that there seems to be no relation between Loc_Attributes and, say, Loc_Attribute_Values. Doesn't have Loc_Attribute_Values a Loc_Attribute_Id so an attribute value relates to an attribute? It would be hard to believe that there is no such relation.
Moreover: Is it guaranteed that your classification subquery doesn't return more than one record per attribute?
Here is your query re-written:
select
iav.item_id as attr_item_id,
listagg(la.attribute_name || '|~|' || lav.attribute_value || ' ' || lau.attribute_uom,
'}~}') within group (order by ica.disp_seq, la.attribute_name) as attr
from item_attribute_values iav
join loc_attribute_values lav
on lav.loc_attribute_value_id = iav.loc_attribute_value_id
and lav.loc_attribute_id = iav.loc_attribute_id -- <== maybe?
join loc_attributes la
on la.loc_attribute_id = lav.loc_attribute_id
and la.loc_attribute_id = lav.loc_attribute_id -- <== maybe?
and la.locale_id = 1
left join loc_attribute_uoms lau
on lau.loc_attribute_uom_id = iav.loc_attribute_uom_id
and lau.loc_attribute_id = iav.loc_attribute_id -- <== maybe?
left join
(
-- aggregation needed to get no more than one sortkey per item attribute?
select ic.item_id, ca.attribute_id, min (ca.disp_seq) as disp_seq
from item_classification ic
join category_attributes ca on ca.taxonomy_tree_id = ic.taxonomy_tree_id
where ic.default_category = 'y'
group by ic.item_id, ca.attribute_id
) ica on ica.item_id = iav.item_id and ica.attribute_id = iav.attribute_id
group by iav.item_id;
Well, you get the idea; check your keys and alter your join criteria where necessary. Maybe this gets rid of duplicates, so LISTAGG has to concatenate less attributes, and maybe the result even stays within 4000 characters.
Xquery approach.
Creating extra types or function isn't necessary.
with test_tab
as (select object_name
from all_objects
where rownum < 1000)
, aggregate_to_xml as (select xmlagg(xmlelement(val, object_name)) xmls from test_tab)
select xmlcast(xmlquery('for $row at $idx in ./*/text() return if($idx=1) then $row else concat(",",$row)'
passing aggregate_to_xml.xmls returning content) as Clob) as list_in_lob
from aggregate_to_xml;
I guess you need to write a small function to concatenate the strings into a CLOB, because even when you cast TO_CLOB() the LISTAGG at the end, this might not work.
Here´s a sample-function that takes a SELECT-Statement (which MUST return only one string-column!) and a separator and returns the collected values as a CLOB:
CREATE OR REPLACE FUNCTION listAggCLob(p_stringSelect VARCHAR2
, p_separator VARCHAR2)
RETURN CLOB
AS
cur SYS_REFCURSOR;
s VARCHAR2(4000);
c CLOB;
i INTEGER;
BEGIN
dbms_lob.createtemporary(c, FALSE);
IF (p_stringSelect IS NOT NULL) THEN
OPEN cur FOR p_stringSelect;
LOOP
FETCH cur INTO s;
EXIT WHEN cur%NOTFOUND;
dbms_lob.append(c, s || p_separator);
END LOOP;
END IF;
i := length(c);
IF (i > 0) THEN
RETURN dbms_lob.substr(c,i-length(p_separator));
ELSE
RETURN NULL;
END IF;
END;
This function can be used f.e. like this:
WITH cat AS (
SELECT DISTINCT t1.category
FROM lookup t1
)
SELECT cat.category
, listAggCLob('select t2.name from lookup t2 where t2.category = ''' || cat.category || '''', '|') allcategorynames
FROM cat;

How to dynamically store the value of a loop and return it once the for loop breaks?

I have a code something like this
FOR K IN (SELECT E.COLUMN_VALUE
FROM TABLE (SELECT CAST(LEAVE_HOLIDAY_CAL_PKG_NEW.GES_LEV_COLUMN_TO_ROWS_FNC(V_CAL_SUBTSR,
',') AS
LEV_TABLE_OF_VARCHAR_TYP)
FROM DUAL) E) LOOP
V_CAL_DESC := CASE WHEN K.COLUMN_VALUE = 'W' THEN 'Project Weekend-' || TO_CHAR((V_DATE1 + V_ITERATION), 'Day') WHEN K.COLUMN_VALUE = 'H' THEN 'Holiday' ELSE 'Working day' END;
IF K.COLUMN_VALUE = 'H' THEN
FETCH C_HOLIDAY_CURSR
INTO V_HOLIDAY_ID;
SELECT H.HOLIDAY_DESC
INTO V_CAL_DESC
FROM LEAVE.LEV_NEW_EMP_HOLIDAY_DTLS H
WHERE H.HOLIDAY_ID = V_HOLIDAY_ID;
END IF;
INSERT INTO LEV_CAL_TEMP_TBL
VALUES
(IN_PERSON_ID, K.COLUMN_VALUE, V_DATE1 + V_ITERATION, V_CAL_DESC);
COMMIT;
V_ITERATION := V_ITERATION + 1;
END LOOP;
OPEN C_CAL_CURSR FOR
select *from LEV_CAL_TEMP_TBL;
So every time this for loop runs one row is inserted in the table GES_LEV_CAL_TEMP_TBL.
But I wanted to avoid this as this might affect the performance of the system,So is there any way I can store those value somewhere
and return the same in cursor once the FOR loop ends.
Thanks a lot in advance.
A cursor FOR LOOP is row-by-row a.k.a slow-by-slow process.
If you must do it in PL/SQL, then use the BULK COLLECT and FORALL statement.
Declare a collection type:
For example,
TYPE t_lev_cal_temp_tbl IS TABLE OF lev_cal_temp_tbl%ROWTYPE;
l_lev_cal t_lev_cal_temp_tbl := t_lev_cal_temp_tbl();
FORALL insert statement:
For example,
FORALL i IN l_lev_cal.first .. l_lev_cal.last
INSERT INTO lev_cal_temp_tbl VALUES l_tab(i);

What is << some text >> in oracle

I found this character while reading some blog of pl sql << some text >> .
I found this character from following blog http://www.oracle-base.com/articles/8i/collections-8i.php
As others have said, <<some_text>> is a label named "some_text". Labels aren't often used in PL/SQL but can be helpful in a variety of contexts.
As an example, let's say you have several nested loops, execution has reached the very inner-most level, and the code needs to exit from all the nested loops and continue after the outer-most one. Here a label can be used in the following fashion:
<<outer_most_loop>>
LOOP
...
<<next_inner_loop>>
LOOP
...
<<inner_most_loop>>
LOOP
...
IF something <> something_else THEN
EXIT outer_most_loop;
END IF;
...
END LOOP inner_most_loop;
...
END LOOP next_inner_loop;
...
END LOOP outer_most_loop;
-- Execution continues here after EXIT outer_most_loop;
something := something_else;
...
Next, let's say that you've got some code with nested blocks, each of which declares a variable of the same name, so that you need to instruct the compiler about which of the same-named variables you intend to use. In this case you could use a label like this:
<<outer>>
DECLARE
nNumber NUMBER := 1;
BEGIN
<<inner>>
DECLARE
nNumber NUMBER := 2;
BEGIN
DBMS_OUTPUT.PUT_LINE('outer.nNumber=' || outer.nNumber);
DBMS_OUTPUT.PUT_LINE('inner.nNumber=' || inner.nNumber);
END inner;
END outer;
Labels can also be useful if you insist on giving a variable the same name as a column in a table. As an example, let's say that you have a table named PEOPLE with a non-nullable column named LASTNAME and you want to delete everyone with LASTNAME = 'JARVIS'. The following code:
DECLARE
lastname VARCHAR2(100) := 'JARVIS';
BEGIN
DELETE FROM PEOPLE
WHERE LASTNAME = lastname;
END;
will not do what you intended - instead, it will delete every row in the PEOPLE table. This occurs because in the case of potentially ambiguous names, PL/SQL will choose to use the column in the table instead of the local variable or parameter; thus, the above is interpreted as
DECLARE
lastname VARCHAR2(100) := 'JARVIS';
BEGIN
DELETE FROM PEOPLE p
WHERE p.LASTNAME = p.lastname;
END;
and boom! Every row in the table goes bye-bye. :-) A label can be used to qualify the variable name as follows:
<<outer>>
DECLARE
lastname VARCHAR2(100) := 'JARVIS';
BEGIN
DELETE FROM PEOPLE p
WHERE p.LASTNAME = outer.lastname;
END;
Execute this and only those people with LASTNAME = 'JARVIS' will vanish.
And yes - as someone else said, you can GOTO a label:
FUNCTION SOME_FUNC RETURN NUMBER
IS
SOMETHING NUMBER := 1;
SOMETHING_ELSE NUMBER := 42;
BEGIN
IF SOMETHING <> SOMETHING_ELSE THEN
GOTO HECK;
END IF;
RETURN 0;
<<HECK>>
RETURN -1;
END;
(Ewwwww! Code like that just feels so wrong..!)
Share and enjoy.
It's often used to label loops, cursors, etc.
You can use that label in goto statements. Else, it is just 'comment'.
Sample from Oracle:
DECLARE
p VARCHAR2(30);
n PLS_INTEGER := 37; -- test any integer > 2 for prime
BEGIN
FOR j in 2..ROUND(SQRT(n)) LOOP
IF n MOD j = 0 THEN -- test for prime
p := ' is not a prime number'; -- not a prime number
GOTO print_now; -- << here is the GOTO
END IF;
END LOOP;
p := ' is a prime number';
<<print_now>> -- << and it executes this
DBMS_OUTPUT.PUT_LINE(TO_CHAR(n) || p);
END;
/
It is a label, a subgroup of comments in the plsql syntax.
http://ss64.com/oraplsql/operators.html
Its is a label delimeter
<< label delimiter (begin)
label delimiter (end) >>
http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/02_funds.htm