Oracle SQL -- find the values NOT in a table - sql

Take this table WORDS
WORD
Hello
Aardvark
Potato
Dog
Cat
And this list:
('Hello', 'Goodbye', 'Greetings', 'Dog')
How do I return a list of words that AREN'T in the words table, but are in my list?
If I have a table that "contains all possible words", I can do:
SELECT * from ALL_WORDS_TABLE
where word in ('Hello', 'Goodbye', 'Greetings', 'Dog')
and word not in
(SELECT word from WORDS
where word in ('Hello', 'Goodbye', 'Greetings', 'Dog')
);
However I do not have such a table. How else can this be done?
Also, constructing a new table is not an option because I do not have that level of access.

Instead of hard coding the list values into rows, use DBMS_DEBUG_VC2COLL to dynamically convert your delimited list into rows, then use the MINUS operator to eliminate rows in the second query that are not in the first query:
select column_value
from table(sys.dbms_debug_vc2coll('Hello', 'Goodbye', 'Greetings', 'Dog'))
minus
select word
from words;

Try this solution :
SELECT
a.word
FROM
(
SELECT 'Hello' word FROM DUAL UNION
SELECT 'Goodbye' word FROM DUAL UNION
SELECT 'Greetings' word FROM DUAL UNION
SELECT 'Dog' word FROM DUAL
) a
LEFT JOIN ALL_WORDS_TABLE t ON t.word = a.word
WHERE
t.word IS NULL

You can turn your list into a view like this:
select 'Hello' as word from dual
union all
select 'Goodbye' from dual
union all
select 'Greetings' from dual
union all
select 'Dog' from dual
Then you can select from that:
select * from
(
select 'Hello' as word from dual
union all
select 'Goodbye' from dual
union all
select 'Greetings' from dual
union all
select 'Dog' from dual
)
where word not in (select word from words);
Possibly not as neat a solution as you might have hoped for...
You say you don't have sufficient privileges to create tables, so presumably you can't create types either - but if you can find a suitable type "lying around" in your database you can do this:
select * from table (table_of_varchar2_type('Hello','Goodbye','Greetings','Dog'))
where column_value not in (select word from words);
Here table_of_varchar2_type is imagined to be the name of a type that is defined like:
create type table_of_varchar2_type as table of varchar2(100);
One such type you are likely to be able to find is SYS.KU$_VCNT which is a TABLE OF VARCHAR2(4000).

Related

Regexp pattern for special characters

I have the data in the format like
Input:
Code_1
FAB
?
USP BEN,
.
-
,
Output:
Code_1
FAB
IP BEN,
I need to exclude only the value which have length as 1 and and are special characters
I am using (regexp_like(code_1,'^[^<>{}"/|;:.,~!?##$%^=&*\]\\()\[¿§«»ω⊙¤°℃℉€¥£¢¡®©0-9_+]')) AND LENGTH(CODE_1)>=1
I have also tried REGEXP_LIKE(CODE_1,'[A-Za-z0-9]')
Based on your requirements which I understand are you want data that is not single character AND non-alpha numeric (at the same time), this should do it for you.
The 'WITH' clause just sets up test data in this case and can be thought of like a temp table here. It is a great way to help people help you by setting up test data. Always include data you don't expect!
The actual query starts below and selects data that uses grouping to get the data that is NOT a group of non-alpha numeric with a length of one. It uses a POSIX shortcut of [:alnum:] to indicate [A-Za-z0-9].
Note your requirements will allow multiple non-alnum characters to be selected as is indicated by the test data.
WITH tbl(DATA) AS (
SELECT 'FAB' FROM dual UNION ALL
SELECT '?' FROM dual UNION ALL
SELECT 'USP BEN,' FROM dual UNION ALL
SELECT '.' FROM dual UNION ALL
SELECT '-' FROM dual UNION ALL
SELECT '----' FROM dual UNION ALL
SELECT ',' FROM dual UNION ALL
SELECT 'A' FROM dual UNION ALL
SELECT 'b' FROM dual UNION ALL
SELECT '5' FROM dual
)
SELECT DATA
FROM tbl
WHERE NOT (REGEXP_LIKE(DATA, '[^[:alnum:]]')
AND LENGTH(DATA) = 1);
DATA
----------
FAB
USP BEN,
----
A
b
5
6 rows selected.

