using oracle sql, how to convert each digit to sum 9 - oracle

I need help to convert a mobilenumber as a way of masking, i need to convert each digit to 9. Please see my sample below:
sample:
123456789
111111111
77771111
result:
876543210
888888888
22228888
notice that if you add each digit for (sample and result) the result is 9.

Use TRANSLATE:
SELECT value,
TRANSLATE( value, '1234567890', '8765432109' ) AS substitution
FROM table_name
Which, for your sample data:
CREATE TABLE table_name ( value ) AS
SELECT '123456789' FROM DUAL UNION ALL
SELECT '111111111' FROM DUAL UNION ALL
SELECT '77771111' FROM DUAL;
Gives:
VALUE | SUBSTITUTION
:-------- | :-----------
123456789 | 876543210
111111111 | 888888888
77771111 | 22228888
DO NOT use a substitution cipher to try to anonymise data.
However, this is not masking the data as it is (very) easy to get the original data back; you just put the substituted value back through the same translation and you have "unmasked" the data. So, if you are relying on this process to anonymise personal information then you have not achieved that goal as it is easy to reconstruct the original and de-anonymise the data.
SELECT value,
TRANSLATE( value, '1234567890', '8765432109' ) AS substitution,
TRANSLATE(
TRANSLATE( value, '1234567890', '8765432109' ),
'1234567890',
'8765432109'
) AS reversed_substitution
FROM table_name
Outputs:
VALUE | SUBSTITUTION | REVERSED_SUBSTITUTION
:-------- | :----------- | :--------------------
123456789 | 876543210 | 123456789
111111111 | 888888888 | 111111111
77771111 | 22228888 | 77771111
db<>fiddle here

Related

xsd format number , 5 decimal places

I have xsd code which is printing LINE_AMOUNT value as 14,952.59 , now i want to display this as 14,952.59000(5 decimal places).
How to achieve this?
Thank you
SQL Fiddle
Query 1 Either (if you want to use the current NLS values for decimal and thousands characters):
SELECT TO_CHAR(
14952.59,
'FM9G999G999G999G990D00000'
)
FROM DUAL
Results:
| TO_CHAR(14952.59,'FM9G999G999G999G990D00000') |
|-----------------------------------------------|
| 14,952.59000 |
Query 2 or:
SELECT TO_CHAR(
14952.59,
'FM9,999,999,999,990.00000'
)
FROM DUAL
Results:
| TO_CHAR(14952.59,'FM9,999,999,999,990.00000') |
|-----------------------------------------------|
| 14,952.59000 |
Update: SQL Fiddle
Query 3:
SELECT TO_CHAR(
TO_NUMBER(
'13,214,952.59',
'FM9G999G999G999G990D99999'
),
'FM9G999G999G999G990D00000'
) AS formatted_value
FROM DUAL
Results:
| FORMATTED_VALUE |
|------------------|
| 13,214,952.59000 |
Query 4:
SELECT TO_CHAR(
TO_NUMBER(
'13,214,952.59',
'FM9,999,999,999,990.99999'
),
'FM9,999,999,999,990.00000'
) AS formatted_value
FROM DUAL
Results:
| FORMATTED_VALUE |
|------------------|
| 13,214,952.59000 |
Try this, it will work for you I think.
select trim(to_char(14952.59,9999999999.99999)) from dual
OUTPUT
14952.59000

Oracle - Find Best Match between Two tables

