Reputation: 345
{{5,23}, {8,45}, {1,12}}
I want to sort this array according the first element of each sub-array elements, like;
{{1,12}, {5,23}, {8,45}}
How can I do that?
Edit:
This code works;
create or replace function arraysortingaccordingfirstindexofsubarrayelements()
returns void as $$
declare samplearraydata integer[][];
declare sortedarraydata int[][];
begin
samplearraydata:=ARRAY[[5,8], [1,6],[3,9]];
EXECUTE 'CREATE TEMP TABLE temptable (
firstindex integer,
secondindex integer
) on commit drop;';
WITH
data as (select samplearraydata as arr)
insert into temptable select
arr[i][1],
arr[i][2] FROM data,
generate_subscripts((SELECT arr FROM data), 1) i
order by 1;
sortedarraydata:=(SELECT array_agg_mult(ARRAY[ARRAY[y.firstindex, y.secondindex]])) FROM temptable y;
raise notice '%', sortedarraydata;
end;
$$ language plpgsql;
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
,STYPE = anyarray
,INITCOND = '{}'
);
CREATE TEMP TABLE arrtbl (
firstindex integer,
secondindex integer
) on commit drop;
Credits to Erwin:)
Upvotes: 1
Views: 2470
Reputation: 656962
ships with a variant of array_agg()
that serves as drop-in replacement for the custom aggregate function array_agg_mult()
below - and is considerably faster. The manual:
Function Argument Type(s) Return Type array_agg(expression) any array type same as argument data type Description input arrays concatenated into array of one higher dimension (inputs must all have same dimensionality, and cannot be empty or NULL)
The built-in aggregate function array_agg()
currently (Postgres 9.4) only works for non-array input data types. Since we are going to aggregate arrays, we need a custom aggregate function like detailed in this related answer:
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
, STYPE = anyarray
, INITCOND = '{}'
);
Basic understanding of array syntax / how to access arrays is required. Read this chapter of the manual if you aren't there, yet.
Then, based on the same setup as this earlier answer today (you may want to read that one, too):
SELECT arrtbl_id
, array_agg_mult(arr[i:i][lo2:up2] ORDER BY arr[i:i][lo2])
FROM (SELECT arrtbl_id, arr
, array_lower(arr, 2) AS lo2
, array_upper(arr, 2) AS up2
FROM arrtbl) t
, generate_subscripts(t.arr, 1) i
GROUP BY 1;
Compute lower and upper bound for the 2nd array dimension in the base table, that's cheaper than repeating it for every array slice.
I am not simply starting with index 1 to cover a possible corner case. Postgres allows non-standard array subscripts:
LATERAL
join the base table to generate_subscripts(arr,1)
to get the first index for each sub-array (no matter how many dimensions).
The expression arr[i:i][lo2:up2]
(or simply arr[i:i][:]
in pg 9.6+) returns each array slice preserving dimensions. This works for any number of elements and dimensions (greater than 1).
The expression arr[i:i][lo2]
returns the first slice within each array slice, which defines sort order. For strictly 2-dimnesional arrays, you can use arr[i][lo2]
to return the first element of each slice as well, but the former works for any dimensionality greater than 1.
Aggregate with array_agg_mult()
which happily accepts values of appropriate dimension (everything falls into place nicely).
Upvotes: 2
Reputation: 305
Since Postgres 9.4 if you can break your two dimensional array to two one dimensional arrays you can use operator
unnest(anyarray, anyarray [, ...])
Example:
SELECT * FROM unnest(ARRAY[6,4,3,5], ARRAY[64,2,1,-1], ARRAY[45,2,4,6]) ORDER BY 1
Return:
4 2 2
3 1 4
5 -1 6
6 64 45
If you want to sort by third elemen, you should change
... ORDER BY 3
Upvotes: 0