How to use regex to select rows where the column has more than two words in oracle

for example:
id
center
1
man
2
some men here
I want to select rows with three or more words so ouput should be:
id
center
2
some men here
I've tried using this: regexp_like(center, '\w{3,}') but it's not giving the expected output.
You can use REGEXP_COUNT to look for more than 2 sets of words
WITH
some_table (id, center)
AS
(SELECT 1, 'man' FROM DUAL
UNION ALL
SELECT 2, 'some men here' FROM DUAL)
SELECT *
FROM some_table
WHERE REGEXP_COUNT (center, '\w+') > 2;
You could use the regex pattern \w+ \w+ \w+:
SELECT id, center
FROM yourTable
WHERE REGEXP_LIKE(center, '\w+[:space:]+\w+[:space:]+\w+);
I think this is the regex you are looking for:
regexp_like(center, '((\s|^)\w+(\s|$)?){3,}')
or with a short test:
select * from (
select 'abc' center
from dual
union all
select 'abc def'
from dual
union all
select 'abc def ghi'
from dual
union all
select 'abc def ghi jkl'
from dual
)
where regexp_like(center, '((\s|^)\w+(\s|$)?){3,}')
It says
Start of line or whitespace
One or more letters
Whitespace or end of line, non-greedy
Repeat all of the above at least three times

Find value that is not a number or a predefined string

I have to test a column of a sql table for invalid values and for NULL.
Valid values are: Any number and the string 'n.v.' (with and without the dots and in every possible combination as listed in my sql command)
So far, I've tried this:
select count(*)
from table1
where column1 is null
or not REGEXP_LIKE(column1, '^[0-9,nv,Nv,nV,NV,n.v,N.v,n.V,N.V]+$');
The regular expression also matches the single character values 'n','N','v','V' (with and without a following dot). This shouldn't be the case, because I only want the exact character combinations as written in the sql command to be matched. I guess the problem has to do with using REGEXP_LIKE. Any ideas?
I guess this regexp will work:
NOT REGEXP_LIKE(column1, '^([0-9]+|n\.?v\.?)$', 'i')
Note that , is not a separator, . means any character, \. means the dot character itself and 'i' flag could be used to ignore case instead of hard coding all combinations of upper and lower case characters.
No need to use regexp (performance will increase by large data) - plain old TRANSLATE is good enough for your validation.
Note that the first translate(column1,'x0123456789','x') remove all numeric charcters from the string, so if you end with nullthe string is OK.
The second translate(lower(column1),'x.','x') removes all dots from the lowered string so you expect the result nv.
To avoid cases as n.....v.... you also limit the string length.
select
column1,
case when
translate(column1,'x0123456789','x') is null or /* numeric string */
translate(lower(column1),'x.','x') = 'nv' and length(column1) <= 4 then 'OK'
end as status
from table1
COLUMN1 STATUS
--------- ------
1010101 OK
1012828n
1012828nv
n.....v....
n.V OK
Test data
create table table1 as
select '1010101' column1 from dual union all -- OK numbers
select '1012828n' from dual union all -- invalid
select '1012828nv' from dual union all -- invalid
select 'n.....v....' from dual union all -- invalid
select 'n.V' from dual; -- OK nv
You can use:
select count(*)
from table1
WHERE TRANSLATE(column1, ' 0123456789', ' ') IS NULL
OR LOWER(column1) IN ('nv', 'n.v', 'nv.', 'n.v.');
Which, for the sample data:
CREATE TABLE table1 (column1) AS
SELECT '12345' FROM DUAL UNION ALL
SELECT 'nv' FROM DUAL UNION ALL
SELECT 'NV' FROM DUAL UNION ALL
SELECT 'nV' FROM DUAL UNION ALL
SELECT 'n.V.' FROM DUAL UNION ALL
SELECT '...................n.V.....................' FROM DUAL UNION ALL
SELECT '..nV' FROM DUAL UNION ALL
SELECT 'n..V' FROM DUAL UNION ALL
SELECT 'nV..' FROM DUAL UNION ALL
SELECT 'xyz' FROM DUAL UNION ALL
SELECT '123nv' FROM DUAL;
Outputs:
COUNT(*)
5
or, if you want any quantity of . then:
select count(*)
from table1
WHERE TRANSLATE(column1, ' 0123456789', ' ') IS NULL
OR REPLACE(LOWER(column1), '.') = 'nv';
Which outputs:
COUNT(*)
9
db<>fiddle here

How do I Count the words in a string using regex

I'm trying to count the words in a string using regex in Oracle 10g.
I've been trying this
select *
from books
where REGEXP_LIKE(title, '[ ]{2}');
so that its returning titles with at least 3 words in the title.
INSTR is also a viable option. By looking for the second occurrence of a space, that will indicate that the string has at least 3 words.
WITH
books
AS
(SELECT 'Tom Sawyer' title FROM DUAL
UNION ALL
SELECT 'A tale of two cities' FROM DUAL
UNION ALL
SELECT 'The Little Prince' FROM DUAL
UNION ALL
SELECT 'Don Quixote' FROM DUAL)
SELECT title
FROM books
WHERE instr(title, ' ', 1, 2) > 0;
If you do with to stick with regex, the regex expression below can be used to find books that have 3 or more words.
WITH
books
AS
(SELECT 'Tom Sawyer' title FROM DUAL
UNION ALL
SELECT 'A tale of two cities' FROM DUAL
UNION ALL
SELECT 'The Little Prince' FROM DUAL
UNION ALL
SELECT 'Don Quixote' FROM DUAL)
SELECT title
FROM books
WHERE REGEXP_LIKE (title, '(\S+\s){2,}');
(Thanks #Littlefoot for the books!)
REPLACE does the job (with some calculation).
SQL> with books as
2 (select 'Tom Sawyer' title from dual union all
3 select 'A tale of two cities' from dual union all
4 select 'The Little Prince' from dual union all
5 select 'Don Quixote' from dual
6 )
7 select title
8 from books
9 where length(title) - length(replace(title, ' ', '')) >= 2;
TITLE
--------------------
A tale of two cities
The Little Prince
SQL>
The below one is simple and easy to understand (works on 11g and later):
The below is just to create some sample data
create table books as
with tab as
(
select 'Tom Sawyer' title from dual
union all
select 'A tale of two cities' from dual
union all
select 'The Little Prince' from dual
union all
select 'The_Little_Prince' from dual
union all
select 'Don Quixote' from dual
union all
select null from dual
)
select title
from tab;
The below is your solution to get those titles that have at least 3 words in it
select title
from books
where regexp_count(title, '\w+') > 2
Output:

How to cut everything after a specific character, but in case string doesn't contain it do nothing?

Let's say i have following data:
fjflka, kdjf
ssssllkjf fkdsjl
skfjjsld, kjl
jdkfjlj, ksd
lkjlkj hjk
I want to cut out everything after ',' but in case the string doesn't contain this character, it wont do anything, if i use substr and cut everything after ',' the string which doesn't contain this character shows as null. How do i achieve this? Im using oracle 11g.
This should work. Simply use regexp_substr
with t_view as (
select 'fjflka, kdjf' as text from dual union
select 'ssssllkjf fkdsjl' from dual union
select 'skfjjsld, kjl' from dual union
select 'jdkfjlj, ksd' from dual union
select 'lkjlkj hjk' from dual
)
select text,regexp_substr(text,'[^,]+',1,1) from t_view;
Assuming your table :
SQL> desc mytable
s varchar2(100)
you may use:
select decode(instr(s,','),0,s,substr(s,1,instr(s,',')-1)) from mytable;
demo
Well the below query works as per your requirement.
with mytable as
(select 'aaasfasf wqwe' s from dual
union all
select 'aaasfasf, wqwe' s from dual)
select s,substr(s||',',1,instr(s||',',',')-1) from mytable;