sql >> Databáze >  >> RDS >> PostgreSQL

Procházejte sloupce RECORD

Jak vysvětlil @Pavel, není jednoduše možné procházet záznamem, jako byste mohli procházet pole. Ale existuje několik způsobů, jak to obejít - v závislosti na vašich přesných požadavcích. Nakonec, protože chcete vrátit všechny hodnoty ve stejném sloupci, musíte je přetypovat do stejného typu - text je zřejmý společný základ, protože pro každý typ existuje textová reprezentace.

Rychlé a špinavé

Řekněme, že máte tabulku s integer , text a date sloupec.

CREATE TEMP TABLE tbl(a int, b text, c date);
INSERT INTO tbl VALUES
 (1, '1text',     '2012-10-01')
,(2, '2text',     '2012-10-02')
,(3, ',3,ex,',    '2012-10-03')  -- text with commas
,(4, '",4,"ex,"', '2012-10-04')  -- text with commas and double quotes

Pak může být řešení jednoduché jako:

SELECT unnest(string_to_array(trim(t::text, '()'), ','))
FROM   tbl t;

Funguje pro první dva řádky, ale selže pro speciální případy řádku 3 a 4.
Problém s čárkami v reprezentaci textu můžete snadno vyřešit:

SELECT unnest(('{' || trim(t::text, '()') || '}')::text[])
FROM   tbl t
WHERE  a < 4;

To by fungovalo dobře - kromě řádku 4, který má v textové reprezentaci dvojité uvozovky. Těm se podaří uniknout jejich zdvojnásobením. Ale konstruktor pole by je potřeboval, aby byly escapovány pomocí \ . Nejste si jisti, proč je zde tato nekompatibilita ...

SELECT ('{' || trim(t::text, '()') || '}') FROM tbl t WHERE a = 4

Výtěžky:

{4,""",4,""ex,""",2012-10-04}

Ale budete potřebovat:

SELECT '{4,"\",4,\"ex,\"",2012-10-04}'::text[];  -- works

Správné řešení

Pokud byste znali názvy sloupců předem, čisté řešení by bylo jednoduché:

SELECT unnest(ARRAY[a::text,b::text,c::text])
FROM tbl

Protože pracujete se záznamy dobře známého typu, stačí se dotázat na systémový katalog:

SELECT string_agg(a.attname || '::text', ',' ORDER  BY a.attnum)
FROM   pg_catalog.pg_attribute a 
WHERE  a.attrelid = 'tbl'::regclass
AND    a.attnum > 0
AND    a.attisdropped = FALSE

Vložte to do funkce s dynamickým SQL:

CREATE OR REPLACE FUNCTION unnest_table(_tbl text)
  RETURNS SETOF text LANGUAGE plpgsql AS
$func$
BEGIN

RETURN QUERY EXECUTE '
SELECT unnest(ARRAY[' || (
    SELECT string_agg(a.attname || '::text', ',' ORDER  BY a.attnum)
    FROM   pg_catalog.pg_attribute a 
    WHERE  a.attrelid = _tbl::regclass
    AND    a.attnum > 0
    AND    a.attisdropped = false
    ) || '])
FROM   ' || _tbl::regclass;

END
$func$;

Volejte:

SELECT unnest_table('tbl') AS val

Vrátí:

val
-----
1
1text
2012-10-01
2
2text
2012-10-02
3
,3,ex,
2012-10-03
4
",4,"ex,"
2012-10-04

Funguje to bez instalace dalších modulů. Další možností je nainstalovat rozšíření hstore a používat jej, jak ukazuje @Craig.



  1. Předejte funkci více sad nebo polí hodnot

  2. 7 Možnosti pro povolení Pipes (||) jako operátora zřetězení v MariaDB

  3. Jak aktualizovat Oracle Clob pomocí JDBC

  4. Vytvořte více instancí Postgres na stejném počítači