Using pl/sql output in WHERE-statement - sql

I have a little question. So I'm using the Levenshtein-score to search for a comparison of more than 85% between street names in two different tables. But when I use my Levenshtein-score calculation in my WHERE-statement, I get as output for example this:
street names in one table: BEAU SITE 1ÈRE AVENUE & BEAU SITE 2ÈME AVENUE
street names in the other table: BEAU SITE-1ÈRE AVENUE & BEAU SITE-2ÈRE AVENUE
output: linking between all, first one with first and second on, and second one with first and second.
So I have to use the largest score for all the score-calculations and is this like this:
DECLARE
L_SCORE NUMBER;
L_NEW_SCORE NUMBER;
L_BEST_MAP varchar2(255);
CURSOR C_TO_FIND IS
SELECT TT_NAME, L_MUNI, R_MUNI
FROM Y_TT_NOT_LINKED_STREETS ;
CURSOR C_TOMTOM_STREET (L_MUNI VARCHAR2) IS
SELECT STREET_NAME
FROM STREET_NAME SN
JOIN STREET STR ON STR.STREET_ID = SN.STR_STREET_ID
JOIN ADMINISTRATIVE_AREA_NAME AAN ON AAN.AAR_ADMIN_AREA_ID = STR.AAR_ADMIN_AREA_ID
WHERE AAN.ADMIN_AREA_NAME = L_MUNI
AND STR.STREET_ID NOT IN (SELECT ROMA_STREET_ID FROM Y_DS_STREETS_LINK);
BEGIN
FOR S IN C_TO_FIND LOOP
L_SCORE := 0;
L_NEW_SCORE := 0;
FOR R IN C_TOMTOM_STREET(S.L_MUNI) LOOP
L_SCORE := PCK$ADDRESSMATCH.GET_LEVENSHTEIN_SCORE(S.TT_NAME,R.STREET_NAME);
IF L_SCORE > L_NEW_SCORE THEN
L_NEW_SCORE := L_SCORE ;
L_BEST_MAP := R.STREET_NAME ||CHR(9)||TO_CHAR(L_NEW_SCORE);
END IF;
END LOOP;
IF L_NEW_SCORE > 85 THEN
DBMS_OUTPUT.PUT_LINE(S.L_MUNI||CHR(9)||S.TT_NAME||chr(9)||L_BEST_MAP);
END IF;
L_NEW_SCORE := 0;
END LOOP;
END;
Now is the question, how can I use the output in a WHERE-statement, so that I can link with only the largest Levenshtein-score and the problem above will not occur?
So that:
SELECT ...
FROM ...
WHERE (largest score from previous block code)
(or on another way, after a whole week doing SQL I can't see a solution for this)
Thx! =)

Related

String operations with regexp

