APEX Oracle Compare Two Fields (varchar2 ) - sql

I want to compare two varchar2 fields and based on the percentage similarity to get this percentage as a result in my function, and the ID of this record from this table.
I have the table (SYMPTOMS), I also have the field Symptom_Descr (VARCHAR2) of this table and the variable v_symptom (varchar2) and I want to compare this variable with this field.
For example, this is my table:
The variable that I want to compare is:
'flashes the room lights 5 times'
I want as a result=
id
1
0%
2
0%
3
90%
Another example if the variable is 'washes her hands 7 times':
id
1
80%
2
0%
3
10%
The above percentages are not exact.
If the above cannot be done, then what can I do to find the similarities?

You can use the UTL_MATCH package:
SELECT id,
UTL_MATCH.EDIT_DISTANCE_SIMILARITY(
symptom_descr,
'flashes the room lights 5 times'
) AS ed_similarity,
UTL_MATCH.JARO_WINKLER_SIMILARITY(
symptom_descr,
'flashes the room lights 5 times'
) AS jw_similarity
FROM symptoms;
Which, for the sample data:
CREATE TABLE symptoms (id, symptom_descr) AS
SELECT 1, 'washes his hands constantly' FROM DUAL UNION ALL
SELECT 2, 'checks several times if he turned off the water heater' FROM DUAL UNION ALL
SELECT 3, 'flashes the room lights too many times' FROM DUAL;
Outputs:
ID
ED_SIMILARITY
JW_SIMILARITY
1
30
62
2
25
62
3
79
93
db<>fiddle here

Related

Finding a value in multiple columns in Oracle table

I have a table like below
ID NUMBER 1 NUMBER 2 NUMBER 3 LOC
1-14H-4950 0616167 4233243 CA
A-522355 1234567 TN
A-522357 9876543 WY
A-522371 1112223 WA
A-522423 1234567 2345678 1234567 NJ
A-A-522427 9876543 6249853 6249853 NJ
and I have a bunch of values (1234567, 9876543, 0616167, 1112223, 999999...etc) which will be used in where clause, if a value from where clause found in one of the three Number columns (Number 1 or Number 2 Number 3) then I will have to write that to output1 (its like VLOOKUP of Excel).
If the value is found in more than one of the three columns then it will be different output2 with a flag as MultipleMatches. If the value is not found in any of the three columns then it should be in Output2 with flag as No Match. I tried using self join and or clauses, but not able to get what I want.
I want to write the SQL to generate both outputs. Outputs will include all the columns from the above table. For eg:
Output 1 from above sample data will look like
ID NUMBER 1 NUMBER 2 NUMBER 3 LOC
1-14H-4950 0616167 4233243 CA
A-522371 1112223 WA
Output 2 will be like:
ID NUMBER 1 NUMBER 2 NUMBER 3 LOC Flag
A-522423 1234567 2345678 1234567 NJ Multiple Match
A-A-522427 9876543 6249853 6249853 NJ Multiple Match
1234 No Match
I want to write the SQL to generate both outputs.
One SELECT operator cannot produce two output sets.
The main question is, why split the output when that the difference is only in the FLAG column? If you really need two different output of the result, then you can do this:
(Rightly) create a common cursor for the query, where the FLAG column will be calculated and split the output screens already in the UI.
drop table test_dt;
create table test_dt as
select '1-14h-4950' id,null num1,616167 num2,4233243 num3,'ca' loc from dual
union all
select 'a-522355',null ,1234567,null,'tn' from dual union all
select 'a-522357',null ,9876543,null,'wy' from dual union all
select 'a-522371',null ,1112223,null,'wa' from dual union all
select 'a-522423',1234567,2345678,1234567,'nj' from dual union all
select 'a3-522423',null,null,null,'nj' from dual union all
select 'a-a-522427',9876543,6249853,6249853,'nj' from dual;
--
select
d.*,
case when t.cc_ndv=0 and t.cc_null=3 then 'Not matching'
when t.cc_ndv=(3-t.cc_null) then 'Once'
else 'Multiplay match'
end flag
--t.cc_ndv,
--t.cc_null
from test_dt d ,lateral(
select
count(distinct case level when 1 then num1
when 2 then num2
when 3 then num3
end ) cc_ndv,
count(distinct case level when 1 then nvl2(num1,null,1)
when 2 then nvl2(num2,null,2)
when 3 then nvl2(num3,null,3)
end ) cc_null
from dual connect by level<=3 and sys_guid()is not null
) t;
Or
create a procedure(see to dbms_sql.return_result) that returns a some data sets.
Process these data of cursors / datasets separately.

Select row with shortest string in one column if there are duplicates in another column?

