【问题标题】:Postgresql - return entire row as arrayPostgresql - 将整行作为数组返回
【发布时间】:2012-07-15 08:46:20
【问题描述】:

有没有办法将以下结果转换为数组?

select pg_tables from pg_tables

这将只返回一列,但数据类型不是数组。

编辑:我使用的是 PostgreSql 9.1.4

更新:我需要一个相当于下面的SQL语句,不需要写列名,适用于每个表:

select 
    string_to_array(
    schemaname || '|' ||
    tablename || '|' || 
    tableowner || '|' ||
    coalesce(tablespace,'') || '|' ||
    hasindexes || '|' ||
    hasrules || '|' ||
    hastriggers
    ,'|')
from 
    pg_tables

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    可能是这样的:http://www.sqlfiddle.com/#!1/d41d8/364

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

    工作原理(由内而外),5 个步骤:

    第一个:

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

    样本输出:

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

    第二个:

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

    样本输出:

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

    第三:

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

    样本输出:

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

    第四:

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

    样本输出:

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

    最后:

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

    样本输出:

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

    现场测试:http://www.sqlfiddle.com/#!1/d41d8/373

    为了证明它有效:

    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;
    

    样本输出:

    | 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 |
    

    【讨论】:

    • 感谢您的回答,但这不是我需要的。我试图改进我的问题以使其更清楚。
    • @twn08 更新了答案。格式错误的数组无法解析(例如逗号之间的空元素),我使用的是最新版本,9.1,文章是 2005:postgresql.1045698.n5.nabble.com/…
    • @MichaelBuen 谢谢,我认为这与我正在寻找的解决方案最接近。请注意,如果列中有“,”作为值,这也不起作用: CREATE TABLE TEST_DATA ( my_id int, my_long_char varchar );插入 test_data 值(1,'Text Text Text Text');插入 test_data 值(2,'文本,文本,文本,文本'); select translate(string_to_array(x.*::text,',')::text,'()','')::text[] from test_data as x;
    • 我还看到了从行中提取列值的实用性。举个例子,它可以为触发器okbob.blogspot.com/2010/12/… 生成一个通用日志记录在这里找到的文档:postgres.cz/wiki/PL_toolbox_(en) 我正在寻找record_expand Postgresql Windows 的库 (pltoolbox.dll),pgFoundry 上的那个是以 Linux 为中心的,它是编译为pltoolbox.out
    【解决方案2】:

    另一种方法,使用hstore类型,这样更健壮,可以解决字段值中的逗号

    添加hstore contrib 类型,执行一次:

    CREATE EXTENSION hstore; 
    

    创建这个函数:

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

    然后试试这个:

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

    输出:

                      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)
    

    另一个例子:

    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');
    

    查询:

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

    输出:

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

    我们可以看到,即使是逗号的值也被正确地保留了。

    不过,精明的读者会注意到上述输出中的某些内容。 hstore 函数不会保留字段的原始顺序。为了保留它,将表放在子查询上,即

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

    输出:

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

    使用的参考:http://okbob.blogspot.com/2009/10/dynamic-access-to-record-fields-in.html

    下一个要观看的功能:http://www.postgresonline.com/journal/archives/254-PostgreSQL-9.2-Preserving-column-names-of-subqueries.html


    更新

    看起来通过子查询保留列排序只是侥幸。我尝试进行排序(例如在名字上)。

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

    输出不再保留原始列顺序:

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

    将进一步研究如何保留原始列顺序。


    更新

    如果您需要对表进行排序,为了保留原始列顺序,请将ORDER BY 放在子查询之外:

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

    输出:

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

    现在是正确的。

    从内存表中选择也可以:

    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
    

    输出:

                          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)
    

    更新

    原来功能hstore_to_array已经是一个内置功能,只需使用avalshttp://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;
    

    输出:

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

    另一个示例:

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

    输出:

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

    只需使用avals

    现场测试http://www.sqlfiddle.com/#!1/d41d8/388

    请注意,虽然 sqlfiddle 输出没有数组指示符(大括号)和 “我的激情是戒指、鼓和阴影” 上的双引号,但 avals 结果是一个数组和其中带逗号的字符串在实际结果中有双引号,你可以在你的 pgAdmin 或 psql 上测试它

    【讨论】:

    • 我注意到,如果 coluimn 值是带时区的时间戳(又名 ISO8601 刺痛) - 排序 IS NOT 保留....尝试添加“2016-06-13 16 :00:00-04" 作为内存表示例中甲壳虫乐队的第二列...它显示为第一列...小提琴示例 - sqlfiddle.com/#!15/9eecb7db59d16c80417c72d1e1f4fbf1/11397
    【解决方案3】:

    此函数适用于所有极端情况,包括 NULL 值、空字符串或值中的特殊字符。

    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;
    

    呼叫:

    SELECT * FROM f_rows_to_arr ('mytbl');
    

    regclass 的强制转换避免了 SQLi。此版本中未对列进行排序。 this related answer中使用的技术和链接的更多解释。

    【讨论】:

      【解决方案4】:

      string_to_array 可能会有所帮助:

      SELECT string_to_array(pg_tables::text,','::text) FROM pg_tables;
      

      【讨论】:

      • 我试过 string_to_array。不幸的是,该函数将包含所有文本(包括 '(' 和 ')'。当列中有 "," 作为值时,这也不起作用。SELECT (string_to_array(pg_tables::text,','::文本))[1] FROM pg_tables
      • @twn08: pg_tables 中怎么会有带逗号的值?
      • 我猜不是,但我选择了 pg_tables 作为示例。但是我正在为任何表格寻找通用解决方案。
      猜你喜欢
      • 1970-01-01
      • 2014-04-21
      • 2015-12-28
      • 2020-09-04
      • 2021-05-14
      • 2014-07-23
      • 1970-01-01
      • 1970-01-01
      • 2020-07-19
      相关资源
      最近更新 更多