ORA-00942 cannot find table - sql

I ran these statements:
create table SAMPLE(
ID INT
);
INSERT INTO SAMPLE VALUES(1);
COMMIT;
GRANT INSERT, SELECT, UPDATE, DELETE ON SAMPLE TO NEWLEC;
COMMIT;
But Eclipse says cannot find the table.
How can I resolve it?

You are connecting as the newlec user, and unqualified references to tables will look for them in that schema, not under other users.
You can qualify the table name:
SELECT * FROM real_owner.SAMPLE
For example, if you were connected as HR when you created the table, you would do:
SELECT * FROM HR.SAMPLE
You could also create a public synonym, which is probably overkill and can cause other issues and confusion; or create a private synonym for the newlec user which points to the rea table, e.g.:
CREATE SYNONYM SAMPLE FOR real_owner.SAMPLE;
SELECT * FROM SAMPLE;
so the unqualified query now sees the synonym, and through that the real table owned by someone else. Or you could set your current_schema after logon:
ALTER SESSION SET CURRENT_SCHEMA=real_owner;
SELECT * FROM SAMPLE;
so all unqualified queries now see objects owned by that user, not newlec.
However, if this is a basic assignment on a beginner course then you are probably just expected to qualify the name.

Related

Role to access the table only but not data from Table in Oracle Exadata

Users have create table statement with select statement from multiple tables from multiple schema. I want to restrict them to read data and allow them to create empty table in their schema with metadata only not data. This I want to do at user access and roles level.
Please tell me how I can do this?
I have tried giving them read access on underlying tables but users can see data as well.
Create table cust_acct_details
as
select *
from ep_rel.acct a
inner join ep_dnf.Cust_account ca
on a.acct_id = ca.acct_id
Tables should create without data.
Add below condition to your code
-- condition to add where 1<>1
Create table cust_acct_details
as
select *
from ep_rel.acct a
inner join ep_dnf.Cust_account ca
on a.acct_id = ca.acct_id
where 1<>1
Please make sure there are unique column names in your select statement. Oracle will not allow same column name in one table. Please use alias instead of *.
If you remove all tablespace privileges from a user they can still create tables but they won't be able to populate them.
For example, if you run this PL/SQL block to revoke all tablespace quotas from one user:
begin
for users in
(
select 'alter user '||username||' quota 0 on '||tablespace_name v_sql
from dba_ts_quotas
where username = 'TEST_USER'
order by 1
) loop
execute immediate users.v_sql;
end loop;
end;
/
Now the user can create tables but will get an error if they try to add rows:
SQL> create table test1(a number);
Table created.
SQL> insert into test1 values(1);
insert into test1 values(1)
*
ERROR at line 1:
ORA-01536: space quota exceeded for tablespace 'USERS'
For metadata, users can always see the metadata in their own schema. To allow them to view the metadata in other schema, run a grant like:
grant select_catalog_role to the_user;
Then that user can view the metadata either in the ALL_ data dictionary views, or using DBMS_METADATA.GET_DDL.

The command that could copy the table structure, all constraints and priviledge in Oracle