I have the following code :
DECLARE
r_blob_data VARCHAR2(4000);
r_length NUMBER;
r_payor_identifer VARCHAR2(100);
clp07_ctx NUMBER;
BEGIN
r_blob_data := 'ISA*00* *00* *ZZ*HCA835EOB *ZZ*BOFAECSUSO *170726*1513*U*00401*835013201*1*P*~\GS*HP*HCA835EOB*BOFAECSUSO*20170726*1513*13201*X*004010X091A1\ST*835*000000547\BPR*C*7.01*C*ACH*CTX*01*061000052*DA*3299975294*3621796494**01*122105744*DA*2500335303*20170728\NTE*ZZZ*SEE OUR WEBSITE #HEALTHCHOICEAZ.COM FOR INFORMATION ON CLAIMS DISPUTERESOLUTION\\DTM*405*20170728\N1*PR*HEALTH
CHOICE ARIZONA\N3*410 NORTH 44TH ST, SUITE 900\N4*PHOENIX*AZ*850080000\N1*PE*FL
AGSTAFF MEDICAL CT DBA*FI*860110232\N3*PO BOX 29435\N4*PHOENIX*AZ*850389435\LX*1
\CLP*10906801*1*22*7.01*0*HM*719281738*22\CLP*10906802*1*23*8.01*0*HM*719281739*
22\NM1*QC*100080033001*CLAIRITY*MICHAEL*E***MR*A77240030\NM1*82*2*FLAGSTAFF MEDI
CAL CT DBA TRAUM*****F*86-0110232\REF*1W*A77240030\AMT*AU*7.01\SVC*HC|93010*22*7
.01**1\DTM*472*20170616\CAS*CO*45*14.58\AMT*B6*7.01\SE*22*000000547\GE*1*13201\I
EA*1*835013201\ ';
select regexp_count(r_blob_data, 'CLP')
into r_length
from dual;
dbms_output.put_line('Number of CLP = '||r_length);
for i in 1 .. r_length
loop
SELECT instr(r_blob_data, 'CLP')
INTO clp07_ctx
FROM dual;
dbms_output.put_line('Clp07_ctx = '||clp07_ctx);
r_payor_identifer := substr(r_blob_data, instr(r_blob_data, '*',clp07_ctx,7)+1,instr(r_blob_data,'*',clp07_ctx,8)-instr(r_blob_data,'*',clp07_ctx,7)-1);
r_payor_identifer := to_char(r_payor_identifer) + to_char(r_payor_identifer);
dbms_output.put_line('CLP07String = '||r_payor_identifer);
end loop;
dbms_output.put_line('CLP07String = '||r_payor_identifer);
END;
What I am trying to do is count the number of occurrences of the CLP segment(a segment is for example, CLP*10906801*1*22*7.01*0*HM*719281738*22) and pull out the values that are equivalent to CLP value 7, in this case for both occurrences the value of 719281738 and get the r_payor_identifer variable output as "719281738719281738".
Any suggestions?
Try this REGEXP pattern : 'CLP[^\\]+\*(\d+)\*' to extract 719281738 and
719281739 from your string.
It matches CLP followed by anything other than a \ and the
number between last *..*
select REGEXP_SUBSTR(r_blob_data, 'CLP[^\\]+\*(\d+)\*' , 1 ,LEVEL, NULL,1) as clp
FROM t
CONNECT BY LEVEL <= REGEXP_COUNT(r_blob_data,'CLP[^\\]+');
Also, to set r_payor_identifer, use || for concatenation and not +
Demo

calling column name from array oracle sql

my table looks like:
Name Salary Salary_1 Salary_2
AAA 100 70 80
BBB 120 100 110
CCC 20 25 30
This what I want to do is to save sum for each salaries (so for salary, salary_1 and salary_2). I've created the pl/sql block:
declare
type col is table of varchar2(8);
type suma is table of number;
v_col col:=col('SALARY','SALARY_1','SALARY_2');
v_suma suma:=suma();
begin
for i in 1..3 loop
v_col.extend();
v_suma.extend();
select sum(v_col(i))
into v_suma(i) from employees;
dbms_output.put_line('value : ' ||v_suma(i));
end loop;
end;
In dbms_output I get:
value :
value :
value :
I think that I cannot call column names like that from the varray. Am I correct?
Any ideas how to resolve this problem?
Many thanks for your help
Kamil
You are right; you cannot sum the columns the way you are trying it. sum(v_col(i)) simply multiplies the content of v_col(i) (which is null) with the number of records in the table.
However, you don't need a loop to get the three sums:
declare
type suma is table of number;
v_suma suma := suma();
begin
v_suma.extend(3);
select sum(salary), sum(salary_1), sum(salary_2)
into v_suma(1), v_suma(2), v_suma(3)
from employees;
for i in 1 .. 3 loop
dbms_output.put_line('value : ' || v_suma(i));
end loop;
end;

A frustrating PL/SQL Error...PLS-00103

