Reputation: 3
In a SELECT
statement would it be possible to evaluate a Substr
using CASE? Or what would be the best way to return a sub string
based on a condition?
I am trying to retrieve a name from an event description column of a table. The string in the event description column is formatted either like text text (Mike Smith) text text
or text text (Joe Schmit (Manager)) text text
. I would like to return the name only, but having some of the names followed by (Manager)
is throwing off my SELECT
statement.
This is my SELECT
statement:
SELECT *
FROM (
SELECT Substr(Substr(eventdes,Instr(eventdes,'(')+1),1,
Instr(eventdes,')') - Instr(eventdes,'(')-1)
FROM mytable
WHERE admintype = 'admin'
AND entrytime BETWEEN sysdate - (5/(24*60)) AND sysdate
AND eventdes LIKE '%action taken by%'
ORDER BY id DESC
)
WHERE ROWNUM <=1
This returns things like Mike Smith
if there is no (Manager)
, but returns things like Joe Schmit (Manager
if there is.
Any help would be greatly appreciated.
Upvotes: 0
Views: 1543
Reputation: 167867
Oracle 11g R2 Schema Setup:
CREATE TABLE MYTABLE ( id, admintype, entrytime, eventdes ) AS
SELECT 1, 'admin', SYSDATE, 'action taken by (John Doe (Manager)) more text' FROM DUAL;
Query 1:
SELECT *
FROM ( SELECT REGEXP_SUBSTR( eventdes, '\((.*?)(\s*\(.*?\))?\)', 1, 1, 'i', 1 )
FROM mytable
WHERE admintype = 'admin'
AND entrytime BETWEEN sysdate - (5/(24*60)) AND sysdate
AND eventdes LIKE '%action taken by%'
ORDER BY id DESC
)
WHERE ROWNUM <=1
| REGEXP_SUBSTR(EVENTDES,'\((.*?)(\S*\(.*?\))?\)',1,1,'I',1) |
|------------------------------------------------------------|
| John Doe |
Edit:
Oracle 11g R2 Schema Setup:
CREATE TABLE MYTABLE ( id, admintype, entrytime, eventdes ) AS
SELECT 1, 'admin', SYSDATE, 'action taken by (Doe, John (Manager)) more text' FROM DUAL;
Query 1:
SELECT SUBSTR( Name, INSTR( Name, ',' ) + 1 ) || ' ' || SUBSTR( Name, 1, INSTR( Name, ',' ) - 1 ) AS Full_Name,
REGEXP_REPLACE( Name, '^(.*?),\s*(.*)$', '\2 \1' ) AS Full_Name2
FROM ( SELECT REGEXP_SUBSTR( eventdes, '\((.*?)(\s*\(.*?\))?\)', 1, 1, 'i', 1 ) AS Name
FROM mytable
WHERE admintype = 'admin'
-- AND entrytime BETWEEN sysdate - (5/(24*60)) AND sysdate
AND eventdes LIKE '%action taken by%'
ORDER BY id DESC
)
WHERE ROWNUM <=1
| FULL_NAME | FULL_NAME2 |
|-----------|------------|
| John Doe | John Doe |
Upvotes: 3
Reputation: 10360
Here's a slightly different take on the problem. This regexp starts at the position of the first open paren + 1 (the first letter of the name), then returns the first group from that point in the string on that consists of 1 or more characters that is not a close paren or an open paren. The TRIM gets rid of the trailing space if there is a manager.
SQL> with tbl(id, admintype, entrytime, eventdes ) AS
2 ( SELECT 1, 'admin', SYSDATE, 'action taken by (John Doe (Manager)) more text' FROM DUAL
3 union
4 SELECT 1, 'admin', SYSDATE, 'action taken by (Jane Doe) more text' FROM DUAL
5 )
6 select trim(regexp_substr(eventdes, '([^\)\(]+)', instr(eventdes, '(')+1, 1)) name
7 from tbl;
NAME
----------------------------------------------
Jane Doe
John Doe
SQL>
Upvotes: 0
Reputation: 9726
There is probably a regex that would do this without a replace but I am not smart enough to work it out so I combined a REGEXP_SUBSTRING that replaces your multiple instr methods and a REGEXP_REPLACE to replace the ' (MANAGER)' portion is it exists.
SELECT *
FROM (
SELECT REGEXP_REPLACE(
REGEXP_SUBSTR(eventdes, '\((.*)\)', 1, 1, 'i', 1), ' \(MANAGER\)', '')
FROM mytable
WHERE admintype = 'admin'
AND entrytime BETWEEN sysdate - (5/(24*60)) AND sysdate
AND eventdes LIKE '%action taken by%'
ORDER BY id DESC
)
WHERE ROWNUM <=1
Upvotes: 0
Reputation: 60462
You could use INSTR to search the last ')', but I would prefer a Regular Expression.
This extracts everything between the first '(' and the last ')' and the TRIMs remove the brackets (Oracle doesn't support look around in RegEx):
RTRIM(LTRIM(REGEXP_SUBSTR(eventdes, '\(.*\)'), '('), ')')
Upvotes: 1