I have this data in a table
procedure1/loc1/p1
proc2/loc1/p2/c1
proc1/loc2/p2/c2
procedure3/loc1/p1
procedure4/loc3/p1
I want a query to select specific proc, like proc1 and procedure4 , like wouldnt work so
the ouptput should be like this
proc1/loc2/p2/c2
procedure4/loc3/p1
I tried to use REGEXP_SUBSTR, but how include the list of the procedure that i want ?
--this is wrong
select * from tab1 where REGEXP_SUBSTR(col1,
'[^/]+', 1, 1) in ('proc1','procedure4')
you could check, if the length returned by REGEXP_SUBSTR is greater than 0
select *
from (select 'procedure1/loc1/p1' a from dual union
select 'proc2/loc1/p2/c1' from dual union
select 'proc1/loc2/p2/c2' from dual union
select 'procedure3/loc1/p1' from dual union
select 'procedure4/loc3/p1' from dual) t
where length(regexp_substr(t.a, 'procedure4|proc1')) > 0
alternativly you could use REGEXP_LIKE, which does simply return a boolean and in my oppinion would fit better here.
select *
from (select 'procedure1/loc1/p1' a from dual union
select 'proc2/loc1/p2/c1' from dual union
select 'proc1/loc2/p2/c2' from dual union
select 'procedure3/loc1/p1' from dual union
select 'procedure4/loc3/p1' from dual) t
where regexp_like(t.a, 'procedure4|proc1')
O/P
proc1/loc2/p2/c2
procedure4/loc3/p1
if you would want to get the values from a table you could generate the regex dynamicly with the listagg function provided by oracle. What happens now is, that each possible value, that could occure is getting concatinated with an |, which does represent an or in regex. Due to this you you're not in need for an in, because your regex will have each possible value seperated by an or
select *
from (select 'procedure1/loc1/p1' a from dual union
select 'proc2/loc1/p2/c1' from dual union
select 'proc1/loc2/p2/c2' from dual union
select 'procedure3/loc1/p1' from dual union
select 'procedure4/loc3/p1' from dual) t
where regexp_like(t.a, (select listagg(regexp.b, '|') WITHIN GROUP (ORDER BY regexp.b) regex
from (select 'procedure4' b from dual union
select 'proc1' from dual) regexp))
O/P of the subquery used for the regex would be proc1|procedure4, which would be the regexp needed as seen in the previous example
You don't need to use regular expressions to do that. You just could use ordinary SUBSTR and INSTR to get the substring from the beginning to the first /:
WITH your_table AS (
SELECT 'procedure1/loc1/p1' procedure_name FROM dual
UNION
SELECT 'proc2/loc1/p2/c1' procedure_name FROM dual
UNION
SELECT 'proc1/loc2/p2/c2' procedure_name FROM dual
UNION
SELECT 'procedure3/loc1/p1' procedure_name FROM dual
UNION
SELECT 'procedure4/loc3/p1' procedure_name FROM dual
)
SELECT *
FROM your_table
WHERE SUBSTR(procedure_name,1,INSTR(procedure_name,'/')-1) IN ('proc1','procedure4');
However, if you want to learn to use regular expressions in Oracle. You could use REGEXP_SUBSTR like this:
WITH your_table AS (
SELECT 'procedure1/loc1/p1' procedure_name FROM dual
UNION
SELECT 'proc2/loc1/p2/c1' procedure_name FROM dual
UNION
SELECT 'proc1/loc2/p2/c2' procedure_name FROM dual
UNION
SELECT 'procedure3/loc1/p1' procedure_name FROM dual
UNION
SELECT 'procedure4/loc3/p1' procedure_name FROM dual
)
SELECT *
FROM your_table
WHERE REGEXP_SUBSTR(procedure_name,'^(.+?)/',1,1,'i',1) IN ('proc1','procedure4');
The last parameter tells Oracle to return the match for the pattern between ().
As already mentioned, you also could use REGEXP_LIKE:
WITH your_table AS (
SELECT 'procedure1/loc1/p1' procedure_name FROM dual
UNION
SELECT 'proc2/loc1/p2/c1' procedure_name FROM dual
UNION
SELECT 'proc1/loc2/p2/c2' procedure_name FROM dual
UNION
SELECT 'procedure3/loc1/p1' procedure_name FROM dual
UNION
SELECT 'procedure4/loc3/p1' procedure_name FROM dual
)
SELECT *
FROM your_table
WHERE REGEXP_LIKE(procedure_name,'^(proc1|procedure4)/');
If the procedures you are interesetd in are in a different table, one way could be the following:
Setup:
CREATE TABLE your_table (col) AS
(SELECT 'procedure1/loc1/p1' FROM DUAL UNION ALL
SELECT 'proc2/loc1/p2/c1' FROM DUAL UNION ALL
SELECT 'proc1/loc2/p2/c2' FROM DUAL UNION ALL
SELECT 'procedure3/loc1/p1' FROM DUAL UNION ALL
SELECT 'procedure4/loc3/p1' FROM DUAL
)
CREATE TABLE procedures (name) AS
(SELECT 'proc1' FROM DUAL UNION ALL
SELECT 'procedure4' FROM DUAL
)
You can try this, with no need for regular expressions:
SELECT *
FROM your_table
INNER JOIN procedures
ON (INSTR(col, name) != 0)
Related
I have a column that is giving me output like 'ABC2001' , 'ABC100145', 'ABC009282' ,' ABC1901'
I want to change this column value to have '00' in between literals and numbers if number is less than 6 digits. Something like -
COL_A
------------
ABC2001
ABC100145
ABC009282
ABC1901
Expected output
COL_B
------------
ABC002001
ABC100145
ABC009282
ABC001901
How to use regex for this ? Currently I am using
SELECT SUBSTR(COL_A,1,3)||LPAD(REGEXP_REPLACE(COL_A,'\D+'),6,'0') FROM TAB
and it is giving me output like -
ABC210073
ABC210073
You do not need (slow) regular expressions and can use simple string functions:
SELECT col_a,
SUBSTR(col_a, 1, 3) || LPAD(SUBSTR(col_a, 4), 6, '0') AS col_b
FROM table_name;
Which, for your sample data:
CREATE TABLE table_name (col_a) AS
SELECT 'ABC2001' FROM DUAL UNION ALL
SELECT 'ABC100145' FROM DUAL UNION ALL
SELECT 'ABC009282' FROM DUAL UNION ALL
SELECT 'ABC1901' FROM DUAL;
Outputs:
COL_A
COL_B
ABC2001
ABC002001
ABC100145
ABC100145
ABC009282
ABC009282
ABC1901
ABC001901
db<>fiddle here
Just for fun, for different prefixes:
usual string functions: trim/lpad/substr:
with table_name (col_a) AS (
SELECT 'ABC2001' FROM DUAL UNION ALL
SELECT 'ABC100145' FROM DUAL UNION ALL
SELECT 'ABC009282' FROM DUAL UNION ALL
SELECT 'ABC1901' FROM DUAL UNION ALL
-- other different prefixes:
select 'ABC2001' from dual union all
select 'AB100145' from dual union all
select 'A-BC9282' from dual union all
select 'A8C2374' from dual union all
select '7x-ABC32129' from dual union all
select '123ABC8942' from dual
)
select v.*, prefix||num as col_b
from (
select
col_a,
rtrim(col_a,'0123456789') as prefix,
lpad(substr(col_a,1+length(rtrim(col_a,'0123456789'))),6,'0') as num
from table_name
) v
;
DBFiddle
using regex functions:
with table_name (col_a) AS (
SELECT 'ABC2001' FROM DUAL UNION ALL
SELECT 'ABC100145' FROM DUAL UNION ALL
SELECT 'ABC009282' FROM DUAL UNION ALL
SELECT 'ABC1901' FROM DUAL UNION ALL
-- other different prefixes:
select 'ABC2001' from dual union all
select 'AB100145' from dual union all
select 'A-BC9282' from dual union all
select 'A8C2374' from dual union all
select '7x-ABC32129' from dual union all
select '123ABC8942' from dual
)
select
col_a,
regexp_replace(
regexp_replace(col_a,'(\d+)$','00000\1')
,'0*(\d{6})$'
,'\1'
) as col_b
from table_name
;
DBFiddle
regex solution for padding numbers to the maximum their length, ie not knowing max numbers length(if it's not hard-coded 6):
select
v.*,
regexp_replace(
regexp_replace(col_a,'(\d+)$',rpad('0',max_num_length,'0')||'\1')
,'0*(\d{'||max_num_length||'})$'
,'\1'
) as col_b
from (
select t.*, max(length(regexp_substr(col_a,'\d+$')))over() as max_num_length
from table_name t
) v
;
DBFiddle
I'm trying to create a query where I use two pre-defines lists with multiple values as filters in a where-stakement. This so I can re-use the query easily for many value-pairs en for many value-pairs.
On Stackoverflow i found:
WITH MyListOfValues(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
SELECT *
FROM DatabaseTable
WHERE Column in (
select col1
from MyListOfValues);
Howerver it fails when i do something like:
WITH MyListOfValues1(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
AND
WITH MyListOfValues2(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
SELECT *
FROM DatabaseTable
WHERE Column1 in (
select col1
from MyListOfValues1)
AND Column2 in (
select col1
from MyListOfValues2);
Does anyone has a solution?:) I'm doing this in a siting corporate enviroment I do not have rights (so far i know) to create my own tables.
Hope you can help me out! All help would be mutch appreciated:-)
You have a syntax error. The correct syntax for CTEs is:
WITH MyListOfValues1(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
),
MyListOfValues2(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
SELECT *
FROM DatabaseTable
WHERE Column1 in (select col1 from MyListOfValues1) AND
Column2 in (select col1 from MyListOfValues2);
I would use exits instead
WITH MyListOfValues1(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
),
MyListOfValues2(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
SELECT *
FROM DatabaseTable dt
WHERE EXISTS (SELECT 1 FROM MyListOfValues1 WHERE col1 = dt.Column1) AND
EXISTS (SELECT 1 FROM MyListOfValues2 WHERE col1 = dt.Column2);
Use a collection and the MEMBER OF operator
SYS.ODCIVARCHAR2LIST is a built in VARRAY you can use:
SELECT *
FROM DatabaseTable
WHERE Column1 MEMBER OF SYS.ODCIVARCHAR2LIST( 'MyValue1', 'MyValue2', 'MyValue3' )
AND Column2 MEMBER OF SYS.ODCIVARCHAR2LIST( 'MyValue1', 'MyValue2', 'MyValue3' );
Or you can define your own collection:
CREATE TYPE StringList IS TABLE OF VARCHAR2(20);
SELECT *
FROM DatabaseTable
WHERE Column1 MEMBER OF StringList( 'MyValue1', 'MyValue2', 'MyValue3' )
AND Column2 MEMBER OF StringList( 'MyValue1', 'MyValue2', 'MyValue3' );
You can even pass the collections as bind variables:
SELECT *
FROM DatabaseTable
WHERE Column1 MEMBER OF :List1
AND Column2 MEMBER OF :List2;
This relates to my previous question
What I now want to do is in my value column, if there are any instance of ++ replace this with 999.
So for e.g. if i have 1+2++3this should be updated to 1+2+999+3
How do i achieve this?
Thanks
Oracle Setup:
CREATE TABLE your_table ( value ) AS
SELECT NULL FROM DUAL UNION ALL
SELECT '1' FROM DUAL UNION ALL
SELECT '1+2' FROM DUAL UNION ALL
SELECT '1++2' FROM DUAL UNION ALL
SELECT '+1' FROM DUAL UNION ALL
SELECT '1+' FROM DUAL UNION ALL
SELECT '1+2++3' FROM DUAL;
Query:
SELECT TRIM( BOTH '+' FROM REPLACE( '+' || value || '+', '++', '+999+' ) )
FROM your_table
Output:
VALUE
---------
999
1
1+2
1+999+2
999+1
1+999
1+2+999+3
If you can have more than one missing element to replace in a row then you need a more complicated solution:
Oracle Setup:
CREATE TABLE your_table ( value ) AS
SELECT NULL FROM DUAL UNION ALL
SELECT '1' FROM DUAL UNION ALL
SELECT '1+2' FROM DUAL UNION ALL
SELECT '1++2' FROM DUAL UNION ALL
SELECT '+1' FROM DUAL UNION ALL
SELECT '1+' FROM DUAL UNION ALL
SELECT '1+2++3' FROM DUAL UNION ALL
SELECT '1+2+++3' FROM DUAL UNION ALL
SELECT '+' FROM DUAL;
Query:
SELECT ( SELECT LISTAGG(
COALESCE(
REGEXP_SUBSTR( t.value, '(.*?)(\+|$)', 1, LEVEL, NULL, 1 ),
'999'
),
'+'
) WITHIN GROUP ( ORDER BY LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( t.value, '\+' ) + 1
) AS value
FROM your_table t
Output:
VALUE
-------------
999
1
1+2
1+999+2
999+1
1+999
1+2+999+3
1+2+999+999+3
999+999
I need some help. I tried this and it does not work.
I selected all the data I needed and tried to say what's not in
the original file.
Could someone show me the correct way?
SELECT *
FROM acknowledgement t1
where t1.st01 = '110'
and (t1.shipment ='S640D14268424' or t1.Shipment ='S640D14268924' or
t1.Shipment ='S640D14268925' or t1.Shipment ='S646D14261190' or
t1.Shipment ='S646I14265886' or t1.Shipment ='S640D14268423' ...)
AND [shipment]
NOT IN(
SELECT [shipment] FROM acknowledgement
)
Any help would be useful.
You are looking for something like:
SELECT * FROM (
SELECT 'S640D14268424' AS Shipment
UNION SELECT 'S640D14268924'
UNION SELECT 'S640D14268925'
UNION SELECT 'S646D14261190'
UNION SELECT 'S646I14265886'
UNION SELECT 'S640D14268423'
UNION SELECT 'S646D14269951'
UNION SELECT 'S646D14269939'
UNION SELECT 'S646D14269034'
UNION SELECT 'S646D14269962'
UNION SELECT 'S646D14269953'
UNION SELECT 'S646D14271620'
UNION SELECT 'S646D14269030'
UNION SELECT 'S646D14269941'
UNION SELECT 'S646D14269251'
UNION SELECT 'S646D14273089'
UNION SELECT 'S646D14272388'
UNION SELECT 'S646D14273197'
UNION SELECT 'S646D14273399'
UNION SELECT 'S640D14273543'
UNION SELECT 'S640D14272952'
UNION SELECT 'S640D14272953'
UNION SELECT 'S640D14276996'
UNION SELECT 'S640D14277005'
UNION SELECT 'S640D14277006'
UNION SELECT 'S646D148047394'
UNION SELECT 'S640D14277004'
UNION SELECT 'S646D158049311'
UNION SELECT 'S646D158049791'
UNION SELECT 'S646D158049797'
UNION SELECT 'S646D158049806'
UNION SELECT 'S646D158049781'
UNION SELECT 'S646D158049557'
UNION SELECT 'S646D158049064'
UNION SELECT 'S646D158049561'
UNION SELECT 'S646D158049794'
UNION SELECT 'S646D158049362'
UNION SELECT 'S646D158049361'
UNION SELECT 'S646D158049792'
UNION SELECT 'S646D158049808'
UNION SELECT 'S646D158049788'
UNION SELECT 'S646D158049365'
UNION SELECT 'S646D158049800'
UNION SELECT 'S646D158049790'
UNION SELECT 'S646D158049799'
UNION SELECT 'S646D158049803'
UNION SELECT 'S646D158049784'
UNION SELECT 'S646D158049522'
UNION SELECT 'S646D158049340'
UNION SELECT 'S646D158049796'
UNION SELECT 'S646D158049687'
UNION SELECT 'S646D158049491'
UNION SELECT 'S646D158049499'
UNION SELECT 'S646D158049484'
UNION SELECT 'S646D158049486'
UNION SELECT 'S646D158049494') numbers_to_look
WHERE Shipment NOT IN
(SELECT [shipment] FROM acknowledgement WHERE shipment>'' )
Better way to do this is create a temp table to store the numbers you want to check.
I have to write a query to that has all correctly mastered recipients ( group by first_name and last_name)
I have to write another query that have all poorly mastered recipients ( group by first_name , last_name)
Please see the images below if there are multiple Master Id's against First Name and Last Name then its poorly Mastered.. if it have same Master ID then its correctly Mastered.
Sample data for the query is provided below
WITH DATA1 AS
(
SELECT 5175133 ID,'Yun' FIRST_NAME,'Yue' LAST_NAME,NULL MASTER_ID FROM dual UNION ALL
SELECT 5157093,'Yun','Yue',5157093 FROM dual UNION ALL
SELECT 5226656,'Yun','Yue',NULL FROM dual UNION ALL
SELECT 6345852,'Yun','Yue',5157093 FROM dual UNION ALL
SELECT 5882603,'Ye','Han',5157093 FROM dual UNION ALL
SELECT 5902219,'Ye','Han',5157093 FROM dual UNION ALL
SELECT 6362890,'Rick','Kaylor',NULL FROM dual UNION ALL
SELECT 6362940,'Rick','Kaylor',NULL FROM dual UNION ALL
SELECT 5215659,'Rick','Kaylor',NULL FROM dual UNION ALL
SELECT 5962837,'Rick','Kaylor',5962837 FROM dual UNION ALL
SELECT 5841556,'Rick','Kaylor',5841556 FROM dual UNION ALL
SELECT 5916218,'Sherlene','Heard',5916218 FROM dual UNION ALL
SELECT 6356086,'Sherlene','Heard',5916218 FROM dual UNION ALL
SELECT 5885157,'Ye','Kong',5884937 FROM dual UNION ALL
SELECT 5884937,'Ye','Kong',NULL FROM dual UNION ALL
SELECT 5898890,'Ye','Kong',5884937 FROM dual
)
SELECT * FROM DATA1
I think its a simple query please provide help?
Thanks
As this is very probably some kind of homework or assignment, just a clue:
Have you think about using COUNT(*) in a sub-query ? As far as I can tell, "correctly mastered recipients" will all have one and only one master_id...