Postgresql - return entire row as array

前端 未结 4 2205
南方客
南方客 2021-02-09 17:32

Is there a way how you can cast the following result to array?

select pg_tables from pg_tables

This will return one column only, however the da

相关标签:
4条回答
  • 2021-02-09 17:53

    string_to_array might help:

    SELECT string_to_array(pg_tables::text,','::text) FROM pg_tables;
    
    0 讨论(0)
  • 2021-02-09 18:00

    Another approach, use hstore type, this is more robust, can solve the comma in a field's value

    Add the hstore contrib type, by executing this once:

    CREATE EXTENSION hstore; 
    

    Create this function:

    create or replace function hstore_to_array(r hstore) returns text[] as
    $$
    begin
        return array(select (each(r)).value);
    end;
    $$ language 'plpgsql';
    

    Then try this:

    select hstore_to_array(hstore(r)) from pg_tables r limit 10;
    

    Output:

                      hstore_to_array                  
    ---------------------------------------------------
     {f,pg_statistic,t,pg_catalog,postgres,NULL,f}
     {f,pg_type,t,pg_catalog,postgres,NULL,f}
     {f,pg_attribute,t,pg_catalog,postgres,NULL,f}
     {f,xx,t,public,postgres,NULL,f}
     {f,yy,t,public,postgres,NULL,f}
     {f,tblx,f,public,postgres,NULL,f}
     {f,pg_authid,t,pg_catalog,postgres,pg_global,f}
     {f,pg_proc,t,pg_catalog,postgres,NULL,f}
     {f,pg_class,t,pg_catalog,postgres,NULL,f}
     {f,pg_database,t,pg_catalog,postgres,pg_global,f}
    (10 rows)
    

    Another example:

    create table Beatle(firstname text, middlename text, lastname text);
    
    
    insert into Beatle(firstname, middlename, lastname) values
    ('John','Winston','Lennon'),
    ('Paul','','McCartney'),
    ('George',NULL,'Harrison'),
    ('Ringo','my passions are ring,drum and shades','Starr');
    

    Query:

    select hstore_to_array(hstore(b)) from Beatle b;
    

    Output:

                       hstore_to_array                    
    ------------------------------------------------------
     {Lennon,John,Winston}
     {McCartney,Paul,""}
     {Harrison,George,NULL}
     {Starr,Ringo,"my passions are ring,drum and shades"}
    (4 rows)
    

    As we can see, even the value with comma is preserved properly.

    An astute reader will notice something on the above output though. The hstore function doesn't preseve the original order of fields. In order to preserve it, put the table on subquery, i.e.

    select hstore_to_array(hstore(b)) from (select * from Beatle) as b
    

    Output:

                       hstore_to_array                    
    ------------------------------------------------------
     {John,Winston,Lennon}
     {Paul,"",McCartney}
     {George,NULL,Harrison}
     {Ringo,"my passions are ring,drum and shades",Starr}
    (4 rows)
    

    References used: http://okbob.blogspot.com/2009/10/dynamic-access-to-record-fields-in.html

    Next feature to watch: http://www.postgresonline.com/journal/archives/254-PostgreSQL-9.2-Preserving-column-names-of-subqueries.html


    UPDATE

    It looks like the preservation of column ordering via subquery is just a fluke. I tried putting a sorting(e.g. on firstname).

    select hstore_to_array(hstore(b)) 
    from (select * from Beatle order by firstname) as b
    

    The output doesn't preserve the original columns order anymore:

                       hstore_to_array                    
    ------------------------------------------------------
     {Harrison,George,NULL}
     {Lennon,John,Winston}
     {McCartney,Paul,""}
     {Starr,Ringo,"my passions are ring,drum and shades"}
    (4 rows)
    

    Will investigate further how to preserve original columns order.


    UPDATE

    If you need sort the table, in order to preserve the original columns order, put the ORDER BY outside of subquery:

    select hstore_to_array(hstore(b)) 
    from (select * from Beatle) as b order by firstname;
    

    Output:

                       hstore_to_array                    
    ------------------------------------------------------
     {George,NULL,Harrison}
     {John,Winston,Lennon}
     {Paul,"",McCartney}
     {Ringo,"my passions are ring,drum and shades",Starr}
    (4 rows)
    

    It's correct now.

    And selecting from in-memory table works too:

    select hstore_to_array(hstore(b)) 
    from 
    (
        select * from 
        (values
            ('John',1940,'Winston','Lennon'),
            ('Paul',1942,'','McCartney'),
            ('George',1943,NULL,'Harrison'),
            ('Ringo',1940,'my passions are ring,drum and shades','Starr')
        ) as x(Firstname,BirthYear,Middlename,Lastname)
    ) as b     
    order by BirthYear desc, Firstname desc
    

    Output:

                          hstore_to_array                      
    -----------------------------------------------------------
     {George,1943,NULL,Harrison}
     {Paul,1942,"",McCartney}
     {Ringo,1940,"my passions are ring,drum and shades",Starr}
     {John,1940,Winston,Lennon}
    (4 rows)
    

    UPDATE

    It turns out functionality hstore_to_array is a built-in functionality already, just use avals: http://www.postgresql.org/docs/9.1/static/hstore.html

    select 
        avals (hstore(b))
    from 
    (
        select * from 
        (values
            ('John',1940,'Winston','Lennon'),
            ('Paul',1942,'','McCartney'),
            ('George',1943,NULL,'Harrison'),
            ('Ringo',1940,'my passions are ring,drum and shades','Starr')
        ) as x(Firstname,BirthYear,Middlename,Lastname)
    ) as b 
    order by BirthYear desc, Firstname desc;
    

    Output:

                               avals                           
    -----------------------------------------------------------
     {George,1943,NULL,Harrison}
     {Paul,1942,"",McCartney}
     {Ringo,1940,"my passions are ring,drum and shades",Starr}
     {John,1940,Winston,Lennon}
    (4 rows)
    

    Another sample:

    select avals(hstore(b)) 
    from (select * from Beatle) as b order by Firstname;
    

    Output:

                            avals
    ------------------------------------------------------
     {George,NULL,Harrison}
     {John,Winston,Lennon}
     {Paul,"",McCartney}
     {Ringo,"my passions are ring,drum and shades",Starr}
    (4 rows)
    

    Just use avals

    Live test: http://www.sqlfiddle.com/#!1/d41d8/388

    Please do note that although sqlfiddle output don't have an array indicator(curly brackets) and double quotes on "my passions are ring,drum and shades", the avals result is an array and the string with comma in them has double quote in actual results, you can test it on your pgAdmin or psql

    0 讨论(0)
  • 2021-02-09 18:02

    Might be this: http://www.sqlfiddle.com/#!1/d41d8/364

    select translate(string_to_array(x.*::text,',')::text,'()','')::text[] 
    from pg_tables as x
    

    How it works (inside-out), 5 steps:

    1st:

    select x.*::text from pg_tables as x;
    

    Sample Output:

    |                                                            X |
    ----------------------------------------------------------------
    |                    (pg_catalog,pg_statistic,postgres,,t,f,f) |
    |                         (pg_catalog,pg_type,postgres,,t,f,f) |
    

    2nd:

    select string_to_array(x.*::text,',') from pg_tables as x;
    

    Sample Output:

    |                           STRING_TO_ARRAY |
    ---------------------------------------------
    | (pg_catalog,pg_statistic,postgres,,t,f,f) |
    |      (pg_catalog,pg_type,postgres,,t,f,f) |
    

    3rd:

    select string_to_array(x.*::text,',')::text from pg_tables as x;
    

    Sample Output:

    |                               STRING_TO_ARRAY |
    -------------------------------------------------
    | {(pg_catalog,pg_statistic,postgres,"",t,f,f)} |
    |      {(pg_catalog,pg_type,postgres,"",t,f,f)} |
    

    4th:

    select translate( string_to_array(x.*::text,',')::text, '()', '') from pg_tables as x
    

    Sample Output:

    |                                   TRANSLATE |
    -----------------------------------------------
    | {pg_catalog,pg_statistic,postgres,"",t,f,f} |
    |      {pg_catalog,pg_type,postgres,"",t,f,f} |
    

    Finally:

    select translate( string_to_array(x.*::text,',')::text, '()', '')::text[] 
    from pg_tables as x
    

    Sample Output:

    |                               TRANSLATE |
    -------------------------------------------
    | pg_catalog,pg_statistic,postgres,,t,f,f |
    |      pg_catalog,pg_type,postgres,,t,f,f |
    

    Live test: http://www.sqlfiddle.com/#!1/d41d8/373

    To prove that it works:

    with a as 
    (
      select translate( string_to_array(x.*::text,',')::text, '()', '')::text[] as colArray 
      from pg_tables as x
    )
    select row_number() over(), unnest(colArray)
    from a;
    

    Sample output:

    | ROW_NUMBER |                  UNNEST |
    ----------------------------------------
    |          1 |              pg_catalog |
    |          1 |            pg_statistic |
    |          1 |                postgres |
    |          1 |                         |
    |          1 |                       t |
    |          1 |                       f |
    |          1 |                       f |
    |          2 |              pg_catalog |
    |          2 |                 pg_type |
    |          2 |                postgres |
    |          2 |                         |
    |          2 |                       t |
    |          2 |                       f |
    |          2 |                       f |
    
    0 讨论(0)
  • 2021-02-09 18:06

    This function works with all corner cases including NULL values, empty strings or special characters in the values.

    CREATE OR REPLACE FUNCTION f_rows_to_arr(_tbl text)
      RETURNS SETOF text[] AS
    $BODY$
    BEGIN
    
    RETURN QUERY EXECUTE '
    SELECT ARRAY[' || (
            SELECT string_agg(quote_ident(attname) || '::text', ',')
            FROM   pg_catalog.pg_attribute 
            WHERE  attrelid = _tbl::regclass  -- valid, visible table name 
            AND    attnum > 0                 -- exclude tableoid & friends
            AND    attisdropped = FALSE       -- exclude dropped columns
            ) || ' ]
    FROM   ' || _tbl::regclass;
    
    END;
    $BODY$ LANGUAGE plpgsql;
    

    Call:

    SELECT * FROM f_rows_to_arr ('mytbl');
    

    The cast to regclass avoids SQLi. Columns are not sorted in this version. More explanation for used techniques and links in this related answer.

    0 讨论(0)
提交回复
热议问题