Regular Expression - Get specific group value in SQL - sql

I have the following regular expression problem.
Input:
123_321_009
3111_00_001
5123_123
555
666_A66
777_B77_777
Output request as below:
123_321
3111_00
5123
555
666_A66
777_B77
Is there any way to get the value of the output above?
I tried below statement but lack the idea how to get the value i needed.
^(.*?)\\s?([_0-9])?$
Value appearing after the last underscore are not needed.

You can use REGEXP_REPLACE to remove the numbers following/including the last underscore.
SQL Fiddle
Query:
with x(y) as (
select '123_321_009' from dual union all
select '3111_00_001' from dual union all
select '5123_123' from dual union all
select '666_A66' from dual union all
select '777_B77_777' from dual union all
select '555' from dual
)
select y, regexp_replace(y,'_\d+$') substr
from x
Results:
| Y | SUBSTR |
|-------------|---------|
| 123_321_009 | 123_321 |
| 3111_00_001 | 3111_00 |
| 5123_123 | 5123 |
| 666_A66 | 666_A66 |
| 777_B77_777 | 777_B77 |
| 555 | 555 |
Pattern:
_ --matches an underscore
\d+ --matches one or more numbers
$ --matches end of the string
Effectively, this matches all the digits following/including the last underscore. Third parameter is regexp_replace is omitted. So, the pattern is
removed and replaced by nothing.

Since you a using Oracle, you can use a regex_replace(val,pattern,'') function with this pattern.
The following patterns would satisfy the samples you provided:
_[0-9]{3}$
_[0-9]*$
Here is a demonstration of this approach using SQL*Plus:
SCOTT#dev> WITH tab(num_val) AS
2 ( SELECT '123_321_009' FROM dual
3 UNION ALL
4 SELECT '3111_00_001' FROM dual
5 UNION ALL
6 SELECT '5123_123' FROM dual
7 UNION ALL
8 SELECT '555' FROM dual
9 )
10 SELECT tab.num_val,
11 regexp_replace(tab.num_val,'_[0-9]{3}$') approach_1,
12 regexp_replace(tab.num_val,'_[0-9]*$') approach_2
13 FROM tab
14 /
NUM_VAL APPROACH_1 APPROACH_2
=========== ====================== ==================
123_321_009 123_321 123_321
3111_00_001 3111_00 3111_00
5123_123 5123 5123
555 555 555
If you provided a larger sampling (or a more specific rule), a more specific solution could be provided.

Related

Extract the number from the Title column in SQL

