Select values substituting the values of other column - sql

I have a table like this :-
A B
28496 TS_28496_FX
7365 TS_7365_FX
14760 TS_14760_FX
222 TS_222_AA1
I want to find all the records for column B which does not match the pattern
'TS_' || A || '_FX'
So this shows me the only result
222 TS_222_AA1
Thanks

This is a way:
with yourData(A,B) as (
select '28496' ,'TS_28496_FX' from dual union all
select '7365' ,'TS_7365_FX' from dual union all
select '14760' ,'TS_14760_FX' from dual union all
select '222' ,'TS_222_AA1' from dual union all
select '999' ,'999' from dual
)
select *
from yourData
where B != 'TS_' || A || '_FX'
which gives:
A B
----- -----------
222 TS_222_AA1
999 999
This assumes that B always is not null; otherwise you may use
where nvl(B, '-') != 'TS_' || A || '_FX'

Related

sql query for like to Order exact match at top in list

sql query for like to show exact match first in list:
dataset: "abcd", "a","b","bc","bcd"
select * from table where data like "%bc%";
it should show in order bc, abcd, bcd.
As you said - sort by match.
SQL> with test (col) as
2 (select 'abcd' from dual union all
3 select 'a' from dual union all
4 select 'b' from dual union all
5 select 'bc' from dual union all
6 select 'bcd' from dual
7 )
8 select col
9 from test
10 where col like '%' || '&&par_search_string' ||'%'
11 order by utl_match.jaro_winkler_similarity(col, '&&par_search_string') desc;
Enter value for par_search_string: bc
COL
----
bc
bcd
abcd
SQL> undefine par_search_string
SQL> /
Enter value for par_search_string: cd
COL
----
bcd
abcd
SQL>
One of many methods:
with
t as (
select 'abcd' c from dual union all
select 'a' from dual union all
select 'b' from dual union all
select 'bc' from dual union all
select 'bcd' from dual
)
select *
from t
where c like '%bc%'
order by length(c)
Demo.
I think you can use a query like this one that can return your expected result.
select * from table where data='bc'
union all
select * from table where data like '%bc%' and data<>'bc'
One method is:
select *
from t
where data like '%bc%'
order by (case when data = 'bc' then 1 else 2 end);
Or if you don't want to type so much:
order by nullif(data, 'bc') desc
The descending sort puts NULL values first.

How to convert vertical string into horizontal in Oracle

O
N
K
A
R
how to convert it into ONKAR. reverse of it I know. But this I am not able to solve.
You can't do what you want generally without also having a second column which provides the ordering for each letter. Assuming you do have a column for the position, we can try:
SELECT LISTAGG(letter, '') WITHIN GROUP (ORDER BY position) word
FROM yourTable;
Demo
Data:
letter | position
O | 1
N | 2
K | 3
A | 4
R | 5
Listagg is right solution for strings up to 4000 bytes cuz it returns varchar2 data type. But for longer strings you may get clob data type.
with s (letter, position) as (
select 'O', 1 from dual union all
select 'N', 2 from dual union all
select 'K', 3 from dual union all
select 'A', 4 from dual union all
select 'R', 5 from dual)
select xmlcast(xmlagg(xmlelement(x, letter) order by position) as clob) c
from s;
C
---------------
ONKAR
You can use this as long as data result has all rows that you want to stick together.
with data as (select 'O' as letter from dual
union all
select 'N' from dual
union all
select 'K' from dual
union all
select 'A' from dual
union all
select 'R' from dual)
SELECT LISTAGG(letter, '') WITHIN GROUP (ORDER BY rownum)
FROM data;
If your data is in a single row separated by newline (ASCII 13) characters then you can just use REPLACE( value, CHR(13) ):
Oracle Setup:
CREATE TABLE test_data ( value ) AS
SELECT 'O' || CHR(13) || 'N' || CHR(13) || 'K' || CHR(13) || 'A' || CHR(13) || 'R' FROM DUAL
Query:
SELECT value, REPLACE( value, CHR(13) ) FROM test_data
Output:
VALUE | REPLACE(VALUE,CHR(13))
:-------- | :---------------------
O | ONKAR
N |
K |
A |
R |
db<>fiddle here