My team and I are curious to determine the best way we can match Two Different sets of data. There are no keys that can be joined on as this data as is coming from two separate sources that know nothing about each other. We import this data into two oracle tables and once that is done we can begin to look for matches.
Both Tables contain a full list of Properties(As in Real estate). We are needing to match up the Properties in Table1 to any potential matching Properties found in Table2. For each and every record in Table1 search Table2 for a potential match and determine the probability of the match. My team and I have decided that the best way to do this would be to compare the Address fields from each of the two tables.
The one catch is that Table1 provides the Address in a Parsed format and allocates the address number, address Street and even the Address_type into separate columns while Table2 only contains one column to hold the Address. Each table has City, State and Zip columns that can be compared individually.
For Example - See Below Table1 and Table2:
Notice that the Primary Keys in my pseudo tables below are Key1 and Key2 matching the tables they are in.
+---------------+---------------+---------------+---------------+---------------+-------+-------+
+ + TABLE1 + + + + + +
+---------------+---------------+---------------+---------------+---------------+-------+-------+
| Key1 | Addr_Number | Addr_Street | Addr_Type | City | State | Zip |
+---------------+---------------+---------------+---------------+---------------+-------+-------+
| 1001 | 148 | Panas | Road | Robinson | CA | 76050 |
| 1005 | 110 | 48th | Street | San Juan | NJ | 8691 |
| 1009 | 8571 | Commerce | Loop | Vallejo | UT | 83651 |
| 1059 | 714 | Nettleton | Avenue | Vista | TX | 29671 |
| 1185 | 1587 | Orchard | Drive | Albuquerque | PA | 77338 |
+---------------+---------------+---------------+---------------+---------------+-------+-------+
+---------------+----------------------+---------------+---------------+---------------+
+ + TABLE2 + + + +
+---------------+----------------------+---------------+---------------+---------------+
| Key2 | Address | City | State | Zip |
+---------------+----------------------+---------------+---------------+---------------+
| Ax89f | 148 Panas Road | Robinson | CA | 76050 |
| B184a | 110 48th Street | San Juan | NJ | 08691 |
| B99ff | 8571 Commerce Lp | Vallejo | UT | 83651 |
| D81bc | 714 Nettleton Ave | Vista | TX | 29671 |
| F84a2 | 1587 Orachard Dr | Albuquerqu | PA | 77338 |
+---------------+----------------------+---------------+---------------+---------------+
The goal here is to provide an output to the user that simply displays ALL of the records from Table1 and the highest matched record found in Table2. There could of course be many records that are found that could be a potential match but we want to keep this a one to one relationship and not produce Duplicates in this initial output. The output should just be One Record out of Table one matched to the best find in Table2.
See below an example of the Desired output I am attempting to create:
+--------+-------+----------------+---------------------------+
+ + + Matched_Output + +
+--------+-------+----------------+---------------------------+
| Key1 | Key2 | Percent_Match | num_Matched_Records > 90% |
+--------+-------+----------------+---------------------------+
| 1001 | Ax89f | 100% | 5 | --All Parsed Values Match
| 1005 | B184a | 98% | 4 | --Zip Code prefixed with Zero in Table 2
| 1009 | B99ff | 95% | 3 | --Loop Vs Lp
| 1059 | D81bc | 95% | 2 | --Avenue Vs Ave
| 1185 | F84a2 | 97% | 2 | --City Spelled Wrong in Table 2 and Drive vs Dr
+--------+-------+----------------+---------------------------+
In the output I want to see Key1 from Table1 and the matched record right next to it showing that it matches to the record in Table2 to Key2. Next we are needing to know how well these two records match. There could be many records in Table2 that show a probability to matching a records in Table1. In fact every single record in Table2 can be assigned a percentage all the way from 0% up to a 100% match.
So now to the main question:
How does one obtain this percentage?
How do I Parse the Address column in Table2 so that I can compare each of the individual columns that make up the address in Table1 and then apply comparison algorithm on each parsed value?
So far this is what my team and myself have come up with (Brainstorming, Spitballin, whatever you want to call it).
We have taken a look at a couple of the built in Oracle Functions to obtain the percentages we are looking for as well as trying to utilize Regular Expressions. If I could hit up Google and get some of their Search Algorithms I would. Obviously I don't have that luxury and must design my own.
regexp_count(table2_city,'(^| )'||REPLACE(table1_city,' ','|')||'($| )') city_score,
regexp_count(table2_city,'(^| )') city_max,
to_char((city_score/city_max)*100, '999G999G999G999G990D00')||'%' city_perc,
The above was just what my team and I used as a proof of concept. We have simply selected these values out of the two tables and run the 'regexp_count' function against that columns. Here are a few other functions that we have taken a look at:
SOUNDEX
REGEXP_LIKE
REGEXP_REPLACE
These functions are great but I'm not sure they can be used in a Single Query between both tables to produce the desired output.
Another idea is that we could create a Function() that takes as its parameters the Address fields we are wanting to use to compare. That function would then search Table2 for the highest probable match and return back to the user the Key2 value out of Table2.
Function(Addr_Number, Addr_Street, Addr_type, City, State) RETURN table2.key2
For example maybe something like this 'could' work:
Select tb1.key1, table2Function(tb1.Addr_Number, tb1.Addr_Street, tb1.Addr_type, tb1.City, tb1.State) As Key2
From Table1 tb1;
Lastly, just know that there is roughly 15k records currently in Table1 and 20k records in Table2. Again... each record in Table 1 needs to be checked against each record in Table 2 for a potential match.
I'm all ears. And thank you in advance for your feedback.
Use the UTL_MATCH package:
Oracle Setup:
CREATE TABLE Table1 ( Key1, Addr_Number, Addr_Street, Addr_Type, City, State, Zip ) AS
SELECT 1001, 148, 'Panas', 'Road', 'Robinson', 'CA', 76050 FROM DUAL UNION ALL
SELECT 1005, 110, '48th', 'Street', 'San Juan', 'NJ', 8691 FROM DUAL UNION ALL
SELECT 1009, 8571, 'Commerce', 'Loop', 'Vallejo', 'UT', 83651 FROM DUAL UNION ALL
SELECT 1059, 714, 'Nettleton', 'Avenue', 'Vista', 'TX', 29671 FROM DUAL UNION ALL
SELECT 1185, 1587, 'Orchard', 'Drive', 'Albuquerque', 'PA', 77338 FROM DUAL;
CREATE TABLE Table2 ( Key2, Address, City, State, Zip ) AS
SELECT 'Ax89f', '148 Panas Road', 'Robinson', 'CA', '76050' FROM DUAL UNION ALL
SELECT 'B184a', '110 48th Street', 'San Juan', 'NJ', '08691' FROM DUAL UNION ALL
SELECT 'B99ff', '8571 Commerce Lp', 'Vallejo', 'UT', '83651' FROM DUAL UNION ALL
SELECT 'D81bc', '714 Nettleton Ave', 'Vista', 'TX', '29671' FROM DUAL UNION ALL
SELECT 'F84a2', '1587 Orachard Dr', 'Albuquerqu', 'PA', '77338' FROM DUAL;
Query:
SELECT Key1,
Key2,
UTL_MATCH.EDIT_DISTANCE_SIMILARITY(
A.Addr_Number || ' ' || A.Addr_Street || ' ' || A.Addr_Type
|| ' ' || A.City || ' ' || A.State || ' ' || A.Zip,
B.Address || ' ' || B.City || ' ' || B.State || ' ' || B.Zip
) AS Percent_Match,
CASE WHEN UTL_MATCH.EDIT_DISTANCE_SIMILARITY(
A.Addr_Number || ' ' || A.Addr_Street || ' ' || A.Addr_Type,
B.Address
) >= 90
THEN 1
ELSE 0
END
+
CASE WHEN UTL_MATCH.EDIT_DISTANCE_SIMILARITY( A.City, B.City ) >= 90
THEN 1
ELSE 0
END
+
CASE WHEN UTL_MATCH.EDIT_DISTANCE_SIMILARITY( A.State, B.State ) >= 90
THEN 1
ELSE 0
END
+
CASE WHEN UTL_MATCH.EDIT_DISTANCE_SIMILARITY( A.Zip, B.Zip ) >= 90
THEN 1
ELSE 0
END AS Num_Matched
FROM Table1 A
INNER JOIN
Table2 B
ON ( SYS.UTL_MATCH.EDIT_DISTANCE_SIMILARITY(
A.Addr_Number || ' ' || A.Addr_Street || ' ' || A.Addr_Type
|| ' ' || A.City || ' ' || A.State || ' ' || A.Zip,
B.Address || ' ' || B.City || ' ' || B.State || ' ' || B.Zip
) > 80 );
Output:
KEY1 KEY2 PERCENT_MATCH NUM_MATCHED
---------- ----- ------------- -----------
1001 Ax89f 100 4
1005 B184a 97 3
1009 B99ff 95 3
1059 D81bc 92 3
1185 F84a2 88 3
A few thoughts.
First, you may want to take a look at the utl_match package:
https://docs.oracle.com/cd/E18283_01/appdev.112/e16760/u_match.htm
Then: you surely will want to match by ZIP code and state first. Perhaps adding leading zeros to ZIP code where needed - although apparently one of your concerns is typos, not just different packaging of the input data. If there are typos in the ZIP code you can more or less deal with that, but if there are typos in the state that really sucks.
You may want to score the similarity by city, but often that won't help. For example, for all practical purposes Brooklyn, NY should be seen as matching New York City, NY but there's no way you can do that in your project. So I would put a very low weight on matching by city.
Similar comment about the address type; perhaps you can create a small table with equivalencies, such as Street, Str, Str. or Lane, Ln, Ln. But the fact is often people are not consistent when they give you an address; they may say "Clover Street" to one source and "Clover Avenue" to another. So you may be better off comparing only the street number and the street name.
Good luck!