Please help the query extract the number after "_tid-" from the Title column.
Use the Vertica Regular Expression function collection. Regular expressions in Vertica correspond to the perl regex functionality in their behaviour.
So, with your input, search for the first group that follows _tid- and consists of consecutive digits (\d)...
WITH
-- your input, don't use in final query ...
indata(Title,Extract_ID) AS (
SELECT 'sdffsdvprocessortype%3Alnjklel&text=&textSearch=&pageSize=10&SSid=psj6tcd5b1g7_tid-87945','87945'
UNION ALL SELECT 'https://www.google.com/hk/en/age.html?SSid=ps_c8x4v1r2a3_tid-8952777456','8952777456'
UNION ALL SELECT 'https://www.google.com/hk/en/ge/dhci.html?SSid=ps_7228fk5sbh_tid-5879','5879'
UNION ALL SELECT 'https://www.google.com/fr/fr/c/3328412?q=%3%3AtSearch=&pageSize=10&SSid=pseydgg8h2_tid-9858867','9858867'
UNION ALL SELECT 'https://www.google.com/fr/fr/seas/1011028701?SSid=ps_yne5j6fmqv_tid-6879582','6879582'
UNION ALL SELECT 'https://www.google.com/il/en/sera/p/1010192786?SSid=ps_gydi5nk673_tid-5577484126','5577484126'
UNION ALL SELECT 'pid=ps_98qcokfh3_tid-548965&q=%3Arelevance%3Afacet_Processorstype','548965'
UNION ALL SELECT 'pid=ps_345ey5na9_tid-95861469rq=%3relevance%3Afacet_Processo','95861469'
UNION ALL SELECT 'npyamjhsgx_tid-002154785%20/p/1010192775?SSid=ps_npyamjhsgx_tid-002154785','002154785'
UNION ALL SELECT 'https://www.google.com/us/en/ke.html?ssid=ps_wc998kn__tid-0012889','0012889'
)
-- end of your input, real query starts here ...
SELECT
REGEXP_SUBSTR(
title -- input string
, '_tid-(\d+)' -- regular experssion (note the bit in parentheses, that's the first group)
, 1 -- starting point
, 1 -- occurrence ordinal number
, '' -- modifier (case insensitive, etc. check perl docu)
, 1 -- parentheses base grouping expression's ordinal number
) AS calc_extract
, *
FROM indata;
-- out calc_extract | Title | Extract_ID
-- out --------------+------------------------------------------------------------------------------------------------+------------
-- out 87945 | sdffsdvprocessortype%3Alnjklel&text=&textSearch=&pageSize=10&SSid=psj6tcd5b1g7_tid-87945 | 87945
-- out 8952777456 | https://www.google.com/hk/en/age.html?SSid=ps_c8x4v1r2a3_tid-8952777456 | 8952777456
-- out 5879 | https://www.google.com/hk/en/ge/dhci.html?SSid=ps_7228fk5sbh_tid-5879 | 5879
-- out 9858867 | https://www.google.com/fr/fr/c/3328412?q=%3%3AtSearch=&pageSize=10&SSid=pseydgg8h2_tid-9858867 | 9858867
-- out 6879582 | https://www.google.com/fr/fr/seas/1011028701?SSid=ps_yne5j6fmqv_tid-6879582 | 6879582
-- out 5577484126 | https://www.google.com/il/en/sera/p/1010192786?SSid=ps_gydi5nk673_tid-5577484126 | 5577484126
-- out 548965 | pid=ps_98qcokfh3_tid-548965&q=%3Arelevance%3Afacet_Processorstype | 548965
-- out 95861469 | pid=ps_345ey5na9_tid-95861469rq=%3relevance%3Afacet_Processo | 95861469
-- out 002154785 | npyamjhsgx_tid-002154785%20/p/1010192775?SSid=ps_npyamjhsgx_tid-002154785 | 002154785
-- out 0012889 | https://www.google.com/us/en/ke.html?ssid=ps_wc998kn__tid-0012889 | 0012889

How get all value in same row without using multiple joins conditions in SQL?

I have below table structures
Student
Stud_ID | First_Name | Last_name | Contact
ID001 | AAA | AAA | 111
ID002 | BBB | BBB | 222
StudUser
Stud_ID | NUM | Value
ID001 | 10 | English
ID001 | 20 | Math
ID001 | 30 | Science
ID002 | 10 | English
ID002 | 20 | Math
Expected Output
Stud_id | First_name | 10 | 20 | 30
ID001 | AAA | English | Math | Science
ID002 | BBB | English | Math |
Current query I'm using
select
stud_id,
First_name,
EG.EGUV AS "10",
LE.LEUV AS "20",
FPS.FPSUV AS "30"
from
student,
(SELECT STUD_ID AS EGS,USER_VALUE AS EGUV FROM STUD_USER WHERE COL_NUM='10') AS EG,
(SELECT STUD_ID AS BUS,USER_VALUE AS BUUV FROM STUD_USER WHERE COL_NUM='20') AS BU,
(SELECT STUD_ID AS AUS,USER_VALUE AS AUV FROM STUD_USER WHERE COL_NUM='30') AS A
where
ST.STUD_ID=EG.EGS(+) and
ST.STUD_ID=BU.BUS(+) and
ST.STUD_ID=A.AUS(+)
Please let me know if there is any other optimized way to get all user Values.
Note : this table structure cannot be altered only read permission is available
You can use the Oracle PIVOT clause for this.
It will (sort of) dynamically create additional columns according to values of a selected column.
This is the query I used (using WITH clauses to simulate your input data):
WITH
Student
AS
(SELECT 'ID001' AS Stud_ID, 'AAA' AS First_Name, 'AAA' AS Last_name, 111 AS Contact FROM DUAL
UNION ALL
SELECT 'ID002', 'BBB', 'BBB', 222 FROM DUAL),
StudUser
AS
(SELECT 'ID001' AS Stud_ID, 10 AS NUM, 'English' AS VALUE FROM DUAL
UNION ALL
SELECT 'ID001', 20, 'Math' FROM DUAL
UNION ALL
SELECT 'ID001', 30, 'Science' FROM DUAL
UNION ALL
SELECT 'ID002', 10, 'English' FROM DUAL
UNION ALL
SELECT 'ID002', 20, 'Math' FROM DUAL),
Prepare
AS
(SELECT ST.STUD_ID,
ST.FIRST_NAME,
SU.NUM,
SU.VALUE
FROM STUDENT ST LEFT JOIN STUDUSER SU ON ST.STUD_ID = SU.STUD_ID)
SELECT *
FROM Prepare PIVOT (MIN (VALUE) FOR NUM IN (10, 20, 30))
The PIVOT function expects an aggregate function, because it will go over all of the results where e.g. STUD_ID = ID001 and NUM = 10 and will return a value according to the aggregate function that was used. Your example implies the combination of STUD_ID and NUM will be unique for the StudUser table, therefore most of the Oracle's aggregate functions will do, as they will have to go over just one value. If the combination wasn't unique, you would have to take a second to think about a way you would like to aggregate them.
The FOR section of the pivot clause lets you specify which values you would like to turn into columns. This, unfortunately cannot be generated dynamically, e.g.:
SELECT *
FROM Prepare PIVOT (MIN (VALUE) FOR NUM IN ( SELECT DISTINCT NUM FROM StudUser ))
That would be invalid and wouldn't compile.
You can also specify desired column names for the pivoted columns, like so:
SELECT *
FROM Prepare PIVOT (MIN (VALUE) FOR NUM IN (10 Subject1, 20 Subject2, 30 Subject3))
I found the PIVOT clause merely by searching: oracle turn values into columns, so I kinda guess you didn't find it because you weren't sure how to call this. Can't blame you.

Convert String into Numeric, pulling from the left of ":" and then pulling to the right of ":"

Text_value is column with string values. I need to look for ONLY ':' and separate the left from the right and convert to numeric so I can perform an easy calculation. If ':' does not exist I want nulls to return. I am creating a view in Oracle SQL Developer
Text_Value (Column)
124
7
55:20
73:00
106:24
This is my code:
to_number(REGEXP_SUBSTR(b.text_value,'[^:]*',1,1)) AS Num,
to_number(REGEXP_SUBSTR(B.text_value,'[^:]*$')) AS FRACTION2
These are my results:
I would expect text_values that didn't contain ":" to return as null. That is what I would like to see.
You can check for a two numbers separated by a colon using the regular expression ^(\d+):(\d+)$ like this:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( text_value ) AS
SELECT '124' FROM DUAL UNION ALL
SELECT '7' FROM DUAL UNION ALL
SELECT '55:20' FROM DUAL UNION ALL
SELECT '73:00' FROM DUAL UNION ALL
SELECT '106:24' FROM DUAL;
Query 1:
SELECT text_value,
TO_NUMBER( REGEXP_SUBSTR( text_value, '^(\d+):(\d+)$', 1, 1, NULL, 1 ) ) AS num,
TO_NUMBER( REGEXP_SUBSTR( text_value, '^(\d+):(\d+)$', 1, 1, NULL, 2 ) ) AS fraction2
FROM table_name
Results:
| TEXT_VALUE | NUM | FRACTION2 |
|------------|--------|-----------|
| 124 | (null) | (null) |
| 7 | (null) | (null) |
| 55:20 | 55 | 20 |
| 73:00 | 73 | 0 |
| 106:24 | 106 | 24 |
You could avoid regular expressions and use instr and substr instead:
select text_value,
to_number(case when instr(text_value, ':') > 0
then substr(text_value, 1, instr(text_value, ':') - 1)
else null end) as num,
to_number(case when instr(text_value, ':') > 0
then substr(text_value, instr(text_value, ':') + 1)
else null end) as fraction2
from b;
That's doing more individual function calls, but they may still perform better than regular expressions, and you could move the instr into an inline view if you wanted to, so you aren't doing that four times (though the optimiser might cache the result anyway).
SQL Fiddle demo using a few of the values from your image plus a couple of other variations you didn't refer to, and which you might want to handle differently.
If those are not handled as you want, you can adjust the case expression conditions, e.g. for num changing to > 1, and for fraction2 comparing with the string length - but it depends what you want to see (and if those scenarios can even exist).
You're nearly there. You just need to test to see if the string has a : in it before extracting the 'seconds' portion of the string:
SELECT TEXT_VALUE,
TO_NUMBER(REGEXP_SUBSTR(text_value,'[^:]*',1,1)) AS MINUTES,
CASE
WHEN INSTR(TEXT_VALUE, ':') > 0 THEN TO_NUMBER(REGEXP_SUBSTR(text_value,'[^:]*$'))
ELSE NULL
END AS SECONDS
FROM T;
TEXT_VALUE MINUTES SECONDS
11 11 (null)
00:38 0 38
(null) (null) (null)
69:18 69 18
74:11 74 11
83:43 83 43
00:51 0 51
00:45 0 45
01:42 1 42
7 7 (null)
78:30 78 30
50 50 (null)
03:08 3 8
70:42 70 42
72:24 72 24
123 123 (null)
55:20 55 20
SQLFiddle here
EDIT
You can get rid of the CASE if you change the second regular expression to include, rather than exclude, the colon, then use SUBSTR to grab all characters following the ::
SELECT TEXT_VALUE,
TO_NUMBER(REGEXP_SUBSTR(text_value,'[^:]*',1,1)) AS MINUTES,
SUBSTR(REGEXP_SUBSTR(text_value, ':.*$'), 2) AS SECONDS3
FROM T;
Revised SQLFiddle here

How add separating blank space in numeric value

Unfortunately I couldn't find solutions in the docs.
I want to get numbers in specific format, like this:
234652.24 --> 234 652.24
42145124 --> 42 145 124
select employee_id, to_char(salary, '??????') as "Salary
from employees;
You can specify the NLS_NUMERIC_CHARTACTERS setting as part of the TO_CHAR() call, and use the G and D format model placeholders:
with employees (employee_id, salary) as (
select 1, 234652.24 from dual --> 234 652.24
union all select 2, 42145124 from dual --> 42 145 124
)
select employee_id,
to_char(salary, '999G999G999D99', 'NLS_NUMERIC_CHARACTERS=''. ''') as "Salary"
from employees;
EMPLOYEE_ID Salary
----------- ---------------
1 234 652.24
2 42 145 124.00
If you don't want the trailing zeros in the second value you can add the FM format modifier, which also removes the leading space (which is there to allow for a minus sign if there are any negative values); but that still leaves the trailing period; you can use RTRIM() to get rid of that:
with employees (employee_id, salary) as (
select 1, 234652.24 from dual --> 234 652.24
union all select 2, 42145124 from dual --> 42 145 124
)
select employee_id,
rtrim(to_char(salary, 'FM999G999G999D99', 'NLS_NUMERIC_CHARACTERS=''. '''), '.') as "Salary"
from employees;
EMPLOYEE_ID Salary
----------- ---------------
1 234 652.24
2 42 145 124
You definitely should read about NLS_NUMERIC_CHARACTERS at https://docs.oracle.com/cd/B28359_01/olap.111/b28126/dml_options072.htm
for example,
to_char( 1485, '9g999') ' 1 485'
to_char( 148.5, '999.999') ' 148.500'
to_char( 148.5, '999d999') ' 148,500'
to_char( 3148.5,'9g999d999') ' 3 148,500'
I tried following query and the output is displayed in specified format
mysql> select format(id, '## ###') from test;
+----------------------+
| format(id, '## ###') |
+----------------------+
| 123,456 |
| 123,456,789 |
| 1 |
| 10 |
| 10,000 |
+----------------------+
5 rows in set, 5 warnings (0.00 sec)

Convert the multiple rows Select statement result into a single row string result

I have the following sql query. I'd like the results to be concatenated with a , and I need this as one single query.
Select LOCATION_CODE from LOCATION WHERE ZIPCODE = '555555';
Location table
location_id | location_code | zipcode
--------------------------------------------
1 | ASDFSFD | 555555
2 | OUIXVCX | 555555
3 | 2KLJSDF | 555555
14 | 887CSD | 555555
Need the results like below... ASDFSFD,OUIXVCX,2KLJSDF,887CSD
with location_code as (
select 'ASDFSFD' loc_code, 555555 zipcode from dual
union all select 'OUIXVCX', 555555 from dual
union all select '2KLJSDF', 555555 from dual
union all select '887CSD', 555555 from dual
)
select rtrim (xmlagg (xmlelement (e, loc_code || ',')).extract ('//text()'), ',')
from location_code where zipcode = 555555;
If you are using Oracle 10g, you can also use the undocumented aggregate function WM_CONCAT():
SELECT WM_CONCAT(location_code) FROM location WHERE zipcode = 555555;
One possible caveat is that WM_CONCAT() returns a CLOB in some versions of Oracle 10g (e.g., 10.2.0.5), but a VARCHAR2 in others (e.g., 10.2.0.1).
You can also develop your own string concatenation aggregate function; please see the following links for specifics (as well as other methods of how to accomplish string concatenation):
http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php#wm_concat