Greenplum获取一个SQL结果的字段名

 在Greenplum中,对于任意一个SQL,我们想获取这个SQL执行后的字段名是比较难的。

比方说在写一个通用工具的时候,使用copy命令将一个SQL导出成文本,但是每个字段的名称导出的文本中却没有,如果使用自己解析SQL的话就太复杂了

如果我们想取得这些字段名的话,不真正执行sql,因为在生成执行计划的时候已经,我知道的有以下几种方法:

1.使用JDBC,prepareStatement先生成执行计划,然后获取字段名:

             PreparedStatement pstmt = conn.prepareStatement("select * from gp_segment_configuration a");
             ResultSetMetaData metaData=pstmt.getMetaData();
             for(int i=1;i<=metaData.getColumnCount();i++){
              System.out.println(metaData.getColumnName(i)+" \t\t :"+metaData.getColumnTypeName(i));
             }

ps:不止是JDBC,其他的客户端接口估计都会有这种接口将字段给取出来。看了jdbc的源码,在获取metaData信息的时候,是直接跟数据库交互,然后将这些信息接收过来的。对于其他的,应该都是有定义好的接口的,这个需要自己去挖掘。


2.explain 如果加上verbose会将整个解析后的语法数打印出来。如下:

aligputf8=# explain verbose select * from cxfa;   
                           QUERY PLAN                           
----------------------------------------------------------------
    {MOTION 
    :motionID 1 
    :motionType 1 
    :sendToSecondary false 
    :sendSorted false 
    :numInputSegs 3 
    :inputSegIdx <> 
    :numHashSegs 0 
    :hashSegIdx 
    :hashExpr <> 
    :hashDataTypes <> 
    :numOutputSegs 1 
    :outputSegIdx -1 
    :numSortCols 0 
    :sortColIdx 
    :sortOperators 
    :plan_node_id 1 
    :plan_parent_node_id -1 
    :startup_cost 0.00 
    :total_cost 0.00 
    :plan_rows 1 
    :plan_width 36 

其中最上层的targetlist就是 SQL要返回的字段列表。

   :targetlist (
       {TARGETENTRY 
       :expr 
          {VAR 
          :varno 1 
          :varattno 1 
          :vartype 23 
          :vartypmod -1 
          :varlevelsup 0 
          :varnoold 1 
          :varoattno 1
          }
       :resno 1 
       :resname a 
       :ressortgroupref 0 
       :resorigtbl 28569230 
       :resorigcol 1 
       :resjunk false
       }
       {TARGETENTRY 
       :expr 
          {VAR 
          :varno 1 
          :varattno 2 
          :vartype 25 
          :vartypmod -1 
          :varlevelsup 0 
          :varnoold 1 
          :varoattno 2
          }
       :resno 2 
       :resname b 
       :ressortgroupref 0 
       :resorigtbl 28569230 
       :resorigcol 2 
       :resjunk false
       }
    )


这样,我们能不能利用这个写一个函数,来将这个字段名给取出来呢,如果直接解析这个语法树还是比较麻烦的。我们发现,字段名前面都有一个      :resname开头,我们可以遍历这个数,把“     :resname”开头的都给找出来,就是字段名了。

函数的代码如下:

CREATE or replace FUNCTION public.get_sql_column_name(sqlori text)
      RETURNS setof text
AS $
    sql_ori=sqlori.strip().lower()
    if not sql_ori.startswith('select'):
        return ['SQL is not Select SQL,Please check!']
    retext=[]
    sql="explain verbose " + sql_ori
    #plpy.info(sql)
    rv = plpy.execute(sql)
    for i in rv:
        if i['QUERY PLAN'].startswith("      :resname"):
            retext.append(i['QUERY PLAN'].replace("      :resname",''))
    return retext;
$ LANGUAGE plpythonu;


执行效果如下:

aligputf8=# select get_sql_column_name('select * from cxfa');
 get_sql_column_name 
---------------------
  a 
  b 
(2 rows)

Time: 32.037 ms
aligputf8=# select get_sql_column_name(pg_get_viewdef('pg_partitions'));
    get_sql_column_name     
----------------------------
  schemaname 
  tablename 
  partitionschemaname 
  partitiontablename 
  partitionname 
  parentpartitiontablename 
  parentpartitionname 
  partitiontype 
  partitionlevel 
  partitionrank 
  partitionposition 
  partitionlistvalues 
  partitionrangestart 
  partitionstartinclusive 
  partitionrangeend 
  partitionendinclusive 
  partitioneveryclause 
  partitionisdefault 
  partitionboundary 
(19 rows)

Time: 44.404 ms


 

  

猜你喜欢

转载自blog.csdn.net/scutshuxue/article/details/7080971