How I can distribute values in Oracle

Regards.
Can you help me with the following?
I have the following records:
**ITEM VALUES**
A001 29440
A002 29440
A003 29440
A004 29440
A005 29440
Σ of the field values is equal to 147200, but the real value is 148 200.
How I can distribute each value in the VALUES column for the Σ is exactly equal to 148 200.
Thank you very much.
Without a better guide as to how you got the "real" value and how the difference should be distributed, you could do something trivial to fix the data - such as adding an equal share of the difference to each value.
Like this:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TEST ( ITEM, VALUE ) AS
SELECT 'A001', 29440 FROM DUAL
UNION ALL SELECT 'A002', 29440 FROM DUAL
UNION ALL SELECT 'A003', 29440 FROM DUAL
UNION ALL SELECT 'A004', 29440 FROM DUAL
UNION ALL SELECT 'A005', 29440 FROM DUAL;
UPDATE TEST
SET VALUE = VALUE + ( SELECT (148200 - SUM( VALUE ))/COUNT(1) FROM TEST );
Query 1:
SELECT * FROM TEST
Results:
| ITEM | VALUE |
|------|-------|
| A001 | 29640 |
| A002 | 29640 |
| A003 | 29640 |
| A004 | 29640 |
| A005 | 29640 |

add column check for format number to number oracle

