In my table i don't have a column but i want to use in where condition is it possible or not - sql

Suppose i have two database having same table name but columns name(empno,employee_no) are different so, i want to use single query in both of the table query is given below but i want in a single query.
In where condition i have mention there two different column is it possible or not to write in a single query.
select ename
from emp
where empno = '1234'---- in 1st databse
select ename
from emp
where employee_no = '5678' ---- in 2nd database
I want to execute a single query in both database which have two different column of empno and employee_no.
Can anyone please help with same.

One simple method is:
Create view in both the database with same name and same alias for empno and employee_no.
--In first db
CREATE VIEW MY_TAB_V AS
SELECT EMPNO AS ENO,
...
FROM MY_TAB;
--In second db
CREATE VIEW MY_TAB_V AS
SELECT EMPLOYEE_NO AS ENO,
...
FROM MY_TAB;
Now, you will be able to execute following query in both the databases:
Select * from MY_TAB_V where ENO=1234;
Create a simple view so that you will be able to even update the tables using that view.
Cheers!!

It is possible to have a dynamic SQL statement that queries different columns depending on what is available, by combining DBMS_XMLGEN.GETXML with the data dictionary. However, this solution is weird, slow, and buggy, and should be a last resort. It's usually better to put this level of dynamicism in an application or a PL/SQL block.
--Conditional select on EMP depending on which column exists.
--
--Convert XML to regular values.
select extractvalue(xml, '/ROWSET/ROW/ENAME') empname
from
(
--Convert to XMLType.
--(This is nontrivial because NULL must be handled oddly.)
select
case when xml is null then
xmltype('<?xml version="1.0"?><ROWSET><ROW><ENAME></ENAME></ROW></ROWSET>')
else xmltype(xml)
end xml
from
(
--Get dynamic result as XML.
select dbms_xmlgen.getxml('select ename from emp where '||column_name||' = 1234') xml
from dba_tab_columns
where owner = user
and table_name = 'EMP'
and column_name in ('EMPNO', 'EMPLOYEE_NO')
)
);
Use these commands to test the statement:
drop table emp;
create table emp(ename varchar2(100), empno number);
insert into emp values ('asdf', 1234);
commit;
<run the above SELECT>
drop table emp;
create table emp(ename varchar2(100), employee_no number);
insert into emp values ('qwer', 1234);
commit;
<run the above SELECT>

Related

Oracle Object : How to show all the fields in select query?

I have the following Oracle Object :
CREATE TYPE person_typ AS OBJECT (
Id NUMBER,
first_name VARCHAR2(20),
last_name VARCHAR2(25));
And a table :
CREATE TABLE MyTable (
contact person_typ,
contact_date DATE );
I would like to make a select query to show all the fields of the Person_Typ object without specifiying their names.
When I do
select * from MyTable
The column contact is shown as [unsupported data type], I have to use instead :
select T.contact.ID, T.contact.First_name, T.contact.last_name from MyTable T
Is there another way to show the values of the object without specifying the column names ?
Thanks,
Cheers,
I don't use SQL Developer, but according to this article Showing TYPE’d Column Values in SQL Developer you could use option:
Preferences / Database / Advanced / Display Struct Value in Grid
Also you can query user_type_attr (or all_type_attr) to obtain column names. Then copy/paste select part from output and run it or create view as proposed by #sep. Here is my test data and code block:
insert into mytable values (person_typ(1, 'Paulina', 'Thomson'), date '2017-12-17');
insert into mytable values (person_typ(7, 'Keanu', 'Stevens'), date '2017-12-28');
declare
v_sql varchar2(32000);
begin
select listagg('T.CONTACT.'||attr_name||' '||attr_name, ', ')
within group (order by attr_no)
into v_sql
from user_type_attrs
where type_name = 'PERSON_TYP';
v_sql := 'SELECT '||v_sql||' FROM MYTABLE T';
dbms_output.put_line(v_sql);
execute immediate 'CREATE OR REPLACE VIEW VW_CONTACTS AS '||v_sql;
end;
select * from vw_contacts;
Result:
ID FIRST_NAME LAST_NAME
------ -------------------- -------------------------
1 Paulina Thomson
7 Keanu Stevens
I had the same problem and I created a view with all the fields. In your case:
CREATE VIEW v_myTable AS
select T.contact.ID, T.contact.First_name, T.contact.last_name
from MyTable T
and use the view instead of the table
SELECT * from v_myTable

