split_part function from nth split till end of string - postgresql

After the second space, I need to fetch the values till the particular position in the string.
Source:
"8 115 MACKIE STREET VICTORIA PARK WA 6100 AU"
"6A CAMBOON ROAD MORLEY WA 6062 AU"
output:
"MACKIE STREET VICTORIA PARK"
"CAMBOON ROAD MORLEY"
I'm trying to split the street name and suburb from the unit #,street# present in the beginning and the state, postcode, country present in the end.

t=# with s(v) as (values('6A CAMBOON ROAD MORLEY WA 6062 AU'),('8 115 MACKIE STREET VICTORIA PARK WA 6100 A'))
, split as (select *,count(1) over (partition by v) from s, regexp_matches(v,'( [A-Z]+)','g') with ordinality t(m,o))
select distinct v,string_agg(m[1],'') over (partition by v) from split where o <= count-(3-1);
v | string_agg
---------------------------------------------+------------------------------
8 115 MACKIE STREET VICTORIA PARK WA 6100 A | MACKIE STREET VICTORIA PARK
6A CAMBOON ROAD MORLEY WA 6062 AU | CAMBOON ROAD MORLEY
(2 rows)
I excluded index (or any not fitting mask [A-Z]+) thus cutting not three positions from the end, but two (3-1) where 1 is ahead known index.
Also I start not from the second space as it would be against your desired result...

Related

Extract all matches with a specific pattern in DuckDB

