I'm trying to do the same exercise for both SQLite and Oracle. In SQLite, there is a table sqlite_master containing a description of all of the other tables, indexes, triggers, and views that are contained within the database. I can see the query to generate sqlite_master with .schema sqlite_master.
In Oracle, the data dictionary is presented to us in the form of a number of views (DBA, ALL or USER). Let's take the table USER_TABLES as an example. We can do query on USER_TABLES, for example
SELECT table_name
FROM USER_TABLES;
Is there anyway to get the query used to create the table USER_TABLES in Oracle? I tried
SELECT dbms_metadata.get_ddl('TABLE', 'USER_TABLES')
FROM dual;
but it does not work.
I am not sure what are you looking for but if you want the definition of any table in oracle you can use :
Describe TableName
Or if you want to have list of tables, views or columns you can use below queries:
For Tables :
select * from select * from all_tables
For Columns :
select * from all_tab_columns
For Views :
select * from select * from all_views
To get all the column information of a table:
select *
from all_tab_columns
where upper(table_name) = upper('Test')
order by column_id
Typically oracle stores table_name in uppercase so I used upper() or you can just type 'TEST'
You could use this one:
DECLARE
DDL CLOB;
BEGIN
FOR aTab IN (SELECT TABLE_NAME FROM USER_TABLES) LOOP
DDL := DBMS_METADATA.GET_DDL('TABLE', aTab.TABLE_NAME);
DBMS_OUTPUT.PUT_LINE(DDL);
END LOOP;
END;
You may customize the output with DBMS_METADATA.SET_TRANSFORM_PARAM() before you run the query.
Related
For Microsoft SQL Server I have following statement to only drop a column if the table exist.
IF EXISTS(SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TEST_TABLE')
ALTER TABLE TEST_TABLE DROP COLUMN LEGACY_VALUE
GO
I was wondering if there was a related IF-EXISTS mechanism is present in Oracle.
All the metadata about the columns in Oracle Database is accessible using one of the following views.
user_tab_cols; -- For all tables owned by the user
all_tab_cols ; -- For all tables accessible to the user
dba_tab_cols; -- For all tables in the Database.
So, if you are looking for a column that exists and want to drop it, your code may look something like this ( see below).
Since this appears to be a one time task, is the effort really worth it?
DECLARE
v_column_exists number := 0;
BEGIN
Select count(*) into v_column_exists
from user_tab_cols
where upper(column_name) = 'LEGACY_VALUE''
and upper(table_name) = 'TEST_TABLE';
--and owner = 'SCOTT --*might be required if you are using all/dba views
if (v_column_exists = 1) then
execute immediate 'alter table test_table drop column legacy_value';
end if;
end;
/
This question already has answers here:
Querying an Oracle Database with Dynamic Table names
(1 answer)
dynamic table name without using cursors
(1 answer)
dynamic table name in cursor
(2 answers)
dynamic table name in select statement
(4 answers)
Closed 2 years ago.
without going into details - the tools we use for performance test, it spits out several tables (name changes with every new run) with different type of data. One table has list of all the table names and data type.
I am going to use oracle table as an example so it can be easily explained.
What I am wanting to do...
Query all_table like:
QueryA:
select table_name from all_tables where table_name like 'HZ_CUST_%'
Result will say: Table_name = 'HZ_CUST_ACCOUNTS'
Query using the QueryA result like:
Select * from [QUERYA_RESULT] WHERE creation_date > sysdate, account_number between '500000' and '599999'
I got something like this but not quite sure how to do this.
declare variable TABLE_NAME CHAR(10);
SELECT TABLE_NAME into :V_NAME from all_tables WHERE TABLE_NAME LIKE 'HZ_CUST_ACCOUNTS';
select *
from :V_NAME;
Thank you for the help.
The easiest solution for your problem given what you have expressed in the comment section is to use DYNAMIC SQL
declare
v_table_name varchar2(130);
v_sql clob;
begin
-- get the table name
select table_name into v_table_name from all_tables where table_name like 'HZ_CUST_%' ;
-- Build dynamic statement
v_sql := ' select * from '||v_table_name||' where creation_date > sysdate
and account_number between ''500000'' and ''599999'' ';
execute immediate v_sql;
end;
/
From this small version, you can expand this code to whatever you need to do, specialy with the output. Of course, depending on what you need to do with it. I could for example store the maximum value of a field based on this same sentence.
declare
v_table_name varchar2(130);
v_sql clob;
vmaxvalue pls_integer;
begin
-- get the table name
select table_name into v_table_name from all_tables where table_name like 'HZ_CUST_%' ;
-- Build dynamic statement
v_sql := ' select max(table_field) from '||v_table_name||' where creation_date > sysdate
and account_number between ''500000'' and ''599999'' ';
execute immediate v_sql into vmaxvalue;
end;
/
I don't believe you need for your case to use PTF ( Polymorphic Table Functions ) which are intended to evolve the concept of pipeline functions. However, as you did explain very well what you intent to do with the result of the query, you might want to have a look at them. Check this very good example of PTF ( Remember Oracle 18c or higher ).
Polymorphic Table Functions
I want to write a stored procedure that grabs all of the tables in a schema that have a column called "ID" , once I have those tables I want to output the counts of unique IDs within each table.
ex.
table1
table2
Output:
I have the latter portion implemented but the first part I'm having difficulties with. Here's my script so far:
create or replace PROCEDURE get_id_counts
IS
BEGIN
FOR table_n in (SELECT * FROM dba_tables) LOOP
EXECUTE IMMEDIATE 'SELECT ID, COUNT(*) FROM MySchema.' || table_n.table_name || ' GROUP BY ID';
END LOOP;
END;
/
execute get_id_counts;
Currently I receive the error : "%s: invalid identifier", I assume this is caused by the fact that not all of the tables in the schema have the column "ID"
Assuming that your database is Oracle
Use the dba_tab_columns to get only those which has ID column
So extend your query from
SELECT * FROM dba_tables
to
SELECT * FROM dba_tables where table_name in (select table_name from dba_tab_columns where column_name = 'ID');
I am trying to derive a table with counts from multiple tables. The tables are not on my schema. The table names on the schema that I am interested in all start with 'STAF_' and end with '_TS'. The criteria i am looking for is where SEP = 'MO'. So for example, the query in its base form is:
select area, count(SEP) areacount
from mous.STAF_0001_TS
where SEP = 'MO'
group by area;
I have about 1000 tables that i'd like to do this for.
Ultimatly, I'd like the output to be a table on my schema that looks like the following:
area| areacount
0001| 3
0002| 7
0003| 438
Thank you.
As a first step I'd write an SQL query that generates an SQL query:
SELECT 'SELECT area, count(*) FROM '||c.table_name||'UNION ALL' as run_me
FROM all_tables c
WHERE c.table_name LIKE 'STAF\_%\_MS' escape '\'
Running this will produce an output that is another SQL query. Copy the result text out of your results grid and paste it back into your query pane. Delete the final UNION ALL and run it
Once you dig how to write an SQL query that generate an SQL query, you can look at turning it into a view, or creating a dynamic query in a string.
Gotta say, this is a horrible way to store data; you'd be better off using ONE table with an extra column containing whatever is in xxx of STAF_xxx_MS right now
In Oracle 12c, you can embed a FUNCTION that will query the number of rows in any given table. Then you can use that function in your main query. Here is an example:
WITH FUNCTION cnt ( p_owner VARCHAR2, p_table_name VARCHAR2 ) RETURN NUMBER IS
l_cnt NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT count(*) INTO :cnt FROM ' || p_owner || '.' || p_table_name INTO l_cnt;
RETURN l_cnt;
EXCEPTION WHEN OTHERS THEN
RETURN NULL; -- This will happen for entries in ALL_TABLES that are not directly accessible (e.g., IOT overflow tables)
END cnt;
SELECT t.owner, t.table_name, cnt(t.owner, t.table_name)
FROM all_tables t
where t.table_Name like 'STAF\_%\_MS' escape '\';
Is there a way to select a field from a table and if that field doesn't exist then select a different field from the same table? example:
SELECT MY_FIELD from MY_TABLE
error: "MY_FIELD": invalid identifier
is there any way to check if it exists and if it does then use that field for the query, if it doesn't exist then use example:
SELECT my_field2 from client.
My problem is
I am writing a report that will be used on two databases, but the field names on occasion can be named slightly different depending on the database.
What you really need to do is talk to your management / development leads about why the different databases are not harmonized. But, since this is a programming site, here is a programming answer using dynamic SQL.
As has been pointed out, you could create views in the different databases to provide yourself with a harmonized layer to query from. If you are unable to create views, you can do something like this:
create table test ( present_column NUMBER );
insert into test select rownum * 10 from dual connect by rownum <= 5;
declare
l_rc SYS_REFCURSOR;
begin
BEGIN
OPEN l_rc FOR 'SELECT missing_column FROM test';
EXCEPTION
WHEN others THEN
OPEN l_rc FOR 'SELECT present_column FROM test';
END;
-- This next only works in 12c and later
-- In earlier versions, you've got to process l_rc on your own.
DBMS_SQL.RETURN_RESULT(l_rc);
end;
This is inferior to the other solutions (either harmonizing the databases or creating views). For one thing, you get no compile time checking of your queries this way.
That won't compile, so - I'd say not. You might try with dynamic SQL which reads contents of the USER_TAB_COLUMNS and create SELECT statement on-the-fly.
Depending on reporting tool you use, that might (or might not) be possible. For example, Apex offers (as reports's source) a function that returns query, so you might use it there.
I'd suggest a simpler option - create views on both databases which have unified column names, so that your report always selects from the view and works all the time. For example:
-- database 1:
create view v_client as
select client_id id,
client_name name
from your_table;
-- database 2:
create view v_client as
select clid id,
clnam name
from your_table;
-- reporting tool:
select id, name
from v_client;
This can be done in a single SQL statement using DBMS_XMLGEN.GETXML, but it gets messy. It would probably be cleaner to use dynamic SQL or a view, but there are times when it's difficult to create supporting objects.
Sample table:
--Create either table.
create table my_table(my_field1 number);
insert into my_table values(1);
insert into my_table values(2);
create table my_table(my_field2 number);
insert into my_table values(1);
insert into my_table values(2);
Query:
--Get the results by converting XML into rows.
select my_field
from
(
--Convert to an XMLType.
select xmltype(clob_results) xml_results
from
(
--Conditionally select either MY_FIELD1 or MY_FIELD2, depending on which exists.
select dbms_xmlgen.GetXML('select my_field1 my_field from my_table') clob_results
from user_tab_columns
where table_name = 'MY_TABLE'
and column_name = 'MY_FIELD1'
--Stop transformations from running the XMLType conversion on nulls.
and rownum >= 1
union all
select dbms_xmlgen.GetXML('select my_field2 my_field from my_table') clob_results
from user_tab_columns
where table_name = 'MY_TABLE'
and column_name = 'MY_FIELD2'
--Stop transformations from running the XMLType conversion on nulls.
and rownum >= 1
)
--Only convert non-null values.
where clob_results is not null
)
cross join
xmltable
(
'/ROWSET/ROW'
passing xml_results
columns
my_field number path 'MY_FIELD'
);
Results:
MY_FIELD
--------
1
2
Here's a SQL Fiddle if you want to see it running.