Is it possible to duplicate all values in a table while updating one or more columns

I have a table with many columns, and what I would like to do is duplicate all of the rows in the table, but also update one of the columns to a new value.
For example lets say I have the table below. I want to add to my table a duplicate of each row, except instead of BASIC access, it will have 'ADVANCED':
Before:
NAME, GENDER, ACCESS
----------------------
STEVE, MALE, BASIC
MOLLY, FEMALE, BASIC
After
NAME, GENDER, ACCESS
----------------------
STEVE, MALE, BASIC
MOLLY, FEMALE, BASIC
STEVE, MALE, ADVANCED
MOLLY, FEMALE, ADVANCED
Is there a way to do this without specifying all columns? I have 60 columns in the table, and the structure can change (meaning columns may be added, removed, renamed, etc).
Is it possible in Oracle SQL to automate this?
Just use insert . . . select:
insert into t (name, gender, access)
select name, gender, 'ADVANCED'
from t;
You need to list all the columns. You can shorten the manual process by using a query to generate the list. If you had to do this a lot and always knew you were leaving out access and access is the last column, you could use a view:
create view v_t as
select . . . -- all but access
from t;
insert into t ( . . . )
select v.*, 'ADVANCED'
from v_t;
Or you could use dynamic SQL to generate the statement.
However, I don't recommend any of those. Instead I would be concerned about a data model where you are regularly adding and modifying the columns in a table. That sounds dangerous.
Without specifying all the columns? With some help of a "temporary" table, here's how:
Your current table:
SQL> create table test
2 (name varchar2(10),
3 gender varchar2(20),
4 caccess varchar2(20));
Table created.
SQL> insert into test
2 select 'steve', 'male', 'basic' from dual union all
3 select 'molly', 'female', 'basic' from dual;
2 rows created.
Create a "temporary" table as a copy of the "original" table
update column you want to modify
copy the whole "temporary" table to the "original"
drop the "temporary" table
SQL> create table test_temp as select * From test;
Table created.
SQL> update test_temp set caccess = 'advanced';
2 rows updated.
SQL> insert into test select * From test_temp;
2 rows created.
SQL> drop table test_Temp;
Table dropped.
SQL> select * From test;
NAME GENDER CACCESS
---------- -------------------- --------------------
steve male basic
molly female basic
steve male advanced
molly female advanced
SQL>
Apparently, that works, but - what if the original table is huge? It takes a lot of space, and its copy takes approximately twice as much. Why are you doing that, anyway?
Try below method with anonymous block to avoid listing columns in insert statements
CREATE TABLE ACCESS_CHN
(NAAME VARCHAR2(100),
GENDER VARCHAR2(20),
ACCCESS VARCHAR2(30))
INSERT into ACCESS_CHN values('STEVE','MALE','BASIC');
INSERT into ACCESS_CHN values('MOLLY','FEMALE','BASIC');
COMMIT;
DECLARE
column_list varchar2(2000):=NULL;
plsql_block VARCHAR2(1000);
BEGIN
select LISTAGG(column_name,',') within group (order by column_id)
into column_list
from user_tab_columns
where table_name='ACCESS_CHN';
plsql_block := 'CREATE TABLE ACCESS_CHN_BKP as select '|| column_list || ' from ACCESS_CHN';
EXECUTE IMMEDIATE plsql_block;
plsql_block := 'UPDATE ACCESS_CHN_BKP set ACCCESS=''ADVANCED'' ';
EXECUTE IMMEDIATE plsql_block;
COMMIT;
plsql_block := 'CREATE TABLE ACCESS_CHN_FINAL as select * from ACCESS_CHN
union all
select * from ACCESS_CHN_BKP';
EXECUTE IMMEDIATE plsql_block;
END;
--To rerun drop tables ACCESS_CHN_BKP and ACCESS_CHN_FINAL

If the first field doesn't exists in a table then look at a different field in the same table

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.

how to get table name from column value in oracle sql?