Oracle SQL - How to Cut out characters from a string with SUBSTR?

I have values like "ABC1234", "ABC", "DEF456", "GHI" etc. in a specific column which I need.
Now I need to split this string but only if the character (e.g. "ABC") are followed by digits.
So if the value is "ABC1234" then I need to cut out ABC and 1234 seperated. But if there is only "ABC" as a value, I just need the "ABC". I can't find any solution with SUBSTR. Do you have any idea?
Note: The length of the characters can differ from 1 to 10 and also the length from the digits (sometimes there isn't any like I showed you).
So if the value is "ABC1234" then I need to cut out ABC and 1234
seperated. But if there is only "ABC" as a value, I just need the
"ABC".
Amidst of other solutions, I propose one solution as shown below:
Logic:
1) Replace all the digits to 1. Check the position of the digit occurring in the string. If
there is no digit in the string then use the String.
2) Extract the alphabets from 1st position to the position where
digit starts.
3) Extract the digit from the position it starts till end. If digit doesnot exists the set it NULL
--Dataset Preparation
with test (col) as
(select 'ABC1234' from dual union all
select 'ABC' from dual union all
select 'dEfH456' from dual union all
select '123GHI' from dual union all
select '456' from dual
)
--Query
select col Original_Column,
CASE
WHEN (instr(regexp_replace(col,'[0-9]','1'),'1',1)) = 0
then col
else
substr( col,1,instr(regexp_replace(col,'[0-9]','1'),'1',1)-1)
end Col_Alp,
CASE
WHEN (instr(regexp_replace(col,'[0-9]','1'),'1',1)) = 0
then NULL
Else
substr( col,instr(regexp_replace(col,'[0-9]','1'),'1',1))
END col_digit
from test
where regexp_like(col, '^[a-zA-Z0-9]+$');
Result:
SQL> /
Original_Column Col_Alp col_digit
---------- ----- -----
ABC1234 ABC 1234
ABC ABC NULL
dEfH456 dEfH 456
123GHI NULL 123GHI
456 NULL 456
Using SUBSTR (and INSTR and TRANSLATE):
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE data ( value ) AS
SELECT 'ABC1234' FROM DUAL UNION ALL
SELECT 'ABC123D' FROM DUAL UNION ALL
SELECT 'ABC ' FROM DUAL UNION ALL
SELECT 'ABC' FROM DUAL UNION ALL
SELECT 'DEFG456' FROM DUAL UNION ALL
SELECT 'GHI' FROM DUAL UNION ALL
SELECT 'JKLMNOPQRS9' FROM DUAL;
Query 1:
SELECT value,
SUBSTR( value, 1, first_digit - 1 ) AS prefix,
TO_NUMBER( SUBSTR( value, first_digit ) ) AS suffix
FROM (
SELECT value,
INSTR(
TRANSLATE( value, '-1234567890', ' ----------' ),
'-',
1
) AS first_digit
FROM data
)
WHERE SUBSTR( value, first_digit ) IS NOT NULL
AND TRANSLATE( SUBSTR( value, first_digit ), '-1234567890', ' ' ) IS NULL
Results:
| VALUE | PREFIX | SUFFIX |
|-------------|------------|--------|
| ABC1234 | ABC | 1234 |
| DEFG456 | DEFG | 456 |
| JKLMNOPQRS9 | JKLMNOPQRS | 9 |
Try this below query for scenarios mentioned , I didn't split if characters followed by numbers:
with test (col) as
(select 'ABC1234' from dual union all
select 'ABC' from dual union all
select 'dEfH456' from dual union all
select '123GHI' from dual union all
select '456' from dual
)
select col,reverse(trim(regexp_replace(reverse(col),'^[0-9]+',' '))) string ,trim(regexp_replace(col,'^[a-zA-Z]+',' ')) numbers from test
if like to move that characters&string to any place my case statement
with test (col) as
(select 'ABC1234' from dual union all
select 'ABC' from dual union all
select 'dEfH456' from dual union all
select '123GHI' from dual union all
select '456' from dual
)
select v.col,case when v.string=v.numbers THEN NULL ELSE string end string , v.numbers
from (select col,reverse(trim(regexp_replace(reverse(col),'^[0-9]+',' '))) string ,trim(regexp_replace(col,'^[a-zA-Z]+',' ')) numbers from test) v
Would something like this do?
SQL> with test (col) as
2 (select '"ABC1234", "ABC", "dEf456", "123GHI", "456"' from dual),
3 inter as
4 (select trim(regexp_substr(replace(col, '"', ''), '[^,]+', 1, level)) token
5 from test
6 connect by level <= regexp_count(col, ',') + 1
7 )
8 select regexp_substr(token, '^[a-zA-Z]+') letters,
9 regexp_substr(token, '[0-9]+$') digits
10 from inter
11 where regexp_like(token, '^[a-zA-Z]+[0-9]+$');
LETTERS DIGITS
---------- ----------
ABC 1234
dEf 456
SQL>

