I need to check if a database link already exists before I create one. How can I do that?
I am writing an SQL script that starts with this:
DROP DATABASE LINK mydblink
then I create one:
CREATE DATABASE LINK mydblink
CONNECT TO testuser
IDENTIFIED BY mypswd
USING 'mypersonaldb'
I will of course get an error in the first step if the database link doesn't exists. And if I omit the first step and just go ahead and create a db link, I will again get an error saying that it already exists with the same name.
What can I do in order to check if the the database link already exists?
SELECT COUNT(1)
FROM dba_objects -- user_objects
WHERE object_type = 'DATABASE LINK'
AND object_name = 'ARGUS51P';
For example (untested):
declare
l_link_cnt pls_integer := 0;
l_sql varchar2(32767);
begin
-- link creation sql (fill in details of how you want this created)
l_sql := 'create public database link ...';
select count(1)
into l_link_cnt
from dba_objects
where object_type = 'DATABASE LINK'
and object_name = 'SOME_LINK';
-- create link if it doesn't exist yet
if (l_link_cnt = 0) then
-- create link
execute immediate l_sql;
end if;
end;
Oracle has no way to test for existence before a DROP or CREATE. (Well, ok, you could write some PL/SQL, but, that's probably more trouble than it's worth.) In Oracle scripting, it's pretty standard to simply do both the DROP and the CREATE in a script. If the DROP errors out, so be it. It won't affect execution of the script.
-Mark
Related
I need to automate DDL generation on Oracle where I have read only access. When attempting to do this via dbms_metadata e.g. dbms_metadata.get_ddl('TABLE', 'SOME_TABLE') I get:
ORA-00604: error occurred at recursive SQL level 1
ORA-16000: database or pluggable database open for read-only access
Which is surprising as I am not asking to write to the database.
It is not possible for me to get more access to fix this.
However, I can successfully use Intellij or DataGrip to generate DDL https://www.jetbrains.com/datagrip/features/generation.html and the output is sufficient.
Any idea how the IDEs are doing this? Or what (if any) open source package Intellij are using?
I don't have a pluggable database but I used the following on livesql and my database and it works well.
The error indicates a read only database do you have a read/write db to test on?
Note if you are trying my example change the value of owner to meet your requirements
CREATE OR REPLACE PROCEDURE get_metadata(
p_object_type VARCHAR2,
p_object_name VARCHAR2,
p_owner VARCHAR2) authid current_user is
x clob;
begin
x :=
dbms_metadata.get_ddl(
p_object_type,
p_object_name,
p_owner);
dbms_output.put_line(x);
end;
/
BEGIN
FOR cur_r IN(
SELECT OBJECT_TYPE,
OBJECT_NAME,
OWNER
FROM ALL_OBJECTS
WHERE OWNER like 'SQL%'
AND OBJECT_TYPE IN ('TABLE', 'INDEX', 'FUNCTION', 'PROCEDURE', 'TYPE','PACKAGE', 'SEQUENCE') order by OBJECT_NAME
)
LOOP
get_metadata
(cur_r.OBJECT_TYPE,
cur_r.OBJECT_NAME,
cur_r.OWNER);
END LOOP;
END;
They might be selecting from all_source:
SELECT text
FROM all_source
WHERE owner = 'CEAADMIN'
AND name = 'APPLICATION_LIST'
AND TYPE IN ('PACKAGE', 'PACKAGE BODY')
ORDER BY TYPE, line;
View source can be retrieved from all_views. The difference is that the view is kept in a WIDEMEMO type.
SELECT *
FROM all_views
WHERE owner = 'CEAADMIN' AND view_name = 'MYLINKS_VW';
I have wrote simple stored procedure in Oracle SQL Developer but found, attached ,error on execution/run step.
Here is my code:
CREATE OR REPLACE PROCEDURE EMP_NAME (EMP_ID_IN IN VARCHAR2,
EMP_NAME_OUT OUT VARCHAR2)
AS
BEGIN
SELECT first_name
INTO EMP_NAME_OUT
FROM employee
WHERE emp_id = EMP_ID_IN;
END EMP_NAME;
It also shows this error
The procedure itself seems to be OK. However, its execution is somewhat strange.
I suggest you to run it from the Worksheet itself, such as
declare
l_out employee.first_name%type;
begin
emp_name(100, l_out);
dbms_output.put_line('Result = ' || l_out);
end;
/
Though, why is it a procedure? Wouldn't a function be a better choice? E.g.
create or replace function emp_name (emp_id_in in varchar2)
return employee.first_name%type
is
retval employee.first_name%type;
begin
select first_name
into retval
from employee
where emp_id = emp_id_in;
return retval;
end;
/
You'd run it in a simple manner, as
select emp_name(100) from dual;
There's something wrong with your data dictionary. edit: you're on DB 10g, I'm guessing object_id isn't in the all arguments view. When we go to execute a stored procedure, we ask the database for some information about your code.
SELECT data_type, argument_name name
FROM all_arguments a, all_objects o
WHERE a.object_id=o.object_id
AND o.object_name=? and o.owner=? and a.package_name is NULL
order by position
The error about an invalid object_id - that's coming from this query. What version Oracle Database are you running? Can you see your PL/SQL object in ALL_OBJECTS and do your arguments show up in ALL_ARGUMENTS?
I've taken your code and modified it for the HR.EMPLOYEES table.
It works as expected.
We run some code to be able to show you the two parameters.
I put in a value of '101' for employee number or ID, and hit OK.
Then the OUT parameter is displayed below in the Log panel.
If you open your log panel (view -> log), you'll see a 'Statements' page as well. It's there that you can see ALL the code we execute on the database. That's where I went to get the SQL that's failing for you on the OBJECT_ID. Go look at that, and walk the code and confirm what's not working.
To fix this, go find an OLD copy of SQLDev that supports 10g..like maybe 2.1, OR upgrade your DB to at least 11.2.0.4.
I want to export all the data from a database like functions, procedures, views, triggers for which an user has owner privilegies. I know that SQL Developer has the option for exporting databases in sql file, but I want to do this from the code. When I run the code I want to create a file with .sql extension which must contain all data from the database. First of all, I want to know if that is possible, and if it is, can anyone tell me some hints for doing this?
I started with making a file:
CREATE DIRECTORY test_dir AS 'H:\';
DECLARE
out_File UTL_FILE.FILE_TYPE;
BEGIN
out_File := UTL_FILE.FOPEN('test_dir', 'test.sql' , 'W');
UTL_FILE.PUT_LINE(out_file , 'here will be the database export');
UTL_FILE.FCLOSE(out_file);
END;
The Oracle export/import utilities will export/import database objects in user mode (use OWNER parameter) using a binary file format
http://docs.oracle.com/cd/B28359_01/server.111/b28319/exp_imp.htm
However, if you want to export the metadata for your objects and data into sql files, you can query Oracle's catalog users views like user_objects -> for a user's database objects user_tables -> tables, user_constraints -> constraints (even user_source to get text for compiled objects). If you intend your .sql files to re-create objects and data, you are in for some heavy lifting, especially if you want your scripts to be portable. In that case I would look 3rd party tools.
I guess this should be the answer for what you are looking for. Hope it helps. This is just an example for what you are asking. Other types can also be incorporated as required.
spool on;
spool <target path>/filename;
SET SERVEROUTPUT ON SIZE UNLIMITED;
BEGIN
FOR I IN
(SELECT al.*
FROM ALL_SOURCE al
WHERE OWNER = 'AVROY'
ORDER BY name,
line
)
LOOP
dbms_output.put_line(I.TEXT);
END LOOP;
FOR I IN
(SELECT * FROM ALL_TABLES WHERE OWNER = 'AVROY'
)
LOOP
BEGIN
dbms_output.put_line(dbms_metadata.get_ddl('TABLE',i.table_name,'AVROY'));
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
END LOOP;
END;
SPOOL OFF;
You might want to use the export and import utility of Oracle database.
http://www.oracle-dba-online.com/export_and_import.htm
I would like to create database link inside of script, and want to receive all table names from the linked database. If I am correct, I need to create database link in order to use, but Oracle does not allow me to create such thing neither inside of my_fn or DECLARE section. Any suggestion?
DECLARE
TYPE tp_col_array IS TABLE OF varchar2(1000);
FUNCTION my_fn(
p_in_dblink_name IN VARCHAR2,
p_in_schema_name IN VARCHAR2)
RETURN varchar2 AS
vr_coll_table tp_col_array;
vr_coll_owner tp_col_array;
BEGIN
create database link "database1"
connect to my_name
identified by "my_password"
using 'database1';
SELECT owner, table_name
bulk collect into vr_coll_owner, vr_coll_table
FROM all_tables#database1
WHERE OWNER NOT IN ('SYS');
RETURN TO_CHAR(vr_coll_owner(1)); //just for temporary
END my_fn;
BEGIN
DBMS_OUTPUT.PUT_LINE(my_fn('link1','schema1'));
END;
EDIT
I also tried the following, but no luck :(
Execute immediate q'[create database link "database1"
connect to my_name
identified by "my_password"
using 'database1']';
If you create a database link dynamically in a PL/SQL block, every reference to that database link would also need to use dynamic SQL otherwise your block won't compile. Your SELECT statement would need to use EXECUTE IMMEDIATE as well. Stepping back, creating database links at runtime is generally a poor practice-- I'd seriously question why you're going down that path.
According to Justin Cave's comment
Make sure the definer-schema is granted the "create database link" privilege.
This one is working:
me#XE> execute execute immediate 'create database link superlink connect to a identified by b using ''TNSALIAS''';
PL/SQL procedure successfully completed.
me#XE> #mylinks
DB_LINK USERNAME PASSWORD HOST CREATED
--------------- --------------- --------------- ------------------------- --------------------
SUPERLINK A TNSALIAS 22.10.2014 22:42:19
I am trying the code below to create a table in PL/SQL:
DECLARE
V_NAME VARCHAR2(20);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE TEMP(NAME VARCHAR(20))';
EXECUTE IMMEDIATE 'INSERT INTO TEMP VALUES(''XYZ'')';
SELECT NAME INTO V_NAME FROM TEMP;
END;
/
The SELECT statement fails with this error:
PL/SQL: ORA-00942: table or view does not exist
Is it possible to CREATE, INSERT and SELECT all in a single PL/SQL Block one after other?
I assume you're doing something like the following:
declare
v_temp varchar2(20);
begin
execute immediate 'create table temp(name varchar(20))';
execute immediate 'insert into temp values(''XYZ'')';
select name into v_name from temp;
end;
At compile time the table, TEMP, does not exist. It hasn't been created yet. As it doesn't exist you can't select from it; you therefore also have to do the SELECT dynamically. There isn't actually any need to do a SELECT in this particular situation though you can use the returning into syntax.
declare
v_temp varchar2(20)
begin
execute immediate 'create table temp(name varchar2(20))';
execute immediate 'insert into temp
values(''XYZ'')
returning name into :1'
returning into v_temp;
end;
However, needing to dynamically create tables is normally an indication of a badly designed schema. It shouldn't really be necessary.
I can recommend René Nyffenegger's post "Why is dynamic SQL bad?" for reasons why you should avoid dynamic SQL, if at all possible, from a performance standpoint. Please also be aware that you are much more open to SQL injection and should use bind variables and DBMS_ASSERT to help guard against it.
If you run the program multiple time you will get an error even after modifying the program to run the select statement as dynamic SQL or using a returning into clause.
Because when you run the program first time it will create the table without any issue but when you run it next time as the table already created first time and you don't have a drop statement it will cause an error: "Table already exists in the Database".
So my suggestion is before creating a table in a pl/sql program always check if there is any table with the same name already exists in the database or not. You can do this check using a Data dictionary views /system tables which store the metadata depending on your database type.
For Example in Oracle you can use following views to decide if a tables needs to be created or not:
DBA_TABLES ,
ALL_TABLES,
USER_TABLES