select matching string from another table oracle - oracle

I have a database (Oracle) Table A with some strings in one of columns, Now I want to get matching records from Table B against each column value of Table A for example,
Table A
Name
-----------
ABC
DEE
GHI
JKL
Table B
Name
-----------
ABC
DEF
GHI
JKL
MNO
PQR
Now i want that each string in Table A must be checked against Table B's column and if some string is found almost identical then it should appear against original Value as per below
Table OutPut
Name Matched
--------|----------
ABC | ABC
DEE | DEF
GHI | GHI
JKL | JKL
I have tried following query
with data as(
SELECT Name FROM TABLE_A UNION ALL
SELECT Name FROM TABLE_B
)
SELECT Name
FROM
(
SELECT t.*,utl_match.edit_distance_similarity(upper(Name),upper('DEE')) eds
FROM data t
ORDER BY eds DESC
)
WHERE rownum = 1
but problem is that using this query i can check only one record at a time and that too against a hard coded string. Is there any way to check whole column from Table A one by one against Table B and produce result in output against each string.

Not too clever (hint: performance issue, but - see if it helps. Might be OK if there aren't too many rows involved.
You need lines 21 onwards.
I set similarity to be greater than 80 - adjust it, if needed (which is very probable, as data you posted is really sample data).
SQL> WITH ta (name)
2 AS (SELECT 'ABC' FROM DUAL
3 UNION ALL
4 SELECT 'DEE' FROM DUAL
5 UNION ALL
6 SELECT 'GHI' FROM DUAL
7 UNION ALL
8 SELECT 'JKL' FROM DUAL),
9 tb (name)
10 AS (SELECT 'ABC' FROM DUAL
11 UNION ALL
12 SELECT 'DEF' FROM DUAL
13 UNION ALL
14 SELECT 'GHI' FROM DUAL
15 UNION ALL
16 SELECT 'JKL' FROM DUAL
17 UNION ALL
18 SELECT 'MNO' FROM DUAL
19 UNION ALL
20 SELECT 'PQR' FROM DUAL)
21 SELECT ta.name,
22 tb.name,
23 UTL_MATCH.jaro_winkler_similarity (ta.name, tb.name) sim
24 FROM ta, tb
25 WHERE UTL_MATCH.jaro_winkler_similarity (ta.name, tb.name) > 80
26 ;
NAM NAM SIM
--- --- ----------
ABC ABC 100
DEE DEF 82
GHI GHI 100
JKL JKL 100
SQL>

Related

Insert record from one table to another table - Oracle

I have a table TABLE1 which has 5 columns (ROLL_NO, NAME, UNITS, CODE, AMOUNT);
CREATE TABLE TABLE1 (ROLL_NO VARCHAR2(3), NAME VARCHAR2(4), UNITS NUMBER, AMOUNT NUMBER, CODE VARCHAR2(3));
------------------------------------------------------------------------------------------
INSERT INTO TABLE1 VALUES ('101', 'JOHN', 1, 6, 'ABC');
INSERT INTO TABLE1 VALUES ('101', 'JOHN', 2, 6, 'ABC');
INSERT INTO TABLE1 VALUES ('102', 'TOMS', 1, 7, 'ABC');
INSERT INTO TABLE1 VALUES ('102', 'TOMS', 6, 7, 'ABC');
INSERT INTO TABLE1 VALUES ('103', 'FINN', 1, 1, 'BCD');
ROLL_NO NAME UNITS AMOUNT CODE
-------------------------------------------------------
101 JOHN 1 6 ABC
101 JOHN 2 6 ABC
-------------------------------------------
102 TOMS 1 7 ABC
102 TOMS 6 7 ABC
103 FINN 1 1 BCD
There is second table TABLE2 where we need to insert data from TABLE1
CREATE TABLE TABLE2 (ROLL_NO VARCHAR2(3), NAME VARCHAR2(4), RESULT VARCHAR2(3));
There are three conditions to insert data into TABLE2
1st case : If CODE is 'ABC' and SUM(UNITS) of particular ROLL_NO is equal to AMOUNT then don't insert data into TABLE2
2nd case : If CODE is 'ABC' and SUM(UNITS) of particular ROLL_NO is not equal to AMOUNT then insert data with RESULT column value as 'YES'
3rd case : If CODE is not 'ABC' then RESULT column will be 'YES'.
Note: NAME, CODE and AMOUNT will be same for particular ROLL_NO though ROLL_NO has multiple UNITS.
Example :
ROLL_NO 102 CODE 'ABC' and two lines with SUM(UNITS) as 7 and its equal to AMOUNT i.e. 7 and (1st case)
ROLL_NO 101 has CODE 'ABC' and two lines with SUM(UNITS) as 3 and its not equal to AMOUNT i.e. 6 (2nd case)
ROLL_NO 103 has CODE 'BCD' which is not equal to 'ABC'(3rd case)
At the end TABLE2 should have
ROLL_NO NAME RESULT
-----------------------------
101 JOHN YES
103 FINN YES
I have tried this oracle query but it is inserting data related to 102 ROLL_NO which I don't need
SELECT T1.ROLL_NO, T1.NAME,
CASE
WHEN T1.CODE <> 'ABC' THEN 'YES'
WHEN T1.CODE = 'ABC' AND T2.TOT_UNITS <> T1.AMOUNT THEN 'YES'
END RESULT
FROM (SELECT DISTINCT ROLL_NO, NAME, AMOUNT, CODE
FROM TABLE1 ) T1
JOIN (SELECT ROLL_NO, SUM(UNITS) AS TOT_UNITS
FROM TABLE1
GROUP BY ROLL_NO) T2 ON T1.ROLL_NO = T2.ROLL_NO
I am not able to figure out how to not insert ROLL_NO 102 record into TABLE2..Can anyone provide better query than this if possible? Thank you
A "better" option is to scan table1 only once.
SQL> insert into table2 (roll_no, name, result)
2 with temp as
3 (select roll_no, name, sum(units) sum_units, amount, code,
4 case when code = 'ABC' and sum(units) = amount then 'NO'
5 when code = 'ABC' and sum(units) <> amount then 'YES'
6 else 'YES'
7 end as result
8 from table1
9 group by roll_no, name, amount, code
10 )
11 select roll_no, name, result
12 from temp
13 where result = 'YES';
2 rows created.
SQL> select * from table2;
ROL NAME RES
--- ---- ---
101 JOHN YES
103 FINN YES
SQL>

Extract Data Between Brackets in Oracle SQL

I have a table with data in below format
COURSE
[]
["12345"]
["12345","7890"
I want to extract the data between [] but without "
So, my output would be in below format
COURSE
12345
12345, 7890
I tried the below code which works fine for first 3 rows
select REGEXP_SUBSTR (COURSE,
'"([^"]+)"',
1,
1,
NULL,
1) from TEST;
But 4th row only results in 12345.
Why not simple translate?
SQL> with test (course) as
2 (select '[]' from dual union
3 select null from dual union
4 select '["12345"]' from dual union
5 select '["12345","7890"]' from dual
6 )
7 select course,
8 translate(course, 'a[]"', 'a') result
9 from test;
COURSE RESULT
---------------- -----------------------------------------
["12345","7890"] 12345,7890
["12345"] 12345
[]
SQL>

combine multiple rows result in single row based on one column value

I i want to combine multiple rows result into single row based on one column called type.
Ex say suppose i have below result from my query .
seqnum type name
456 SH Google2
456 CN transwork
123 SH partyshipper
123 CN consignee
Actual result i want is something like below table
seqnum consigneename shippername
456 transwork Google2
123 consignee partyshipper
Basically i want to get result like consignee name when type is CN and shipper name is when type is SH if its not both then i can add extra column with name just like otherparty.
I can get result and iterate result set and set value of object. but i think this will be better if we get formatted result in query only.can some one help in in getting this.
Thanks for the help.
Something like this usually helps; lines #1 - 7 represent your sample data. Code you need begins at line #8.
SQL> with test (seqnum, type, name) as
2 (select 456, 'SH', 'Google2' from dual union all
3 select 456, 'CN', 'transwork' from dual union all
4 select 123, 'SH', 'partyshipper' from dual union all
5 select 123, 'CN', 'consignee' from dual union all
6 select 999, 'XX', 'littlefoot' from dual
7 )
8 select seqnum,
9 max(case when type = 'CN' then name end) consigneename,
10 max(case when type = 'SH' then name end) shipppername,
11 max(case when type not in ('CN', 'SH') then name end) otherparty
12 from test
13 group by seqnum;
SEQNUM CONSIGNEENAM SHIPPPERNAME OTHERPARTY
---------- ------------ ------------ ------------
123 consignee partyshipper
999 littlefoot
456 transwork Google2
SQL>
Borrowing the query from #Littlefoot. You may also use PIVOT for this getting the expected result.
with test (seqnum, type, name) as
(select 456, 'SH', 'Google2' from dual union all
select 456, 'CN', 'transwork' from dual union all
select 123, 'SH', 'partyshipper' from dual union all
select 123, 'CN', 'consignee' from dual union all
select 999, 'OT', 'littlefoot' from dual
)
select * from test
pivot (
min(name) for type in
(
'SH' shippingname
, 'CN' consigneename
, 'OT' someother
)
)
;
SEQNUM SHIPPINGNAME CONSIGNEENAM SOMEOTHER
---------- ------------ ------------ ------------
999 littlefoot
456 Google2 transwork
123 partyshipper consignee
I'd self join the table and filter different types in each side of the join:
SELECT COALESCE(c.seqnum, s.seqnum) AS seqnum,
COALESCE(c.name, 'other') AS consigneename,
COALESCE(s.name, 'other') AS shippername
FROM (SELECT *
FROM mytable
WHERE type = 'CN') c
FULL OUTER JOIN (SELECT *
FROM mytable
WHERE type = 'SN') s ON c.seqnum = s.seqnum

display multiple column records in one column in oracle

I have Table having following columns in Oracle;
ID NIC NTN MBL NAME
---------------------------------------
1 1234512 ABC
2 321 XYZ
3 5421 POI
4 541245 624
I need to display like this in select query
ID NIC/NTN/MBL NAME
1 1234512 ABC
2 321 XYZ
3 5421 POI
4 541245 // taking first value
I was trying to do with
SELECT
A.ID,
"CNIC/NTN/MBL"
A.NAME,
A.REASON
B.NAME
FROM TABLEA A
INNER JOIN TABLEB B ON A.R_ID = B.R_ID
UNPIVOT INCLUDE NULLS
(
CNIC/NTN/MBL FOR cols IN (A.NIC, A.NTN, A.MBL)
)
but unable to do.
Use COALESCE:
SELECT
ID,
COALESCE(NIC, NTN, MBL) AS "NIC/NTN/MBL",
NAME
FROM yourTable;
This should work because in the call to COALESCE above, I list the three columns from left to right, and the first non NULL value will be retained.
You need the COALESCE function (which simply returns the first non-null value in the specified inputs, reading from left to right), like so:
WITH your_table AS (SELECT 1 ID, 1234512 nic, NULL ntn, NULL mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 2 ID, NULL nic, 321 ntn, NULL mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 3 ID, NULL nic, NULL ntn, 5421 mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 4 ID, 541245 nic, 624 ntn, NULL mbl, 'ABC' NAME FROM dual)
SELECT ID,
COALESCE(nic, ntn, mbl) nic_ntn_mbl,
NAME
FROM your_table;
ID NIC_NTN_MBL NAME
---------- ----------- ----
1 1234512 ABC
2 321 ABC
3 5421 ABC
4 541245 ABC

oracle sqlplus report compute columns

new to this site, so I may not be formatting things right
I have a SQLPlus report that has a very unique requirement that I can't seem to figure out. What I need to do is based on the total value of a break column display a piece of text that says 'Available' or 'Full'.
Here is what the report looks like:
date column 1 column 2 count
===== ======== ======== =====
1/5/14 ABC ABC 10
DEF DEF 20
****** -----
total 30 - this would be a normal compute when break on date
What I need to do is compare that total count field (30 in this case) and if it is > a hard-coded value (say 20) print 'Full' otherwise 'Available'. I'm open to any suggestions, I don't have to print the 30 if there is a way to substitute the text in its place or print on another line or next to it somewhere (Or even if I can make the label say text I want). Issue I have is applying that compare logic in the sqlplus report itself.
Any ideas would be greatly appreciated.
Many thanks.
Mark
SQLPlus has only basic reporting features. In particular, you can't really customize most of its features like BREAK and COMPUTE SUM.
However, you can use all of SQL features so you can probably customize your SQL to get the result you want. Something like this:
SQL> WITH DATA AS (
2 SELECT DATE '2014-05-01' d, 'ABC' c1, 'ABC' c2, 10 cnt FROM dual UNION ALL
3 SELECT DATE '2014-05-01' d, 'DEF' c1, 'DEF' c2, 20 cnt FROM dual UNION ALL
4 SELECT DATE '2014-06-01' d, 'GHI' c1, 'GHI' c2, 10 cnt FROM dual UNION ALL
5 SELECT DATE '2014-06-01' d, 'JKL' c1, 'JKL' c2, 5 cnt FROM dual
6 )
7 SELECT CASE
8 WHEN GROUPING(c1) = 1 THEN '**Total**'
9 ELSE to_char(d, 'dd/mm/yyyy')
10 END dt,
11 c1, c2, SUM(cnt),
12 CASE
13 WHEN GROUPING(c1) = 1 AND SUM(cnt) > 20 THEN 'Full'
14 WHEN GROUPING(c1) = 1 AND SUM(cnt) <= 20 THEN 'Available'
15 END AVAILABILITY
16 FROM DATA
17 GROUP BY d, ROLLUP ((c1, c2));
DT C1 C2 SUM(CNT) AVAILABILITY
---------- --- --- ---------- ------------
01/05/2014 ABC ABC 10
01/05/2014 DEF DEF 20
**Total** 30 Full
01/06/2014 GHI GHI 10
01/06/2014 JKL JKL 5
**Total** 15 Available
6 rows selected
For further reading: an excellent article about GROUP BY, ROLLUP and CUBE by Rob van Wijk.

Resources