ORACLE display count to zero, when row is null in column

I have a table with many of columns, I count the specific names on column and if that name not on list, I want to display it zero, but not get in to list.
SELECT Names, COUNT (*)
FROM NAMESTABLE
WHERE names IN
('Jenny',
'Penny',
'George',
'James',
'Jessica',
'Monica',
'Erica')
AND
adeddate BETWEEN '2014/10/15' AND '2014/10/16'
GROUP BY names
NAMES || COUNT(*)
Jenny || 33
Penny || 4
George || 25
James || 87
so i want to Jessica, Monica, Erica as ZERO even these names are not in COLUMN
Names || Count(*)
Jenny || 33
Penny || 4
George || 25
James || 87
Jessica || 0
Monica || 0
Erica || 0
nvl(count(*),0) does not work
You could group your results by name and then left join the result to a table of your names to fill in the blanks:
SELECT rn.name, NVL(cnt, 0)
FROM (SELECT 'Jenny' AS name FROM dual
UNION ALL
SELECT 'Penny' FROM dual
UNION ALL
SELECT 'George' FROM dual
UNION ALL
SELECT 'James' FROM dual
UNION ALL
SELECT 'Jessica' FROM dual
UNION ALL
SELECT 'Monica' FROM dual
UNION ALL
SELECT 'Erica' FROM dual) rn
LEFT JOIN (SELECT name, COUNT(*) AS cnt
FROM namestable
WHERE adeddate BETWEEN '2014/10/15' AND '2014/10/16'
GROUP BY name) n ON n.name = rn.name
Then you must use other syntax:
SELECT t.Names, COUNT(n.Names)
FROM (
SELECT 'Jenny' AS names FROM DUAL UNION ALL
SELECT 'Penny' FROM DUAL UNION ALL
SELECT 'George' FROM DUAL UNION ALL
SELECT 'James' FROM DUAL UNION ALL
SELECT 'Jessica' FROM DUAL UNION ALL
SELECT 'Monica' FROM DUAL UNION ALL
SELECT 'Erica' FROM DUAL
) t
LEFT OUTER JOIN NAMESTABLE n
ON n.names = t.names AND n.adeddate BETWEEN '2014/10/15' AND '2014/10/16'
GROUP BY t.names
This should work with a CTE..
WITH CTE AS
(SELECT 'Jenny' Names FROM dual UNION ALL
SELECT 'Penny' FROM dual UNION ALL
SELECT 'George' FROM dual UNION ALL
SELECT 'James' FROM dual UNION ALL
SELECT 'Jessica' FROM dual UNION ALL
SELECT 'Monica' FROM dual UNION ALL
SELECT 'Erica' FROM dual)
SELECT CTE.names, coalesce(count(NT.Names),0)
FROM CTE
LEFT JOIN NAMESTABLE NT
on CTE.Names = NT.Names
and adeddate BETWEEN '2014/10/15' AND '2014/10/16'
GROUP BY CTE.Names
You could create an a table containing all valid names, eg valid_names table. Then join to your namestable using an outerjoin. Eg:
select valid_names.name, count(1)
from namestable, valid_names
where valid_names.name=namestable.name (+)
group by valid_names.name
order by valid_names.name;

Oracle SQL REGEX_LIKE

