I am using this query to split a string of a text area field inside my SQL query:
select * from "MyTable" a
where NAME in (select * from
TABLE(apex_string.split(:P23_TEXTAREA, ',')))
It works but I would like to split the string with a new line delimiter instead of a comma. I tried already "\n", "\r\n", "" but without success. If I remove the delimiter and use the default, the string gets split only once with a new line. How can I split my string with multiple new line separated entries?
You can try the CHR function:
SELECT *
FROM TABLE(apex_string.split(:P23_TEXTAREA, CHR(10)))
or a string literal containing a newline:
SELECT *
FROM TABLE(apex_string.split(:P23_TEXTAREA, '
'))
Your :P23_TEXTAREA value is: 'TRI_1000'||CHR(13)||CHR(10)||'TRI_10' which, if you split it on CHR(10) (LF) will give you the values 'TRI_1000'||CHR(13) and 'TRI_10' and the second will probably match but the first will not due to the trailing carriage return (CR) character.
It appears you need to either trim the result or split on CR/LF (or an optional CR) rather than just LF:
SELECT *
FROM "MyTable"
WHERE name IN (SELECT *
FROM TABLE(apex_string.split(:P23_TEXTAREA, '\r?\n'))
)
or:
SELECT *
FROM "MyTable"
WHERE name IN (SELECT RTRIM(COLUMN_VALUE, CHR(13))
FROM TABLE(apex_string.split(:P23_TEXTAREA, CHR(10)))
)
The default delimiter for apex_string.split is LF (line feed) so one way to do this is to replace the CR+LF combos with a single LF before passing it to split:
select * from "MyTable" a
where NAME in (select * from
TABLE(apex_string.split(
replace(:P23_TEXTAREA, chr(13)||chr(10), chr(10))
))
)
Related
I have a pipe delimited file which has to be loaded via SQL*Loader in Oracle.
My control file looks like this:
LOAD DATA
REPLACE
INTO TABLE1
FIELDS TERMINATED BY '|'
TRAILING NULLCOLS
(
ID "TRIM(:ID)",
TEXT "NVL(TRIM(:TEXT),' ')"
)
The TEXT column in the data file can contain text with "|"- i.e., delimiter too.
How can I accept pipe in the TEXT column?
You can't escape the delimiter; but if you want everything up to the first pipe to be the ID and everything after the first pipe to be TEXT, you could treat the record in the data file as a single field and split it using SQL functions, e.g.:
LOAD DATA
INFILE ...
REPLACE
INTO TABLE TABLE1
TRAILING NULLCOLS
(
ID CHAR(4000) "regexp_replace(:ID, '^(.*?)(\\|(.*))?$', '\\1')",
TEXT EXPRESSION "regexp_replace(:ID, '^(.*?)(\\|(.*))?$', '\\3')"
)
There is no FIELDS clause.
The ID is initially up to 4000 characters from the line (just a large value to hopefully capture any data you have). A regex replace is then applied to that; the pattern defines a first group as any characters (non-greedy), optionally followed by a second group comprising a pipe and a third inner group of zero or more characters after that pipe. The original value is replaced by group 1.
The TEXT is defined as an EXPRESSION, meaning it isn't obtained directly from the file; instead the same regex pattern is applied to the original ID value, but now that is replaced by the third group, which is everything after the first pipe (if there is one).
An equivalent in plain SQL as a demo would be:
with data (id) as (
select '123|test 1' from dual
union all
select '234|test 2|with pipe' from dual
union all
select '345|test 3|with|multiple|pipes|' from dual
union all
select null from dual
union all
select '678' from dual
union all
select '789|' from dual
)
select id as original,
regexp_replace(ID, '^(.*?)(\|(.*))?$', '\1') as id,
regexp_replace(ID, '^(.*?)(\|(.*))?$', '\3') as text
from data;
which gives:
ORIGINAL ID TEXT
------------------------------- ---- ------------------------------
123|test 1 123 test 1
234|test 2|with pipe 234 test 2|with pipe
345|test 3|with|multiple|pipes| 345 test 3|with|multiple|pipes|
567 567
678| 678
If you don't need to worry about records without that first pipe, or with that first pipe but followed by nothing, then the regex could be simpler:
(
ID CHAR(4000) "regexp_replace(:ID, '^(.*?)\\|(.*)$', '\\1')",
TEXT EXPRESSION "regexp_replace(:ID, '^(.*?)\\|(.*)$', '\\2')"
)
I would like to extract following string in Oracle. How can I do that?
Original String: 011113584378(+) CARD, STAFF
Expected String: STAFF CARD
I presume you have the luxury of writing a PL/SQL function? Then just use "SUBSTR", and/or "INSTR", and || concatenation operator to parse your input.
Here is an example:
https://www.techonthenet.com/oracle/questions/parse.php
...The field may contain the following value:
F:\Siebfile\YD\S_SR_ATT_1-60SS_1-AM3L.SAF
In this case, I need to return the value of '1-60SS', as this is the value that resides between the 3rd and 4th underscores.
SOLUTION:
create or replace function parse_value (pValue varchar2)
return varchar2
is
v_pos3 number;
v_pos4 number;
begin
/* Return 3rd occurrence of '_' */
v_pos3 := INSTR (pValue, '_', 1, 3) + 1;
/* Return 4rd occurrence of '_' */
v_pos4 := INSTR (pValue, '_', 1, 4);
return SUBSTR (pValue, v_pos3, v_pos4 - v_pos3);
end parse_value;
Ok, I'll bite. This example uses REGEXP_REPLACE to describe the string, saving the parts you need in order to rearrange them before returning them. It would be better if you showed some real-world examples of the data you are dealing with as I can only guarantee this example will work with the one line you provided.
The regular expression matches any characters starting at the beginning of the string and ending with a close paren-space. The next set of any characters up to but not including the comma-space is "remembered" by enclosing them in parens. This is called a captured group. The next captured group is the set of characters after that comma-space separator until the end of the line (the dollar sign). The captured groups are referred to by their order from left to right. The 3rd argument is the string to return, which is the 2nd and 1st captured groups, in that order, separated by a space.
SQL> with tbl(str) as (
select '+011113584378(+) CARD, STAFF' from dual
)
select regexp_replace(str, '^.*\) (.*), (.*)$', '\2 \1') formatted
from tbl;
FORMATTED
----------
STAFF CARD
SQL>
I'm trying to all rows where a column contains any control charters with the exception of the line feed character (hex value of A). I've tried the following, but this only returns results that have a control character and don't have a line feed. I really want the set of characters that are control characters, LESS the line feed character. Is there a 'minus' operation for character sets, where you can exclude particular ones from it?
SELECT *
FROM MyTable
WHERE REGEXP_LIKE(MyColumn, '[:cntrl: &&[^' || UTL_RAW.CAST_TO_VARCHAR2(HEXTORAW('A')) || ']]{1,}');
Any thoughts?
Thanks!
Well here's a first try that will work but I'm sure this can be made more elegant and efficient:
SELECT *
FROM MyTable
WHERE regexp_like(MyColumn, '[[:cntrl:]]')
AND MyColumn NOT like '%' || chr(10) || '%';
I have a DB with more than 1,000,000 entries in it, some of them contain space char at the start/end of the value.
I have tried the following queries and it works but i would have to go through 1,000,000 records because all id's are unique
select * from tablename where id like '%1234%';
select * from tablename where id='1234 ';
select * from tablename where id=' 1234';
select * from tablename where id=' 1234 ';
is there a query that can be run that returns all values with space/empty char at the start/end of the value?
Appreciate your help
B
You can use a regular expression that says "one or more spaces at the start of the string OR one of more spaces at the end of the string".
select * from tablename where id ~ '^\s+|\s+$';
Each special character:
^ match start of the string
\s match a white space character
| the or operator
+ one or more times
$ match the end of the string.
I found the way to do this
select * from tablename where id like '% %';
I am trying to select a column from a table that contains newline (NL) characters (and possibly others \n, \r, \t). I would like to use the REGEXP to select the data and replace (only these three) characters with a space, " ".
No need for regex. This can be done easily with the ASCII codes and boring old TRANSLATE()
select translate(your_column, chr(10)||chr(11)||chr(13), ' ')
from your_table;
This replaces newline, tab and carriage return with space.
TRANSLATE() is much more efficient than its regex equivalent. However, if your heart is set on that approach, you should know that we can reference ASCII codes in regex. So this statement is the regex version of the above.
select regexp_replace(your_column, '([\x0A|\x0B|`\x0D])', ' ')
from your_table;
The tweak is to reference the ASCII code in hexadecimal rather than base 10.
select translate(your_column, chr(10)||chr(11)||chr(13), ' ') from your_table;
to clean it is essential to serve non-null value as params ...
(oracle function basically will return null once 1 param is null, there are few excpetions like replace-functions)
select translate(your_column, ' '||chr(10)||chr(11)||chr(13), ' ') from your_table;
this examples uses ' '->' ' translation as dummy-value to prevent Null-Value in parameter 3