Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selecting data into a Postgres array

I have the following data:

name          id             url

John          1              someurl.com
Matt          2              cool.com
Sam           3              stackoverflow.com

How can I write an SQL statement in Postgres to select this data into a multi-dimensional array, i.e.:

{{John, 1, someurl.com}, {Matt, 2, cool.com}, {Sam, 3, stackoverflow.com}}

I've seen this kind of array usage before in Postgres but have no idea how to select data from a table into this array format.

Assuming here that all the columns are of type text.

like image 227
harman_kardon Avatar asked Aug 01 '12 15:08

harman_kardon


People also ask

How do I select an array in PostgreSQL?

PostgreSQL allows us to define a table column as an array type. The array must be of a valid data type such as integer, character, or user-defined types. To insert values into an array column, we use the ARRAY constructor.

How do I select data in PostgreSQL?

If you want to select data from all the columns of the table, you can use an asterisk ( * ) shorthand instead of specifying all the column names. The select list may also contain expressions or literal values. Second, specify the name of the table from which you want to query data after the FROM keyword.

How do I create an array in PostgreSQL?

To create a column of an array type, the [] symbol is used. The following examples illustrate this: create table contacts ( first_name varchar, last_name varchar, phone_numbers varchar[] ); create table player_scores ( player_number integer, round_scores integer[] );

Is it OK to use arrays in Postgres?

PostgreSQL allows columns of a table to be defined as variable-length multidimensional arrays. Arrays of any built-in or user-defined base type, enum type, composite type, range type, or domain can be created.


2 Answers

You cannot use array_agg() to produce multi-dimensional arrays, at least not up to PostgreSQL 9.4.
(But the upcoming Postgres 9.5 ships a new variant of array_agg() that can!)

What you get out of @Matt Ball's query is an array of records (the_table[]).

An array can only hold elements of the same base type. You obviously have number and string types. Convert all columns (that aren't already) to text to make it work.

You can create an aggregate function for this like I demonstrated to you here before.

CREATE AGGREGATE array_agg_mult (anyarray)  (
    SFUNC     = array_cat
   ,STYPE     = anyarray
   ,INITCOND  = '{}'
);

Call:

SELECT array_agg_mult(ARRAY[ARRAY[name, id::text, url]]) AS tbl_mult_arr
FROM   tbl;

Note the additional ARRAY[] layer to make it a multidimensional array (2-dimenstional, to be precise).

Instant demo:

WITH tbl(id, txt) AS (
    VALUES
      (1::int, 'foo'::text)
     ,(2,      'bar')
     ,(3,      '}b",') -- txt has meta-characters
    )
    , x AS (
    SELECT array_agg_mult(ARRAY[ARRAY[id::text,txt]]) AS t
    FROM   tbl
    )
SELECT *, t[1][3] AS arr_element_1_1, t[3][4] AS arr_element_3_2
FROM   x;
like image 82
Erwin Brandstetter Avatar answered Oct 08 '22 00:10

Erwin Brandstetter


You need to use an aggregate function; array_agg should do what you need.

SELECT array_agg(s) FROM (SELECT name, id, url FROM the_table ORDER BY id) AS s;
like image 28
Matt Ball Avatar answered Oct 07 '22 23:10

Matt Ball