SQL query help - find table in unknown schema and query data - sql

I have a couple of simple queries I run manually in Oracle as sysdba to check the version info for a java application. The tricky part is that the schema names vary, so sometimes I have to search for the table to find the owner/schema and then query the info.
Is there a way to take the output from one query and use it to perform a schema-qualified query, so it can be automated?
The queries I use are:
SELECT username FROM dba_tables WHERE table_name LIKE 'APPVERSDATA%';
SELECT max(appfullversion) from SCHEMA.APPVERSDATA;
There must be a way to pass the name of the schema from the first query as a variable to the second query?
Edit: Ultimately I would like to set the output as a variable in shell script.
TIA

I assume that SCHEMA.APPVERSDATA would be the output of the first query so the best thing to do might be execute some PL/SQL as a store function or procedure:
DECLARE
l_schema varchar2(10);
BEGIN
SELECT DISTINCT owner
INTO l_schema
FROM dba_tables
WHERE table_name LIKE 'APPVERSDATA%';
EXECUTE IMMEDIATE 'SELECT max(appfullversion) from ' || l_schema || '.APPVERSDATA';
end;
/
This doesn't address what you are going to do with the data once it executes though. Update the question and I'll update the answer.
Edit(Version 2!):
So your shell would look something like this:
x () {
sqlplus -s u/p<<EOF
set serveroutput on;
set feedback off;
DECLARE
l_schema varchar2(10);
BEGIN
SELECT DISTINCT owner
INTO l_schema
FROM dba_tables
WHERE table_name LIKE 'APPVERSDATA%';
EXECUTE IMMEDIATE 'SELECT max(appfullversion) from ' || l_schema || '.APPVERSDATA';
dbms_output.put_line(l_return);
end;
/
EOF
}
echo $(x $1)

Related

How to convert every Table from a specific User to JSON Format using the "trick" provided by SQL Developer

I want to convert all tables from a specific user to JSON (or XML) Format. I've read about a "trick" mentioned by SQL Developer.
In other words, I already started to create a Procedure with two parameters:
p_format: The format (in my case it will be "json")
p_user: The username
As IDE I use Oracle SQL Developer and my database is an Oracle XE Database.
At first the procedure loops though all tables of the given user and in the loop, it should execute the following:
SELECT /*p_format*/ * FROM p_user || '.' || table
Unfortunately, I cannot use this SELECT Statement as mentioned above. I need to use the command EXECUTE IMMEDIATE <Statement>.
The next problem I faced was the following: I wanted to output the result of the EXECUTE IMMEDIATE command. Therefore I used the command EXECUTE IMMEDIATE <Statement> INTO <Variable>. After compiling the procedure and executing it, I stumpled across the following Error:
"inconsistent datatypes: expected %s got %s"
This is my code of the procedure:
CREATE OR REPLACE PROCEDURE EXPORT_TABLE_TO_FORMAT_FROM(p_format VARCHAR2, p_user VARCHAR2) IS
/***************************************************************************
Author:
Class:
School:
Date:
Function - EXPORT_TABLE_TO_JSON_FROM(p_user):
Displays the data of every table from a given User as JSON
Parameter: p_user ... User
***************************************************************************/
v_tableData VARCHAR2(32767);
v_sqlStatement VARCHAR2(200);
BEGIN
FOR tablerec IN (SELECT *
FROM ALL_TABLES
WHERE OWNER = p_user)
LOOP
v_sqlStatement := 'SELECT /*' || p_format || '*/ * FROM ' || p_user || '.' || tablerec.TABLE_NAME;
EXECUTE IMMEDIATE v_sqlStatement INTO v_tableData;
DBMS_OUTPUT.PUT_LINE (v_sqlStatement);
END LOOP;
END;
You can see that I loop though all tables of a given user and created a sql statement with p_format and p_user and with tablerec.TABLE_NAME.
The desired result should look exactly like that:
{"results":[{"columns":[{"name":"COUNTRY_ID","type":"CHAR"},
{"name":"COUNTRY_NAME","type":"VARCHAR2"},{"name":"REGION_ID","type":"NUMBER"}],"items":
[
{"country_id":"AR","country_name":"Argentina","region_id":2},
{"country_id":"AU","country_name":"Australia","region_id":3},
{"country_id":"BE","country_name":"Belgium","region_id":1},
{"country_id":"BR","country_name":"Brazil","region_id":2},
{"country_id":"CA","country_name":"Canada","region_id":2},
{"country_id":"CH","country_name":"Switzerland","region_id":1},
{"country_id":"CN","country_name":"China","region_id":3},
{"country_id":"DE","country_name":"Germany","region_id":1},
{"country_id":"DK","country_name":"Denmark","region_id":1},
{"country_id":"EG","country_name":"Egypt","region_id":4},
{"country_id":"FR","country_name":"France","region_id":1},
{"country_id":"IL","country_name":"Israel","region_id":4},
{"country_id":"IN","country_name":"India","region_id":3},
{"country_id":"IT","country_name":"Italy","region_id":1},
{"country_id":"JP","country_name":"Japan","region_id":3},
{"country_id":"KW","country_name":"Kuwait","region_id":4},
{"country_id":"ML","country_name":"Malaysia","region_id":3},
{"country_id":"MX","country_name":"Mexico","region_id":2},
{"country_id":"NG","country_name":"Nigeria","region_id":4},
{"country_id":"NL","country_name":"Netherlands","region_id":1},
{"country_id":"SG","country_name":"Singapore","region_id":3},
{"country_id":"UK","country_name":"United Kingdom","region_id":1},
{"country_id":"US","country_name":"United States of America","region_id":2},
{"country_id":"ZM","country_name":"Zambia","region_id":4},
{"country_id":"ZW","country_name":"Zimbabwe","region_id":4}]}]}
The JSON hint is specific to SQL Developer and SQLcl, not the database directly. So you need to run the entire thing within these tools.
Easiest way to do that is to have your script write a script that you can then run, eg
spool /tmp/get_all_json.sql
select 'select /*json*/ * from '||table_name||';'
from user_tables;
spool off
#/tmp/get_all_json.sql

