Unnest a two-dimensional array to a table - postgresql

Is it possible to convert the following into a two-columned table?
SELECT * FROM UNNEST([[1,'a'],[2,'b'], [3,'c']) AS tbl (num,str);
Or more generally into a table of n columns where n is the size of the inner array (i.e., the length of a row).
The array structure is arr[rows][cols]

Arrays in PostgreSQL can contain elements of one type (but it can be composite type). So array like array[1,2,'e'] is invalid in PostgreSQL.
What can be done is to unnest two arrays in one statement
SELECT UNNEST(array[1,2,3]),unnest(array['a','b','c'])

Related

Is it possible to index the position of an array column in PostgreSQL?

Let's say I want to find rows in the table my_table that have the value 5 at the first position of the array column my_array_column. To prepare the table, I executed the following statements:
CREATE TABLE my_table (
id serial primary key,
my_array_column integer[]
);
CREATE INDEX my_table_my_array_column_index on "my_table" USING GIN ("my_array_column");
SET enable_seqscan TO off;
INSERT INTO my_table (my_array_column) VALUES ('{5,7,10}');
Now, the query can look like this:
select * from my_table where my_array_column[1] = 5;
This works, but it doesn't use the created GIN index. Is it possible to search for the value 5 at a specific position with an index?
I want to find rows in the table my_table that have the value 5 at the first position of the array column
A partial index would be most efficient for that definition:
CREATE INDEX my_table_my_array_special_idx ON my_table ((true))
WHERE my_array_column[1] = 5;
If only a small fraction of rows qualifies, a partial index is accordingly smaller. Plus, the actual index column only occupies minimum space (typically 8 bytes). And, on top of that, Postgres 13 or later can apply index deduplication to make the index much smaller, yet.
Once the index is fully cached, its small size does not make it much faster, but still.
And most writes do not have to manipulate the index, which may be the most important benefit, depending on the workload.
Oh, and Postgres collects statistics for a partial index. So you can expect the query planner to make a fully educated choice when that index is involved.
Related:
PostgreSQL partial index unused when created on a table with existing data
Index that is not used, yet influences query
It's applicable when the query repeats the same condition.
Typically, you have something useful as index field on top of your declared purpose. But if you don't, just use any small constant - true in my example, but anything < 8 bytes is equally good.
Minor disclaimer: The "first position" in a Postgres array does not necessarily have index 1. If non-standard array indexes are possible, consider:
...
WHERE (my_array_column[:])[1] = 5;
In index and queries.
See:
Normalize array subscripts for 1-dimensional array so they start with 1
You can index just the first position. You need an extra set of parentheses in the create statement to do that:
create index on my_table ((my_array_column[1]));
Or you could augment your query to work with your gin index, on the theory that an array can't have the first element be 5 unless at least one element is 5.
select * from my_table where my_array_column[1] = 5 and my_array_column #> ARRAY[5];
Of course this won't be very efficient if a lot of your arrays contain 5, but in some other spot in the array. It would have to recheck all of those "false matches" to eliminate them. So if you only care about the first element, the first index I showed is better. (Of course, if you only care about the first element, why use an array to start with?)
If you always look at the first position a regular B-Tree index will do:
create index on my_table ( (my_array_column[1]) );
If you don't know the position, then a GIN index is indeed needed, but you need to use an operator that is supported by a gin index, that would be e.g. the #> operator. But for that you need to use a different query:
select *
from my_table
where my_array_column #> array[5];
That would find all rows where the array column contains the value 5.
But you should head the advice given in the manual regarding the use of arrays:
Arrays are not sets; searching for specific array elements can be a sign of database misdesign. Consider using a separate table with a row for each item that would be an array element. This will be easier to search, and is likely to scale better for a large number of elements.

Redshift Super Data type Querying

Redshift's new super data type uses partiql for querying. I have an array of data that is not nested eg: [0,1,2,3,4]
What is the best way to query this data? All the documentation talks about nested arrays, but this is at the root level and there is no testing.
I have tried select supercolumnname[n] from tablewithsuper; and I am getting nulls, which isn't right.
The best way (that I know right now) is to unnest the array:
CREATE TEMPORARY TABLE my_table (my_array SUPER);
INSERT INTO my_table VALUES (JSON_PARSE('[10001,10002,3333]'));
SELECT m FROM my_table as t, t.my_array as m;

Selecting a row by searching a specific value in an Array column

We have a table where one of the columns is an array. I need to select a row or many rows as long as my search value matches their values using ILIKE. My problem is that I need to search the values of an array column as well. I tried using ANY but the value needs to be exact to select a row. I need something similar to ILIKE but for that array column.
Thank you in advance.
Use unnest function:
SELECT x.value
FROM my_table t, unnest(t.my_array_column) as x(value)
WHERE x.value ILIKE 'foo'
Once your question is also tagged elixir, for converting this to Ecto use Ecto.Query.API.fragment/1 for the select condition and Ecto.Query.API.ilike/2 for match.

How to turn a column of ints into one array in postgres

I currently have a table with one column and 400 rows; each row has an integer. How can I create an int array with all of these integers that preserves order?
I am using postgreSQL-9.2.
select array_agg(int_column order by some_column) as int_array_column
from the_table;
Where some_column is the column that defines the "order" of the integer values. Rows in relational database do not have "an order", so your request "that preserves order" only makes sense if you have a column that defines that sort order that you try to preserve.
SELECT array_agg(column_name ORDER by sort_column_name) AS ints
FROM table

Create an index for json_array_elements in PostgreSQL

I need to create an index from a query that uses json_array_elements()
SELECT *, json_array_elements(nested_json_as_text::json) as elements FROM my_table
Since the json contains multiple elements, the result is that the original index is now duplicated across rows and no longer unique.
I am not very familiar with creating indices and want to avoid doing anything destructive. What is the best way to create a column of unique integers for this case?
Found an answer:
SELECT *, json_array_elements(nested_json_as_text::json) as elements, row_number() over () as my_index FROM my_table