I am new to oracle. I would like to ask if there exist one single command that could copy table a to table b such that table b would have the same data, same structure and same access priviledge as table a? I would like to make a duplicate of a table which contain the same behavior.
Someone please correct me if I am wrong, but I don't think you can copy it with privileges/indexes as it is. That might be becasuse you need to give a new name for the index,primary key etc, and the database will not know what name needs to be given to these. So you can do this.
Run this to get the DDL of the table you want and then replace it with new table name. (my source table is TZ_TEST and I will create TZ_TEST_NEW. (Thanks to this answer for get_ddl command)
select replace(
(SELECT dbms_metadata.get_ddl( 'TABLE', 'TZ_TEST' ) FROM DUAL),
'TZ_TEST',
'TZ_TEST_NEW')
from dual
Execute the DDL
Use this to get grant permissions
select replace(
(select DBMS_METADATA.GET_DEPENDENT_DDL('OBJECT_GRANT','TZ_TEST') FROM DUAL),
'TZ_TEST',
'TZ_TEST_NEW') from dual
Similarly use DBMS_METADATA to get constraints/index etc. Execute these statmetns.
Insert data
insert into TZ_TEST_NEW
select * from TZ_TEST
Please remember that if you have an auto generated primary key, then while inserting data, you need to exclude that column from insert and select statments.
Anyone please feel free to add if I missed something.
Also we can create a procedure which can so all this but you need to be careful with all the steps. So once you do it couple of times and it works, we can create a procedure for it.
If you are using TOAD for Oracle, then select the table name and press F4. Then select script tab in the describe window.
This will generate the table script. You just need to use Search/Replace to change the table name and execute the script.
The newly created table will contain the same behavior.
I would do it in two steps:
Use CTAS i.e. create table as select .. to first create a copy of the table with new name with the data. You could also use PARALLEL and NOLOGGING feature to increase the performance.
For example,
create table t parallel 4 nologging as select * from emp;
Get the associated structures like indexes, constraints etc. using DBMS_METADATA.GET_DEPENDENT_DDL and execute it. But, you need to first replace the table_name to your new table_name as you have created in step 1.
CTAS would be much faster than traditional insert.

Oracle - Zombie Table

I'm having this odd problem since yesterday. I've tried several options and I actually reinstalled ORACLE and the DB itself.
Here's the problem: I have this table that is somekind of zombie. Here are the symptoms:
SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME='MYTABLE'
Returns a record, meaning that the table exists.
SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME = 'MYTABLE'
Returns all the columns of MYTABLE. So far so good, the table exists.
SELECT * FROM MYTABLE
Returns ORA-00942: table or view does not exist.
At this point I'm quite confused: the table seems to exist on the USERTABLES but I cannot SELECT over it?
CREATE TABLE MYTABLE (Foo NUMBER) TABLESPACE MYTABLESPACE
Returns:
ORA-00604: error occurred at recursive SQL level 1
ORA-00001: unique constraint (SYS.I_OBJ2) violated
I do not understand this error. But the best is yet to come.
SELECT * FROM MYTABLE
Surprisingly, the above query (an exact copy of the 3rd query) returns several records now!
Moreover, I noticed that the column Foo is not present: the table I now see is my initial table that had other columns.
DROP TABLE MYTABLE
I now try to drop the table and I get the following errors:
ORA-00604: error occurred at recursive SQL level 1
ORA-00942: table or view does not exist
ORA-06512: at line 19
SELECT * FROM MYTABLE
More confused than ever, I try the above query and, surprise surprise, the table no longer exists.
I don't undestand this: the table is on USERTABLES but I cannot SELECT over it, however, if I create a new table with the same name, I get an error but now I can SELECT over the previous version of that table with several records.
Any thoughts ? I really need your help :(
EDIT - I checked now: I'm unable to drop ANY table. This might just be a new symptom.
Solution
The problem was that MDSYS.SDO_GEOR_SYSDATA_TABLE table was missing and a drop event trigger was trying to access it, generating the error. The solution was restoring that table.
If have privileges, try this query:
SELECT *
FROM dba_objects
WHERE object_name = 'MYTABLE';
And see what objects exist with that name. It might point you in the right direction.
You didn't qualify the schema names when trying to select and drop. The CURRENT_SCHEMA of your session may be different form the log-on user. Check by trying
select SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') from dual;
Instead of describing what the output was, could you please copy/paste the complete output for us?
Lastly, can you exclude that someone messed up the dictionary? You know, SYSDBA can do anything....

How do I make one user see a different table with same name

Goal: When everybody else does SELECT * FROM mytable they see one version of the table. But when a specific user does SELECT * FROM mytable they see another version of the table.
I think I'm like halfway there with creating a new role and putting the single user in it. Then creating a copy of the default table with SELECT * INTO newrole.mytable FROM dbo.mytable. But when the user does SELECT * FROM mytable they still see the dbo.mytable. How do I get them to default to the newrole.mytable? I still need them to see all the other dbo tables just not this one.
Create a new schema, and a duplicate table (or view onto dbo.table if that's what you want) in it - eg., otheruser.table. Then, set the user's login to default to that schema:
USE atest
GO
CREATE ROLE [arole]
GO
CREATE SCHEMA [aschema] AUTHORIZATION [arole]
GO
CREATE USER [auser] FOR LOGIN [modify_user] WITH DEFAULT_SCHEMA = aschema
GO
EXEC sp_addrolemember 'arole', 'auser'
GO
CREATE TABLE dbo.atable ( col1 int )
GO
CREATE TABLE aschema.atable (col2 varchar(10))
GO
INSERT INTO dbo.atable( col1 ) VALUES( 1 )
GO
INSERT INTO aschema.atable( col2 ) VALUES( 'One' )
GO
PRINT 'dbo'
SELECT * FROM atable
GO
EXECUTE AS USER = 'auser'
GO
PRINT 'aschema'
SELECT * FROM atable
GO
REVERT
GO
I don't know if this may help but you may be able to make a view of a different table with the same name, here is an excerpt from http://www.w3schools.com/SQl/sql_view.asp:
In SQL, a view is a virtual table based on the result-set of an SQL statement.
A view contains rows and columns, just like a real table. The fields in a view are fields from one or more real tables in the database.
You can add SQL functions, WHERE, and JOIN statements to a view and present the data as if the data were coming from one single table.
I use Postgres primarily, so YMMV, but in postgres you need to
1) Create the new schema, preferably owned by the new role, and put the table in it
2) Set the search_path variable to include that schema BEFORE the other one.
Hope it helps.
This is a very bad idea. I'm not sure why people try all these crazy methods to improve security but it's just plain counter productive.
Ultimately every security system comes down to some line like the following if(User.HasAccessTo(object)). In fact, if you've designed a well thought out security system that's almost exactly how it should work. The more disjointed your authentication checks, the more likely you'll make a mistake. If only some users have access to certain record information you should add a flag to those records and verify access based on that.

How can I create a copy of an Oracle table without copying the data?

I know the statement:
create table xyz_new as select * from xyz;
Which copies the structure and the data, but what if I just want the structure?
Just use a where clause that won't select any rows:
create table xyz_new as select * from xyz where 1=0;
Limitations
The following things will not be copied to the new table:
sequences
triggers
indexes
some constraints may not be copied
materialized view logs
This also does not handle partitions
I used the method that you accepted a lot, but as someone pointed out it doesn't duplicate constraints (except for NOT NULL, I think).
A more advanced method if you want to duplicate the full structure is:
SET LONG 5000
SELECT dbms_metadata.get_ddl( 'TABLE', 'MY_TABLE_NAME' ) FROM DUAL;
This will give you the full create statement text which you can modify as you wish for creating the new table. You would have to change the names of the table and all constraints of course.
(You could also do this in older versions using EXP/IMP, but it's much easier now.)
Edited to add
If the table you are after is in a different schema:
SELECT dbms_metadata.get_ddl( 'TABLE', 'MY_TABLE_NAME', 'OTHER_SCHEMA_NAME' ) FROM DUAL;
create table xyz_new as select * from xyz where rownum = -1;
To avoid iterate again and again and insert nothing based on the condition where 1=2
Using sql developer select the table and click on the DDL tab
You can use that code to create a new table with no data when you run it in a sql worksheet
sqldeveloper is a free to use app from oracle.
If the table has sequences or triggers the ddl will sometimes generate those for you too. You just have to be careful what order you make them in and know when to turn the triggers on or off.
You can do this
Create table New_table as select * from Old_table where 1=2 ;
but be careful
The table you create does not have any Index, PK and so on like the old_table.
DECLARE
l_ddl VARCHAR2 (32767);
BEGIN
l_ddl := REPLACE (
REPLACE (
DBMS_LOB.SUBSTR (DBMS_METADATA.get_ddl ('TABLE', 'ACTIVITY_LOG', 'OLDSCHEMA'))
, q'["OLDSCHEMA"]'
, q'["NEWSCHEMA"]'
)
, q'["OLDTABLSPACE"]'
, q'["NEWTABLESPACE"]'
);
EXECUTE IMMEDIATE l_ddl;
END;
Simply write a query like:
create table new_table as select * from old_table where 1=2;
where new_table is the name of the new table that you want to create and old_table is the name of the existing table whose structure you want to copy, this will copy only structure.
SELECT * INTO newtable
FROM oldtable
WHERE 1 = 0;
Create a new, empty table using the schema of another. Just add a WHERE clause that causes the query to return no data:
WHERE 1 = 0 or similar false conditions work, but I dislike how they look. Marginally cleaner code for Oracle 12c+ IMHO is
CREATE TABLE bar AS
SELECT *
FROM foo
FETCH FIRST 0 ROWS ONLY;
Same limitations apply: only column definitions and their nullability are copied into a new table.
If one needs to create a table (with an empty structure) just to EXCHANGE PARTITION, it is best to use the "..FOR EXCHANGE.." clause. It's available only from Oracle version 12.2 onwards though.
CREATE TABLE t1_temp FOR EXCHANGE WITH TABLE t1;
This addresses 'ORA-14097' during the 'exchange partition' seamlessly if table structures are not exactly copied by normal CTAS operation. I have seen Oracle missing some of the "DEFAULT" column and "HIDDEN" columns definitions from the original table.
ORA-14097: column type or size mismatch in ALTER TABLE EXCHANGE
PARTITION
See this for further read...
you can also do a
create table abc_new as select * from abc;
then truncate the table abc_new. Hope this will suffice your requirement.
Using pl/sql developer you can right click on the table_name either in the sql workspace or in the object explorer, than click on "view" and than click "view sql" which generates the sql script to create the table along with all the constraints, indexes, partitions etc..
Next you run the script using the new_table_name
copy without table data
create table <target_table> as select * from <source_table> where 1=2;
copy with table data
create table <target_table> as select * from <source_table>;
In other way you can get ddl of table creation from command listed below, and execute the creation.
SELECT DBMS_METADATA.GET_DDL('TYPE','OBJECT_NAME','DATA_BASE_USER') TEXT FROM DUAL
TYPE is TABLE,PROCEDURE etc.
With this command you can get majority of ddl from database objects.
Create table target_table
As
Select *
from source_table
where 1=2;
Source_table is the table u wanna copy the structure of.
create table xyz_new as select * from xyz;
-- This will create table and copy all data.
delete from xyz_new;
-- This will have same table structure but all data copied will be deleted.
If you want to overcome the limitations specified by answer:
How can I create a copy of an Oracle table without copying the data?
The task above can be completed in two simple steps.
STEP 1:
CREATE table new_table_name AS(Select * from old_table_name);
The query above creates a duplicate of a table (with contents as well).
To get the structure, delete the contents of the table using.
STEP 2:
DELETE * FROM new_table_name.
Hope this solves your problem. And thanks to the earlier posts. Gave me a lot of insight.