How can I generate all trailing substrings following a delimeter?
I think this is my favorite.
create table t (id int,str varchar(100));
insert into t (id,str) values (1,'a.b.c.d.e'),(2,'xxx.yyy.zzz');
ROWS
select id
,array_to_string((string_to_array(str,'.'))[i:],'.')
from t,unnest(string_to_array(str,'.')) with ordinality u(token,i)
;
+----+-----------------+
| id | array_to_string |
+----+-----------------+
| 1 | a.b.c.d.e |
| 1 | b.c.d.e |
| 1 | c.d.e |
| 1 | d.e |
| 1 | e |
| 2 | xxx.yyy.zzz |
| 2 | yyy.zzz |
| 2 | zzz |
+----+-----------------+
ARRAYS
select id
,array_agg(array_to_string((string_to_array(str,'.'))[i:],'.'))
from t,unnest(string_to_array(str,'.')) with ordinality u(token,i)
group by id
;
+----+-------------------------------------------+
| id | array_agg |
+----+-------------------------------------------+
| 1 | {"a.b.c.d.e","b.c.d.e","c.d.e","d.e","e"} |
| 2 | {"xxx.yyy.zzz","yyy.zzz","zzz"} |
+----+-------------------------------------------+
create table t (id int,str varchar(100));
insert into t (id,str) values (1,'a.b.c.d.e'),(2,'xxx.yyy.zzz');
ROWS
select id
,regexp_replace(str,'^([^\.]+\.?){' || gs.i || '}','') as suffix
from t,generate_series(0,cardinality(string_to_array(str,'.'))-1) gs(i)
;
OR
select id
,substring(str from '(([^.]*?\.?){' || gs.i+1 || '})$') as suffix
from t,generate_series(0,cardinality(string_to_array(str,'.'))-1) gs(i)
;
+----+-------------+
| id | suffix |
+----+-------------+
| 1 | a.b.c.d.e |
+----+-------------+
| 1 | b.c.d.e |
+----+-------------+
| 1 | c.d.e |
+----+-------------+
| 1 | d.e |
+----+-------------+
| 1 | e |
+----+-------------+
| 2 | xxx.yyy.zzz |
+----+-------------+
| 2 | yyy.zzz |
+----+-------------+
| 2 | zzz |
+----+-------------+
ARRAYS
select id
,array_agg(regexp_replace(str,'^([^\.]+\.?){' || gs.i || '}','')) as suffixes
from t,generate_series(0,cardinality(string_to_array(str,'.'))-1) gs(i)
group by id
;
OR
select id
,array_agg(substring(str from '(([^.]*?\.?){' || gs.i+1 || '})$')) as suffixes
from t,generate_series(0,cardinality(string_to_array(str,'.'))-1) gs(i)
group by id
;
+----+-------------------------------------------+
| id | suffixes |
+----+-------------------------------------------+
| 1 | {"a.b.c.d.e","b.c.d.e","c.d.e","d.e","e"} |
| 2 | {"xxx.yyy.zzz","yyy.zzz","zzz"} |
+----+-------------------------------------------+
I don't think you need a separate column here; this is an XY-problem. You're just trying to do a suffix search. There are two main ways to optimize that.
Turn the suffix query into a prefix query
You basically do this by reversing everything.
First create an index on the reverse of your column:
CREATE INDEX ON yourtable (reverse(yourcolumn) text_pattern_ops);
Then query using the same:
SELECT * FROM yourtable WHERE reverse(yourcolumn) LIKE reverse('%t.com');
You can throw in an UPPER
call if you want to make it case insensitive:
CREATE INDEX ON yourtable (reverse(UPPER(yourcolumn)) text_pattern_ops);
SELECT * FROM yourtable WHERE reverse(UPPER(yourcolumn)) LIKE reverse(UPPER('%t.com'));
Trigram Indexes
The other option is trigram indexes. You should definitely use this if you need infix queries (LIKE 'something%something'
or LIKE '%something%'
type queries).
First enable the trigram index extension:
CREATE EXTENSION pg_trgm;
(This should come with PostgreSQL out of the box without any extra installation.)
Then create a trigram index on your column:
CREATE INDEX ON yourtable USING GIST(yourcolumn gist_trgm_ops);
Then just select:
SELECT * FROM yourtable WHERE yourcolumn LIKE '%t.com';
Again, you can throw in an UPPER
to make it case insensitive if you like:
CREATE INDEX ON yourtable USING GIST(UPPER(yourcolumn) gist_trgm_ops);
SELECT * FROM yourtable WHERE UPPER(yourcolumn) LIKE UPPER('%t.com');
Your question as written
Trigram indexes actually work using a somewhat more general form of what you're asking for under the hood. It breaks the string down into pieces (trigrams) and builds an index based on those. The index can then be used to search for matches much more quickly than a sequential scan, but for infix as well as suffix and prefix queries. Always try to avoid reinventing what someone else has developed when you can.
Credits
The two solutions are pretty much verbatim from Choosing a PostgreSQL text search method. I highly recommend giving it a read for a detailed analysis of the available text search options in PotsgreSQL.