I have a main table that has two columns with table names and id's. And I have those tables with table names in my DB.
For example, I find particular table name, selecting id. And then I want to populate table with that name with data. And I want to do that in one query. How I can do that?
The goal: to populate with data all tables at once, that has the names that similar with values in table name column from main table.
That is how I'm getting the list of tables. I should probably loop through it.
select tbl from asp_tbl where asp in (
select id from (
SELECT * FROM DIMENSION WHERE EXTERNALKEY LIKE 'W16%')
);
And then I will try to merge the data from other tables inside the table that needs to be populated:
MERGE INTO tbl d
USING
(SELECT ? nums, ? names from data_table) s
ON(d.product = s.product and d.ga = s.ga and d.metric_id = s.metric_id)
WHEN MATCHED THEN UPDATE SET d.names = s.names
WHEN NOT MATCHED THEN INSERT (nums, names)values(s.nums,s.names);
Did I provide enough info?
As I understand you need some stored procedure witch may fulfil a table with some test data. If so you may write something like:
create procedure fulfil_test_data (p_table_name varchar2) is
begin
for x IN (select tbl from asp_tbl where asp in (
SELECT table_id FROM DIMENSION WHERE EXTERNALKEY LIKE p_table_name )) loop
execute immediate 'insert into '|| x.tbl ||' (nums, names)
select level , chr(ascci(''A'') + mod(level,26)) from dual connect by level < 1001';
end loop;
end;
/
And call it
begin
fulfil_test_data('W16%');
end;
/

Procedure to insert data from one column into two columns in another table

I'm trying to get a procedure that will allow me to get data from a column and insert it into two different columns in a different table. the first table currently has both first and last name in a single column. I have another table with first name and last name in different columns and I need to separate and insert them from Column1/Table1 into the two columns in Table2 preferably using a procedure since I have a lot of names to migrate.
Column1(Name) in Table 1 looks like this
NAME
First_Name1 Last_name1
First_Name2 Last_Name2
First_Name3 Last_Name3
And I need the data to be separated like this in Table2 as FName/LName using the data from the first table:
F_Name | L_Name
First_Name1|Last_Name1
First_Name2|Last_Name2
First_Name3|Last_Name3
I figured out how to get the data from the last and the first name separated using SUBSTR and INSTR, but I can't figure out how to put this inside a Procedure, or how to Loop it since I want to use it for several rows.
select substr(staff.name, 0, instr(staff.name, ' ')-1) as Fname
from staff;
select substr(staff.name, instr(staff.name,' ')+1) as Lname
from Staff;
Any ideas/Help? Thanks guys.
Building a Looping PL/SQL Based DML Cursor For Multiple DML Targets
A PL/SQL Stored Procedure is a great way to accomplish your task. An alternate approach to breaking down your single name field into FIRST NAME and LAST NAME components could be to use an Oracle Regular Expression, as in:
SELECT REGEXP_SUBSTR('MYFIRST MYLAST','[^ ]+', 1, 1) from dual
-- Result: MYFIRST
SELECT REGEXP_SUBSTR('MYFIRST MYLAST','[^ ]+', 1, 2) from dual
-- Result: MYLAST
A procedure based approach is a good idea; first wrap this query into a cursor definition. Integrate the cursor within a complete PL/SQL stored procedure DDL script.
CREATE or REPLACE PROCEDURE PROC_MYNAME_IMPORT IS
-- Queries parsed name values from STAFF (the source) table
CURSOR name_cursor IS
SELECT REGEXP_SUBSTR(staff.name,...) as FirstName,
REGEXP_SUBSTR(... ) as LastName
FROM STAFF;
BEGIN
FOR i IN name_cursor LOOP
--DML Command 1:
INSERT INTO Table_One ( first_name, last_name )
VALUES (i.FirstName, i.LastName);
COMMIT;
--DML Command 2:
INSERT INTO Table_Two ...
COMMIT;
END LOOP;
END proc_myname_import;
As you can see from the example block, a long series of DML statements can take place (not just two) for a given cursor record and its values as it is handled by each loop iteration. Each field may be referenced by the name assigned to them within the cursor SQL statement. There is a '.' (dot) notation where the handle assigned to the cursor call is the prefix, as in:
CURSOR c1 IS
SELECT st.col1, st.col2, st.col3
FROM sample_table st
WHERE ...
Then the cursor call for looping through the main record set:
FOR my_personal_loop IN c1 LOOP
...do this
...do that
INSERT INTO some_other_table (column_one, column_two, column_three)
VALUES (my_personal_loop.col1, my_personal_loop.col2, ...);
COMMIT;
END LOOP;
... and so on.
This should work for you.
insert into newtable(FirstName, LastName)
select substr(staff.name, 0, instr(staff.name, ' ') - 1),
substr(staff.name, instr(staff.name, ' ') + 1)
from staff;