SELECT first_name, last_name
FROM employees
WHERE REGEXP_LIKE (first_name, '^Ste(v|ph)en$');
The following query returns the first and last names for those employees with a first name of Steven or Stephen (where first_name begins with Ste and ends with en and in between is either v or ph)
is there a call that is opposite where the query will return everything that would not have (v or ph) between Ste and en?
so that it would return things like:
Stezen
Stellen
is it as simple as putting NOT in front of REGEXP_LIKE?
How about MINUS
SELECT *
FROM employees
WHERE REGEXP_LIKE( first_name , '^Ste([[:alpha:]])+en$')
MINUS
SELECT *
FROM employees
WHERE REGEXP_LIKE( first_name , '^Ste(v|ph)en$');
and this too:
WITH t AS
( SELECT 'Stezen' first_name FROM dual
UNION ALL
SELECT 'Steven' FROM dual
UNION ALL
SELECT 'Stephen' FROM dual
)
SELECT *
FROM t
WHERE REGEXP_LIKE( first_name , '^Ste([[:alpha:]])+en$')
AND NOT REGEXP_LIKE( first_name , '^Ste(v|ph)en$');
You need something like this:
SELECT 'Match'
FROM dual
WHERE REGEXP_LIKE ('Steden', '^Ste[^(v|ph)]en$');
EDIT
This will exclude any two (or more) letter combinations but still allow "v" :
SELECT 'Match'
FROM dual
WHERE REGEXP_LIKE ('Stephen', '^Ste[[:alpha:]]en$');
Since Oracle does not support look-ahead functionality, I will have to agree with others that we will have to deal with "v" explicitly, either by excluding the entire name(word) or at least specifying its exact position.
SELECT name
FROM WhateverTable
WHERE REGEXP_LIKE (name, '^Ste[[:alpha:]]en$') AND SUBSTR(name, 4, 1) <> 'v';
Two options:
The first query uses two REGEXP_LIKE tests: one regular expression to generically match; and one for excluding the invalid matches.
The second query uses REGEXP_SUBSTR to testfor a generic match and extract the sub-group of the match and then tests to see whether it should be exluded.
The third query then looks at how you can extend the query by having another table containing the match criteria and allows you to build and test multiple name variants.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE tbl ( str ) AS
SELECT 'Stephen' FROM DUAL
UNION ALL SELECT 'Steven' FROM DUAL
UNION ALL SELECT 'Stepen' FROM DUAL
UNION ALL SELECT 'Steephen' FROM DUAL
UNION ALL SELECT 'Steeven' FROM DUAL
UNION ALL SELECT 'Steeven' FROM DUAL
UNION ALL SELECT 'Smith' FROM DUAL
UNION ALL SELECT 'Smithe' FROM DUAL
UNION ALL SELECT 'Smythe' FROM DUAL
UNION ALL SELECT 'Smythee' FROM DUAL;
CREATE TABLE exclusions ( prefix, exclusion, suffix ) AS
SELECT 'Ste', 'v|ph', 'en' FROM DUAL
UNION ALL SELECT 'Sm', 'ithe?|ythe', '' FROM DUAL;
Query 1:
SELECT str
FROM tbl
WHERE REGEXP_LIKE( str, '^Ste(\w+)en$' )
AND NOT REGEXP_LIKE( str, '^Ste(v|ph)en$' )
Results:
| STR |
|----------|
| Stepen |
| Steephen |
| Steeven |
| Steeven |
Query 2:
SELECT str
FROM (SELECT str,
REGEXP_SUBSTR( str, '^Ste(\w+)en$', 1, 1, NULL, 1 ) AS match
FROM tbl)
WHERE match IS NOT NULL
AND NOT REGEXP_LIKE( match, '^(v|ph)$' )
Results:
| STR |
|----------|
| Stepen |
| Steephen |
| Steeven |
| Steeven |
Query 3:
SELECT str
FROM tbl t
WHERE EXISTS ( SELECT 1
FROM exclusions e
WHERE REGEXP_LIKE( t.str, '^' || e.prefix || '(\w+)' || e.suffix || '$' )
AND NOT REGEXP_LIKE( t.str, '^' || e.prefix || '(' || e.exclusion || ')' || e.suffix || '$' )
)
Results:
| STR |
|----------|
| Stepen |
| Steephen |
| Steeven |
| Steeven |
| Smythee |