2010-05-26 27 views
20

Quiero escribir un procedimiento almacenado que obtenga una matriz como parámetro de entrada y ordenar esa matriz y devolver la matriz ordenada.Ordenar elementos de la matriz

Amablemente ayuda.

Respuesta

7

sólo tiene que utilizar la función de UNNEST():

SELECT 
    unnest(ARRAY[1,2]) AS x 
ORDER BY 
    x DESC; 

Ver array functions en la documentación Pg.

7

En PostrgreSQL 8,4 y hasta puede utilizar:

select array_agg(x) from (select unnest(ARRAY[1,5,3,7,2]) AS x order by x) as _; 

pero no va a ser muy rápido.


En Postgres más antiguas que se pueden implementar UNNEST como esto

CREATE OR REPLACE FUNCTION unnest(anyarray) 
    RETURNS SETOF anyelement AS 
$BODY$ 
SELECT $1[i] FROM 
    generate_series(array_lower($1,1), 
        array_upper($1,1)) i; 
$BODY$ 
    LANGUAGE 'sql' IMMUTABLE 

Y ARRAY_AGG así:

CREATE AGGREGATE array_agg (
     sfunc = array_append, 
     basetype = anyelement, 
     stype = anyarray, 
     initcond = '{}' 
); 

pero será aún más lento.


También puede implementar cualquier algoritmo de ordenación en/pgsql pl o cualquier otro idioma se puede conectar a postgres.

+0

La forma más rápida es la 'sort' función en el' intarray' módulo contrib. –

5

Esto funcionó para mí desde http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks_I#General_array_sort

CREATE OR REPLACE FUNCTION array_sort (ANYARRAY) 
RETURNS ANYARRAY LANGUAGE SQL 
AS $$ 
SELECT ARRAY(
    SELECT $1[s.i] AS "foo" 
    FROM 
     generate_series(array_lower($1,1), array_upper($1,1)) AS s(i) 
    ORDER BY foo 
); 
$$; 

Véase la respuesta de Craig ya que es mucho más más conocedor de Postgres y tiene una mejor respuesta. También si es posible vote para eliminar mi respuesta.

+1

Obtuve ese artículo de wiki actualizado con algunas técnicas más modernas, así que use el código en el artículo (o vea mi respuesta), no el anterior que se muestra aquí. –

2

Muy buena exposición de las características de PostgreSQL es el procedimiento general para la clasificación de David Fetter.

CREATE OR REPLACE FUNCTION array_sort (ANYARRAY) 
RETURNS ANYARRAY LANGUAGE SQL 
AS $$ 
SELECT ARRAY(
    SELECT $1[s.i] AS "foo" 
    FROM 
     generate_series(array_lower($1,1), array_upper($1,1)) AS s(i) 
    ORDER BY foo 
); 
$$; 
+0

@MartijnPieters Observe cómo es la misma respuesta que la mía pero respondí hace un año y mencioné de dónde lo saqué. –

+0

@ AdamGent: Creo que encontré esto en la primera cola de respuestas y solo reformateé el SQL para hacerlo legible. En otras palabras, no tenía otro contexto que el formateo ilegible. –

27

La mejor manera de ordenar una matriz de enteros es sin duda utilizar el intarray extension, lo que hará que sea mucho, mucho, mucho más rápido que cualquier formulación de SQL:

CREATE EXTENSION intarray; 

SELECT sort(ARRAY[4,3,2,1]); 

Una función que que funciona para cualquier tipo de matriz es:

CREATE OR REPLACE FUNCTION array_sort (ANYARRAY) 
RETURNS ANYARRAY LANGUAGE SQL 
AS $$ 
SELECT ARRAY(SELECT unnest($1) ORDER BY 1) 
$$; 

(he reemplazado mi versión con Pavel's slightly faster one después de la discusión en otro lugar).

+0

Craig He votado para eliminar mi respuesta, pero por alguna razón no puedo terminarla por mí mismo;). Así que hice una nota para ver tu respuesta. –

+0

Si no me equivoco, la función 'array_sort()' anterior se debe definir con la etiqueta 'STABLE' (o tal vez 'IMMUTABLE') después del segundo' $$ '. Otros programadores pueden mirar esas etiquetas de volatilidad para obtener pistas sobre cómo funciona una determinada función. 'LANGUAGE SQL'-funciones son (típicamente) inlineadas por Postgres, pero no hay daño en agregar la etiqueta de cualquier manera. – SeldomNeedy

+1

Tenga en cuenta que 'unnest' desagrava todos los niveles de una matriz: por lo tanto, si está tratando de ordenar una matriz de matrices, obtendrá resultados inesperados: la forma de las matrices se mantiene, pero los valores se ordenan individualmente. no como una sub-matriz. –

0

Si está buscando una solución que funcione en cualquier tipo de datos, le recomiendo tomar el enfoque expuesto en YouLikeProgramming.com.

Esencialmente, puede crear un procedimiento almacenado (código a continuación) que realiza la clasificación por usted, y todo lo que necesita hacer es pasar su matriz a ese procedimiento para que se ordene adecuadamente.

También he incluido una implementación que no requiere el uso de un procedimiento almacenado, si está buscando que su consulta sea un poco más transportable.

Crear el procedimiento almacenado

DROP FUNCTION IF EXISTS array_sort(anyarray); 
CREATE FUNCTION 
    array_sort(
    array_vals_to_sort anyarray 
) 
    RETURNS TABLE (
    sorted_array anyarray 
) 
    AS $BODY$ 
    BEGIN 
     RETURN QUERY SELECT 
     ARRAY_AGG(val) AS sorted_array 
     FROM 
     (
      SELECT 
      UNNEST(array_vals_to_sort) AS val 
      ORDER BY 
      val 
     ) AS sorted_vals 
     ; 
    END; 
    $BODY$ 
LANGUAGE plpgsql; 

Ordenando valores de la matriz (funciona con cualquier matriz de tipo de datos)

-- The following will return: {1,2,3,4} 
SELECT ARRAY_SORT(ARRAY[4,3,2,1]); 

-- The following will return: {in,is,it,on,up} 
SELECT ARRAY_SORT(ARRAY['up','on','it','is','in']); 

Ordenando valores de matriz sin un procedimiento almacenado

En el siguiente ing consulta, basta con sustituir ARRAY[4,3,2,1] con su matriz o consulta que devuelve una matriz:

WITH 
    sorted_vals AS (
    SELECT 
     UNNEST(ARRAY[4,3,2,1]) AS val 
    ORDER BY 
     val 
) 
SELECT 
    ARRAY_AGG(val) AS sorted_array 
FROM 
    sorted_vals 

... o ...

SELECT 
    ARRAY_AGG(vals.val) AS sorted_arr 
FROM (
    SELECT 
    UNNEST(ARRAY[4,3,2,1]) AS val 
    ORDER BY 
    val 
) AS vals 
+0

Es más largo, pero ¿es mejor que la solución de Craig? –

+0

No estoy seguro de entender la sangría de su pregunta. Si usted decide si es "mejor" para su implementación. –

+0

Bueno, Craig ofrece una solución de trabajo de 5 líneas. Casi un año después, agrega una respuesta con una solución mucho más larga. Así que supongo que su solución debe ser de alguna manera mejor, o funcionar en algunos casos donde la otra no. Soy un novato SQL (Postgre), así que no puedo juzgar, por lo tanto, pregunto. :) –

Cuestiones relacionadas