通过循环创建UNION ALL语句

时间:2019-03-12 13:25:00

标签: sql oracle

手动地,我可以使用下面的第一个代码块在内部查询中选择分区。有没有办法通过循环以更优雅的方式做到这一点?我在这里显示3个分区,但是我大约有200个分区,并且这些分区是基于日期列的,因此当我在以后的日期再次运行此查询时,分区名称将需要更改。

SELECT *
FROM ( 

        SELECT * FROM RSS_ACQ.TRX_ARQ PARTITION("SYS_P211048") UNION ALL 
        SELECT * FROM RSS_ACQ.TRX_ARQ PARTITION("SYS_P210329") UNION ALL
        SELECT * FROM RSS_ACQ.TRX_ARQ PARTITION("SYS_P176323")

     )  TRX_ARQ
;

使用此语句,我创建了一个输出UNION ALL语句的循环。

BEGIN
  FOR ALL_TAB_PARTITIONS IN 
      ( 
              SELECT PARTITION_NAME
              FROM ALL_TAB_PARTITIONS
              where TABLE_OWNER = 'TABLEOWNER'
              AND TABLE_NAME = 'TABLENAME'
              AND PARTITION_POSITION > 123
              ORDER BY partition_position DESC 
        )      
            LOOP
   DBMS_OUTPUT.PUT_LINE( 'SELECT * FROM RSS_ACQ.TRX_ARQ PARTITION(\"' 
                                             || ALL_TAB_PARTITIONS.PARTITION_NAME || '\") UNION ALL');
  END LOOP;
END;

在此块中,我尝试使用内部查询中的循环。它的格式尚未正确,我需要避免在最后一个分区使用UNION ALL

SELECT *
FROM ( 
            BEGIN
            FOR ALL_TAB_PARTITIONS IN 
                  ( 
                          SELECT PARTITION_NAME
                          FROM ALL_TAB_PARTITIONS
                          where TABLE_OWNER = 'TABLEOWNER'
                          AND TABLE_NAME = 'TABLENAME'
                          AND PARTITION_POSITION > 123
                          ORDER BY partition_position DESC 
                    )      
                        LOOP
               DBMS_OUTPUT.PUT_LINE( 'SELECT * FROM RSS_ACQ.TRX_ARQ PARTITION(\"' 
      || ALL_TAB_PARTITIONS.PARTITION_NAME || '\") UNION ALL');
              END LOOP;
            END;      
     )  TRX_ARQ
;

这是一些错误,但还有更多错误。它们是语法错误,指向查询的其他部分,因此我希望转义引号时遇到问题。

Error starting at line : 99 in command -
END LOOP
Error report -
Unknown Command

Error starting at line : 100 in command -
END
Error report -
Unknown Command

Error starting at line : 101 in command -
)
Error report -
Unknown Command

Error starting at line : 102 in command -
)  TABLENAME
Error report -
Unknown Command

2 个答案:

答案 0 :(得分:2)

我们无法在SELECT语句中执行匿名PL / SQL块。

您需要做的是将ALL_TAB_PARTITIONS循环的输出假脱机到一个文件(或SQL工作表(如果您使用的是SQL Developer这样的IDE))。这将为您提供一个脚本,您可以在编辑后单独运行该脚本(您需要从最终生成的SELECT中修剪UNION ALL。

也许有更多优雅的方法可以实现相同的目的,但是这项任务似乎很错误,以至于我不值得为此付出努力。您要在单个语句中查询200个分区。这是蛮力的操作,查询命名块不会带来任何麻烦。实际上,产生200个独立查询的并集可能比单个查询更昂贵。那么为什么不尝试这样的事情呢?

select * from RSS_ACQ.TRX_ARQ
where partition_key_col >= date '2018-08-01' -- or whatever    

  

“我认为您忽略了在WITH子句中使用PL / SQL的12c功能”

该12c功能用于功能而不是过程,因此它不会帮助OP运行其代码。可以使用WITH子句函数,但这需要:

  • 创建与目标表具有相同投影的类型
  • 以及基于该类型的嵌套表类型
  • 具有WITH子句功能的汇编和执行动态SQL语句
  • 我们不能在SQL中使用REF CURSOR,所以...
  • 该函数必须执行动态选择INTO局部集合变量...
  • 然后在集合和PIPE ROW上循环以输出这些行...
  • 因此主查询可以通过table()调用来调用函数

可以对WITH子句函数进行流水线处理吗?我在文档中找不到任何不能说的内容(目前无法访问12c进行测试)。

答案 1 :(得分:2)

这有点猜测,但是评论太久了。

我假设您的表是间隔分区的。在这种情况下,从> 123的分区位置获取所有数据与获取比123的最高日期具有更高日期的所有行相同。

您可以从ALL_TAB_PARTITIONS获取该日期,然后将其用于查询表。像这样:

WITH FUNCTION get_high_value RETURN DATE IS 
  l_high_val_expr ALL_TAB_PARTITIONS.HIGH_VALUE%TYPE;
  l_high_value DATE;
BEGIN
  SELECT high_value
  INTO   l_high_val_expr
  FROM   all_tab_partitions 
  WHERE  table_owner = 'RSS_ACQ'
  AND    table_Name = 'TRX_ARQ'
  and    partition_position = 123; 

  EXECUTE IMMEDIATE 'SELECT ' || l_high_val_expr || ' FROM DUAL' INTO l_high_value;

  RETURN l_high_value;
END;
SELECT * FROM rss_acq.trx_arq
-- Replace "partitioned_date_column" with the name of the column on which the
-- table is interval partitioned.
WHERE partitioned_date_column > get_high_value;