Synonym to point two tables with same name but different suffix? - oracle

I am pretty new to oracle and trying to create a synonym to point two different tables on different days. Please see my example below.
I have two tables named table_1 and table _2 and a synonym table. At first i point the synonym to table_1;
CREATE SYNONYM table for schema.table_1;
Next day i would want to point the synonym to table_2. Should i use another statement like
CREATE OR REPLACE SYNONYM table for schema.table_2;
or is there any other way. Could someone help me?

There are numerous options.
Create a database job which will do synonym update by schedule. It may cause troubles for queries which are using the synonym at the time of its replacement.
Create a package with procedures which will hide table switching from application layer.
Create a view to hide table switching based on example select below. Assuming that you are only reading and tables have the same structure.
Don't duplicate tables.
Select for view
SELECT DUMMY
FROM (
SELECT 'X' AS DUMMY, 0 AS SEP FROM DUAL TABLE1
UNION ALL
SELECT 'Y' AS DUMMY, 1 AS SEP FROM DUAL TABLE2)
WHERE
SEP = MOD(EXTRACT(DAY FROM SYSDATE), 2)

Related

How to create a temporary table/view inside an Oracle procedure?

I am making a new procedure making queries to a huge table.
The structure of my procedure is as follows:
{
open cursor for
QUERY 1
UNION
QUERY 2
UNION
QUERY 3
}
The structure of QUERY 1 is INNER JOIN 2 ([INNER JOIN 1 (TABLE) x (TABLE) ] x TABLE )
The structure of QUERY 2 is INNER JOIN 3 ([INNER JOIN 1 (TABLE) x (TABLE) ] x TABLE )
Is there a way to store [INNER JOIN 1 (TABLE) x (TABLE) ] somewhere so that I don't have to do it twice?
EDIT: Forgot to add that I cannot create a table outside of the procedure because multiple instances of this procedure will run in parallel. They will just block each other from running by inserting in the same table. Also, I don't know how many instances will run in parallel so I cannot create as many tables as instances.
Don't create any tables from PL/SQL. It is possible (hint: dynamic SQL), but that's not how Oracle works.
If you need a table, then create it BEFORE running this procedure, either using CREATE TABLE (and name all columns you need), or using CTAS (Create Table As Select) which would - basically - be your current query.
That table can be "normal" or "global (or private, depending on database version) temporary table" (GTT). If you use a GTT, only you can see data stored within. If it is a "normal" table, everyone sees data so you might need to pay attention to who sees & uses what.
Another option is to use the CTE (Common Table Expression, a.k.a. the WITH factoring clause) which can be used directly in the procedure as
with your_view as
(select ...
from table1 join table2 on ...
join table3 on ...
)
select whatever
from some_other_table join your_view
where ...
union
select whatever_else
from yet_another_table join your_View
where ...
[EDIT, after seeing your edit]
If you don't want to use a CTE for some reason, then a GTT might be your choice. Why? See my 3rd paragraph ("everyone sees only their own data").
You could always use a Global Temporary table:
https://oracle-base.com/articles/misc/temporary-tables#temporary-tables

Is there any major performance issues if I use virtual columns in Oracle?

Is there any major performance issues if I use virtual columns in an Oracle table?
We have a scenario where the db has fields stored as strings. Since other production apps run off those fields we can't easily convert them.
I am tasked with generating reports from the same db. Since I need to be able to filter by dates (which are stored as strings) it was brought to my attention that we could create a virtual date field so that I can query against that.
Has anyone ran into any roadblocks with this approach?
A virtual column is defined using an expression that is evaluated when you select from the table. There is no performance hit on inserts/updates on the table.
For example:
create table t1 (
datestr varchar2(100),
datedt date generated always as (to_date(datestr,'YYYYMMDD'))
);
Table created.
SQL> insert into t1 (datestr) values ('20160815');
1 row created.
SQL> insert into t1 (datestr) values ('xxx');
1 row created.
SQL> commit;
Commit complete.
Note that I was able to insert an invalid date value into datestr. Now we can try to select the data:
SQL> select * from t1 where datedt = date '2016-08-15';
ERROR:
ORA-01841: (full) year must be between -4713 and +9999, and not be 0
This could be a problem for you if you can't guarantee all the strings hold valid dates.
As for performance, when you run the above query what you are really running is:
select * from t1 where to_date(datestr,'YYYYMMDD') = date '2016-08-15';
So the query will not be able to use an index on the datestr column (probably), and you may want to add an index on the virtual column. Again, this won't work if any of the strings don't contain valid dates.
Another consideration is potential impact on existing code. Hopefully you won't have any code like insert into t1 values (...); i.e. not specifying the column list. If you do you will get the error:
ORA-54013: INSERT operation disallowed on virtual columns

