how to split a column that is created with array_agg - postgresql

I'm trying to split up an arrayed column that was created using an array_agg. the following is severely cut down, original query is something like 210 lines
select
distinct on (visitor.id)
id,
array_agg(distinct item.code::text)
from
8xfullouter joins
where
exists(
select
distinct on(visitor.id)
item.code::text
from
3 full outer join that all appear in the first query
group by
visit.id,
item.code
order by
visit.id
)
I need to break the array_agg(distinct item.code::text) into multiple columns. I've tried split_part(array_agg(distinct item.code::text), ',', 1) but received the following
> [Err] ERROR: function split_part(character varying[], unknown,
> integer) does not exist LINE 159: split_part (array_agg(distinct
> "public".procedure_group_cpt_...
thanks!!!

Use an index of the array, e.g.:
select (array_agg(code::text))[1]
from (values ('code1'), ('code2')) as codes(code)
array_agg
-----------
code1
(1 row)
Alternatively, you can use string_agg() instead of array_agg(), e.g.:
select split_part(string_agg(code::text, ','), ',', 1)
from (values ('code1'), ('code2')) as codes(code)
split_part
------------
code1
(1 row)

Related

How to aggregate all the resulted rows column data in one column?

I have a case driven query . Below is the simplest form
select Column 1 from mytable
Results :
Column 1
latinnametest
LatinManual
LatinAuto
Is it possible to show the aggregated data of column 1 data of all the resulted rows in another Column say column 5 in front of each row with comma separated ?
Expected :
Column 1 Column 2
latinnametest latinnametest,LatinManual,LatinAuto
LatinManual latinnametest,LatinManual,LatinAuto
LatinAuto latinnametest,LatinManual,LatinAuto
I have used array_agg and concat() but it aggregates the same row data in column 2 but not as expected to add all rows column data comma separated . Any help please.
Edit :
I have tried the solution mentioned below but I am getting repetitive data in the column . see the screenshot. I have hover the mouse over that last column and see the repetitive data . Any solution to this ?
[![enter image description here][1]][1]
You can use string_agg() as a window function:
select column_1,
string_agg(column_1, ',') over () as all_values
from the_table;
Edit, after the scope was changed:
If you need distinct values, use a derived table:
select column_1,
string_agg(column_1, ',') over () as all_values
from (
select distinct column_1
from the_table
) t;
Alternatively with a common table expression:
with vals as (
select string_agg(distinct column_1, ',') as all_values
from the_table
)
select t.column_1, v.all_values
from the_table t
cross join vals v

Split and sequentially join string parts in Postgresql

I need to create a DB view with parts of sequential combinations of string parts of a source column. Example:
IN:
tag
--------
A_B_C_D
X_Y_Z
OUT:
subtag
--------
A
A_B
A_B_C
A_B_C_D
X
X_Y
X_Y_Z
The answer seems to be somewhere around WITH RECURSIVE, but I cannot put it all together.
demo:db<>fiddle
SELECT
array_to_string( -- 3
array_agg(t.value) OVER (PARTITION BY tags ORDER BY t.number), --2
'_'
) AS subtag
FROM
tags,
regexp_split_to_table(tag, '_') WITH ORDINALITY as t(value, number) -- 1
Split the string into one row per element. The WITH ORDINALITY adds a row count which can be used to hold the original order of the elements
Using array_agg() window function to aggregate the elements. The ORDER BY makes it cumulative
Reaggregate the array into a string.
You can use a recursive query:
WITH RECURSIVE s AS (
SELECT tag FROM tag
UNION
SELECT regexp_replace(tag, '_[^_]*$', '') FROM s
)
SELECT * FROM s;
tag
---------
A_B_C_D
X_Y_Z
A_B_C
X_Y
A_B
X
A
(7 rows)
The idea is to successively cut off _* at the end.
Thanks a lot #laurenz-albe! There is a problem with your code that it's missing recursion break condition. So I ended up with this:
WITH RECURSIVE s AS (
SELECT tag FROM tag
UNION
SELECT regexp_replace(tag, '_[^_]*$', '')
FROM s
WHERE tag LIKE '%\_%'
)
SELECT * FROM s;
db<>fiddle

Postgres - Repeating an element N times as array

For example, where the element is 'hi', and where N is 3, I need a PostgreSQL snippet I can use in a SELECT query that returns the following array:
['hi', 'hi', 'hi']
Postgres provides array_fill for this purpose, e.g.:
SELECT array_fill('hi'::text, '{3}');
SELECT array_fill('hi'::text, array[3]);
The two examples are equivalent but the 2nd form is more convenient if you wish to replace the dimension 3 with a variable.
See also: https://www.postgresql.org/docs/current/functions-array.html
You may use array_agg with generate_series
select array_agg(s) from ( values('hi')) as t(s) cross join generate_series(1,3)
Generic
select array_agg(s) from ( values(:elem)) as t(s) cross join generate_series(1,:n)
DEMO
sql demo
with cte as (
select 'hi' as rep_word, generate_series(1, 3) as value
) -- ^^^ n = 3
select array(SELECT rep_word::text from cte);

How to split a string in a smart way?

Function string_to_array splits strings without grouping substrings in apostrophes:
# select unnest(string_to_array('one, "two,three"', ','));
unnest
--------
one
"two
three"
(3 rows)
I would like to have a smarter function, like this:
# select unnest(smarter_string_to_array('one, "two,three"', ','));
unnest
--------
one
two,three
(2 rows)
Purpose.
I know that COPY command does it in a proper way, but I need this feature internally.
I want to parse a text representation of rows of existing table. Example:
# select * from dataset limit 2;
id | name | state
----+-----------------+--------
1 | Smith, Reginald | Canada
2 | Jones, Susan |
(2 rows)
# select dataset::text from dataset limit 2;
dataset
------------------------------
(1,"Smith, Reginald",Canada)
(2,"Jones, Susan","")
(2 rows)
I want to do it dynamically in a plpgsql function for different tables. I cannot assume constant number of columns of a table nor a format of columns values.
There is a nice method to transpose a whole table into a one-column table:
select (json_each_text(row_to_json(t))).value from dataset t;
If the column id is unique then
select id, array_agg(value) arr from (
select row_number() over() rn, id, value from (
select id, (json_each_text(row_to_json(t))).value from dataset t
) alias
order by id, rn
) alias
group by id;
gives you exactly what you want. Additional query with row_number() is necessary to keep original order of columns.

select the inverse of sql result as a string list

having a sql e.g. something like the following resulting in some rows with one value.
I search a different sql than SELECT * FROM some_sql which results in one row with comma separated values.
WITH some_sql AS (
SELECT 1 FROM DUAL
UNION
SELECT 2 FROM DUAL
)
SELECT * FROM some_sql
this SQL results in the two rows with value 1 and 2.
I seach a SQl resulting in 1,2 without changing the code of 'some_sql'.
Consider http://halisway.blogspot.com/2006/08/oracle-groupconcat-updated-again.html
Sice you are on 11G you can use LISTAGG
WITH some_sql AS (
SELECT 1 x FROM DUAL
UNION
SELECT 2 x FROM DUAL
)
SELECT LISTAGG(x, ',') WITHIN GROUP(ORDER BY x) FROM some_sql