zoukankan      html  css  js  c++  java
  • Oracle 分区表的 FOR 语句,你这样用过吗?

    在11g以后,Oracle简化了指定分区的方式,不再需要明确指定分区名称,而是可以通过指定分区键值列数据的方式来指向对应的分区。

    指定一个分区除了使用分区名称外,很多时候还可以使用FOR语句。
    从11g开始,对分区进行操作的时候,不仅可以使用分区名称,还可以使用FOR语句。
    在10g中,MERGE RANGE分区的语句如下:

    SQL> SELECT * FROM V$VERSION;
    BANNER
    ----------------------------------------------------------------
    Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
    PL/SQL Release 10.2.0.3.0 - Production
    CORE    10.2.0.3.0      Production
    TNS for Solaris: Version 10.2.0.3.0 - Production
    NLSRTL Version 10.2.0.3.0 - Production
    SQL> CREATE TABLE T_PART_RANGE
      2  (ID NUMBER, 
      3  NAME VARCHAR2(30), 
      4  CREATE_DATE DATE)
      5  PARTITION BY RANGE (CREATE_DATE) 
      6  (PARTITION P1 VALUES LESS THAN (TO_DATE('2009-1', 'YYYY-MM')),
      7  PARTITION P2 VALUES LESS THAN (TO_DATE('2009-4', 'YYYY-MM')),
      8  PARTITION P3 VALUES LESS THAN (TO_DATE('2009-7', 'YYYY-MM')));
    
    
    表已创建。
    
    SQL> SELECT * FROM V$VERSION;
    BANNER
    ----------------------------------------------------------------
    SQL> ALTER TABLE T_PART_RANGE 
      2  MERGE PARTITIONS P2, P3
      3  INTO PARTITION P3;
    
    
    表已更改。
    
    

    而在11g中,除了使用分区名称外,还可以使用FOR语句来代替,比如:

    
    SQL> SELECT * FROM V$VERSION;
    BANNER
    --------------------------------------------------------------------------------
    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
    PL/SQL Release 11.2.0.1.0 - Production
    CORE    11.2.0.1.0      Production
    TNS for Linux: Version 11.2.0.1.0 - Production
    NLSRTL Version 11.2.0.1.0 - Production
    SQL> CREATE TABLE T_PART_RANGE
      2  (ID NUMBER, 
      3  NAME VARCHAR2(30), 
      4  CREATE_DATE DATE)
      5  PARTITION BY RANGE (CREATE_DATE) 
      6  (PARTITION P1 VALUES LESS THAN (TO_DATE('2009-1', 'YYYY-MM')),
      7  PARTITION P2 VALUES LESS THAN (TO_DATE('2009-4', 'YYYY-MM')),
      8  PARTITION P3 VALUES LESS THAN (TO_DATE('2009-7', 'YYYY-MM')));
    
    
    表已创建。
    
    SQL> ALTER TABLE T_PART_RANGE
      2  MERGE PARTITIONS
      3  FOR(TO_DATE('2009-01', 'YYYY-MM')), 
      4  FOR(TO_DATE('2009-04', 'YYYY-MM'))
      5  INTO PARTITION P3;
    
    
    表已更改。
    
    

    这种语法的优势对于范围分区还不是很明显,而对于INTERVAL分区就十分有意义了。由于INTERVAL分区的分区名称是系统产生的,用户对INTERVAL分区最直观的莫过于存在分区中的数据的范围,根据分区的定义和INTERVAL的设置很容易可以确定分区的范围和其中的数据,但是分区的名称就必须通过数据字典才能查询得到。

    一个INTERVAL分区的简单的例子:

    
    SQL> CREATE TABLE T_PART_INTER
      2  (ID NUMBER, 
      3  NAME VARCHAR2(30), 
      4  CREATE_DATE DATE)
      5  PARTITION BY RANGE (CREATE_DATE) 
      6  INTERVAL (INTERVAL '3' MONTH)
      7  (PARTITION P1 VALUES LESS THAN (TO_DATE('2009-1', 'YYYY-MM')),
      8  PARTITION P2 VALUES LESS THAN (TO_DATE('2009-4', 'YYYY-MM')));
    
    
    表已创建。
    
    SQL> INSERT INTO T_PART_INTER
      2  SELECT ROWNUM, OBJECT_NAME, SYSDATE - ROWNUM * 10
      3  FROM USER_OBJECTS;
    
    
    已创建9行。
    SQL> COMMIT;
    
    
    提交完成。
    
    SQL> ALTER TABLE T_PART_INTER
      2  MERGE PARTITIONS
      3  FOR(TO_DATE('2009-10', 'YYYY-MM')),
      4  FOR(TO_DATE('2010-1', 'YYYY-MM'));
    
    
    表已更改。
    
    

    继续上面的例子:

    
    SQL> CREATE TABLE T_PART_RANGE
      2  (ID NUMBER,
      3  NAME VARCHAR2(30),
      4  CREATE_DATE DATE)
      5  PARTITION BY RANGE (CREATE_DATE)
      6  (PARTITION P1 VALUES LESS THAN (TO_DATE('2009-1', 'YYYY-MM')),
      7  PARTITION P2 VALUES LESS THAN (TO_DATE('2009-4', 'YYYY-MM')),
      8  PARTITION P3 VALUES LESS THAN (TO_DATE('2009-7', 'YYYY-MM')));
    
    
    表已创建。
    
    

    下面打算通过FOR语句的方式合并P2和P3分区:

    
    SQL> ALTER TABLE T_PART_RANGE
      2  MERGE PARTITIONS
      3  FOR(TO_DATE('2009-4', 'YYYY-MM')),
      4  FOR(TO_DATE('2009-7', 'YYYY-MM'))
      5  INTO PARTITION P3;
    ALTER TABLE T_PART_RANGE
                *
    
    
    第 1 行出现错误:
    
    ORA-14702: 分区编号无效或超出范围
    语句出现了ORA-14702错误,查询Oracle的错误文档:
    ORA-14702: The partition number is invalid or out-of-range
    Cause: Attempted to use nonnumerical value or the number was out of range of the partitions.
    Action: Use a valid partition number.
    
    

    根据错误文档的描述,感觉是分区键值指定出现了错误,查询分区信息:

    SQL> SELECT PARTITION_NAME, HIGH_VALUE
      2  FROM USER_TAB_PARTITIONS
      3  WHERE TABLE_NAME = 'T_PART_RANGE'
      4  ORDER BY 1;
    PARTITION_NAME HIGH_VALUE
    -------------- ----------------------------------------------------------------------------------
    P1             TO_DATE(' 2009-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
    P2             TO_DATE(' 2009-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
    P3             TO_DATE(' 2009-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
    

    难道是分区键值指定有问题:

    SQL> ALTER TABLE T_PART_RANGE
      2  MERGE PARTITIONS
      3  FOR(TO_DATE(' 2009-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
      4  FOR(TO_DATE(' 2009-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
      5  INTO PARTITION P3;
    ALTER TABLE T_PART_RANGE
                *
    
    
    第 1 行出现错误:
    
    ORA-14702: 分区编号无效或超出范围
    
    
    完全仿照USER_TAB_PARTITIONS视图中的分区定义,错误依旧。
    

    最终发现了问题所在,FOR语句中指定的并不是分区定义时使用的值,而是存储在当前分区中的值:

    
    SQL> ALTER TABLE T_PART_RANGE
      2  MERGE PARTITIONS
      3  FOR(TO_DATE('2009-1', 'YYYY-MM')),
      4  FOR(TO_DATE('2009-4', 'YYYY-MM'));
    
    
    表已更改。
    
    SQL> SELECT PARTITION_NAME, HIGH_VALUE
      2  FROM USER_TAB_PARTITIONS
      3  WHERE TABLE_NAME = 'T_PART_RANGE'
      4  ORDER BY 1;
    PARTITION_NAME  HIGH_VALUE
    --------------- ---------------------------------------------------------------------------------
    P1              TO_DATE(' 2009-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
    SYS_P78         TO_DATE(' 2009-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
    
    
    
    可以看到,在使用FOR语句的时候,是根据P1和P2分区定义时的日期指定的分区,但是MERGE的结果却是P2和P3分区进行了合并。
    

    因此Oracle并非根据分区定义来判断分区,而是根据用户给出的值,来判断所属分区,所以,P1分区和SYS_P78分区的合并完全可以写成:

    
    SQL> ALTER TABLE T_PART_RANGE
      2  MERGE PARTITIONS
      3  FOR(TO_DATE('1970-1', 'YYYY-MM')),
      4  FOR(TO_DATE('2009-5', 'YYYY-MM'));
    
    
    表已更改。
    
    

    由于FOR语句的这种特性,使得HASH分区也可以使用这个特性:

    
    SQL> CREATE TABLE T_PART_HASH
      2  (ID NUMBER,
      3  NAME VARCHAR2(30))
      4  PARTITION BY HASH(ID)
      5  PARTITIONS 16;
    
    
    表已创建。
    
    SQL> ALTER TABLE T_PART_HASH
      2  MOVE PARTITION FOR(6);
    
    
    表已更改。
    
    

    这个例子对包含ID为6的分区进行了MOVE操作,而且甚至不需要指定的ID存在。

    最后给一个简单的LIST分区的SPLIT的例子:

    
    SQL> CREATE TABLE T_PART_LIST
      2  (
      3     OWNER VARCHAR2(30),
      4     TABLE_NAME VARCHAR2(30),
      5     TABLESPACE_NAME VARCHAR2(30),
      6     STATUS VARCHAR2(18)
      7  )
      8  PARTITION BY LIST (TABLESPACE_NAME)
      9  (
     10  PARTITION P1 VALUES ('SYSTEM'),
     11  PARTITION P2 VALUES ('YANGTK'),
     12  PARTITION P3 VALUES (DEFAULT)
     13  );
    
    
    表已创建。
    
    SQL> ALTER TABLE T_PART_LIST
      2  SPLIT PARTITION FOR('SYSAUX')
      3  VALUES ('SYSAUX')
      4  INTO (PARTITION P3, PARTITION P4);
    
    
    表已更改。
    
    SQL> SELECT PARTITION_NAME, HIGH_VALUE
      2  FROM USER_TAB_PARTITIONS
      3  WHERE TABLE_NAME = 'T_PART_LIST'
      4  ORDER BY 1;
    PARTITION_NAME  HIGH_VALUE
    --------------- -------------------------------------
    P1              'SYSTEM'
    P2              'YANGTK'
    P3              'SYSAUX'
    P4              DEFAULT
    
    出处:https://www.modb.pro/db/15418
    
    

    点击下图查看更多 ↓

    云和恩墨大讲堂 | 一个分享交流的地方

    长按,识别二维码,加入万人交流社群

    请备注:云和恩墨大讲堂

      点个“在看”

    你的喜欢会被看到????

  • 相关阅读:
    uC/OS-II时间(OS_time)块
    uC/OS-II任务(OS_task)块
    uC/OS-II信号(OS_sem)块
    uC/OS-II队列(OS_q)块
    uC/OS-II互斥信号(OS_mutex)块
    uC/OS-II内存(OS_mem)块
    elasticsearch-installation
    rabbitmq的安装
    str_翻转字符串
    str_2.判断两个字符串是否互为旋转词
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13311805.html
Copyright © 2011-2022 走看看