I want to change a table name by appending SYSDATE to it. For example, I want to change table EXAMPLE_TABLE to EXAMPLE_TABLE_05_01_2015, but I want to get the date from SYSDATE.
I prepared the following but it is not working:
ALTER TABLE "MYDB"."EXAMPLE_TABLE" rename to (SELECT 'EXAMPLE_TABLE' || TO_CHAR(SYSDATE, '_dd_MM_yyyy') FROM DUAL);
How can I make it work?
Here is the error:
SQL Error: ORA-14047: ALTER TABLE|INDEX RENAME may not be combined with other operations
14047. 00000 - "ALTER TABLE|INDEX RENAME may not be combined with other operations"
*Cause: ALTER TABLE or ALTER INDEX statement attempted to combine
a RENAME operation with some other operation which is illegal
*Action: Ensure that RENAME operation is the sole operation specified in
ALTER TABLE or ALTER INDEX statement;
Use execute immediate.
begin
execute immediate
'alter table mydb.example_table rename to ' ||
'example_table_' || to_char(sysdate, 'dd_mm_yyyy');
end;
/
That said, I have the hunch that you'd be better off using partitioned tables.
In SQL*Plus, you could use the variable substitution.
Just another way :
SQL> CREATE TABLE t(ID NUMBER)
2 /
Table created.
SQL>
SQL> COLUMN new_tablename NEW_VALUE new_tablename
SQL> SELECT 't_' || to_char(sysdate, 'dd_mm_yyyy') AS new_tablename from dual
2 /
NEW_TABLENAM
------------
t_05_01_2015
SQL>
SQL> RENAME t TO &new_tablename
2 /
old 1: RENAME t TO &new_tablename
new 1: RENAME t TO t_05_01_2015
Table renamed.
SQL>
SQL> select * from t_05_01_2015;
no rows selected
SQL>
So, now the table T is renamed to T_05_01_2015.
Related
trying to run below procedure, but temp table is not getting updated with TEMP_JOB_ID_FROM_JOB_DOC_' and date.
create or replace PROCEDURE scheduler_cleanup
(P_IN_DATE IN DATE)
IS
BEGIN
EXECUTE IMMEDIATE 'create table TEMP_ID_STAT_TIME_FRM_JOB_DOC as select JOB_ID, last_update_time_utc, status from J_DOC where
LAST_UPDATE_TIME_UTC <= TRUNC(SYSDATE) - 90 and status=''Sent''';
EXECUTE IMMEDIATE 'DELETE hub_sign
WHERE job_id IN ( SELECT JOB_ID
FROM TEMP_ID_STAT_TIME_FRM_JOB_DOC )';
EXECUTE IMMEDIATE 'DELETE j_doc
WHERE job_id IN ( SELECT JOB_ID
FROM TEMP_ID_STAT_TIME_FRM_JOB_DOC )';
--EXECUTE IMMEDIATE 'RENAME TABLE TEMP_ID_STAT_TIME_FRM_JOB_DOC TO TEMP_JOB_ID_FROM_JOB_DOC_1119';
--BEGIN
-- EXECUTE IMMEDIATE 'DROP TABLE TEMP_JOB_ID_FROM_JOB_DOC_1119';
--EXCEPTION
--WHEN OTHER THEN
-- NULL;
-- END;
EXECUTE IMMEDIATE 'ALTER TABLE TEMP_ID_STAT_TIME_FRM_JOB_DOC RENAME TO || TO_CHAR(P_IN_DATE, 'MMYY');
END;
That's the last ALTER; you're renaming a table to TO_CHAR(30-11-2020, 'MMYY') which - when executed - does this:
SQL> alter table temp rename to to_char(sysdate, 'mmy');
alter table temp rename to to_char(sysdate, 'mmy')
*
ERROR at line 1:
ORA-14047: ALTER TABLE|INDEX RENAME may not be combined with other operations
Should have been just RENAME, not ALTER:
SQL> begin
2 execute immediate 'rename temp to temp_' || to_char(sysdate, 'mmy');
3 end;
4 /
PL/SQL procedure successfully completed.
SQL> select * From tab where tname like 'TEMP%';
TNAME TABTYPE CLUSTERID
------------------------------ ------- ----------
TEMP_120 TABLE
SQL>
Though, do you really really want to do it this way? In Oracle, we usually don't create tables dynamically. Renaming them so that they contain date component scales as a goat which flies (i.e. doesn't scale at all). How will you write queries against bunch of tables whose name differs by the "date" suffix? Dynamic SQL again? Well, good luck with that.
Two other options I can think of:
an "ordinary" table with a date column; filter rows by including that column into the WHERE clause (don't forget to index the column)
partitioning
As suggested by Littlefoot also, You can achieve the desired behavior with minimal dynamic queries.
If you really want to store the intermediate data then you can use the GLOBAL TEMPORARY TABLE or PL/SQL collections.
I am giving an example of how you can use the global temporary table as follows:
Create the Global temporary table:
-- use the data type of the column as per requirement
CREATE GLOBAL TEMPORARY TABLE GT_TABLE (
JOB_ID NUMBER,
LAST_UPDATE_TIME_UTC TIMESTAMP,
STATUS VARCHAR2(100)
) ON COMMIT DELETE ROWS;
Use the global temporary table in the procedure:
CREATE OR REPLACE PROCEDURE SCHEDULER_CLEANUP (
P_IN_DATE IN DATE
) IS
BEGIN
INSERT INTO GT_TABLE
SELECT JOB_ID,
LAST_UPDATE_TIME_UTC,
STATUS
FROM J_DOC
WHERE LAST_UPDATE_TIME_UTC <= TRUNC(SYSDATE) - 90
AND STATUS = 'Sent';
DELETE FROM HUB_SIGN
WHERE JOB_ID IN (
SELECT JOB_ID
FROM GT_TABLE
);
DELETE FROM J_DOC
WHERE JOB_ID IN (
SELECT JOB_ID
FROM GT_TABLE
);
EXECUTE IMMEDIATE 'create table TEMP_JOB_ID_FROM_JOB_DOC_' || TO_CHAR(P_IN_DATE,'MMYY')
|| ' as select JOB_ID, last_update_time_utc, status from GT_TABLE ';
END;
/
The goal is to use the table name returned from subselect in insert/update/delete statements. It fails to achieve desired results.
If we execute with TABLE (TABLE is oracle syntax word as described in reference)
delete from TABLE
(select DECODE(this returns table name as string) from REF_TABLE where where_clause);
then:
22905. 00000 - "cannot access rows from a non-nested table item"
If we execute without TABLE:
delete from
(select DECODE(this returns table name as string) from REF_TABLE where where_clause);
Then it actually deletes from REF_TABLE the record that satisfies when clause.
What is a proper way to pass table name from subselect to outer query?
Doc examples
EXECUTE IMMEDIATE 'delete from table :1' USING (select DECODE(...) from REF_TABLE WHERE where_clause);
PLS-00103: Encountered the symbol "delete from table :1" when
expecting one of the following:
:= . ( # % ;
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
You never mention table keyword when executing a DML query for example Insert, update and delete
delete from table_name;
update table_name set field='value';
insert into table_name (field) values ('value');
Table keyword is mentioned when you are executing a DDL statement like Create, Alter, drop and Truncate
Create table table_name (field varchar2(100));
Alter table table_name modify field1 varchar2(1000);
Drop table table_name;
truncate table table_name;
Hence the below query mentioned by you is correct
delete from
(select DECODE(this returns table name as string) from REF_TABLE where where_clause);
only limitation with the above query is that you have to use table_name source from a fixed table or view i.e. it cannot be picked from data dictionary views or you will get below error.
SQL Error: ORA-02030: can only select from fixed tables/views
02030. 00000 - "can only select from fixed tables/views"
*Cause: An attempt is being made to perform an operation other than
a retrieval from a fixed table/view.
*Action: You may only select rows from fixed tables/views.
you can use PL/SQL block similar as mentioned below to delete tables recursively
DECLARE
CURSOR c
IS
SELECT table_name FROM user_tables WHERE table_name LIKE '%SANDEEP26FEB16_2%';
BEGIN
FOR c1 IN c
LOOP
EXECUTE IMMEDIATE 'delete from ' || c1.table_name;
COMMIT;
END LOOP;
END;
This needs to be done in sql plus.
Hi, I'm struggling to rename two columns in my table. They are named "TYPE" and "LEVEL".
This needs to be done in sql plus with no exception.
The following does not work (works in sql developer tho):
alter table client rename column level to clevel;
alter table client rename column "level" to clevel;
LEVEL is an Oracle keyword, though not reserved. If you want to use it as an object name then you need to represent the name of an object with a quoted identifier using double quotation marks whenever you refer to that object.
SQL> SELECT keyword, reserved FROM V$RESERVED_WORDS WHERE keyword='LEVEL';
KEYWORD R
------------------------------ -
LEVEL N
SQL>
That is the reason if you use the keyword LEVEL as nonquoted identifier, it will throw an error:
SQL> CREATE TABLE t(level NUMBER);
CREATE TABLE t(level NUMBER)
*
ERROR at line 1:
ORA-00904: : invalid identifier
Now, per the documentation about Database Object Names and Qualifiers, if you create the object using double-quotation marks, it becomes case sensitive and must be always used the same way wherever the object is referenced.
For example,
SQL> CREATE TABLE t1("level" NUMBER);
Table created.
SQL>
SQL> ALTER TABLE t1 RENAME COLUMN "level" to clevel;
Table altered.
SQL>
SQL> CREATE TABLE t2("LEVEL" NUMBER);
Table created.
SQL>
SQL> ALTER TABLE t2 RENAME COLUMN "LEVEL" to clevel;
Table altered.
SQL>
It is better not to use the keyword, and give a proper naming convention.
SQL> CREATE TABLE t(clevel NUMBER);
Table created.
SQL>
You can also execute sql scripts in sqlplus. Just save your statement in a file and then use the following command:
#{file-path}
See also this link
How to truncate any table using its synonym in oracle?
-- in Server_A
Create Table table_a ( col int);
-- in server_B
CREATE SYNONYM syn_table_a FOR table_a#dblink_server_a;
--insert into
INSERT INTO syn_table_a values (1);
--Truncate
How to truncate table using synonym only?.
A truncate statement cannot be used on a synonym.
Synonyms cannot be used in a drop table, drop view or truncate
table/cluster statements. If this is tried, it results in a ORA-00942:
table or view does not exist
For example,
SQL> CREATE TABLE t(col NUMBER);
Table created.
SQL>
SQL> CREATE SYNONYM t_syn FOR t;
Synonym created.
SQL>
SQL> TRUNCATE TABLE t_syn;
TRUNCATE TABLE t_syn
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL>
You could use dynamic SQL to do it, e.g.:
declare
d varchar2(1000);
begin
select 'TRUNCATE TABLE "' || table_owner || '"."' || table_name || '"'
into d
from all_synonyms
where synonym_name = 'MYSYNONYM';
execute immediate d;
end;
If the table is accessed via a database link, this will not work. In that case, you could create a procedure on the remote instance that does the truncate, then call that procedure across the database link, e.g.
begin
truncate_my_table#dblinkname;
end;
In Oracle, you can also get ORA-14410 while trying to drop/truncate a table using synonym.
The alert log:
ORA-00604: error occurred at recursive SQL level 1
ORA-14410: RPI LOCK TABLE issued to table referenced through synonym
Follow the above dynamic SQl to drop/truncate it.
I want to create a simple function based index on a simple table but i get error.
So, first of all I created a function
CREATE OR REPLACE FUNCTION promo_function(p_promo_category VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
RETURN UPPER(p_promo_category);
END promo_function;
Then I would execute this, but fails
CREATE INDEX promotions_fbi
ON SH.PROMOTIONS (promo_function (promo_category));
Why? The error is ORA-00904:"PROMO_FUNCTION": Invalid identifier
But the function works well in a query:
SELECT *
FROM sh.sales s,
sh.promotions p,
sh.times t
WHERE s.promo_id = p.promo_id
AND s.time_id = t.time_id
AND t.time_id BETWEEN DATE '2000-01-01' AND DATE '2000-03-31'
AND promo_function(p.promo_category) = 'AD NEWS';
Many thanks!
There is nothing inherently wrong with your code. I can create a function-based index like this:
SQL> create table promotions (promo_category varchar2(10))
2 /
Table created.
SQL> CREATE OR REPLACE FUNCTION promo_function
2 (p_promo_category in VARCHAR2)
3 RETURN VARCHAR2 DETERMINISTIC
4 IS
5 BEGIN
6 RETURN UPPER(p_promo_category);
7 END promo_function;
8 /
Function created.
SQL> CREATE INDEX promotions_fbi
2 ON PROMOTIONS (promo_function (promo_category));
Index created.
SQL>
The only difference between my code and yours is that I don't prefix the table in the CREATE INDEX statement. Everything is in the same schema, so I don't need to.
So, can I re-create your scenario? Here's one way. I drop the index and function, then give another uses all privileges on teh table...
SQL> drop index promotions_fbi;
Index dropped.
SQL> drop function PROMO_FUNCTION;
Function dropped.
SQL> grant all on promotions to B;
Grant succeeded.
SQL>
As that user I can create a normal index ...
SQL> conn b/b
Connected.
SQL> select * from apc.promotions;
no rows selected
SQL> CREATE INDEX promotions_i
2 ON APC.PROMOTIONS (promo_category);
Index created.
SQL>
However, if I create a function I cannot create a function-based index using it....
SQL> conn b/b
Connected.
SQL> CREATE INDEX promotions_fbi
2 ON APC.PROMOTIONS (promo_function (promo_category));
ON APC.PROMOTIONS (promo_function (promo_category))
*
ERROR at line 2:
ORA-00904: : invalid identifier
SQL>
The invalid identifier fingers the function name. Why? Because although schema B would own the index schema APC owns the table, and needs to be able to execute the function too.
The solution is to grant execute rights on the function to the table owner:
SQL> conn b/b
Connected.
SQL> grant execute on promo_function to APC;
Grant succeeded.
SQL> CREATE INDEX promotions_fbi
2 ON APC.PROMOTIONS (B.promo_function (promo_category));
Index created.
SQL>
Note that we must explicitly reference the function owner as well as the table owner in this statement. It's a bit nasty, and that's why it's generally a bad idea to spread privileges across two schemas in this fashion.
Not sure how #zaratustra gets their findings, as I can definitely create function-based in indexes using the word FUNCTION in the name...
SQL> r
1 select i.table_owner, i.owner as index_owner, i.index_name
2 , i.index_type, e.column_expression
3 from all_indexes i
4 left join all_ind_expressions e
5 on i.owner = e.index_owner
6 and i.index_name = e.index_name
7* where i.table_name = 'PROMOTIONS'
TABLE_OWNER INDEX_OWNER
------------------------------ ------------------------------
INDEX_NAME INDEX_TYPE
------------------------------ ---------------------------
COLUMN_EXPRESSION
--------------------------------------------------------------------------------
APC APC
PROMOTIONS_FBI FUNCTION-BASED NORMAL
"APC"."PROMO_FUNCTION"("PROMO_CATEGORY")
APC A
PROMO_B_I FUNCTION-BASED NORMAL
"A"."B_FUNCTION"("PROMO_CATEGORY")
APC APC
PROMOTIONS_I NORMAL
SQL>
Although I am on a different point release so that might explain it
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
SQL>
During my experiments I realized that Oracle can't let you create function-based index with the function word in the name of the procedure. Looks like a bug for me:
CREATE OR REPLACE FUNCTION func_function(p_promo_category IN VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
RETURN UPPER(p_promo_category);
END func_function;
create table t1 (
promo_category varchar2(4000)
);
Table created
CREATE INDEX promotions_fbi ON t1 (func_function (promo_category));
ORA-00911: invalid character
Let's create a function without the function word in the name:
CREATE OR REPLACE FUNCTION func_functio(p_promo_category IN VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
RETURN UPPER(p_promo_category);
END func_functio;
CREATE INDEX promotions_fbi ON t1 (func_functio (promo_category));
Index created
select index_name, index_type
from user_indexes
where lower(index_name) = 'promotions_fbi'
INDEX_NAME INDEX_TYPE
-------------------------------------
PROMOTIONS_FBI FUNCTION-BASED NORMAL
My Oracle version:
select banner from v$version
BANNER
----------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production