I need to add a column to a table that check for input to be a max value of 999 to 999, like a soccer match score. How do I write this statement?
example:
| Score |
---------
| 1-2 |
| 10-1 |
|999-999|
| 99-99 |
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE SCORES (Score ) AS
SELECT '1-2' FROM DUAL
UNION ALL SELECT '10-1' FROM DUAL
UNION ALL SELECT '999-999' FROM DUAL
UNION ALL SELECT '99-99' FROM DUAL
UNION ALL SELECT '1000-1000' FROM DUAL;
Query 1:
SELECT SCORE,
CASE WHEN REGEXP_LIKE( SCORE, '^\d{1,3}-\d{1,3}$' )
THEN 'Valid'
ELSE 'Invalid'
END AS Validity
FROM SCORES
Results:
| SCORE | VALIDITY |
|-----------|----------|
| 1-2 | Valid |
| 10-1 | Valid |
| 999-999 | Valid |
| 99-99 | Valid |
| 1000-1000 | Invalid |

How to get latest two rows with certain value by date in SQL [duplicate]

This question already has answers here:
Get top results for each group (in Oracle)
(5 answers)
Closed last year.
My question is that I have certain table with some varchar2 values and insert date.
What I want to do is to get latest two such entries grouped by this varchar2 value
Is it possible to include some top(2) instead of max in Oracle group by ?
EDIT Updated to not count duplicate date value for the same varchar2.
Replaced RANK() with DENSE_RANK() such that it assigns consecutive ranks, then used distinct to eliminate the duplicates.
You can use DENSE_RANK()
SELECT DISTINCT TXT, ENTRY_DATE
FROM (SELECT txt,
entry_date,
DENSE_RANK () OVER (PARTITION BY txt ORDER BY entry_date DESC)
AS myRank
FROM tmp_txt) Q1
WHERE Q1.MYRANK < 3
ORDER BY txt, entry_date DESC
Input:
txt | entry_date
xyz | 03/11/2014
xyz | 25/11/2014
abc | 19/11/2014
abc | 04/11/2014
xyz | 20/11/2014
abc | 02/11/2014
abc | 28/11/2014
xyz | 25/11/2014
abc | 28/11/2014
Result:
txt | entry_date
abc | 28/11/2014
abc | 19/11/2014
xyz | 25/11/2014
xyz | 20/11/2014

Resources