2010-01-15 22 views
25

¿Hay alguna manera de eliminar un valor de una matriz en pgSQL? O para ser más precisos, ¿mostrar el último valor? Juzgando por this list la respuesta parece ser no. Puedo obtener el resultado que quiero con un puntero de índice adicional, pero es un poco engorroso.Eliminar valores de matriz en pgSQL

Respuesta

12

No, no creo que puedas. Al menos no sin escribir algo feo como:

SELECT ARRAY (
SELECT UNNEST(yourarray) LIMIT (
    SELECT array_upper(yourarray, 1) - 1 
) 
) 
+0

A juzgar por lo que Google me dice, parece que me hipocresía.Voy a marcar esto como la respuesta aceptada a menos que alguien demuestre que está equivocado :) – oggy

8

No estoy seguro acerca de su contexto, pero esto debe darle algo con que trabajar:

CREATE TABLE test (x INT[]); 
INSERT INTO test VALUES ('{1,2,3,4,5}'); 

SELECT x AS array_pre_pop, 
     x[array_lower(x,1) : array_upper(x,1)-1] AS array_post_pop, 
     x[array_upper(x,1)] AS popped_value 
FROM test; 


array_pre_pop | array_post_pop | popped_value 
---------------+----------------+-------------- 
{1,2,3,4,5} | {1,2,3,4}  |   5 
+0

Gracias, eso funcionaría, aunque supongo que cortar no es exactamente una solución eficiente. – oggy

+0

Creo que es su mejor método considerando que no hay una función incorporada para pop(). Sin conocer los detalles, no puedo dar mejores consejos. Si desea recorrer el contenido de un registro en particular, entonces unnest() probablemente sería mejor, ya que se convertiría en un conjunto de registros. Sin embargo, si solo quiere actualizar una tabla para eliminar todos los "últimos elementos" de la matriz en múltiples registros, el corte de matrices sería el camino a seguir. –

2

He creado una función de modo array_pop puede eliminar un elemento con valor conocido de una matriz.

CREATE OR REPLACE FUNCTION array_pop(a anyarray, element character varying) 
RETURNS anyarray 
LANGUAGE plpgsql 
AS $function$ 
DECLARE 
    result a%TYPE; 
BEGIN 
SELECT ARRAY(
    SELECT b.e FROM (SELECT unnest(a)) AS b(e) WHERE b.e <> element) INTO result; 
RETURN result; 
END; 
$function$ 

también hay una versión GIST https://gist.github.com/1392734

5

Aquí es una función que utilizo para matrices de enteros []

CREATE OR REPLACE FUNCTION array_remove_item (array_in INTEGER[], item INTEGER) 
RETURNS INTEGER[] 
LANGUAGE SQL 
AS $$ 
SELECT ARRAY(
    SELECT DISTINCT $1[s.i] AS "foo" 
    FROM GENERATE_SERIES(ARRAY_LOWER($1,1), ARRAY_UPPER($1,1)) AS s(i) 
    WHERE $2 != $1[s.i] 
    ORDER BY foo 
); 
$$; 

Esto es obviamente para matrices de enteros pero podría ser modificado para ANYARRAY anyelement

=> select array_remove_item(array[1,2,3,4,5], 3); 
-[ RECORD 1 ]-----+---------- 
array_remove_item | {1,2,4,5} 
14

La forma más sencilla de eliminar el último valor:

array1 = array[1,2,3] 
array1 = (select array1[1:array_upper(array1, 1) - 1]) 
+2

Esta debería ser la respuesta aceptada. – Lucian

+0

Sí, esta es la respuesta - funciona bien para mí con algunos puntos y comas. – Vidar

9

hay una manera fácil de quitar un valor de una matriz en la llanura de SQL:

SELECT unnest('{5,NULL,6}'::INT[]) EXCEPT SELECT NULL 

que eliminará todos los valores NULL de matriz. El resultado será:

#| integer | 
------------ 
1| 5 | 
2| 6 | 
+0

Los usuarios de la versión 9.3+ deben ver [esta respuesta] (http://stackoverflow.com/a/27346920/3159183). Los usuarios de la versión 9.2 y siguientes pueden resumir el código anterior para su reutilización como este: http://sqlfiddle.com/#!15/03d32/1/0 – SeldomNeedy

3

estoy corriendo en 9.2 y estoy capaz de ejecutar esto:

update tablename set arrcolumn=arrcolumn[1:array_length(arrcolumn)-1]; 

o se puede desplazar fuera del elemento frontal con el mismo tipo de cosas:

update tablename set arrcolumn=arrcolumn[2:array_length(arrcolumn)]; 

Cuidadosos programadores, por alguna razón aún desconocida para la ciencia, los arreglos pgsql tienen 1 índice en lugar de 0 indexados.

0

Prueba esto:

update table_name set column_name=column_name[1:array_upper(column_name, 1)-1]; 
-1

Mi función para todos los tipos de matrices.

función externa:

CREATE OR REPLACE FUNCTION "outer_array"(anyarray, anyarray) RETURNS anyarray AS $$ 
    SELECT 
     "new"."item" 
    FROM (
     SELECT 
      ARRAY(
       SELECT 
        "arr"."value" 
       FROM (
        SELECT 
         generate_series(1, array_length($1, 1)) AS "i", 
         unnest($1)        AS "value" 
       ) "arr" 
       WHERE 
        "arr"."value" <> ALL ($2) 
       ORDER BY 
        "arr"."i" 
      ) AS "item" 
    ) "new" 
    $$ 
LANGUAGE sql 
IMMUTABLE 
RETURNS NULL ON NULL INPUT 
; 

función interna:

CREATE OR REPLACE FUNCTION "inner_array"(anyarray, anyarray) RETURNS anyarray AS $$ 
    SELECT 
     "new"."item" 
    FROM (
     SELECT 
      ARRAY(
       SELECT 
        "arr"."value" 
       FROM (
        SELECT 
         generate_series(1, array_length($1, 1)) AS "i", 
         unnest($1)        AS "value" 
       ) "arr" 
       WHERE 
        "arr"."value" = ANY ($2) 
       ORDER BY 
        "arr"."i" 
      ) AS "item" 
    ) "new" 
$$ 
LANGUAGE sql 
IMMUTABLE 
RETURNS NULL ON NULL INPUT 
; 
55

En la versión 9.3 y superior que puede hacer:

update users set flags = array_remove(flags, 'active') 
+0

A partir de 2015, esta es la respuesta más adecuada, suponiendo que ' volver a ejecutar al menos PostgreSQL 9.3. –

+0

Para aquellos de ustedes que aún no han podido pasar a la versión 9.3+, deberían poder escribir su propio 'array_remove()' como se muestra: http://sqlfiddle.com/#!15/03d32/1/0 – SeldomNeedy

+0

Esto es absolutamente ** no ** "la respuesta más adecuada", ya que la pregunta explícitamente pregunta si podemos "mostrar el último valor". Incluso si primero consultara el valor del último elemento, si ese valor se repitiera en absoluto en la matriz, ** todas las instancias de este se eliminarán. Obviamente, esta no es la funcionalidad deseada de algo así como una función 'array_pop()', que es lo que el OP está pidiendo. – JMTyler