Create script to drop several tables (PostgreSQL)

I want to create a script that detect and drop the public tables in my posgresql database...
The request I build is the following :
SELECT CONCAT('DROP TABLE ', table_schema,'.',table_name,';') AS stmt FROM information_schema.TABLES
WHERE table_schema='public' AND table_catalog='capsana'
Here is a screenshot of the output I got
I want now to execute the commands (in the stmt column) in an automatic way .. without doing copy paste !
Is there any way to do that ?
You can use dynamic sql to do this;
DO $$
DECLARE
drop_stmt text;
BEGIN
FOR drop_stmt IN
SELECT CONCAT('DROP TABLE ', table_schema,'.',table_name) AS stmt
FROM information_schema.TABLES
WHERE table_schema='public' AND table_catalog='capsana' LOOP
EXECUTE drop_stmt;
END LOOP;
END$$;

variable as column name in where clause in Oracle PL/SQL

I am working on PL/SQL code where I need to perform a select query using variable as column name in where clause. Column names are stored in a table as varchar and I am using a loop to pass those column names to my select statement.
Please find sample code segment I am trying to run:
set serveroutput on;
declare
var varchar2(100);
counter number;
begin
var:='description';
select count(*)
into counter
from nodetable
where var like '%Ship%';
dbms_output.put_line(counter);
end;
Output:
anonymous block completed
0
However the result should be 86.
Oracle is comparing last condition as two string and not column=string.
Please let me know if this is even feasible in oracle or if there is a workaround for it.
Regards
Ankit
You have to use dynamic SQL, preferrably with bind-variables:
EXECUTE IMMEDIATE
'select count(*) from nodetable where '||var||' like :p1'
INTO counter
USING '%Ship%';
Try this
declare
var varchar2(100);
counter number;
begin
var:='description';
EXECUTE IMMEDIATE
'select count(*)
into counter
from nodetable
where '||var||' like ''%Ship%'' ';
dbms_output.put_line(counter);
end;
You need to be carefull with the colon's (').
I agreed with previous answer in implementation, but i strictly recommend you to change your technical requirements, because you can't use bind variables for this, and it's potential place for injection. For example, if someone will edit value in your table which stores column names, to something like that: "description = inject_function or description". Then your dynamic sql block will execute this statement:
select count(*) from nodetable where description = inject_function or description like '%Ship%
and example implementation of function
create function inject_function
return varchar2
is pragma autonomous_transaction;
begin
delete * from most_important_table;
commit;
return to_char(null);
exception when others then
rollback;
return to_char(null);
end;

Oracle - Performing operation on each row of result set