I am trying to translate a query from Postgres to DuckDB that does the following: for a given string the query returns
All numbers
All pairs of consecutive tokens
The original Postgres queries are:
select (regexp_matches('34 121 adelaide st melbourne 3000', '[\d]+', 'g'))[1];
select (regexp_matches ( '34 121 adelaide st melbourne 3000', '[a-z0-9]+ [a-z0-9]+', 'g' ))[1] union select (regexp_matches ( regexp_replace ( '34 121 adelaide st melbourne 3000', '[a-z0-9]+', '' ), '[a-z0-9]+ [a-z0-9]+', 'g' ))[1];
For example, given the string '34 121 adelaide st melbourne 3000':
Return a table with row values 34, 121, 3000
Return a table with row values '34 121', '121 adelaide', 'adelaide st', 'st melbourne', 'melbourne 3000']
Using the regexp_extract function I can only return the first match. E.g.,
select regexp_extract('34 121 adelaide st melbourne 3000', '[\d]+');
produces '34' but none of the other digits.
Similarly select regexp_extract('34 121 adelaide st melbourne 3000', '[a-z0-9]+ [a-z0-9]+'); produces '34 121'
The second query I can re-write using a join to produce the correct results (although I would still prefer to do this in a simpler way).
Would anyone be able to assist?
I tried `select regexp_extract('34 121 adelaide st melbourne 3000', '[\d]+');' which results in a table containing only '34' and none of the other numbers.

Updating a specific word in a column

How could I update the St. to Street on this column? I am getting a hard time on how to figure this out
Address
125 Center St, New York City, NY 10001
68 Hickory St, Seattle, WA 98101
I am trying to update one word on a column which is the St. to Street
I would use an expression like
regexp_replace(col, '\mSt\M\.?', 'Street', 'g')

How to search records while ignoring the special characters in postgres

I have a table in Postgres that has records like
ID
Address
1
862 N Longbranch Road Voorhees, NJ 08043
2
7300 Overlook, Ave Moncks Corner, SC 29461
3
76 SW Green Lake, Street Sterling, VA 20164
4
597 Wintergreen St Erlanger, KY 41018
So for searching a specific address my query is simple
select * from profile where address ilike '7300 Overlook, Ave Moncks Corner, SC%'
This is returning record 2
What I want is
select * from profile where address ilike '7300 Overlook Ave Moncks Corner SC%'
(Please note that commas are missing in second query)
Even if the string inside ilike doesn't contain comma , result 2 should be returned.

GROUP BY name and ORDER BY point & time MYSQLi

I'm new to this forum and I hope to find my solution about my problem.
I have this table :
name time points car date
Daniel | 55s | 210 | red |20/01/2018
Daniel | 45s | 250 | green |21/01/2018
Julie | 54s | 220 | red |19/01/2018
Julie | 33s | 150 | yellow|22/01/2018
and I wish to sort it like this
name time points car date
Daniel | 45s | 250 |green |21/01/2018
Julie | 54s | 220 |red |19/01/2018
first sorting by points, than sorting by time and group by name (optional the count)
I use this
SELECT NAME, MAX(POINTS) POINTS, MAX(TIME) TIME, MAX(CAR) CAR, MAX(DATE) DATE
FROM ( SELECT A.* FROM test A LEFT OUTER JOIN test B ON A.NAME=B.NAME AND
A.POINTS<B.POINTS AND A.TIME>B.TIME WHERE B.NAME IS NULL ) as sub GROUP BY NAME
and I get this :
name POINTS TIME CAR DATE
Daniel 250 45 green 2018-01-21
Julie 220 54 yellow 2018-01-22
Julie should have car=red & 2018-01-19
For Daniel it looks good
how can I get thise values (car & date) ?
thanks
Nico
You could give this a shot. It contains the table against itself and gets only records with the highest points and lowest time.
SELECT NAME, MAX(POINTS) POINTS, MAX(TIME) TIME
FROM
(
SELECT A.* FROM test A
LEFT OUTER JOIN test B ON A.NAME=B.NAME AND A.POINTS<B.POINTS AND A.TIME>B.TIME
WHERE B.NAME IS NULL
) GROUP BY NAME
For additional, try this:
SELECT * FROM
(
SELECT OUTERTEST.*,
#row_num := IF(#prev_value=OUTERTEST.name,#row_num+1,1) AS RowNumber,
#prev_value := OUTERTEST.name
FROM (SELECT * FROM TEST ORDER BY NAME, TEST.POINTS DESC, TEST.TIME ASC) OUTERTEST, (SELECT #row_num := 1, #prev_value := '') x
) A
WHERE A.ROWNUMBER=1
I did more test with this table
id name time points
1 Daniel 55 1140
2 Judie 54 1144
3 Judie 33 1028
4 Daniel 45 1180
5 Judie 53 1148
I apply this request
SELECT NAME, MAX(POINTS) POINTS, sub.TIME FROM (SELECT * FROM Testpoint ORDER BY POINTS DESC, TIME ASC) AS sub
GROUP BY sub.name
I have the max point for each name but the time is not the right one
name POINTS time
Daniel 1180 55
Judie 1148 54
Judie should have 53 for time and not 54
What I did wrong?
thankyou
Nico

Preserve the order of distinct inside string_agg

My SQL function:
with recursive locpais as (
select l.id, l.nome, l.tipo tid, lp.pai
from loc l
left join locpai lp on lp.loc = l.id
where l.id = 12554
union
select l.id, l.nome, l.tipo tid, lp.pai
from loc l
left join locpai lp on lp.loc = l.id
join locpais p on (l.id = p.pai)
)
select * from locpais
gives me
12554 | PARNA Pico da Neblina | 9 | 1564
12554 | PARNA Pico da Neblina | 9 | 1547
1547 | São Gabriel da Cachoeira | 8 | 1400
1564 | Santa Isabel do Rio Negro | 8 | 1400
1400 | RIO NEGRO | 7 | 908
908 | NORTE AMAZONENSE | 6 | 234
234 | Amazonas | 5 | 229
229 | Norte | 4 | 30
30 | Brasil | 3 |
which is a hierarchy of places. "PARNA" stands for "National Park", and this one covers two cities: São Gabriel da Cachoeira and Santa Isabel do Rio Negro. Thus it's appearing twice.
If I change the last line for
select string_agg(nome,', ') from locpais
I get
"PARNA Pico da Neblina, PARNA Pico da Neblina, São Gabriel da
Cachoeira, Santa Isabel do Rio Negro, RIO NEGRO, NORTE AMAZONENSE,
Amazonas, Norte, Brasil"
Which is almost fine, except for the double "PARNA Pico da Neblina". So I tried:
select string_agg(distinct nome, ', ') from locpais
but now I get
"Amazonas, Brasil, Norte, NORTE AMAZONENSE, PARNA Pico da Neblina, RIO
NEGRO, Santa Isabel do Rio Negro, São Gabriel da Cachoeira"
Which is out of order. I'm trying to add an order by inside the string_agg, but couldn't make it work yet. The definition of the tables were given here.
As you've found out, you cannot combine DISTINCT and ORDER BY if you don't order by the distinct expression first:
neither in aggregates:
If DISTINCT is specified in addition to an order_by_clause, then all the ORDER BY expressions must match regular arguments of the aggregate; that is, you cannot sort on an expression that is not included in the DISTINCT list.
nor in SELECT:
The DISTINCT ON expression(s) must match the leftmost ORDER BY expression(s).
However could use something like
array_to_string(arry_uniq_stable(array_agg(nome ORDER BY tid DESC)), ', ')
with the help of a function arry_uniq_stable that removes duplicates in an array w/o altering it's order like I gave an example for in https://stackoverflow.com/a/42399297/5805552
Please take care to use an ORDER BY expression that actually gives you an deterministic result. With the example you have given, tid alone would be not enough, as there are duplicate values (8) with different nome.
select string_agg(nome,', ')
from (
select distinct nome
from locpais
order by tid desc
) s