Let's say I have a database with rows like this
ID PNR NAME
1 35 Television
2 35 Television, flat screen
3 35 Television, CRT
4 87 Hat
5 99 Cup
6 99 Cup, small
I want to select each individual type of item (television, hat, cup) - but for the ones that have multiple entries in PNR I only want to select the one with the shortest NAME. So the result set would be
ID PNR NAME
1 35 Television
4 87 Hat
5 99 Cup
How would I construct such a query using SQLite? Is it even possible, or do I need to do this filtering in the application code?
Since SQLite 3.7.11, you can use MIN() or MAX() to select a row in a group:
SELECT ID,
PNR,
Name,
min(length(Name))
FROM MyTable
GROUP BY PNR;
You can use MIN(length(name))-aggregate function to find out the minimum length of several names; the slightly tricky thing is to get corresponding ID and NAME into the result. The following query should work:
select mt1.ID, mt1.PNR, mt1.Name
from MyTable mt1 inner join (
select pnr, min(length(Name)) as minlength
from MyTable group by pnr) mt2
on mt1.pnr = mt2.pnr and length(mt1.Name) = mt2.minlength

Any built-in function in Oracle to round down numbers and distribute the remaining values randomly

I have a table say STAFF that stores the staff names and their salaries.
Below are some sample data:
STAFF | SALARY
===========================
ALEX | 100.4
JESSICA | 100.4
PETER | 99.2
The total of salaries is always a whole number and I want to round down all staff's salaries and then randomly put the remaining value to one of them.
For example, the output would be like below if JESSICA is selected to receive the remaining value.
STAFF | SALARY
===========================
ALEX | 100
JESSICA | 101
PETER | 99
Does Oracle provide any built-in function to perform the described operation.
The quantity SALARY - TRUNC(SALARY) should give the decimal portion of each salary, for each record. You can sum this for the entire table, and then increment a certain user's salary but this amount. Try something like this:
UPDATE yourTable
SET SALARY = TRUNC(SALARY) + (SELECT SUM(SALARY - TRUNC(SALARY)) FROM yourTable)
WHERE STAFF = 'JESSICA'
here I have tried one thing that gives random result based on generated random no.
with mine(STAFF,salary,status) as
(
select 'ALEX',100.4,'Y' from dual union all
select 'JESSICA',100.4,'Y' from dual union all
select 'PETER',99.2,'Y' from dual union all
select 'randomno',floor(dbms_random.value(1,4)),'N' vno from dual
)
select STAFF,decode(rndno,rno,csalary,rsalary) salary,decode(rndno,rno,'selected to receive the remaining value',null) selected from(
select rownum rno,STAFF,salary,round(salary) rsalary,ceil(salary) csalary,
(select salary from mine where status='N') rndno
from mine where status='Y'
);
here on every run on query new user is selected which have floating salary.
in above query i have add one onther rows that supply random no and compare with acual result rows.

Oracle SQL - How to "pivot" one row to many

In Oracle 12c, I have a view, which takes a little time to run. When I add the where clause, it will return exactly one row of interest. The row has columns/value like this...
I need this flipped so that I can see one row per EACH "set". I need the SQL to return something like
I know I can do a UNION ALL for each of the entry sets, but as the view takes a little while to run, plus there are about 30 different sets (I only showed 3 - Car, Boat, and truck)
Is there a better way of doing this? I have looked at PIVOT/UNPIVOT, but I didn't see how to make this work.
I think you are looking for UNPIVOT
WITH TEMP_DATA (ID1, CarPrice, CarTax, BoatPrice, BoatTax, TruckPrice, TruckTax)
AS (
select 'AAA', 1, 2, 3, 4, 5, 6 from dual )
select TYPE, PRICE, TAX
from temp_data
unpivot
(
(PRICE, TAX)
for TYPE IN
(
(CarPrice, CarTax) as 'CAR',
(BoatPrice, BoatTax) as 'BOAT',
(TruckPrice, TruckTax) as 'TRUCK'
)
)
;
OUTPUT:
TYPE PRICE TAX
----- ---------- ----------
CAR 1 2
BOAT 3 4
TRUCK 5 6

Analyze intervals for gaps

I have a table with roads that contain mileage of start/end of every road.
I need to analyze this data and get query with same data more rows that contain mileage of start/end of gaps between roads with filled column name with value 'gap'.
Initial table:
id name kmstart kmend
1 road1 0 150
2 road2 150 200
3 road3 220 257
4 road4 260 290
Result query:
id name kmstart kmend
1 road1 0 150
2 road2 150 200
null gap 200 220
3 road3 220 257
null gap 257 260
4 road4 260 290
Try this query:
SELECT NULL, 'gap', previous_kmend AS kmstart, kmstart AS kmend
FROM (
SELECT id, name, kmstart, kmend, LAG(kmend) OVER (ORDER BY kmstart, kmend) AS previous_kmend
FROM roads
)
WHERE previous_kmend < kmstart
UNION ALL
SELECT id, name, kmstart, kmend
FROM roads
ORDER BY kmstart, kmend
I just put up a quick test and it works for me.
It uses the LAG function to get the previous kmend row, and then returns the "gap" row if it is less than the current record's kmstart row. I've written an article about the LAG function recently so it was helpful to remember.
Is this what you're after?
Also, as the other commenters have mentioned, "name" isn't a good column name as it's a reserved word. I've left it here in the code so it's consistent with your question though.