Reputation: 11
Hi I have a partitioned table and when I am trying to update taking few selected partition in a loop with passing partition name dynamically, it s not working.
for i in 1..partition_tbl.count Loop
UPDATE cdr_data PARTITION(partition_tbl(i)) cdt
SET A='B'
WHERE
cdt.ab='c'
End Loop;
The partition_tbl object has all the partition in which I want to perform this update.
Please suggest me how to proceed here.
Thanks in advance
Upvotes: 1
Views: 16073
Reputation: 542
In case of table partitioned by RANGE INTERVAL(...) on DATE column querying by that column the range has to fit in single interval, if the range overlaps on neighbouring partition the query seems to be scanning ALL partitions (20s execution instead of below 1s)
CREATE TABLE "BP_AUDIT_LOG_PRC"
(
"AUDIT_LOG_SKID" NUMBER(19,0) NOT NULL ENABLE,
...
"CRTN_DATE" DATE DEFAULT ON NULL SYSDATE NOT NULL ENABLE,
...
CONSTRAINT "BP_AUDIT_LOG_PRC_PK" PRIMARY KEY ("AUDIT_LOG_SKID")
USING INDEX
) ...
PARTITION BY RANGE ("CRTN_DATE") INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(PARTITION "P_INITIAL" VALUES LESS THAN
(TO_DATE(' 2019-01-01 00:00:00',
'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) )
> select min(crtn_date),max(crtn_date) from bp_audit_log_prc PARTITION (SYS_P61497)
> 1 row retrieved starting from 1 in 699 ms (execution: 678 ms, fetching: 21 ms)
--PARTITION (SYS_P61497)
--MIN(CRTN_DATE) MAX(CRTN_DATE)
--2024-02-01 00:01:24 2024-02-29 23:59:43
> select min(crtn_date),max(crtn_date) from bp_audit_log_prc
where 1=1 and crtn_date between to_date('2024.02.01','YYYY.MM.DD') and to_date('2024.03.01','YYYY.MM.DD')
> 1 row retrieved starting from 1 in 20 s 686 ms (execution: 20 s 647 ms, fetching: 39 ms)
> select min(crtn_date),max(crtn_date) from bp_audit_log_prc
where 1=1 and crtn_date between to_date('2024.02.01','YYYY.MM.DD') and to_date('2024.03.01','YYYY.MM.DD')-1/24/60/60
> 1 row retrieved starting from 1 in 786 ms (execution: 769 ms, fetching: 17 ms)
...so querying by specific partition might be better choice for someone.
Upvotes: 0
Reputation: 829
Preferably let Oracle take care about partitions - pretend in your statement they do not exist
UPDATE cdr_data cdt SET A='B' WHERE cdt.ab='c'
it will from the where conditions and your partitions definitions choose the right partition(s) to apply the command on.
There may be rare event when you need a partition bounded DML, but certainly it is not the example shown. In such situation you can't provide partition name dynamically, like you can't normally provide table name dynamically e.g. you can't
select * from _variable_containing_table_name
If you really insist on partition bounded command then it would be
select * from table_name partition (partition_Name)
e.g.
select * from bills partition (p201403)
To use dynamic partition name the whole statement would have to be dynamically executed via execute immediate or dbms_sql.
But once again, do not choose partition, Oracle will.
Upvotes: 3
Reputation: 231661
What is the problem that you are trying to solve? It doesn't make sense to run separate UPDATE
statements against each partition in a loop. If you really want to update every row in the table where ab = 'c'
, just issue a single UPDATE
statement
UPDATE cdr_data cdt
SET a = 'B'
WHERE ab = 'c'
potentially with a PARALLEL
hint that would allow Oracle to update multiple partitions in parallel.
If you really, really want to update each partition independently, it would make much more sense to do so based on the partition keys. For example, if your table has daily partitions based on a date
FOR i IN 1 .. <<number of daily partitions>>
LOOP
UPDATE cdr_data cdt
SET a = 'B'
WHERE ab = 'c'
AND partition_key = <<minimum date>> + i;
END LOOP;
Using the partition( <<partition name>> )
syntax is an absolute last resort. If you're really determined to go down that path, you'd need to use dynamic SQL, constructing the SQL statement in the loop and using EXECUTE IMMEDIATE
or dbms_sql
to execute it.
Upvotes: 4