How to get only last two values(Helloworld - test0 - test!) in oracle using function "regexp_substr"? - oracle10g

From the below query, I want to display the substring "test0 -test!" after the string is splitted by the delimeter "-".
select regexp_substr('Helloworld - test0 - test!' ,'[^ - ]+',1,1)from dual;
Could you please help me on this?
Thanks!!!

You could expand the pattern to:
select regexp_substr('Helloworld - test0 - test!' ,'[^ -]+ - [^ -]+$', 1, 1)
from dual;
REGEXP_SUBSTR
-------------
test0 - test!
... which treats any run of spaces and dashes the same, as your original pattern did (because it's in square brackets).
You could also use regexp_replace() with back references (this can probably be simplified!):
select regexp_replace('Helloworld - test0 - test!' ,'(.*)( - )(.*)( - )(.*)$', '\3\4\5')
from dual;
REGEXP_REPLAC
-------------
test0 - test!
But you don't need regular expressions, as long as you know there are at least two - separators you can use substr() with instr():
select substr('Helloworld - test0 - test!',
instr('Helloworld - test0 - test!', ' - ', -1, 2) + 3)
from dual;
SUBSTR('HELLO
-------------
test0 - test!
The instr() counts backwards from the end of the string (because of the -1 as the third argument), and finds the second appearance counting backwards, which puts you at the space immediately after the d. You then add three to step back over the delimiter, to find the start of the bit you want.
If you actually want to skip the first token (as you suggested in a comment), rather than always get the last two tokens (as the question says), then it's even easier:
select substr('Helloworld - test0 - test!',
instr('Helloworld - test0 - test!', ' - ', 1, 1) + 3)
from dual;
SUBSTR('HELLO
-------------
test0 - test!
or with your second string:
select substr('welcome - to - stackoverflow - test!',
instr('welcome - to - stackoverflow - test', ' - ', 1, 1) + 3)
from dual;
SUBSTR('WELCOME-TO-STACKOV
--------------------------
to - stackoverflow - test!
You can still use regexp_replace() if you prefer, though it's usually more expensive:
select regexp_replace('Helloworld - test0 - test!', '^[^ -]+ - ', null, 1, 1)
from dual;
REGEXP_REPLAC
-------------
test0 - test!
select regexp_replace('welcome - to - stackoverflow - test!', '^[^ -]+ - ', null, 1, 1)
from dual;
REGEXP_REPLACE('WELCOME-TO
--------------------------
to - stackoverflow - test!
If you want to split just on a dash, not space-dash-space, then that's simpler again. but if you also want to remove any leading spaces that leaves behind you'll need to add a trim to get rid of that:
ltrim(substr(your_string, instr(your_string, '-', 1, 1) + 1))
or:
ltrim(regexp_replace(your_string ,'^[^-]+-', null, 1, 1))
or remove it as part of the pattern:
regexp_replace(your_string ,'^[^- ]+ ?- ?', null, 1, 1)
etc.

Related

PostgreSQL return last n words

How to return last n words using Postgres.
I have tried using LEFT method.
SELECT DISTINCT LEFT(name, -4) FROM my_table;
but it return last 4 characters ,i want to return last 3 words.
demo:db<>fiddle
You can do this using a the SUBSTRING() function and regular expressions:
SELECT
SUBSTRING(name FROM '((\S+\s+){0,3}\S+$)')
FROM my_table
This has been explained here: How can I match the last two words in a sentence in PostgreSQL?
\S+ is a string of non-whitespace characters
\s+ is a string of whitespace characters (e.g. one space)
(\S+\s+){0,3} Zero to three words separated by a space
\S+$ one word at the end of the text.
-> creates 4 words (or less if there are no more).
One way is to use regexp_split_to_array() to split the string into the words it contains and then put a string back together using the last 3 words in that array.
SELECT coalesce(w.words[array_length(w.words, 1) - 2] || ' ', '')
|| coalesce(w.words[array_length(w.words, 1) - 1] || ' ', '')
|| coalesce(w.words[array_length(w.words, 1)], '')
FROM mytable t
CROSS JOIN LATERAL (SELECT regexp_split_to_array(t."name", ' ') words) w;
db<>fiddle
RIGHT() should do
SELECT RIGHT('MYCOLUMN', 4); -- returns LUMN
UPD
You can convert to array and then back to string
SELECT array_to_string(sentence[(array_length(sentence,1)-3):(array_length(sentence,1))],' ','*')
FROM
(
SELECT regexp_split_to_array('this is the one of the way to get the last four words of the string', E'\\s+') AS sentence
) foo;
DEMO HERE

Get Substrings From DB2 Column

I Have: AAAA/DATA1/Data2;xyx;pqr
this data
I want only:DATA1 And Data2
If this is for a specific row, maybe use SUBSTR? Something like
SELECT
SUBSTR(column, 6, 5) AS col1
, SUBSTR(column, 13, 5) AS col2
FROM table
Here is something else you can do.. Although it gets pretty complicated, and this isn't the exact answer you are looking for but it will get you started. Hope this helps:
WITH test AS (
SELECT characters
FROM ( VALUES
( 'AAAA/DATA1/Data2;xyx;pqr'
) )
AS testing(characters)
)
SELECT
SUBSTR(characters, 1, LOCATE('/', characters) - 1) AS FIRST_PART
, SUBSTR(characters, LOCATE('/', characters) + 1) AS SECOND_PART
, SUBSTR(characters, LOCATE('/', characters, LOCATE('/', characters) + 1) + 1)
AS THIRD_PART
FROM test
;
DB2 does not have a single function for this, unfortunately. Check out this answer here: How to split a string value based on a delimiter in DB2

concatenate arrays in aggregate query

i have a starting table where there are some meteo data stored every 15 minutes, one field stores leaf wet at 1 minute sampling in a numeric array form, thus i have a 15 values array each row.
Now i want to create a 1 hour aggregation of this table, crating an array of 60 values for this field.
I tried array_cat at first place, but says
array_cat(numeric[]) not existing
the function obviuously exists, so i tought the format was not the one expected, i tried first unnesting and then aggregating, not working again.
Finally i was able to aggregate trough string conversion, but it's not what i wanted (i might in the future apply some numeric elaboration oh that 60-values array)
I paste the query for further investigations
SELECT dati1_v.id_stazione,
to_char(dati1_v.data_ora, 'YYYY-MM-DD HH24:00:00'::text) AS date_hour,
round(avg(dati1_v.temp1_media), 2) AS t_avg,
round(avg(dati1_v.ur1_media), 2) AS hum_avg,
sum(dati1_v.pioggia) AS rain_tot,
max(dati1_v.pioggia) AS rain_max,
round((avg((SELECT avg(lw.lw) AS avg FROM unnest(dati1_v.lw_top_array) lw(lw))) - lws.top_min) /
(lws.top_max - lws.top_min) * 100::numeric, 2) AS lw_top_avg,
array_agg((SELECT round((avg(lw.lw) - lws.top_min) / (lws.top_max - lws.top_min) * 100::numeric, 2) AS round
FROM unnest(dati1_v.lw_top_array) lw(lw))) AS lw_top_array,
array_cat(dati1_v.lw_top_array) AS lw_top_array_tot,
-- array_agg((select lw_top_array from unnest(dati1_v.lw_top_array))) AS lw_top_array_tot,
-- array_agg(array_to_string(dati1_v.lw_top_array, ',')) AS lw_top_array_tot,
round((avg((SELECT avg(lw.lw) AS avg FROM unnest(dati1_v.lw_bottom_array) lw(lw))) - lws.bottom_min) /
(lws.bottom_max - lws.bottom_min) * 100::numeric, 2) AS lw_bottom_avg,
array_agg((SELECT round((avg(lw.lw) - lws.bottom_min) / (lws.bottom_max - lws.bottom_min) * 100::numeric,
2) AS round
FROM unnest(dati1_v.lw_bottom_array) lw(lw))) AS lw_bottom_array
FROM dati1_v,
lw_settings lws
WHERE lws.id = 1
GROUP BY dati1_v.id_stazione, to_char(dati1_v.data_ora, 'YYYY-MM-DD HH24:00:00'::text), lws.top_min, lws.top_max,
lws.bottom_min, lws.bottom_max
ORDER BY dati1_v.id_stazione, to_char(dati1_v.data_ora, 'YYYY-MM-DD HH24:00:00'::text)
in particular, my tries were related to this specific block:
array_cat(dati1_v.lw_top_array) AS lw_top_array_tot,
-- array_agg((select lw_top_array from unnest(dati1_v.lw_top_array))) AS lw_top_array_tot,
-- array_agg(array_to_string(dati1_v.lw_top_array, ',')) AS lw_top_array_tot
Thanks
For me in similar case helped UNNEST in subquery and ARRAY_AGG of unnnested
SELECT
ARRAY_AGG(
DISTINCT lw_top
) as lw_top_array
FROM (
SELECT
UNNEST(lw_top_array) AS lw_top
FROM
dati1_v
) as tmp;
for me helped next query
SELECT
my_table.key,
array_agg(_unnested.item) as array_coll
from my_table
left join LATERAL (SELECT unnest(my_table.array_coll) as item) _unnested ON TRUE
GROUP by my_table.key
In PostgreSQL, the Group_concat function is not available but you can get similar result as string_agg and array_to_string.
string_agg(array_to_string(file_ids, ','), ',') filter ( where file_ids notnull ) AS file_ids_str
array_to_string and array_to_string works in next way
array_to_string([1, 2, 456], ',') => '1,2,456'
string_agg(['a', 'ab'], ',') => 'a,ab'
the only problem is that result is string with ',' as separator

How to replace captured group with evaluated expression (adding an integer value to capture group)

I need to convert some strings with this format:
B12F34
to something like that:
Building 12 - Floor 34
but I have to add a value, say 10, to the second capture group so the new string would be as:
Building 12 - Floor 44
I can use this postgres sentence to get almost everything done, but I don't know how to add the value to the second capture group.
SELECT regexp_replace('B12F34', 'B(\d+)F(\d+)', 'Building \1 - Floor \2', 'g');
I have been searching for a way to add a value to \2 but all I have found is that I can use 'E'-modifier, and then \1 and \2 need to be \\1 and \\2:
SELECT regexp_replace('B12F34', 'B(\d+)F(\d+)', E'Building \\1 - Floor \\2', 'g')
I need some sentence like this one:
SELECT regexp_replace('B12F34', 'B(\d+)F(\d+)', E'Building \\1 - Floor \\2+10', 'g')
to get ........ Floor 44 instead of ........ Floor 34+10
You can not do this in regexp alone because regexp does not support math on captured groups even if they are all numeric characters. So you have to get the group that represents the floor number, do the math and splice it back in:
SELECT regexp_replace('B12F34', 'B(\d+)F(\d+)', 'Building \1 - Floor ') ||
((regexp_matches('B12F34', '[0-9]+$'))[1]::int + 10)::text;
Not very efficient because of the two regexp calls. Another option is to just get the two numbers in a sub-query and assemble the string in the main query:
SELECT format('Building %L - Floor %L', m.num[1], (m.num[2])::int + 10)
FROM (
SELECT regexp_matches('B12F34', '[0-9]+', 'g') AS num) m;

Extract the first word of a string in a SQL Server query

What's the best way to extract the first word of a string in sql server query?
SELECT CASE CHARINDEX(' ', #Foo, 1)
WHEN 0 THEN #Foo -- empty or single word
ELSE SUBSTRING(#Foo, 1, CHARINDEX(' ', #Foo, 1) - 1) -- multi-word
END
You could perhaps use this in a UDF:
CREATE FUNCTION [dbo].[FirstWord] (#value varchar(max))
RETURNS varchar(max)
AS
BEGIN
RETURN CASE CHARINDEX(' ', #value, 1)
WHEN 0 THEN #value
ELSE SUBSTRING(#value, 1, CHARINDEX(' ', #value, 1) - 1) END
END
GO -- test:
SELECT dbo.FirstWord(NULL)
SELECT dbo.FirstWord('')
SELECT dbo.FirstWord('abc')
SELECT dbo.FirstWord('abc def')
SELECT dbo.FirstWord('abc def ghi')
I wanted to do something like this without making a separate function, and came up with this simple one-line approach:
DECLARE #test NVARCHAR(255)
SET #test = 'First Second'
SELECT SUBSTRING(#test,1,(CHARINDEX(' ',#test + ' ')-1))
This would return the result "First"
It's short, just not as robust, as it assumes your string doesn't start with a space. It will handle one-word inputs, multi-word inputs, and empty string inputs.
Enhancement of Ben Brandt's answer to compensate even if the string starts with space by applying LTRIM(). Tried to edit his answer but rejected, so I am now posting it here separately.
DECLARE #test NVARCHAR(255)
SET #test = 'First Second'
SELECT SUBSTRING(LTRIM(#test),1,(CHARINDEX(' ',LTRIM(#test) + ' ')-1))
Adding the following before the RETURN statement would solve for the cases where a leading space was included in the field:
SET #Value = LTRIM(RTRIM(#Value))
Marc's answer got me most of the way to what I needed, but I had to go with patIndex rather than charIndex because sometimes characters other than spaces mark the ends of my data's words. Here I'm using '%[ /-]%' to look for space, slash, or dash.
Select race_id, race_description
, Case patIndex ('%[ /-]%', LTrim (race_description))
When 0 Then LTrim (race_description)
Else substring (LTrim (race_description), 1, patIndex ('%[ /-]%', LTrim (race_description)) - 1)
End race_abbreviation
from tbl_races
Results...
race_id race_description race_abbreviation
------- ------------------------- -----------------
1 White White
2 Black or African American Black
3 Hispanic/Latino Hispanic
Caveat: this is for a small data set (US federal race reporting categories); I don't know what would happen to performance when scaled up to huge numbers.
DECLARE #string NVARCHAR(50)
SET #string = 'CUT STRING'
SELECT LEFT(#string,(PATINDEX('% %',#string)))
Extract the first word from the indicated field:
SELECT SUBSTRING(field1, 1, CHARINDEX(' ', field1)) FROM table1;
Extract the second and successive words from the indicated field:
SELECT SUBSTRING(field1, CHARINDEX(' ', field1)+1, LEN (field1)-CHARINDEX(' ', field1)) FROM table1;
A slight tweak to the function returns the next word from a start point in the entry
CREATE FUNCTION [dbo].[GetWord]
(
#value varchar(max)
, #startLocation int
)
RETURNS varchar(max)
AS
BEGIN
SET #value = LTRIM(RTRIM(#Value))
SELECT #startLocation =
CASE
WHEN #startLocation > Len(#value) THEN LEN(#value)
ELSE #startLocation
END
SELECT #value =
CASE
WHEN #startLocation > 1
THEN LTRIM(RTRIM(RIGHT(#value, LEN(#value) - #startLocation)))
ELSE #value
END
RETURN CASE CHARINDEX(' ', #value, 1)
WHEN 0 THEN #value
ELSE SUBSTRING(#value, 1, CHARINDEX(' ', #value, 1) - 1)
END
END
GO
SELECT dbo.GetWord(NULL, 1)
SELECT dbo.GetWord('', 1)
SELECT dbo.GetWord('abc', 1)
SELECT dbo.GetWord('abc def', 4)
SELECT dbo.GetWord('abc def ghi', 20)
Try This:
Select race_id, race_description
, Case patIndex ('%[ /-]%', LTrim (race_description))
When 0 Then LTrim (race_description)
Else substring (LTrim (race_description), 1, patIndex ('%[ /-]%', LTrim (race_description)) - 1)
End race_abbreviation
from tbl_races