PostgreSQL substring - postgresql

I have a function and I want to get a string between two strings where the first one is "Start" and the second one is the new line character.
I mean: From "Start blablabla \n" I only want "blablabla".
I've tried this, but it doesn't work:
select substring(test from 'Start(.+)\n') into vtest;
How can I identify the newline character??
Thanks!

It needs to be double-escaped:
test=> select substring('foo
bar' from E'\\A(.*)\\r?\\n');
substring
-----------
foo
(1 row)
Alternative version:
select substring('foo
bar' from E'\\A.*(?=\\r?\\n)');

The $ symbol matches the string end:
select substring('Start123' from 'Start(.+)$');
substring
-----------
123

Related

find nth position of a specific character in a string in Postgres

I am running Postgres 9.6
I have a list of various class codes.
Here is:
'What I have' And 'What I Want'
what I have --> what I want.
Equip:Mold --> Equip:Mold
Raw:Resin:TPA --> Raw:Resin
FG --> FG
...
My strategy to accomplish this is to write a user defined function that will find the character count 2nd ':' in my list then use the LEFT function with a LEFT('Raw:Resin:TPA',nthpositionget('Raw:Resin:TPA',':',2))
I tried using the following question to no avail.
Postgres: extract text up to the Nth Character in a String
This overall problem is best handled with regexp_replace():
select regexp_replace('Raw:Resin:TPA', '(^.*:.*):', '\1');
regexp_replace
----------------
Raw:ResinTPA
(1 row)
select regexp_replace('Equip:Mold', '(^.*:.*):', '\1');
regexp_replace
----------------
Equip:Mold
(1 row)
select regexp_replace('FG', '(^.*:.*):', '\1');
regexp_replace
----------------
FG
(1 row)
If you want something that finds the nth occurrence of a substring, then something like this could be made into a function:
with invar as (
select 'Raw:Resin:TPA' as a, ':' as d
)
select case
when length(array_to_string((string_to_array(a, d))[1:2], d)) = length(a) then -1
else length(array_to_string((string_to_array(a, d))[1:2], d)) + 1
end
from invar;

Substring from an escape character onwards

I'm using PostgreSQL and I need to truncate a text string, I need to show from an escape character (:) onwards.
I'm trying something like that:
SELECT SUBSTRING ('CATEGORIA DE TRABAJOS: EJECUTIVO' FROM '%#":#"%' FOR '#');
t=# select split_part('CATEGORIA DE TRABAJOS: EJECUTIVO',':',2);
split_part
------------
EJECUTIVO
(1 row)
just split by first found delimiter?..

TRIM not works with lines and tabs of a xpath in PostgreSQL?

With this query
SELECT trim(title) FROM (
SELECT
unnest( xpath('//p[#class="secTitle1"]', xmlText )::varchar[] ) AS title
FROM t1
) as t2
and XML input text with lines and spaces,
<root>
...
<p class="x">
text text
text text
</p><p> ...</p>
...
</root>
The trim() have no effect (!). It is a PostgreSQL bug? How to apply fn:normalize-space() with the XPath? I need something like "WHERE title is not null"? (Oracle is simpler...) How to do this simple query with PostreSQL?
Workaround
I need a well-configured build-in function, not a workaround... But I need to work and to show results, so I am using regular expression...
SELECT id, TRIM(regexp_replace(tit, E'[\\n\\r\\t ]+', ' ', 'g')) AS tit
FROM (
SELECT
id, -- xpath returns array of 1, 2, or more strings
unnest( xpath('//p[#class="secTitle1"]', texto )::VARCHAR[] ) AS tit
FROM t
) AS tmp
So, a "only simple space trim" is not friendly, not util (!).
EDIT after #mu comment
I try
SELECT id, TRIM(tit, E'\\n\\r\\t') AS tit
and
SELECT id, TRIM(tit, '\n\r\t') AS tit
both NOT WORKs.
QUESTION REMAINS:
there are no TRIM-option or postgresql configuration to say to TRIM work as it is required?
can I use normalize-space() at xpath? How?
I am using PostgreSQL 9.1, need to upgrade?
It works in 9.2, and it works on 8.4 too.
postgres=# select trim(unnest(string_to_array(e'\t\tHello\n\t\tHello\n\t\tHello', e'\n')), e'\t');
btrim
-------
Hello
Hello
Hello
(3 rows)
your regexp replace any char \n or \r or \t, but trim working with string "\n\r\t". It has different meaning than you expect.

PostgreSQL change part of a string to uppercase

I have a field named rspec in a table trace.
So for now the field is like "Vol3/data/20070204_191426_FXBS.v3a".
All I need is a query to change it to the format "Vol3/data/20070204_191426_FXBS.V3A".
Assuming the current version:
select left(rspec, - 3)||upper(right(rspec, 3))
from trace
For older versions:
select substr(rspec, 1, length(rspec) - 3)||upper(substring(rspec from '...$'))
from trace
Or, to cover all possibilities like
file extensions of variable length: abc123.jpeg
no file extension at all: abc123
dot as last character: abc123.
multiple dots: abc.123.jpg
SELECT CASE WHEN rspec ~~ '%.%'
THEN substring(rspec, E'^.*\\.')
|| upper(substring(rspec , E'([^.]*)$'))
ELSE rspec
END AS rspec
FROM (VALUES
('abc123.jpeg')
, ('abc123')
, ('abc123.')
, ('abc.123.jpg')
) ASx(rspec); -- testcases
Explain:
If the string has no dot, use the string.
Else, take everything up to and including the last dot in the string.
Append everything after the last dot in upper case.

replace string with split_part function

I want to replace the first word before delimeter ' ,' with ' 0, the first word ')
select replace('tab,graph,map', split_part('tab,graph', ',', 1) like 'tab','0, tab')
ERROR: function replace(unknown, boolean, unknown) does not exist
LINE 1: select replace('tab,graph,map', split_part('tab,graph', ',',...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
The replace function replaces all occurrences of the string so you have to make sure the string to replace is unique or use something else. However, regexp_replace only replaces the first occurrence by default so you can use that; your question is a little unclear about what the expected output is but maybe this is is what you're looking for:
=> select regexp_replace('tab,graph,map', ',', '0,');
regexp_replace
----------------
tab0,graph,map
Or this one:
=> select regexp_replace('tab,graph,map', 'tab,', '0,');
regexp_replace
----------------
0,graph,map
Or maybe even this:
=> select regexp_replace('tab,graph,map', 'tab,', '0,,');
regexp_replace
----------------
0,,graph,map
you need to cast, since the function expects replace(text, text, text) and does not know how to handle your literal strings calling them unknown...
cast('tab,graph,map' AS text)
also the 2nd param is a LIKE comparison ? which returns boolean, but the function replace expects it to be the delimiter.
CAST(split_part('tab,graph', ',', 1) AS text)
finally the last param (same problem as the first)
cast('0, tab' AS text)
of course if you really just want to prepend '0, ' to your string, 'tab,graph,map' you could just do that...
SELECT '0, ' || 'tab,graph,map' ;