简体   繁体   中英

Oracle - How to convert this extracted XML value to a date?

I have found this sql that help avoid high_value long type column.

--VER HIGH VALUE
col partition_name for a30
col high_value for a120
col PARTITION for a20
WITH xml AS
(
 SELECT dbms_xmlgen.getxmltype('SELECT table_name,partition_name,partition_position,high_value 
                                  FROM dba_tab_partitions 
                                 WHERE TABLE_OWNER = UPPER(''MY_SCHEMA'') ----MY SCHEMA HERE') AS x
    FROM dual
)
SELECT extractValue(rws.object_value, '/ROW/TABLE_NAME') table_name,
       extractValue(rws.object_value, '/ROW/PARTITION_NAME') partition,
       extractValue(rws.object_value, '/ROW/HIGH_VALUE') high_value
  FROM xml x, table(xmlsequence(extract(x.x, '/ROWSET/ROW'))) rws;

The sample output:

SAMPLE_TABLE                     P82                  TO_DATE(' 2021-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P83                  TO_DATE(' 2021-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P84                  TO_DATE(' 2021-11-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P85                  TO_DATE(' 2021-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P86                  TO_DATE(' 2022-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P87                  TO_DATE(' 2022-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P88                  TO_DATE(' 2022-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P89                  TO_DATE(' 2022-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P90                  TO_DATE(' 2022-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P91                  TO_DATE(' 2022-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P92                  TO_DATE(' 2022-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P93                  TO_DATE(' 2022-08-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P94                  TO_DATE(' 2022-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P95                  TO_DATE(' 2022-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P96                  TO_DATE(' 2022-11-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P97                  TO_DATE(' 2022-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
SAMPLE_TABLE                     P98                  MAXVALUE

How can I convert column high_value directly to a date

IE: instead of getting:

`TO_DATE(' 2022-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')`

I'd like to get:

2022-12-01

Or, if I change the date mask, I got:

alter session set nls_date_format = 'dd/mm/yyyy hh24:mi:ss';

01/12/2022 00:00:00

With your sample output it looks like you need to extract substring of the HIGH_VALUE column from position 11, take 10 characters and convert it to date. The last row containing tekst 'MAXVALUE' should be handled too. Below is SQL that converts the dates and instead of MAXVALUE tekst results with the preceding row's date...

Select 
    TABLE_NAME, 
    PARTITION_NAME, 
    PARTITION_POSITION,
    CASE WHEN HIGH_VALUE != 'MAXVALUE' THEN To_Date(SubStr(HIGH_VALUE, 11, 10), 'yyyy-mm-dd') 
    ELSE LAST_VALUE(To_Date(SubStr(HIGH_VALUE, 11, 10), 'yyyy-mm-dd')) OVER(ORDER BY PARTITION_NAME ROWS BETWEEN 1 PRECEDING And 1 PRECEDING)
  END "HIGH_VALUE"
From 
    dba_tab_partitions
WHERE 
    TABLE_OWNER = UPPER(''''MY_SCHEMA'''')'
/*  
    R e s u l t :
TABLE_NAME   PARTITION_NAME PARTITION_POSITION HIGH_VALUE
------------ -------------- ------------------ ----------
SAMPLE_TABLE P82            Null               01-SEP-21  
SAMPLE_TABLE P83            Null               01-OCT-21  
SAMPLE_TABLE P84            Null               01-NOV-21  
SAMPLE_TABLE P85            Null               01-DEC-21  
SAMPLE_TABLE P86            Null               01-JAN-22  
SAMPLE_TABLE P87            Null               01-FEB-22  
SAMPLE_TABLE P88            Null               01-MAR-22  
SAMPLE_TABLE P89            Null               01-APR-22  
SAMPLE_TABLE P90            Null               01-MAY-22  
SAMPLE_TABLE P91            Null               01-JUN-22  
SAMPLE_TABLE P92            Null               01-JUL-22  
SAMPLE_TABLE P93            Null               01-AUG-22  
SAMPLE_TABLE P94            Null               01-SEP-22  
SAMPLE_TABLE P95            Null               01-OCT-22  
SAMPLE_TABLE P96            Null               01-NOV-22  
SAMPLE_TABLE P97            Null               01-DEC-22  
SAMPLE_TABLE P98            Null               01-DEC-22
*/

Regards...

You rather can use a dynamic SQL statement within a PL/SQL code block in order to be able to return desired date value after conversion from LONG to VARCHAR2 such as

DECLARE
  v_dt  DATE;
  v_chr VARCHAR2(4000);
BEGIN
  DBMS_OUTPUT.PUT_LINE('table_name       partition_name       high_value');
  FOR c IN ( 
            SELECT table_name,partition_name,partition_position,high_value 
              FROM user_tab_partitions 
           )
  LOOP             
    v_chr := SUBSTR(c.high_value, 1, 4000);
    EXECUTE IMMEDIATE 'SELECT '||v_chr||' FROM dual' INTO v_dt;
    DBMS_OUTPUT.PUT(c.table_name||'    ');
    DBMS_OUTPUT.PUT(c.partition_name||'    ');
    DBMS_OUTPUT.PUT_LINE(v_dt);
  END LOOP;
END;
/

In this case, I could directly used the current date conversion expression without need any extra conversion or extraction by some substring operations.

Btw, Presuming you need to handle it for the current schema, preferred using user_tab_partitions dictionary view instead.

You may execute HIGH_VALUE expression as dynamic SQL and obtain the date without any parsing.

 create table t ( id int, dt date ) partition by range (dt) interval (interval '3' day) ( partition pmin values less than(date '2022-01-01') )
 insert into t (id, dt) select level, date '2022-01-01' + dbms_random.value(0,7)*level from dual connect by level < 10
 with function f_evaluate_date_expr(p_expr varchar2) /*Evaluates date expression to avoid any manual parsing*/ return date as l_dt date; begin if p_expr = 'MAXVALUE' then l_dt:= timestamp '9999-12-31 23:59:59'; else execute immediate 'select ' || p_expr || ' from dual' into l_dt; end if; return l_dt; end; select table_name, partition_name, f_evaluate_date_expr(high_value) as high_value from xmltable( '/ROWSET/ROW' passing dbms_xmlgen.getxmltype(' select table_name, partition_name, high_value from user_tab_partitions ') columns table_name varchar2(30), partition_name varchar2(30), high_value varchar2(100) )
TABLE_NAME PARTITION_NAME HIGH_VALUE
T PMIN 2022-01-01 00:00:00
T SYS_P4420 2022-01-10 00:00:00
T SYS_P4421 2022-01-13 00:00:00
T SYS_P4422 2022-01-22 00:00:00
T SYS_P4423 2022-01-28 00:00:00
T SYS_P4424 2022-01-07 00:00:00
T SYS_P4425 2022-01-31 00:00:00
T SYS_P4426 2022-01-19 00:00:00

fiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM