Xpath select function? - xpath

I'm using feed import module in Drupal 7 cms that accepts xpath directives to map the data for the import. Is it possible to select only part of the atomic value or explode it with xpath?
For example:
<book>
...
<categories>1,4,88</categories>
...
</book>
Is it possible to get only 1 or 4 or 88 separately with xpath statement?

You can use the substring-before() and substring-after() functions:
To select 1: substring-before(/book/categories, ',')
To select 4: substring-before(substring-after(/book/categories, ','), ',')
To select 88: substring-after(substring-after(/book/categories, ','), ',')
With XPath 2.0 you could use the tokenize() function:
To select 1: tokenize(/book/categories, ',')[1]
To select 4: tokenize(/book/categories, ',')[2]
To select 88: tokenize(/book/categories, ',')[3]

Or, using XPath 2.0, one can access the Nth component by:
tokenize(/*/categories[1], ',')[$pN]
where $pN is the desired 1-based index.

Related

Substring using Oracle When there is multiple Matches?

Hi I am trying to fetch substring in oracle for the below two strings. I want result if the pattern matches starting with S9C and the having 8 numbers after S9C
For Eg: for the below two inputs I need output like
Input:
1.CABLE : THERMINAL 3X2X0.25MM FPCP PLUS UNITRONIC S9C000019651
2.Motor Protection Relay EMR-3MPO-2S9CB1-1 (was IQ1000II / MP 3000)
3.GREASE : BEM 41-132 3KG CARTRIDGE KLUBERPLEX S9C00019171 (Order by KG's required)
4.DO NOT USE CARRIER SPIDEX ZK 38 98 SH. S9C00011593 (SUPERSEDE BY S9C10204555 - WIN0020775)
Output:
1.Null
2.Null
3.S9C00019171
4.S9C10204555
You can use a combination of REGEXP_SUBSTR and REGEXP_COUNT to solve your question:
WITH test_data(input) AS
(
SELECT '1.CABLE : THERMINAL 3X2X0.25MM FPCP PLUS UNITRONIC S9C000019651' FROM DUAL UNION ALL
SELECT '2.Motor Protection Relay EMR-3MPO-2S9CB1-1 (was IQ1000II / MP 3000)' FROM DUAL UNION ALL
SELECT '3.GREASE : BEM 41-132 3KG CARTRIDGE KLUBERPLEX S9C00019171 (Order by KG''s required)' FROM DUAL UNION ALL
SELECT '4.DO NOT USE CARRIER SPIDEX ZK 38 98 SH. S9C00011593 (SUPERSEDE BY S9C10204555 - WIN0020775)' FROM DUAL
)
SELECT regexp_substr(td.input,
'S9C[0-9]{8}( |$)',
1,
GREATEST(1, regexp_count(td.input, 'S9C[0-9]{8}( |$)')))
FROM test_data td
Here's a quick explanation of how it works:
REGEXP_COUNT counts the occurrences of the target pattern, so we can get the last occurrence later.
Wrap the result in in GREATEST because 0 is invalid for REGEXP_SUBSTR parameter.
Call REGEXP_SUBSTR to grab the last occurrence of the target string.
Here is a DBFiddle to show you it working (DBFiddle)

Substring of a string using Oracle (SUBSTRING or REGEXP_SUBSTR) When there is multiple Matches

Hi I am trying to fetch substring in oracle for the below two strings. I want result if the pattern matches starting with S9C and the having next numbers
For Eg: for the below two inputs I need output like
Input:
1.CABLE : THERMINAL 3X2X0.25MM FPCP PLUS UNITRONIC S9C000019651
2.Motor Protection Relay EMR-3MPO-2S9CB1-1 (was IQ1000II / MP 3000)
3.GREASE : BEM 41-132 3KG CARTRIDGE KLUBERPLEX S9C00019171 (Order by KG's required)
4.DO NOT USE CARRIER SPIDEX ZK 38 98 SH. S9C00011593 (SUPERSEDE BY S9C10204555 - WIN0020775)
Output:
1.S9C000019651
2.Null
3.S9C00019171
4.S9C10204555
Or Else the Better way is to fetch first matching String from back of the text.
I think you can achieve the desired result with below script where you can pick the second group. If that is null, Pick the first group -
WITH DATA AS (SELECT 'CABLE : THERMINAL 3X2X0.25MM FPCP PLUS UNITRONIC S9C000019651' STR FROM DUAL
UNION ALL
SELECT 'Motor Protection Relay EMR-3MPO-2S9CB1-1 (was IQ1000II / MP 3000)' FROM DUAL
UNION ALL
SELECT 'GREASE : BEM 41-132 3KG CARTRIDGE KLUBERPLEX S9C00019171 (Order by KG''s required)' FROM DUAL
UNION ALL
SELECT 'DO NOT USE CARRIER SPIDEX ZK 38 98 SH. S9C00011593 (SUPERSEDE BY S9C10204555 - WIN0020775)' FROM DUAL)
SELECT NVL(REGEXP_SUBSTR(STR, 'S9C\d{7,}', 1, 2), REGEXP_SUBSTR(STR, 'S9C\d{7,}'))
FROM DATA;
Demo.

How to evaluate an expression in one table field into another?

I have a table, inside there is a field called x, the x field contain value of '1+2', '1+3' etc, how to get these value and calculate it and save into another field?
For simple arithmetic expressions - and depending on your Oracle version - you could use xmlquery to evaluate. Note that / has special meaning in xml, the operator for division is the keyword div - so you need a replace in case you may have forward slashes in the arithmetic expression. (If you don't have any divisions, you can simplify the query by removing the call to replace.)
Here is an example - including the test data at the top, in a with clause (not part of the solution!)
with
test_data (str) as (
select '1 + 3' from dual union all
select '3 * 5 - 2' from dual union all
select '2/4*6' from dual union all
select '3 * (1 - 3)' from dual
)
select str, xmlquery(replace(str, '/', ' div ') returning content).getNumberVal()
as evaluated_expression
from test_data;
STR EVALUATED_EXPRESSION
----------- --------------------
1 + 3 4
3 * 5 - 2 13
2/4*6 3
3 * (1 - 3) -6
If you only have valid PL/SQL arithmetic expressions in your formulas, then you can use EXECUTE IMMEDIATE to evaluate them.
For this, you'll need to create a function:
create or replace function eval_expression(p_expression in varchar2)
return number is
query varchar2(100);
result number;
begin
query := 'select ' || p_expression || ' from dual';
execute immediate query
into result;
return result;
end eval_expression;
Then you can use this function in UPDATE query:
update t
--val is another field
set t.val = eval_expression(t.x)
Naturally, with EXECUTE IMMEDIATE this query won't be extremely efficient, but it'll work. Also, with dynamic queries we're going into unsafe territory, so make sure that you don't have malicious code among your formulas.
Also, see "Evaluate Expression" on Ask TOM. Tom Kyte used a slightly more civilized approach (dbms_sql package) and created a package with a single variable support.
If the case you have mentioned needs to be considered then I will suggest you use the following query:
select
xmlquery('3+4'
returning content
).getNumberVal()
from
dual;
If More operators are involved except division then the aforementioned query will work but if the division operator is also involved then you must have to replace "/" with " div " keyword. Something like the following:
select
xmlquery(
replace( '20/5', '/', ' div ')
returning content
).getNumberVal()
from
dual;
Now, you can use it in your update statement or anywhere else.
update tab
set tab.result_column_name = xmlquery(t.your_expr_column_name
returning content
).getNumberVal()
update tab
set tab.result_column_name = xmlquery(
replace( t.your_expr_column_name, '/', ' div ')
returning content
).getNumberVal()
Demo
Cheers!!

How to use replace function in Oracle to remove a string?

In my table, I have data like PAT5DSA-(ALRP), LAR6DAOP-(RAH) etc..But I want to remove the strings like -(xxxx) or -(xxx) which can be any alphabets inside braces. Tried using the below:
select replace(:code,'-(Aa-Zz)',null) from employee;
But this didn't work..Can anyone please help?
We can do a regex replacement using REGEXP_REPLACE:
SELECT REGEXP_REPLACE('PAT5DSA-(ALRP)', '-\(.*?\)', '')
FROM dual;
PAT5DSA
The plain replace() doesn't understand patterns. You could use a regular expression replace, e.g.:
-- CTE for sample data
with cte (code) as (
select 'PAT5DSA-(ALRP)' from dual
union all
select 'LAR6DAOP-(RAH)' from dual
)
select code, regexp_replace(code, '-\(.*?\)$') as result
from cte;
CODE RESULT
-------------- --------------
PAT5DSA-(ALRP) PAT5DSA
LAR6DAOP-(RAH) LAR6DAOP
This will remove anything inside a pair of parentheses which is preceded by a dash, at the end of the original string. If the parentheses to be removed could be anywhere in the string then remove the $.
Use INSTR and SUBSTR:
WITH cteVals AS (SELECT 'PAT5DSA-(ALRP)' AS COL_VAL FROM DUAL UNION ALL
SELECT 'LAR6DAOP-(RAH)' AS COL_VAL FROM DUAL)
SELECT SUBSTR(COL_VAL, 1, INSTR(COL_VAL, '-')-1)
FROM cteVals;
Best of luck.

Replace multiple substrings with one expression in Oracle SQL

I would like to delete multiple substrings from one column. I tried the replace function with the following code:
select replace('testetstestetststst', 'test'||'et'||'s', '')
from dual;
My expected result is ttt, but I get tstst.
In R it works with:
gsub("test|et|s", "", "testetstestetststst")
How can I replace many different substrings with nothing ('') in a column in clob format in Oracle SQL?
You need the REGEXP version of REPLACE:
select regexp_replace('testetstestetststst', 'test|et|s', '')
from dual;
In your code, you are concatenating strings, instead of using an OR operator; that is, your code is equivalent to
select replace('testetstestetststst', 'testets', '')
from dual;
Rather than using regular expressions, you can nest multiple REPLACE functions:
SELECT REPLACE(
REPLACE(
REPLACE(
'testetstestetststst',
'test'
),
'et'
),
's'
)
FROM DUAL;
We can directly use decode function.
select decode(job,'clerk','1','manager','2','salesman','3',4) from emp;
This will replace clerk with 1,manager with 2,salesman with 3 and other values with 4.

Resources