I have been learning PL/SQL for one of my classes and I am having a difficult time debugging the PLS-00103 error. I have searched the error online, but the solutions I have found aren't necessarily specific enough to solve my problem. Maybe I just need a few more eyes on this. Below you will find my code and the corresponding error message. Thank you in advance! The sample output is below the error.
Code:
create or replace procedure pro_AvgGrade as
min_avg NUMBER := 100;
max_avg NUMBER := 0;
bins NUMBER := 0;
binlen NUMBER := 10;
temp NUMBER := 0;
binprint NUMBER := 0;
CURSOR grades IS SELECT AvgGrade FROM (SELECT DeptName, AVG(GradeAsPercentage) AS AvgGrade FROM Department JOIN Course on Department.DeptId = Course.DeptId JOIN Offering on Course.CourseId = Offering.CourseId JOIN Registration on Offering.OfferingId = Registration.OfferingId GROUP BY DeptName ORDER BY DeptName ASC);
grade_tuple grades%ROWTYPE;
BEGIN
open grades;
for grade_tuple in grades loop
temp := grade_tuple.AvgGrade;
if (temp>max) then
max_avg := temp;
elsif (temp<min) then
min_avg := temp;
end if;
end loop;
close grades;
binprint := min_avg;
bins := max_avg-min_avg;
bins := bins/binlen;
dbms_output.put_line('DeptName AvgGrade: ');
LOOP
dbms_output.put('>' || min_avg || ',' || '<=');
min_avg := binlen+10;
dbms_output.put(min_avg);
dbms_output.put(' ');
i := i+1;
EXIT WHEN i>bins;
END LOOP;
END pro_AvgGrade;
/
begin
pro_AvgGrade;
end;
/
Error:
LINE/COL ERROR
-------- -----------------------------------------------------------------
19/15 PLS-00103: Encountered the symbol ")" when expecting one of the
following:
(
21/18 PLS-00103: Encountered the symbol ")" when expecting one of the
following:
(
Sample Output:
DEPTNAME AVGGRADE: >70, <=80 >80,<=90
May be it's because max and min are reserved words...so it looking for max() and min()...
But it looks more that you just made a mistake. I think you need to try this :
if (temp>max_avg) then
max_avg := temp;
elsif (temp<min_avg) then
min_avg := temp;
end if;
There is no need for parenthesis in your if block. Write it like this:
if temp>max then
max_avg := temp;
elsif temp<min then
min_avg := temp;
end if;

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

String Split/ String replace based on character length

Here my problem in a notes column having 2000 characters max, i want my string output based on 35 characters, ya i need to replace <br> tag after 30 characters in the string.. example string "hi hello how are you doing out there, need your help!", i need out put as "hi hello how are you doing out<br> there, need your help! similar i need to calculate the sting length and have to split it 35+35+35.. i don't know how to perform this in sql/plsql.
select substr(note,1,(instr(note, ' ',35)))||'<br>'||substr(note,instr(note, ' ',35),
(instr(note, ' ',35)))notes from test
DECLARE
CURSOR notes_cur IS
SELECT 1 note_id, 'hi hello how are you doing out there, need your help! hi hello how are you doing out there, need your help!' note FROM DUAL UNION ALL
SELECT 2, 'hi hello how are you doing out there, need your help! hi hello how are you doing out there, need your help!' note FROM DUAL;
TYPE notes_ntt IS TABLE OF notes_cur%ROWTYPE;
l_notes notes_ntt;
l_loop_counter NUMBER;
l_split notes_ntt := notes_ntt();
l_space_start NUMBER;
l_string_start NUMBER;
l_space_position NUMBER;
BEGIN
OPEN notes_cur;
FETCH notes_cur BULK COLLECT INTO l_notes;
CLOSE notes_cur;
FOR indx IN 1..l_notes.COUNT LOOP
l_space_start := 33;
l_string_start := 1;
l_loop_counter := TRUNC(LENGTH(l_notes(indx).note) / 35);
FOR note IN 1..l_loop_counter LOOP
l_split.EXTEND;
l_split(l_split.LAST).note_id := l_notes(indx).note_id;
l_space_position := INSTR(l_notes(indx).note, CHR(32), l_space_start, 1);
l_split(l_split.LAST).note := SUBSTR
(
l_notes(indx).note
, l_string_start
, CASE
WHEN l_space_position = 0
THEN l_string_start
ELSE l_space_position - l_string_start
END
) || CHR(10);
l_space_start := l_space_position + 33;
l_string_start := l_space_position + 1;
END LOOP;
END LOOP;
FOR indx IN 1..l_split.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(l_split(indx).note_id || ' ' || l_split(indx).note);
NULL;
END LOOP;
END;
/*
1 hi hello how are you doing out there,
1 need your help! hi hello how are
1 you doing out there, need your help!
2 hi hello how are you doing out there,
2 need your help! hi hello how are
2 you doing out there, need your help!
*/
You could do this:
declare
l_in_string varchar2(1000) := 'hi hello how are you doing out there, need your help!';
l_out_string varchar2(1000);
begin
while length(l_in_string) > 35 loop
l_out_string := l_out_string || substr(l_in_string, 1, 35) || '<br>';
l_in_string := substr(l_in_string, 36);
end loop;
l_out_string := l_out_string || l_in_string;
dbms_output.put_line(l_out_string);
end;
However this is quite likely to break mid-word e.g.
hi hello how are you doing out there, need your help!
You would need to write more sophisticated code if you want to break on spaces only.