need to connect to two different db from sqlplus - oracle

I need to take information from two different data bases.
select * from TABLE_ONDB2 where column_on_db2 in ( select column_on_db1 from TABLE_ONDB1 );
Problem is both are on different db instances so I am not able to figure out how to put table names and column names etc.
I hope my question is clear.

I'd try to do it with a Database Link:
http://download.oracle.com/docs/cd/B28359_01/server.111/b28310/ds_concepts002.htm
That is, however, not a SQL*Plus feature. It works by makeing a connection from DB2 to DB1 (the database is doing that).
You can then query both tables from DB2 with the '#db-link' name notation. e.g.,
select *
from TABLE_ONDB2
where column_on_db2
in (select column_on_db1 from TABLE_ONDB1#DB_LINK_NAME);
^^^^^^^^^^^^^
The benefit is that you can access the table in all different ways, also as a join.

Related

Switching between multiple tables at runtime in Oracle

I am working in an environment where we have separate tables for each client (this is something which I can't change due to security and other requirements). For example, if we have clients ACME and MEGAMART then we'd have an ACME_INFO table and MEGAMART_INFO tables and both tables would have the same structure (let's say ID, SOMEVAL1, SOMEVAL2).
I would like to have a way to easily access the different tables dynamically.
To this point I've dealt with this in a few ways including:
Using dynamic SQL in procedures/functions (not fun)
Creating a view which does a UNION ALL on all of the tables and which adds a CLIENT_ID COLUMN (i.e. "CREATE VIEW COMBINED_VIEW AS SELECT 'ACME' CLIENT_ID, ID, SOMEVAL1, SOMEVAL2 FROM ACME_INFO UNION ALL SELECT 'MEGMART' CLIENT_ID, ID, SOMEVAL1, SOMEVAL2") which performs surprisingly well, but is a pain to maintain and kind of defeats some of the requirements which dictate that we have separate tables for each client.
SYNONYMs won't work because we need different connections to act on different clients
A view which refers to a package which has a package variable for the active client. This is just evil and doesn't even work out all that well.
What I'd really like is to be able to create a table function, macro, or something else where I can do something like
SELECT * FROM FN_CLIENT_INFO('ACME');
or even
UPDATE (SELECT * FROM FN_CLIENT_INFO('ACME')) SET SOMEVAL1 = 444 WHERE ID = 3;
I know that I can partially achieve this with a pipelined function, but this mechanism will need to be used by a reporting platform and if the reporting platform does something like
SELECT * FROM FN_CLIENT_INFO('ACME') WHERE SOMEVAL1 = 4
then I want it to run efficiently (assuming SOMEVAL1 has an index for example). This is where a macro would do well.
Macros seem like a good solution, but the above won't work due to protections put in place to prevent against SQL injection.
Is there a way to create a macro that somehow verifies that the passed in VARCHAR2 is a valid table name and therefore can be used or is there some other approach to address what I need?
I was thinking that if I had a function which could translate a client name to a DBMS_TF.TABLE_T then I could use a macro, but I haven't found a way to do that well.
A lesser-known method for such cases is to use a system-partitioned table. For instance, consider the following code:
Full example: https://dbfiddle.uk/UQsAgHCk
create table t_common(a int, b int)
partition by system (
partition ACME_INFO,
partition MEGAMART_INFO
);
insert into t_common partition(acme_info)
values(1,1);
insert into t_common partition(megamart_info)
values(2,2);
commit;
select * from t_common partition(acme_info);
select * from t_common partition(megamart_info);
As demonstrated, a common table can be used with different partitions for different clients, allowing it to be used as a regular table. We can create a system-partitioned table and utilize the exchange partition feature with older tables. Then, we can drop the older tables and create views with the same names, so that older code continues to work with views while all new code can work with the common table by specifying a partition.

Run 2 SETs in an Update Statement Oracle

Is it possible to update 2 columns in an Update statement that are in different tables? - The reason for the"scripted":
Where "Scripted" will be the "flag" so the formula does not run again on the same records if this field is filled in.
MERGE INTO arinvt_lot_docs ALD
USING
(SELECT arinvt.id,arinvt.class,fgmulti.in_date fgmulti.cuser3 FROM arinvt,fgmulti
WHERE arinvt.class LIKE 'CP%'
OR arinvt.class LIKE 'FG%'
OR arinvt.class LIKE 'IN%'
OR arinvt.class LIKE 'LA%'
OR arinvt.class LIKE 'PK%') Classes
ON (ALD.arinvt_id = classes.id
AND to_date(in_date) = '31-Dec-2015') --just picked a date to validate
WHEN MATCHED THEN
UPDATE SET non_conform_id = '21', fgmulti.cuser3 = 'SCRIPTED' --this text "Scripted" will fill in a field that will tell us in our reports if this was set by the script
I would like to join the tables using the arinvt.id field that is present in all 3 tables ARINVT_LOT_DOCS, FGMULTI & obviously ARINVT. ARINVT_LOT_DOCS & FGMULTI contain the NON_CONFROM_ID field that needs to be changed to '21'. The FGMULTI table also contains the CUSER3 field that would have "SCRIPTED" entered in it. The ARINVT table contains the Class of the inventory item which reflects in the conditions mentioned.
You cannot update two tables in one query in Oracle and other DBMS such as SQL Server but you can use transaction to achieve similar result.
This oracle community answers exactly that, if you try to join two tables, you will get this error
ORA-01776: cannot modify more than one base table through a join view
You can use transactions to update two tables in batch-like statement.
This https://stackoverflow.com/a/2044520 shows how to do it but for SQL Sever though. You need similar statement in Oracle.

How to use synonym of a DBlink in Oracle?

I have created a synonym for a dblink.
create synonym dblink2 for dblink1
But when I query anything using the synonym instead of the dblink, I'm getting connection description for remote database not found error.
SELECT * FROM DUAL#DBLINK2
How do I query using the synonym?Edit: I know that it'll work if I create a view of the table using dblink. But my requirement is the above question.
Unfortunately creation of synonyms for dblinks is not supported. If you read the documentation on synonyms, you will find that the permitted objects for synonyms are only:
Use the CREATE SYNONYM statement to create a synonym, which is an
alternative name for a table, view, sequence, procedure, stored
function, package, materialized view, Java class schema object,
user-defined object type, or another synonym.
The reason why your second query fails is that the synomym you have created is not functioning correctly. It is not being validated properly at creation time, and you can create any sort of incorrect synonyms like that. To verify, just test the following statement:
create synonym dblink3 for no_object_with_this_name;
You will still get a response like this:
*Synonym DBLINK3 created.*
But of course nothing will work via this synonym.
I don't see the point in creating a synonym for the dblink itself. Ideally you create the synonym for the remote table using the dblink.
CREATE DATABASE LINK my_db_link CONNECT TO user IDENTIFIED BY passwd USING 'alias';
CREATE SYNONYM my_table FOR remote_table#my_db_link;
Now, you could query the remote table using the synonym:
SELECT * FROM my_table;
I'm trying to think of the business issue that gets solved by putting a synonym on a db_link, and the only thing I can think of is that you need to deploy constant code that will be selecting from some_Table#some_dblink, and although the table names are constant different users may be looking across different db_links. Or you just want to be able to swap which db_link you are operating across with a simple synonym repoint.
Here's the problem: it can't be done that way. db_link synonyms are not allowed.
Your only solution is to have the code instead reference the tables by synonyms, and set private synonyms to point across the correct db_link. That way your code continues to "Select from REMOTE_TABLE1" and you just can flip which DB_LINK you are getting that remote table from.
Is it a pain to have to set/reset 100+ private synonyms? Yep. But if it is something you need to do often then bundle up a procedure to do it for you where you pass in the db_link name and it cycles through and resets the synonyms for you.
While I understand that this question is 3+ years old, someone might be able to benefit from a different answer in the future.
Let's imagine that I have 4 databases, 2 for production and 2 for dev / testing.
Prod DBs: PRDAPP1DB1 and PRDAPP2DB1
Dev DBs: DEVAPP1DB1 and DEVAPP2DB1
The "APP2" databases are running procedures to extract and import data from the APP1 databases. In these procedures, there are various select statements, such as:
declare
iCount INTEGER;
begin
insert into tbl_impdata1
select sysdate, col1, col2, substr(col3,1,10), substr(col3,15,3)
from tbl1#dblink2; -- Where dblink2 points to DEVAPP1DB1
...
<more statements here>
...
EXCEPTION
<exception handling code here>
end;
Now that is okay for development but the dblink2 constantly needs to be changed to dblink1 when deploying the updated procedure to production.
As it was pointed out, synonyms cannot be used for this purpose.
But instead, create the db links with the same name, different connection string.
E.g. on production:
CREATE DATABASE LINK "MyDBLINK" USING 'PRDAPP1DB1';
And on dev:
CREATE DATABASE LINK "MyDBLINK" USING 'DEVAPP1DB1';
And then in the procedures, change all "#dblink1" and "#dblink2" to "#mydblink" and it all should be transparent from there.
If you are trying to have the DB link accessible for multiple schemas (users) the answer is to create a public db link
example:
CREATE PUBLIC DATABASE LINK dblink1 CONNECT TO user IDENTIFIED BY password USING 'tnsalias';
After that any schema can issue a:
SELECT * FROM TABLE#dblink1

Oracle accessing multiple databases

I'm using Oracle SQL Developer version 4.02.15.21.
I need to write a query that accesses multiple databases. All that I'm trying to do is get a list of all the IDs present in "TableX" (There is an instance of Table1 in each of these databases, but with different values) in each database and union all of the results together into one big list.
My problem comes with accessing more than 4 databases -- I get this error: ORA-02020: too many database links in use. I cannot change the INIT.ORA file's open_links maximum limit.
So I've tried dynamically opening/closing these links:
SELECT Local.PUID FROM TableX Local
UNION ALL
----
SELECT Xdb1.PUID FROM TableX#db1 Xdb1;
ALTER SESSION CLOSE DATABASE LINK db1
UNION ALL
----
SELECT Xdb2.PUID FROM TableX#db2 Xdb2;
ALTER SESSION CLOSE DATABASE LINK db2
UNION ALL
----
SELECT Xdb3.PUID FROM TableX#db3 Xdb3;
ALTER SESSION CLOSE DATABASE LINK db3
UNION ALL
----
SELECT Xdb4.PUID FROM TableX#db4 Xdb4;
ALTER SESSION CLOSE DATABASE LINK db4
UNION ALL
----
SELECT Xdb5.PUID FROM TableX#db5 Xdb5;
ALTER SESSION CLOSE DATABASE LINK db5
However this produces 'ORA-02081: database link is not open.' On whichever db is being closed out last.
Can someone please suggest an alternative or adjustment to the above?
Please provide a small sample of your suggestion with syntactically correct SQL if possible.
If you can't change the open_links setting, you cannot have a single query that selects from all the databases you want to query.
If your requirement is to query a large number of databases via database links, it seems highly reasonable to change the open_links setting. If you have one set of people telling you that you need to do X (query data from a large number of tables) and another set of people telling you that you cannot do X, it almost always makes sense to have those two sets of people talk and figure out which imperative wins.
If we can solve the problem without writing a single query, then you have options. You can write a bit of PL/SQL, for example, that selects the data from each table in turn and does something with it. Depending on the number of database links involved, it may make sense to write a loop that generates a dynamic SQL statement for each database link, executes the SQL, and then closes the database link.
If you want need to provide a user with the ability to run a single query that returns all the data, you can write a pipelined table function that implements this sort of loop with dynamic SQL and then let the user query the pipelined table function. This isn't really a single query that fetches the data from all the tables. But it is as close as you're likely to get without modifying the open_links limit.

query from different oracle connections in sqldeveloper

I have 2 connections with different tables in sqldeveloper.
let's say:
ConnectionA with tables: A,B,C
ConnectionB with tables: D,E,F
Now I want to have a query that looks like this:
select aa.name,dd.id
from A aa,D dd;
How can i do this?
If you want to query objects in two different databases using a single SQL statement, you would need to create a database link between the two databases. A database link is an object that resides in the database and is independent of the query tool. In database A, for example, you could create the database link
CREATE DATABASE LINK to_b
CONNECT TO username IDENTIFIED BY password
USING tns_alias_on_a_pointing_to_b
And then when you connect to A, you could do something like
SELECT aa.name, dd.id
FROM a aa,
d#to_b dd
WHERE aa.some_key = dd.some_key
Apparently TOAD Data Point supports Cross-Connection Queries , see:
http://dev.toadfordataanalyst.com/webhelp/Content/Query_Builder/Create_CrossConnection_Queries.htm
Also Oracle SQL Developer seems to support something similar. (see this blog post: Cross Connection Queries)
I found this helpful and to the point of the OP question for Oracle 11g rel 2 and later: http://www.dba-oracle.com/t_how_create_database_link.htm . Basically, right-click on the connection in the Connections pane in SQL Developer, click Properties, and you get the hostname, port, and service name that you can plug into the "USING" part of the CREATE DATABASE LINK statement. Whether you put in Service Name or SID I assume depends on which you used in your connection. example:
create public database link
mylink
connect to
remote_username
identified by
mypassword
using 'myserver:1521/MYSID';

Resources