Hive - How to query a table to get its own name?

I want to write a query such that it returns the table name (of the table I am querying) and some other values. Something like:
select table_name, col1, col2 from table_name;
I need to do this in Hive. Any idea how I can get the table name of the table I am querying?
Basically, I am creating a lookup table that stores the table name and some other information on a daily basis in Hive. Since Hive does not (at least the version we are using) support full-fledged INSERTs, I am trying to use the workaround where we can INSERT into a table with a SELECT query that queries another table. Part of this involves actually storing the table name as well. How can this be achieved?
For the purposes of my use case, this will suffice:
select 'table_name', col1, col2 from table_name;
It returns the table name with the other columns that I will require.

SQLDeveloper Trigger Error report - ORA-00942: table or view does not exist

I put this code into SQL Developer's Worksheet:
CREATE TRIGGER T_testDSNa
before INSERT
on testDSNa
referencing new as new
for each ROW
BEGIN
SELECT S_testDSN.nextval INTO :NEW.SYSID FROM dual;
END;
I get this:
Error report -
ORA-00942: table or view does not exist
00942. 00000 - "table or view does not exist"
*Cause:
*Action:
Would anyone know why? This has worked for 3 previous tables until I tried to run the DDL to create a 4th. Alternatively, is there a better way to set up an autoincrementing PK?
The problem was lack of schema. Oracle Definition of a schema :
Collection of database objects, including logical structures such as
tables, views, sequences, stored procedures, synonyms, indexes,
clusters, and database links. A schema has the name of the user who
controls it.
If you want to know the objects accessible without alias. You have to look on [USER_OBJECTS]. Which describes the relational objects owned by the current user :
SELECT
OBJECT_NAME
, OBJECT_TYPE
, LAST_DDL_TIME
FROM USER_OBJECTS;
If you want to know the objects accessible to the current user :
SELECT
OWNER
, OBJECT_NAME
, OBJECT_TYPE
, LAST_DDL_TIME
FROM ALL_OBJECTS;
In your case to see your objects in the list of available tables you need:
SELECT * FROM ALL_OBJECTS WHERE OWNER = 'USER';
You can also alter the session to avoid alias :
ALTER SESSION SET current_schema = User;
For priviliges/ roles views you can look at :
SELECT * FROM USER_SYS_PRIVS;
SELECT * FROM USER_ROLE_PRIVS;
The last method but not the most secure to avoid alias. Is to log on with a user that has the same name as the schema.
Hoping that it can help
I was getting the same issue.
Solution: What I observed that my table which I created was surrounded by double quotes, which made it case sensitive.
So for each time I refer to my table, I need to surround it by double quotes.
CREATE TRIGGER T_testDSNa
before INSERT
on "testDSNa"
referencing new as new
for each ROW
BEGIN
SELECT S_testDSN.nextval INTO :NEW.SYSID FROM dual;
END;
refer this link: What exactly do quotation marks around the table name do?

How to swap table name in oracle

I have 2 oracle tables that are identical in definition just different in partition definition. I want to test one table vs another table design. Is there a way to swap the table name? I don't want to drop a table because they are big and takes a long time to load data into them.
Use a synonym that points to the real tables.
For example,
CREATE OR REPLACE SYNONYM partition_test FOR partition_table1;
Test partition_table1, e.g. select pt.* from partition_test pt;
CREATE OR REPLACE SYNONYM partition_test FOR partition_table2;
Test partition_table2, e.g. select pt.* from partition_test pt;
Notice the test code is then same each time.
When you're done testing, drop the synonym.
DROP SYNONYM partition_test;
Just rename them. For example, if you have TABLE_A, rename it to TABLE_A_TEMP. Then rename TABLE_B to TABLE_A. Then rename TABLE_A_TEMP to TABLE_B.
To rename, you'll have to issue
alter table table_name rename to new_table_name;
A third method would be to use a view. Let's say your "real" table names are TABLE_A and TABLE_B. Create a view, MY_DATA_VIEW (or whatever), and have it point to whichever table you want it to point to:
CREATE OR REPLACE VIEW TEST_VIEW AS SELECT * FROM TABLE_A;
or
CREATE OR REPLACE VIEW TEST_VIEW AS SELECT * FROM TABLE_B;
Share and enjoy.

Resources