Date range Partitioning
Hello Gurus,
I have one table which i partioned by yearly.
select partition_name, num_rows from dba_tab_partitions where table_name='TEST_OMAN';
PARTITION_NAME NUM_ROWS
CHANGE_DATE_DEC2005 1278654
CHANGE_DATE_DEC2006 2867545
CHANGE_DATE_DEC2007 3657438
CHANGE_DATE_DEC2008 4563575
CHANGE_DATE_DEC2009 0
CHANGE_DATE_DEC2010 154
Here, is the procedure i used to partioned the table.
CREATE TABLE OMANPRD.TEST_OMAN (
NID NUMBER,
TICKET_NBR VARCHAR2(20),
CHANGE_DATE DATE,
CHANGE_DESC VARCHAR2(4000),
OPERATOR VARCHAR2(255),
TYPE VARCHAR2(255),
LAST_MODIFIED DATE
PARTITION BY RANGE (CHANGE_DATE)
(PARTITION CHANGE_DATE_DEC2010 VALUES LESS THAN (MAXVALUE));
ALTER TABLE OMANPRD.TEST_OMAN
EXCHANGE PARTITION CHANGE_DATE_DEC2010
WITH TABLE OMANPRD.TEST_OMAN2
WITHOUT VALIDATION
UPDATE GLOBAL INDEXES;
ALTER TABLE OMANPRD.TEST_OMAN
SPLIT PARTITION CHANGE_DATE_DEC2010 AT (TO_DATE('31-DEC-2005 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
INTO (PARTITION CHANGE_DATE_DEC2005,
PARTITION CHANGE_DATE_DEC2010)
UPDATE GLOBAL INDEXES;
ALTER TABLE OMANPRD.TEST_OMAN
SPLIT PARTITION CHANGE_DATE_DEC2010 AT (TO_DATE('31-DEC-2006 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
INTO (PARTITION CHANGE_DATE_DEC2006,
PARTITION CHANGE_DATE_DEC2010)
UPDATE GLOBAL INDEXES;
ALTER TABLE OMANPRD.TEST_OMAN
SPLIT PARTITION CHANGE_DATE_DEC2010 AT (TO_DATE('31-DEC-2007 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
INTO (PARTITION CHANGE_DATE_DEC2007,
PARTITION CHANGE_DATE_DEC2010)
UPDATE GLOBAL INDEXES;
ALTER TABLE OMANPRD.TEST_OMAN
SPLIT PARTITION CHANGE_DATE_DEC2010 AT (TO_DATE('31-DEC-2008 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
INTO (PARTITION CHANGE_DATE_DEC2008,
PARTITION CHANGE_DATE_DEC2010)
UPDATE GLOBAL INDEXES;
ALTER TABLE OMANPRD.TEST_OMAN
SPLIT PARTITION CHANGE_DATE_DEC2010 AT (TO_DATE('31-DEC-2009 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
INTO (PARTITION CHANGE_DATE_DEC2009,
PARTITION CHANGE_DATE_DEC2010)
UPDATE GLOBAL INDEXES;
Now, there is some records which has change_date not in the corrrect date format or Null value which i want to send them to defualt table.
Right now I think those all record which has change_date null value and wrong date format are going to CHANGE_DATE_DEC2010 154 which i want to remove it from that partition and send it to defualt table partition.
I have tried
ALTER TABLE OMANPRD.TEST_OMAN
SPLIT PARTITION CHANGE_DATE_DEC2010 AT (TO_DATE(' ', 'DD-MON-YYYY HH24:MI:SS'))
INTO (PARTITION CHANGE_DATE_DEFAULT,
PARTITION CHANGE_DATE_DEC2010)
UPDATE GLOBAL INDEXES;
but it gives me a error.
Please,put some light on it
Danny
ORA-14019: partition bound element must be one of: string, datetime or interval literal, number, or MAXVALUE
But there is some records which has no CHANGE_DATE column value.
I have tried (TO_DATE(' ','DD-MON-YYYY HH24:MI:SS'))
or (TO_DATE('0','DD-MON-YYYY HH24:MI:SS'))
or (TO_DATE('null','DD-MON-YYYY HH24:MI:SS'))
but same error
Similar Messages
-
How to Implement 30 days Range Partitioning with Date column. Not Interval
Hi,
I am using the db:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit
Current table structure is:
CREATE TABLE A
a NUMBER,
CreationDate DATE
PARTITION BY RANGE (CreationDate)
INTERVAL ( NUMTODSINTERVAL (30, 'DAY') )
(PARTITION P_FIRST
VALUES LESS THAN (TIMESTAMP ' 2001-01-01 00:00:00'))
How can I define virtual column based partitioning with RANGE partitioning without using INTERVAL partitioning.
And that is with Intervals of 30 days.
For monthly I am trying as
CREATE TABLE A
a NUMBER,
CreationDate DATE,
monthly_interval date as (to_char(CreationDate,'MM-YYYY')) VIRTUAL
PARTITION BY RANGE (monthly_interval)
partition p_AUG12 values less than (to_date('08-2012','mm-yyyy')),
partition p_SEP12 values less than (to_date('09-2012','mm-yyyy')),
partition p_OCT12 values less than (to_date('10-2012','mm-yyyy'))
Enable ROw Movement
BUT CAN'T INSERT the data even for that:
Insert into a (a, CreationDate)
Values (1, '12-10-2012')
Insert into a (a, CreationDate)
Values (1, '12-10-2012')
Please suggest..Hi rp,
Interval Partitioned to Range. Created Daily Partitions from Monthly Part. got complicated so I am posting here.
Basically,
I know Interval Partitioning is a kind of Range partitioning. But explicitly for Interval Partitioned tables XML Indexes are not allowed as discussed here:
XMLIndexes on an Interval Partitioned Table??
I can do monthly partitions as :
CREATE TABLE A
a NUMBER,
CreationDate DATE,
monthly_interval varchar2(8) as (to_char(CreationDate,'MM-YYYY')) VIRTUAL
PARTITION BY RANGE (monthly_interval)
partition p_AUG12 values less than ('09-2012'),
partition p_SEP12 values less than ('10-2012'),
partition p_OCT12 values less than ('11-2012')
) Enable ROw Movement
Insert into a (a, CreationDate)
Values (1, '12-SEP-2012')
Insert into a (a, CreationDate)
Values (1, '14-SEP-2012')
Select * from A partition (p_SEP12)
Select * from A partition (p_AUG12)
Select * from A partition (p_OCT12)
Can we do it for 30 days partitions, instead of the monthly partitions. ANY suggestions..
Thanks.. -
Get table partition name dynamically for given date range
Dear All,
Could you please tell me how to get the partition name dynamicaly for given date range ?
Thank you.SQL> select table_name,
partition_name,
to_date (
trim (
'''' from regexp_substr (
extractvalue (
dbms_xmlgen.
getxmltype (
'select high_value from all_tab_partitions where table_name='''
|| table_name
|| ''' and table_owner = '''
|| table_owner
|| ''' and partition_name = '''
|| partition_name
|| ''''),
'//text()'),
'syyyy-mm-dd hh24:mi:ss')
high_value_in_date_format
from all_tab_partitions
where table_name = 'SALES' and table_owner = 'SH'
TABLE_NAME PARTITION_NAME HIGH_VALUE_IN_DATE_FORMAT
SALES SALES_1995 01-JAN-96
SALES SALES_1996 01-JAN-97
SALES SALES_H1_1997 01-JUL-97
SALES SALES_H2_1997 01-JAN-98
SALES SALES_Q1_1998 01-APR-98
SALES SALES_Q2_1998 01-JUL-98
SALES SALES_Q3_1998 01-OKT-98
SALES SALES_Q4_1998 01-JAN-99
SALES SALES_Q1_1999 01-APR-99
SALES SALES_Q2_1999 01-JUL-99
SALES SALES_Q3_1999 01-OKT-99
SALES SALES_Q4_1999 01-JAN-00
SALES SALES_Q1_2000 01-APR-00
SALES SALES_Q2_2000 01-JUL-00
SALES SALES_Q3_2000 01-OKT-00
SALES SALES_Q4_2000 01-JAN-01
SALES SALES_Q1_2001 01-APR-01
SALES SALES_Q2_2001 01-JUL-01
SALES SALES_Q3_2001 01-OKT-01
SALES SALES_Q4_2001 01-JAN-02
SALES SALES_Q1_2002 01-APR-02
SALES SALES_Q2_2002 01-JUL-02
SALES SALES_Q3_2002 01-OKT-02
SALES SALES_Q4_2002 01-JAN-03
SALES SALES_Q1_2003 01-APR-03
SALES SALES_Q2_2003 01-JUL-03
SALES SALES_Q3_2003 01-OKT-03
SALES SALES_Q4_2003 01-JAN-04
28 rows selected. -
Is there a way to have a count be partition over a date range
count(records) over(partition by ids range start_date to end_date)Hi,
Whenever you have a question, post a little sample data (CREATE TABLE and INSERT statements, relevant columns only) for all tables involved, and also post the results you want from that data.
Explain, using specific examples, how you get those results from that data.
Always say which version of Oracle you're using (e.g., 11.2.0.2.0).
See the forum FAQ: https://forums.oracle.com/message/9362002
Since I don't have a copy of your table, I'll use the scott.emp table to illustrate. Of course, there's nothing about cloudy days in scott.emp, so let's count the number of employees in non-magement positions, that is, anyone who has a job other than 'MANAGER' or 'PRESIDENT'.
For every employee hired, we want to see the total number of non-management employees hired so far in the same year, and also so far in the same month, like this:
ENAME HIREDATE JOB YEAR_CNT MONTH_CNT
SMITH 17-Dec-1980 CLERK 1 1
ALLEN 20-Feb-1981 SALESMAN 1 1
WARD 22-Feb-1981 SALESMAN 2 2
JONES 02-Apr-1981 MANAGER 2 0
BLAKE 01-May-1981 MANAGER 2 0
CLARK 09-Jun-1981 MANAGER 2 0
TURNER 08-Sep-1981 SALESMAN 3 1
MARTIN 28-Sep-1981 SALESMAN 4 2
KING 17-Nov-1981 PRESIDENT 4 0
JAMES 03-Dec-1981 CLERK 6 2
FORD 03-Dec-1981 ANALYST 6 2
MILLER 23-Jan-1982 CLERK 1 1
SCOTT 19-Apr-1987 ANALYST 1 1
ADAMS 23-May-1987 CLERK 2 1
Here's one way to do that:
WITH got_derived_values AS
SELECT ename, hiredate, job
, CASE
WHEN job NOT IN ('MANAGER', 'PRESIDENT')
THEN 'NON-MANAGEMENT'
END AS non_man
, hiredate - TRUNC (hiredate, 'MONTH') AS month_range
, hiredate - TRUNC (hiredate, 'YEAR' ) AS year_range
FROM scott.emp
SELECT ename, hiredate, job
, COUNT (non_man) OVER ( ORDER BY hiredate
RANGE BETWEEN year_range PRECEDING
AND CURRENT ROW
) AS year_cnt
, COUNT (non_man) OVER ( ORDER BY hiredate
RANGE BETWEEN month_range PRECEDING
AND CURRENT ROW
) AS month_cnt
FROM got_derived_values
ORDER BY hiredate
You've probably heard this before, but it's worth repeating:
Use DATE (or TIMESTAMP) columns to store information about dates. Using any other datatype is simply asking for trouble. -
Adding a partition by giving date range
Hi
I have a table with partition by range over date in julian format. I want to add a new partition for date range 01-jan-2007 to 15-Feb-2007. There are partitions for last date of January and Feburary.
Can I add a new partition as
alter table <table_name> add partition <partition_name>
values less than <date_in_julian> and greater than <date_in_julian>I don't believe that is valid syntax for range partitioning.
The "greater than" piece is taken care of by the "values less than" definition of the partition prior to the one being added.
If I understand your question, you have a partition with a date range ending prior to '01-feb-2007' and another partition with a date range ending prior to '01-mar-2007' and you would like to add a partition to cover the date range of 01-jan-2007 through 15-feb-2007? If so that is not possible and would be a different table all together. If you need to adjust the date ranges of current partitions, you could split the february partition, then merge the january partition with the newly split first 1/2 of february. Or if you need a mechanism to focus in on that date range, perhaps a materialized view of the target table specifying that date range. -
How to get top 11 values per date range
I want to get the top 11 values by date range.
Sample Data
CREATE TABLE SAMPLE_DATA
DOMAIN_NAME VARCHAR2(100),
QTD NUMBER,
LOAD_DATE DATE
-- Insert
BEGIN
FOR lc IN 1..20
LOOP
FOR ld IN 1..30
LOOP
INSERT
INTO SAMPLE_DATA VALUES
'DM_'
||lc,
round(dbms_random.value(0,1000)),
SYSDATE-ld
END LOOP;
END LOOP;
COMMIT;
END;
SELECT *
FROM
(SELECT DOMAIN_NAME,
QTD,
LOAD_DATE
FROM
(SELECT DOMAIN_NAME,
QTD,
LOAD_DATE
FROM SAMPLE_DATA
WHERE LOAD_DATE = TRUNC(SYSDATE-3)
ORDER BY QTD DESC
WHERE ROWNUM <=10
UNION ALL
SELECT 'Others' DOMAIN_NAME,
SUM(QTD) QTD,
LOAD_DATE
FROM
(SELECT DOMAIN_NAME,
QTD,
LOAD_DATE
FROM
(SELECT rownum rn,
DOMAIN_NAME,
QTD,
LOAD_DATE
FROM
(SELECT DOMAIN_NAME,
QTD,
LOAD_DATE
FROM SAMPLE_DATA
WHERE LOAD_DATE = TRUNC(SYSDATE-3)
ORDER BY QTD DESC
WHERE rn > 10
GROUP BY LOAD_DATE
ORDER BY QTD DESC
-- Result
DOMAIN_NAME QTD LOAD_DATE
Others 2888 24/03/13
DM_1 1000 24/03/13
DM_20 933 24/03/13
DM_11 913 24/03/13
DM_3 743 24/03/13
DM_13 572 24/03/13
DM_12 568 24/03/13
DM_9 564 24/03/13
DM_6 505 24/03/13
DM_5 504 24/03/13
DM_2 480 24/03/13
Please, Help me get in one query this result using a range of date.
e.g
using LOAD_DATE BETWEEN '24/03/13' AND '25/03/13'
DOMAIN_NAME QTD LOAD_DATE
Others 2888 24/03/13
DM_1 1000 24/03/13
DM_20 933 24/03/13
DM_11 913 24/03/13
DM_3 743 24/03/13
DM_13 572 24/03/13
DM_12 568 24/03/13
DM_9 564 24/03/13
DM_6 505 24/03/13
DM_5 504 24/03/13
DM_2 480 24/03/13
Others 1948 25/03/13
DM_1 807 25/03/13
DM_8 764 25/03/13
DM_7 761 25/03/13
DM_11 656 25/03/13
DM_18 611 25/03/13
DM_17 523 25/03/13
DM_14 467 25/03/13
DM_19 447 25/03/13
DM_15 437 25/03/13
DM_6 380 25/03/13 Thank you in advance.I got the solution. Just sharing.
I used analytic functions that make my job easy.
Sample Data
DOMAIN_NAME QTD LOAD_DATE
DM_1 807 25/03/2013
DM_1 1000 24/03/2013
DM_2 226 25/03/2013
DM_2 480 24/03/2013
DM_3 244 25/03/2013
DM_3 743 24/03/2013
DM_4 48 25/03/2013
DM_4 413 24/03/2013
DM_5 164 25/03/2013
DM_5 504 24/03/2013
DM_6 380 25/03/2013
DM_6 505 24/03/2013
DM_7 761 25/03/2013
DM_7 212 24/03/2013
DM_8 764 25/03/2013
DM_8 308 24/03/2013
DM_9 354 25/03/2013
DM_9 564 24/03/2013
DM_10 214 25/03/2013
DM_10 367 24/03/2013
DM_11 656 25/03/2013
DM_11 913 24/03/2013
DM_12 37 25/03/2013
DM_12 568 24/03/2013
DM_13 332 25/03/2013
DM_13 572 24/03/2013
DM_14 467 25/03/2013
DM_14 87 24/03/2013
DM_15 437 25/03/2013
DM_15 450 24/03/2013
DM_16 238 25/03/2013
DM_16 299 24/03/2013
DM_17 523 25/03/2013
DM_17 143 24/03/2013
DM_18 611 25/03/2013
DM_18 145 24/03/2013
DM_19 447 25/03/2013
DM_19 464 24/03/2013
DM_20 91 25/03/2013
DM_20 933 24/03/2013 Top 11 QTD of DOMAIN_NAME per Data Range.
SELECT *
FROM
(SELECT DOMAIN_NAME,
QTD,
LOAD_DATE
FROM
(SELECT LOAD_DATE,
DOMAIN_NAME ,
QTD,
(DENSE_RANK() OVER (PARTITION BY LOAD_DATE ORDER BY QTD DESC )) AS RANK_QTD
FROM SAMPLE_DATA
WHERE trunc(load_date) BETWEEN '24/03/2013' AND '25/03/2013'
WHERE RANK_QTD <= 10
UNION ALL
SELECT 'Others',
SUM(QTD) AS QTD,
LOAD_DATE
FROM
(SELECT LOAD_DATE,
DOMAIN_NAME ,
QTD,
(DENSE_RANK() OVER (PARTITION BY LOAD_DATE ORDER BY QTD DESC )) AS RANK_QTD
FROM SAMPLE_DATA
WHERE trunc(load_date) BETWEEN '24/03/2013' AND '25/03/2013'
WHERE RANK_QTD > 10
GROUP BY LOAD_DATE
ORDER BY LOAD_DATE ASC,
QTD DESC
DOMAIN_NAME QTD LOAD_DATE
Others 2888 24/03/2013
DM_1 1000 24/03/2013
DM_20 933 24/03/2013
DM_11 913 24/03/2013
DM_3 743 24/03/2013
DM_13 572 24/03/2013
DM_12 568 24/03/2013
DM_9 564 24/03/2013
DM_6 505 24/03/2013
DM_5 504 24/03/2013
DM_2 480 24/03/2013
Others 1948 25/03/2013
DM_1 807 25/03/2013
DM_8 764 25/03/2013
DM_7 761 25/03/2013
DM_11 656 25/03/2013
DM_18 611 25/03/2013
DM_17 523 25/03/2013
DM_14 467 25/03/2013
DM_19 447 25/03/2013
DM_15 437 25/03/2013
DM_6 380 25/03/2013 -
Continious data range algorithm
I have in my database table 2 important date columns: StartDate (Not null) and EndDate(Allowed Null).
I want to ensure that all records in the table would always create perfect contiues date ranges with no holes inside.
Wor example there may not be records [1-may..1-may, 3-may-...] because there would be a hole [2-may...2-may]. Holes are not allowed.
And overlapping is not allowed, for example [1-may..1-may, 1-may-2may, 3-may-...] is not allowed because overlapping occures on day 1-may. Overlapping and holes are not allowed. But it is allowed that table has no records at all. But all DML manipulations with existing records must ensure that overlapping and holes won't occur.
How to write such check? How to ensure that data ranges would stay continous with no holes and no overlaps?
Oracle 11g.You're setting the wrong value for the start of a group when there is no (null) lagging end date. In my example I set the value to 0 when it was null as I was expecting each group to start at 1. In your case you've set the date to 1/1/1900 which isn't necessarily the day before the first start date of the group. Instead just default it to the start date - 1 to force a match...
SQL> ed
Wrote file afiedt.buf
1 with t as (select 1 as id, to_date('01.04.2013', 'DD.MM.YYYY') as val1, to_date('04.04.2013', 'DD.MM.YYYY') as val2 from dual union all
2 select 1, to_date('05.04.2013', 'DD.MM.YYYY'), to_date('06.04.2013', 'DD.MM.YYYY') from dual union all
3 select 1, to_date('07.04.2013', 'DD.MM.YYYY'), null from dual union all
4 select 2, to_date('01.04.2013', 'DD.MM.YYYY'), to_date('03.04.2013', 'DD.MM.YYYY') from dual union all
5 select 2, to_date('04.04.2013', 'DD.MM.YYYY'), to_date('07.04.2013', 'DD.MM.YYYY') from dual union all
6 select 2, to_date('09.04.2013', 'DD.MM.YYYY'), to_date('12.04.2013', 'DD.MM.YYYY') from dual union all
7 select 2, to_date('13.04.2013', 'DD.MM.YYYY'), null from dual union all
8 select 3, to_date('01.04.2013', 'DD.MM.YYYY'),to_date('03.04.2013', 'DD.MM.YYYY') from dual union all
9 select 3, to_date('04.04.2013', 'DD.MM.YYYY'), null from dual union all
10 select 4, to_date('01.04.2013', 'DD.MM.YYYY'), to_date('01.04.2013', 'DD.MM.YYYY') from dual union all
11 select 4, to_date('01.04.2013', 'DD.MM.YYYY'), null from dual
12 )
13 --
14 select id
15 ,val1 as "start"
16 ,val2 as "end"
17 ,lag(val2) over (partition by id order by val1)
18 ,case when
19 nvl(lag(val2) over (partition by id order by val1),val1-1) != val1-1 then
20 'hole or overlap'
21 else null
22 end as chk
23 from t
24* order by 1, 2
25 /
ID start end LAG(VAL2)OVER(PARTIT CHK
1 01-APR-2013 00:00:00 04-APR-2013 00:00:00
1 05-APR-2013 00:00:00 06-APR-2013 00:00:00 04-APR-2013 00:00:00
1 07-APR-2013 00:00:00 06-APR-2013 00:00:00
2 01-APR-2013 00:00:00 03-APR-2013 00:00:00
2 04-APR-2013 00:00:00 07-APR-2013 00:00:00 03-APR-2013 00:00:00
2 09-APR-2013 00:00:00 12-APR-2013 00:00:00 07-APR-2013 00:00:00 hole or overlap
2 13-APR-2013 00:00:00 12-APR-2013 00:00:00
3 01-APR-2013 00:00:00 03-APR-2013 00:00:00
3 04-APR-2013 00:00:00 03-APR-2013 00:00:00
4 01-APR-2013 00:00:00 01-APR-2013 00:00:00
4 01-APR-2013 00:00:00 01-APR-2013 00:00:00 hole or overlap
11 rows selected. -
How to delete the data from partition table
Hi all,
Am very new to partition concepts in oracle..
here my question is how to delete the data from partition table.
is the below query will work ?
delete from table1 partition (P_2008_1212)
we have define range partition ...
or help me how to delete the data from partition table.
Thanks
Sree874823 wrote:
delete from table1 partition (P_2008_1212)This approach is wrong - as Andre pointed, this is not how partition tables should be used.
Oracle supports different structures for data and indexes. A table can be a hash table or index organised table. It can have B+tree index. It can have bitmap indexes. It can be partitioned. Etc.
How the table implements its structure is a physical design consideration.
Application code should only deal with the logical data structure. How that data structure is physically implemented has no bearing on application. Does your application need to know what the indexes are and the names of the indexes,in order to use a table? Obviously not. So why then does your application need to know that the table is partitioned?
When your application code starts referring directly to physical partitions, it needs to know HOW the table is partitioned. It needs to know WHAT partitions to use. It needs to know the names of the partitions. Etc.
And why? All this means is increased complexity in application code as this code now needs to know and understand the physical data structure. This app code is now more complex, has more moving parts, will have more bugs, and will be more complex to maintain.
Oracle can take an app SQL and it can determine (based on the predicates of the SQL), which partitions to use and not use for executing that SQL. All done totally transparently. The app does not need to know that the table is even partitioned.
This is a crucial concept to understand and get right. -
Assign Month within a date range (by most days in a given month)
I have a begin and end date, sample data as such
select to_date('01-13-12','mm-dd-yy') from_dt,
to_date('02-23-12','mm-dd-yy') to_dt
from dual
union all
select to_date('03-15-2012','mm-dd-yy') from_dt,
to_date('04-16-2012','mm-dd-yy') to_dt
from dual
union all
select to_date('05-13-2012','mm-dd-yy') from_dt,
to_date('07-23-2012','mm-dd-yy') to_dt
from dual
How do I assign a month by the most days in a month within that date range? Sometimes the date range might have the exact same amount of days in a month (like 3/15/2012 has 16 days and 4/16/2012 has 16 days). In this case, I want the earlier month (march).
So from the sample data:
01/13/2012, 02/23/2012, February
03/15/2012, 04/16/2012, March
05/13/2012, 07/23/2012, June
Thanks
Edited by: user4422426 on Mar 1, 2012 5:15 PMHi,
Here's one way:
WITH cntr AS
SELECT LEVEL - 1 AS n
FROM (
SELECT 1 + MAX (to_dt - from_dt) AS max_day_cnt
FROM table_x
CONNECT BY LEVEL <= max_day_cnt
, got_r_num AS
SELECT x.from_dt, x.to_dt
, TRUNC (x.from_dt + c.n, 'MONTH') AS month
, count (*) AS cnt
, ROW_NUMBER () OVER ( PARTITION BY from_dt, to_dt
ORDER BY COUNT (*) DESC
, TRUNC (x.from_dt + c.n, 'MONTH')
) AS r_num
FROM cntr c
JOIN table_x x ON c.n <= x.to_dt - x.from_dt
GROUP BY x.from_dt, x.to_dt
, TRUNC (x.from_dt + c.n, 'MONTH')
SELECT from_dt, to_dt
, TO_CHAR (month, 'Mon YYYY') AS mon
, cnt
FROM got_r_num
WHERE r_num = 1
;Thanks for posting code to create the same data. Please test your code before you post it: you got the order of arguments to TO_DATE reversed. -
All months in date range plus running count
Oracle 11g
Hello all,
Having trouble getting the following query to return proper results. Have a table with a MEMBERNO, BUSINESS_LINE, ELIGIBILITY_START_DATE, ELIGIBILITY_END_DATE.
MEMBERNO is not unique
BUSINESS_LINE is not either
Start and end date are periods of time where: MEMBERNO&BUSINESS_LINE have changed
I need to list the member number, business_line, and each month that falls within the date range beginning with eligibility_start_date & eligibility_end_date, as well as a running count of the total in that span.
Eg.
member, business_line, month, year, count
1234, bus1, 01, 2001, 1
1234, bus1, 02, 2001, 2
1234, bus1, 03, 2001, 3
Here is my SQL, it is not sequencing the months dates correctly and I can not figure out why. Any help is very appreciated:
SELECT memberno,
business_line,
TO_CHAR (ADD_MONTHS (start_date, LEVEL - 1), 'MM') as MONTH,
TO_CHAR (ADD_MONTHS (start_date, LEVEL - 1), 'YYYY') as YEAR,
ROW_NUMBER () OVER (PARTITION BY key1 ORDER BY start_date ASC) as MEMBER_MONTH_COUNT
FROM (SELECT memberno,
business_line,
eligibility_start_date as start_date,
eligibility_end_date as end_date,
member_nbr || business_line as key1
FROM eligibility)
CONNECT BY LEVEL <=
MONTHS_BETWEEN (TRUNC (END_DATE, 'MM'),
TRUNC (START_date, 'MM'))
+ 1;
Edited by: 935047 on Jul 25, 2012 5:58 AM
Edited by: 935047 on Jul 25, 2012 6:18 AM935047 wrote:
I need to list the member number, business_line, and each month that falls within the date range beginning with eligibility_start_date & eligibility_end_date, as well as a running count of the total in that span.
Eg.
member, business_line, month, year, count
1234, bus1, 01, 2001, 1
1234, bus1, 02, 2001, 2
1234, bus1, 03, 2001, 3I could not understand what the Running Count mean. Hence, I used Row_Number (Same as you did).
Below query might match yours.
with data (memb_no, bus_line, st_date, end_date) as
select 1234, 'bus1', to_date('01-01-2001', 'MM-DD-YYYY'), to_date('06-30-2001', 'MM-DD-YYYY') from dual
union all
select 1234, 'bus1', to_date('07-01-2001', 'MM-DD-YYYY'), to_date('07-30-2002', 'MM-DD-YYYY') from dual
min_max as
select memb_no, bus_line, min(st_date) st_date, max(end_date) end_date
from data
group by memb_no, bus_line
lvl as
select level l
from dual
connect by level <= (select max(round(months_between(end_date, st_date))) from min_max)
select memb_no,
bus_line,
to_char(add_months(st_date, l - 1), 'MM') months,
to_char(add_months(st_date, l - 1), 'YYYY') Year,
row_number() over (partition by memb_no, bus_line order by st_date) cnt
from min_max cross join lvl
order by year, months;
----OUTPUT------------------------
MEMB_NO BUS_LINE MONTHS YEAR CNT
1234 bus1 01 2001 1
1234 bus1 02 2001 19
1234 bus1 03 2001 3
1234 bus1 04 2001 4
1234 bus1 05 2001 5
1234 bus1 06 2001 6
1234 bus1 07 2001 7
1234 bus1 08 2001 8
1234 bus1 09 2001 9
1234 bus1 10 2001 10
1234 bus1 11 2001 11
1234 bus1 12 2001 12
1234 bus1 01 2002 13
1234 bus1 02 2002 14
1234 bus1 03 2002 15
1234 bus1 04 2002 16
1234 bus1 05 2002 17
1234 bus1 06 2002 18
1234 bus1 07 2002 2
19 rows selected -
Is there any plan of allowing non-range partitioning of spatial indexes
our application is really lacking the ability of spatial index being partitioned by list. We are binning information in our data warehouse by spatial locations, and when we query it (actually, MapViewer is generating a tile), entire geometry set is searched because table is list-partitioned and we cannot have local spatial index.
Hi,
I'm not in a position to answer the question about list partitioning, but would a pseudo-list partition implemented as a range partition work? For example, something like this:
CREATE TABLE customers (
first_name VARCHAR2(20),
last_name VARCHAR2(20),
address_1 VARCHAR2(20),
address_2 VARCHAR2(20),
city VARCHAR2(20),
state_abrv VARCHAR2(3),
postal_code VARCHAR2(10),
customer_id NUMBER NOT NULL UNIQUE)
PARTITION BY RANGE (state_abrv)
PARTITION ALASKA VALUES LESS THAN ('AKz'),
PARTITION ALABAMA VALUES LESS THAN ('ALz'),
PARTITION ARKANSAS VALUES LESS THAN ('ARz'),
PARTITION AMERICANSAMOA VALUES LESS THAN ('ASz'),
PARTITION ARIZONA VALUES LESS THAN ('AZz'),
PARTITION CALIFORNIA VALUES LESS THAN ('CAz'),
PARTITION WYOMING VALUES LESS THAN ('WYz')
);I've used this method in the past, although I agree a list partitioning solution is much preferred.
Dan -
Subpartition existing range partition in Oracle
I have table xyz with following structure
xyz ( vld_dte date,
prd_typ varchar2(100),
sales number
table XYZ is partitioned by range on field vld_dte and partitions are monthly partitions like JAN-2009 , FEB-2009....DEC-2009 and so on.table is currently loaded with data.
How can I modify existing range partition into composite range-list partition so that every partiton is subpartitioned on prd_typ , basically three sub-partitions for every partition 1- Grocery , 2-Home decoration,3-OTHERSORA-14759: SET INTERVAL is not legal on this table.
Cause: ALTER TABLE SET INTERVAL is only legal on a range partitioned table with a single partitioning column. Additionally this table cannot have a maxvalue partition.
Action: Use SET INTERVAL only on a valid table
mark answered post as helpful / correct* -
Problem with a 2 columns Range Partitioning for a indexed organized table
have an indexed organized table with a 2 column PK. the first field (datum) is a date field the second field (installatieid) is a number(2) field.
Every minute a 7 records are inserted (installatieid 0-6).
I like to partition this table with one partition per year per installatieid.
I tried to do it with:
partition by range(datum,installatieid)
(partition P_2004_0 values less than (to_date('2004-01,'yyyy-mm'),1)
,partition P_2004_6 values less than (to_date('2004-01','yyyy-mm'),7)
partition P_2005_0 values less than (to_date('2005-01','yyyy-mm'),1)
,partition P_2005_6 values less than (to_date('2005-01','yyyy-mm'),7)
but now only the P_2004_0 and P_2005_0 are filled.
I thought about to combine a range partition on datum with a list subpartition on installatieid, but I read this is not allowed with an index organized table.
How can I solve this problem.partition by range(datum,installatieid)
(partition P_2004_0 values less than
(to_date('2004-01,'yyyy-mm'))
,partition P_2004_6 values less than
(to_date('2004-07','yyyy-mm'))
partition P_2005_0 values less than
(to_date('2005-01','yyyy-mm'))
,partition P_2005_6 values less than
(to_date('2005-07','yyyy-mm'))
? Sorry haven't got time to test it this morning ;0) -
We have tables that are interval range partitioned on a DATE column, with a partition for each day - all very standard and straight out of Oracle doc.
A 3rd party application queries the tables to find number of rows based on date range that is on the column used for the partition key.
This application uses date range specified relative to current date - i.e. for last two days would be "..startdate > SYSDATE -2 " - but partition pruning does not take place and the explain plan shows that every partition is included.
By presenting the query using the date in a variable partition pruning does table place, and query obviously performs much better.
DB is 11.2.0.3 on RHEL6, and default parameters set - i.e. nothing changed that would influence optimizer behavior to something unusual.
I can't work out why this would be so. It very easy to reproduce with simple test case below.
I'd be very interested to hear any thoughts on why it is this way and whether anything can be done to permit the partition pruning to work with a query including SYSDATE as it would be difficult to get the application code changed.
Furthermore to make a case to change the code I would need an explanation of why querying using SYSDATE is not good practice, and I don't know of any such information.
1) Create simple partitioned table
CREATETABLE part_test
(id NUMBER NOT NULL,
starttime DATE NOT NULL,
CONSTRAINT pk_part_test PRIMARY KEY (id))
PARTITION BY RANGE (starttime) INTERVAL (NUMTODSINTERVAL(1,'day')) (PARTITION p0 VALUES LESS THAN (TO_DATE('01-01-2013','DD-MM-YYYY')));
2) Populate table 1million rows spread between 10 partitions
BEGIN
FOR i IN 1..1000000
LOOP
INSERT INTO part_test (id, starttime) VALUES (i, SYSDATE - DBMS_RANDOM.value(low => 1, high => 10));
END LOOP;
END;
EXEC dbms_stats.gather_table_stats('SUPER_CONF','PART_TEST');
3) Query the Table for data from last 2 days using SYSDATE in clause
EXPLAIN PLAN FOR
SELECT count(*)
FROM part_test
WHERE starttime >= SYSDATE - 2;
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
| 0 | SELECT STATEMENT | | 1 | 8 | 7895 (1)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 8 | | | | |
| 2 | PARTITION RANGE ITERATOR| | 111K| 867K| 7895 (1)| 00:00:01 | KEY |1048575|
|* 3 | TABLE ACCESS FULL | PART_TEST | 111K| 867K| 7895 (1)| 00:00:01 | KEY |1048575|
Predicate Information (identified by operation id):
3 - filter("STARTTIME">=SYSDATE@!-2)
4) Now do the same query but with SYSDATE - 2 presented as a literal value.
This query returns the same answer but very different cost.
EXPLAIN PLAN FOR
SELECT count(*)
FROM part_test
WHERE starttime >= (to_date('23122013:0950','DDMMYYYY:HH24MI'))-2;
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
| 0 | SELECT STATEMENT | | 1 | 8 | 131 (0)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 8 | | | | |
| 2 | PARTITION RANGE ITERATOR| | 111K| 867K| 131 (0)| 00:00:01 | 356 |1048575|
|* 3 | TABLE ACCESS FULL | PART_TEST | 111K| 867K| 131 (0)| 00:00:01 | 356 |1048575|
Predicate Information (identified by operation id):
3 - filter("STARTTIME">=TO_DATE(' 2013-12-21 09:50:00', 'syyyy-mm-dd hh24:mi:ss'))
thanks in anticipation
JimAs Jonathan has already pointed out there are situations where the CBO knows that partition pruning will occur but is unable to identify those partitions at parse time. The CBO will then use a dynamic pruning which means determine the partitions to eliminate dynamically at run time. This is why you see the KEY information instead of a known partition number. This is to occur mainly when you compare a function to your partition key i.e. where partition_key = function. And SYSDATE is a function. For the other bizarre PSTOP number (1048575) see this blog
http://hourim.wordpress.com/2013/11/08/interval-partitioning-and-pstop-in-execution-plan/
Best regards
Mohamed Houri -
Range Partitioning a table. Max value to be defined
Hi,
I am using a range partitioned table, range partitioned on date, and have defined max value as 6 months after the Creation Date.
I have a proc which creates the partitions I want in advance by splitting up the max partition.
- Now what do I do when max partition is reached after 6 months?
- If I define max partition one year or two year after the current date instead of the currently defined 6 months after creation date. What are the negatives attached with it?
I can't use Interval Partition and have to use Range only.
Kindly suggest.
Thanks..>
I am using a range partitioned table, range partitioned on date, and have defined max value as 6 months after the Creation Date.
I have a proc which creates the partitions I want in advance by splitting up the max partition.
- Now what do I do when max partition is reached after 6 months?
- If I define max partition one year or two year after the current date instead of the currently defined 6 months after creation date. What are the negatives attached with it?
>
Any data with a partition key that does NOT match any partition will cause your INSERT query to fail.
Any partition that has no data to match it will simply remain empty.
A common partitioning scheme is to define one partition for all old data, one partition with a high max value and then split the max value partition to get the partitions you want in the middle.
Let's say you want monthly partitions but don't have that much data from before the current year, 2012.
1. Create one partition for dates < 1/1/2012
2. One partition each for the 12 months of 2012
3. One max value partition to be 1/1/4000
You would just split the max value partition to create each month of 2013. The split could be done ahead of time or a month at a time as you choose.
The only negative is that any data inserted by mistake that has a super-high date will go into the max value partition. But that is going to happen anyway. If you accidentally enter a date of 3/23/3882 it won't be rejected.
But it is easy to query periodically to see if you have any 'bad' data like that. And the alternative is that an INSERT would fail because of the one bad record and all of your good data would be rejected anyway so it's not really much of a negative.
Remember - for best management performance each partition should have its own tablespace and the indexes should all be local if possible.
Maybe you are looking for
-
Print a report on doc format truncate data
hi I have a report launching with a form in an oracle applications, when I print a report on pdf format looks ok but when I print the same report on doc format truncate data on left and right side. Can you help me thanks
-
Why is it so difficult for Adobe to manage a simple Creative Cloud membership?
I have a one year committed Creative Cloud plan which started at the end of December. Actually I tried to purchase it at the end of December, for some reason they managed to validate my subscription in two weeks. Anyway, only 3 months passed and my p
-
My blackberry 9320 won't charge and won't come on at all
I've been charging my phone all night and the led hasn't been flashing to tell its charging when last night it was charging fine and it won't turn on. And when it diddent turn on it was low battery so what shall I do
-
Q: How to get rid of the FACES FEATURE in iPhoto'11???
Does anybody know if it is possible to DISABLE the FACES feature on the new iPhoto'11?? The feature is awful. It's turned my photo library into massive storage places with at least 10 times the photographs that I had originally. Whoever thought it wo
-
Calendar's 2nd Event Alert auto swaps with 1st alert after pressing Done button in the default "Home" Calendar for IOS 7.1. Why? No such problem with the original IOS 6 that included in my iphone 5.