How to convert vertical string into horizontal in Oracle - sql

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

Related

Removing first 'G' character of entire column values in table if it is starting from 'G'

I wanted to remove first 'G' character of full column values of table only if it exist.
I have tried the substr function to remove first char but it will remove the first char even if it is not 'G'. I only wanted to remove first char of entire column values if it is 'G'.
For example in myTable the column values are as follows:
G12345
332157
G54337
G54332
534535
Expected result is as follows:
12345
332157
54337
54332
534535
Wanted to write update query to update the entire column value.
Based on your description, you can use regexp_replace():
select regexp_replace('G12345', 'G', '', 1, 1)
If you only want to remove a 'G' at the beginning of the string, you can use '^G' for the pattern.
Based on your data, you can just use replace():
select replace('G12345', 'G', '')
This removes all 'G's. But your data only seems to have one.
For an update you would just include the logic as an update:
update t
set col = replace(col, 'G', '')
where col like '%G%';
Or whichever of the above functions is what you really want to do.
You want to update the rows where the value starts with a 'G', so use a WHERE clause:
update mytable
set value = substr(value, 2)
where value like 'G%';
As you want to replace only the first G, then
SQL> with test (col) as
2 (select 'G12345' from dual union all
3 select '332157' from dual union all
4 select '11G222' from dual
5 )
6 select col,
7 substr(col, case when substr(col, 1, 1) = 'G' then 2 else 1 end) result
8 from test;
COL RESULT
------ ------
G12345 12345
332157 332157
11G222 11G222
SQL>
You can use:
SELECT CASE WHEN value LIKE 'G%' THEN SUBSTR( value, 2 ) ELSE value END
AS value_without_g
FROM myTable
Which, from the sample data:
CREATE TABLE myTable ( value ) AS
SELECT 'G12345' FROM DUAL UNION ALL
SELECT '332157' FROM DUAL UNION ALL
SELECT 'G54337' FROM DUAL UNION ALL
SELECT 'G54332' FROM DUAL UNION ALL
SELECT '534535' FROM DUAL;
Outputs:
| VALUE_WITHOUT_G |
| :-------------- |
| 12345 |
| 332157 |
| 54337 |
| 54332 |
| 534535 |
db<>fiddle here

Splitting records which has | delimiter [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm having a two columns say Value column is having records like 'abc|comp|science|raja' and I want to split this records like abc,comp,science,raja and I need to compare it with another column say CHECKER which is having record as science
Value
abc|comp|science|raja
Checkers
science
You don't need to split the string and you don't even need a regular expression; just check whether the checker string (with leading a trailing delimiters) is a sub-string of value (with leading and trailing delimiters):
Oracle Setup:
CREATE TABLE your_table ( value, checker ) as
SELECT 'abc|comp|science|raja', 'science' FROM DUAL UNION ALL
SELECT 'abc|def|ghi', 'xyz' FROM DUAL UNION ALL
SELECT 'abc', 'abc' FROM DUAL UNION ALL
SELECT 'abcdef', 'abc' FROM DUAL
Query:
SELECT *
FROM your_table
WHERE '|' || value || '|' LIKE '%|' || checker || '|%';
Output:
VALUE | CHECKER
:-------------------- | :------
abc|comp|science|raja | science
abc | abc
db<>fiddle here
You can split your pipe delimited string in individual values and represent that as a table. Then you can just join to your Checkers table.
The web is full of examples, here are 2 ways to do it.
The REGEXP way...
WITH test_tab AS
(SELECT 'abc|comp|science|raja' str FROM dual
)
SELECT regexp_substr (str, '[^|]+', 1, rownum) split
FROM test_tab
CONNECT BY LEVEL <= LENGTH (regexp_replace (str, '[^|]+')) + 1;
If you have Application Express in your database, you can use apex_string to do the magic for you:
SELECT
column_value
FROM
TABLE(apex_string.split(
'abc|comp|science|raja',
'|'
));
Here's one option:
SQL> with test (id, value, checkers) as
2 (select 1, 'abc|comp|science|raja', 'science' from dual union all
3 select 2, 'xyz|bla|nothing' , 'zzz' from dual
4 )
5 select t.id,
6 regexp_substr(t.value, '[^\|]+', 1, column_value) val,
7 column_value rn,
8 t.checkers,
9 --
10 case when regexp_substr(t.value, '[^\|]+', 1, column_value) = t.checkers then 'Match'
11 else 'No match'
12 end what
13 from test t cross join table(cast(multiset(select level from dual
14 connect by level <= regexp_count(t.value, '\|') + 1
15 ) as sys.odcinumberlist))
16 order by t.id, rn;
ID VAL RN CHECKER WHAT
---------- --------------------- ---------- ------- --------
1 abc 1 science No match
1 comp 2 science No match
1 science 3 science Match
1 raja 4 science No match
2 xyz 1 zzz No match
2 bla 2 zzz No match
2 nothing 3 zzz No match
7 rows selected.
SQL>
It sounds like you just want to check whether the checker is in the value, in that case you can do this:
with mytable as
( select 'abc|comp|science|raja' value
, 'science' as checker
from dual
union all
select 'science|abc|comp|raja'
, 'science'
from dual
union all
select 'abc|comp|raja|science'
, 'science'
from dual )
select x.value
from mytable x
where regexp_like(value, '(^|\|)' || checker || '($|\|)')
The regex_like is searching inside the value for the checker with either a pipe or the end of the string, so it will match the keyword at the beginning, in the middle or at the end of the string. But it would not match "sciences".
Alternatively if you want to see all the rows and check whether they passed the "check" you could do:
with mytable as
( select 'abc|comp|science|raja' value
, 'science' as checker
from dual
union all
select 'science|abc|comp|raja'
, 'science'
from dual
union all
select 'abc|comp|raja|science'
, 'science'
from dual
union all
select 'abc|comp|raja|sciences'
, 'science'
from dual )
select x.value
, x.checker
, case when regexp_substr(value, '(^|\|)' || checker || '($|\|)') is not null
then 'Y'
end as passed
from mytable x

regexp_like to find 10 occurrences of 0's

with smpl as
(
select '000-000-0000' num from dual union
select '0000000000' from dual union
select '00000000000' from dual
)
select * from smpl
where regexp_like(num, '0{10}');
Output:
0000000000
00000000000
How to get records with 10 occurences 0's with optional '-'
Expected:
0000000000
000-000-0000
Use TRANSLATE to strip out the unwanted characters and then LENGTH
with smpl as
(
select '000-000-0000' num from dual union
select '0000000000' from dual union
select '000000000' from dual union
select '00000000000' from dual
)
select * from smpl
where LENGTH( TRANSLATE( num, '0-', '0' ) ) = 10
or compare to 0000000000:
with smpl as
(
select '000-000-0000' num from dual union
select '0000000000' from dual union
select '000000000' from dual union
select '00000000000' from dual
)
select * from smpl
where TRANSLATE( num, '0-', '0' ) = '0000000000'
Outputs:
| NUM |
| :----------- |
| 000-000-0000 |
| 0000000000 |
db<>fiddle here
I want to point out that you can do this strictly with regular expressions. If you are looking for the pattern anywhere in the string:
where regexp_like(num, '(\-*0){10}')
If you are looking for only that pattern in the string:
where regexp_like(num, '^(\-*0){10}\-*$')
With regexp, this is an easy way:
where regexp_count(num, '0') = 10
However, if the only character different from '0' is a '-', I would prefer the non-regexp solution

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 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 |