I need help with a query. The query returns a column of all the views in the database. My ultimate goal is to have the whole result set be one column containing all the views in the database, and the other column containing how many records/rows are present in each corresponding table.
This:
SELECT DISTINCT OWNER,
OBJECT_NAME
FROM DBA_OBJECTS
WHERE OBJECT_TYPE = 'VIEW'
AND OWNER = 'ADMIN'
returns the first column however I can't seem to find a way to combine it with :
select count(*) from view_X
to get the second column of the result set.
Any help would be appreciated.
Thanks
With some XML magic, this can be done with a single statement:
select object_name as view_name,
to_number(extractvalue(xmltype(dbms_xmlgen.getxml('select count(*) c from "'||owner||'"."'||object_name||'"')),'/ROWSET/ROW/C')) as row_count
from dba_objects
where object_type = 'VIEW'
and owner = 'ADMIN'
order by 1;
Ed Gibbs has provided a comprehensive answer.
I have the following solution for what you are looking for.
SET serveroutput ON;
DECLARE
x INTEGER;
BEGIN
FOR i IN (SELECT 'ADMIN' AS owner, object_name
FROM all_objects
WHERE object_type = 'VIEW'
AND owner = 'ADMIN') LOOP
EXECUTE IMMEDIATE ('SELECT count(*) FROM ' || i.object_name) INTO x;
dbms_output.put_line (i.owner || ' | ' || i.object_name || ' | ' || x);
END LOOP;
END;
/
This is a toughie. You can't join to the select count(*) from view_X or anything like that using straight SQL, so the best thing I can think of is a function that takes a view name and returns its count:
CREATE OR REPLACE FUNCTION ViewRowCount(viewName VARCHAR2) RETURN NUMBER
AS
rowCount NUMBER := 0;
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || viewName INTO rowCount;
RETURN rowCount;
END;
/
Once the function is in place you can call it from your query:
SELECT DISTINCT OWNER,
OBJECT_NAME,
ViewRowCount(OBJECT_NAME)
FROM DBA_OBJECTS
WHERE OBJECT_TYPE = 'VIEW'
AND OWNER = 'ADMIN';
BTW, I don't think you need the DISTINCT for this query, but I don't have DBA access today so I can't be sure. The record counting will be slow enough as it is, so if there are duplicates before filtering with DISTINCT there will be a count for every duplicate row, making it even slower.
Also take a look at Rachcha's solution, which doesn't need to create a new object (the function) like mine does. If you'll be calling from a front-end you'll need to use something like my answer, but if you'll be calling from SQL*Plus Rachcha's will work very well.
Take at cursors in Oracle. They let you loop over a result set. Once you do that, you can dynamically execute sql of the form:
EXECUTE IMMEDIATE 'select ''' || OBJECT_NAME || ''' count(*) FROM ' || OBJECT_NAME'
for each view in your list.

Oracle | drop table

I want to drop certain tables in a tablespace that has common name appended to end of each table for an example:
TABLE1_NAME1_COMMON
TABLE2_NAME2_COMMON
TABLE3_NAME3_COMMON
I heard about Oracle functions but I'm not familiar much with those so I'm expecting some helping hand.
Thanks.
If you're completely sure what you're doing, ie, if you're sure that you don't accidentally drop a table that you don't want to drop, you can do a:
set serveroutput on size 1000000
begin
for r in (
select table_name
from user_tables
where table_name like '%\_COMMON' escape '\')
loop
execute immediate 'drop table ' || r.table_name;
end loop;
exception when others then
dbms_output.put_line(sqlerrm);
end;
/
Edit:
Changed Now selecting from user_tables instead of dba_tables as it seems more safe to do.
Added set serveroutput on in order for dbms_output.put_line to be printed
Added begin .. exception .. end in order for errors to be shown.
You could do that in a procedure, but it might be better to just select those DROP-statements, review them and execute them manually:
SELECT 'DROP TABLE ' || table_name || ';'
FROM user_tables
WHERE table_name LIKE '%\_COMMON' ESCAPE '\';
would return
DROP TABLE TABLE1_NAME1_COMMON;
DROP TABLE TABLE2_NAME2_COMMON;
DROP TABLE TABLE3_NAME3_COMMON;
to identify them you can use:
SELECT * FROM user_tables WHERE tablespace_name='MySpace' AND table_name like '%COMMON';
You could then either, derive your DROP statements using a SELECT. Or you could write a PL/SQL function to loop through the "Common Tables" and DROP them using EXECUTE IMMEDIATE.
I would make sure you are 100% sure in the selections first however.