How to perform union on table when table consists of different column name but datatype is same? - oracle

How do I perform union on two tables, when table consists of different column name but datatype is the same. Table1(id, name, location) and table2(id, name, address). Here location(varchar) and address(varchar).
I have tried the following but it returns like this when I run the query:
Query :
SELECT id, name, location, null as address FROM T1
union
SELECT id, name, address, null as location FROM T2;
**output** :
ID NAME LOCATION ADDRESS
1 1 AA NED NULL
2 2 BB AUB NULL
3 2 BB MUN NULL
4 3 CC PUNE NULL
but I need output like below :
ID NAME LOCATION ADDRESS
1 1 AA NED NULL
2 2 BB AUB NULL
3 2 BB NULL MUN
4 3 CC NULL PUNE

The way I see it:
SELECT id, name, location, null as address FROM T1
union
SELECT id, name, null as location, address FROM T2;

Related

How to filter and retrieve the results after a Specific characters from stored procedure in oracle plsql?

I have a column "Names" in the "Employee" table that has following values. The values either contain only single name (first, last, username) or Multiple names separated with semicolon (;). I need to search the values from that table either by first name or last name or username.
I have created a procedure but it is fetching only 1st,4th,5th records. Please let me know how to retrieve 2nd and 3rd records as well.
Firstname and lastname can be given by user with minimum of 2 characters length.
Username is given entire.
Employee:
ID Name Title
1 Andrea Warbutton (awr01) Manager
2 Claire Taylor (cta02);Mark Kites (mak03);Anitha Rooney (anr06) HOD;Supervisor;Business
3 Dave Rites (dar12);Jessica Simpson (jesi10) Lead;Analyst
4 Nick Ken (nik56) Product (Local,Regional)
5 Claire Pilkington (cpt09) Sales Owner
Code:
Create or replace empl (pm_firstname varchar2(100),
pm_lastname varchar2(100),
pm_username varchar2(100))
BEGIN
Select * from Employee
where Upper(Name) like Upper(pm_firstname ||'%'||) -- this will fetch 1st,4th,5th record
OR Upper(SUBSTR(Name, INSTR(Name),' '+1)) like Upper(pm_lastname ||'%'||) -- this will fetch 1st,4th,5th record
OR upper(REGEXP_SUBSTR(Name,'\((.+)\)',1,1,NULL,1)) = Upper(pm_username); -- -- this will fetch 1st,4th,5th record
END;
End empl ;
Please let me know how to retrieve 2nd and 3rd records as well.
Desired Output:
When searched with firstname = "Andrea", the output is below
ID Name Title
1 Andrea Warbutton (awr01) Manager
When searched with firstname = "Claire", the output is below
ID Name Title
2 Claire Taylor (cta02) HOD
5 Claire Pilkington (cpt09) Sales Owner
When searched with lastname = "Simps", the output is below
ID Name Title
3 Jessica Simpson (jesi10) Analyst
When searched with username = "mak03", the output is below
ID Name Title
2 Mark Kites (mak03) Supervisor
When searched with username = "nik56", the output is below
ID Name Title
4 Nick Ken (nik56) Product (Local,Regional)
with
x as (select id, name, '"'||replace(name, ';', '","')||'"' xml from employee),
n as (select id, name, column_value as cv from x, xmltable(xml))
select id,
trim(regexp_substr(cv, '(\S*)(\s)')) fname,
trim(regexp_substr(cv, '(\S*)(\s)', 1, 2)) lname,
regexp_substr(cv, '\((.+)\)', 1, 1, NULL, 1) uname
from n
Your task would be much easier if you normalize these data. Above query outputs:
ID FNAME LNAME UNAME
1 Andrea Warbutton awr01
2 Claire Taylor cta02
2 Mark Kites mak03
2 Anitha Rooney anr06
3 Dave Rites dar12
3 Jessica Simpson jesi10
4 Nick Ken nik56
5 Claire Pilkington cpt09
demo
Now you can search first, last, usernames however you want. First expression finds first word, then second and word between brackets.
Edit:
I posted the table structure with just ID and Name columns. However, I
have Titles column also in the same format separated with (semicolon).
In this case, How can I Normalize Titles as well along with Names
This query worked for provided examples:
with
x as (select id, name, '"'||replace(name, ';', '","')||'"' xmln,
'"'||replace(title, ';', '","')||'"' xmlt
from employee),
n1 as (select id, trim(xn.column_value) nm, rownum rn from x, xmltable(xmln) xn),
n2 as (select id, trim(xt.column_value) tt, rownum rn from x, xmltable(xmlt) xt)
select id, trim(regexp_substr(nm, '(\S*)(\s)')) fname,
trim(regexp_substr(nm, '(\S*)(\s)', 1, 2)) lname,
regexp_substr(nm, '\((.+)\)', 1, 1, NULL, 1) uname,
tt title
from n1 join n2 using (id, rn)
dbfiddle demo
Be careful however, because we cannot write ideal query. If you have entries like Benicio Del Toro, Mary Jo Catlett, Jean Claude Van Damme, it's impossible to write correct regexp. Sometimes second word is part of lastname, sometimes it is firstname, middlename etc.
The proper way is to modify table structure, divide rows, check results and put correct values in correct name columns. Now you have lists which are hard to search and every method may return wrong results.
No need for PL/SQL.
SQL> with temp as
2 (select id,
3 regexp_substr(name, '[^;]+', 1, column_value) name
4 from employee cross join
5 table(cast(multiset(select level from dual
6 connect by level <= regexp_count(name, ';') + 1
7 ) as sys.odcinumberlist))
8 )
9 select id, name
10 from temp
11 where instr(name, '&search_for_name') > 0;
Enter value for search_for_name: Claire
ID NAME
---------- ------------------------------
2 Claire Taylor (cta02)
5 Claire Pilkington (cpt09)
SQL> /
Enter value for search_for_name: mak03
ID NAME
---------- ------------------------------
2 Mark Kites (mak03)
SQL>
What does it do?
temp CTE splits semi-colon separated values into rows
final query uses a simple instr function which detects whether "rows" (extracted previously) contain value you're looking for
If it must be a function, that code can be reused. As you didn't say what exactly (which datatype, I mean) you want to return, I returned a string.
SQL> create or replace function f_search (par_what in varchar2)
2 return sys.odcivarchar2list
3 is
4 retval sys.odcivarchar2list;
5 begin
6 with temp as
7 (select id,
8 regexp_substr(name, '[^;]+', 1, column_value) name
9 from employee cross join
10 table(cast(multiset(select level from dual
11 connect by level <= regexp_count(name, ';') + 1
12 ) as sys.odcinumberlist))
13 )
14 select id ||' - '|| name
15 bulk collect into retval
16 from temp
17 where instr(name, par_what) > 0;
18
19 return retval;
20 end;
21 /
Function created.
SQL> select * from table(f_search('Andrea'));
COLUMN_VALUE
--------------------------------------------------------------------------------
1 - Andrea Warbutton (awr01)
SQL> select * from table(f_search('Claire'));
COLUMN_VALUE
--------------------------------------------------------------------------------
2 - Claire Taylor (cta02)
5 - Claire Pilkington (cpt09)
SQL>

display multiple column records in one column in oracle

I have Table having following columns in Oracle;
ID NIC NTN MBL NAME
---------------------------------------
1 1234512 ABC
2 321 XYZ
3 5421 POI
4 541245 624
I need to display like this in select query
ID NIC/NTN/MBL NAME
1 1234512 ABC
2 321 XYZ
3 5421 POI
4 541245 // taking first value
I was trying to do with
SELECT
A.ID,
"CNIC/NTN/MBL"
A.NAME,
A.REASON
B.NAME
FROM TABLEA A
INNER JOIN TABLEB B ON A.R_ID = B.R_ID
UNPIVOT INCLUDE NULLS
(
CNIC/NTN/MBL FOR cols IN (A.NIC, A.NTN, A.MBL)
)
but unable to do.
Use COALESCE:
SELECT
ID,
COALESCE(NIC, NTN, MBL) AS "NIC/NTN/MBL",
NAME
FROM yourTable;
This should work because in the call to COALESCE above, I list the three columns from left to right, and the first non NULL value will be retained.
You need the COALESCE function (which simply returns the first non-null value in the specified inputs, reading from left to right), like so:
WITH your_table AS (SELECT 1 ID, 1234512 nic, NULL ntn, NULL mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 2 ID, NULL nic, 321 ntn, NULL mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 3 ID, NULL nic, NULL ntn, 5421 mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 4 ID, 541245 nic, 624 ntn, NULL mbl, 'ABC' NAME FROM dual)
SELECT ID,
COALESCE(nic, ntn, mbl) nic_ntn_mbl,
NAME
FROM your_table;
ID NIC_NTN_MBL NAME
---------- ----------- ----
1 1234512 ABC
2 321 ABC
3 5421 ABC
4 541245 ABC

Order by: Special characters before ABC

I have this sql:
SELECT -1 AS ID, '(None)' AS NAME
FROM TABLE_1 WHERE ID=1
UNION
SELECT ID, NAME
FROM TABLE_2
ORDER BY 2
Table data:
ID | NAME
1 | Direct
2 | Personal
3 | Etc
So if i execute this sql in Oracle 10 it returns these:
Result:
ID | NAME
1 | Direct
3 | Etc
-1 | (None)
2 | Personal
How is it possible to sort the "(None)" always to the top?
If i use
' (None) ' as Name
instead of
'(None)' as Name
It works, because the space before the (None), but that is not a solution.
You can add a dummy column ORDER_COL and then order on that column
select ID, NAME from
(
SELECT -1 AS ID, '(None)' AS NAME, 1 as ORDER_COL FROM TABLE_1 WHERE ID=1
UNION
SELECT ID, NAME, 2 as ORDER_COL FROM TABLE_2
)
order by ORDER_COL, NAME;
Try this. NULLS LAST is the default for ascending order in Oracle. make it NULLS FIRST for '(None)'. Also, use UNION ALL as UNION removes duplicates and is less efficient.
SELECT *
FROM (
SELECT -1 AS ID
,'(None)' AS NAME
FROM TABLE_1
WHERE ID = 1
UNION ALL
SELECT ID
,NAME
FROM TABLE_2
)
ORDER BY CASE
WHEN NAME = '(None)'
THEN NULL
ELSE NAME -- or id if you want
END NULLS FIRST;

Counting null dates in Oracle

I have a question with null dates in Oracle
I've got a table like this:
ID DATE
1 '02/08/2015'
1 NULL
1 '02/06/2014'
2 NULL
2 '06/02/2013'
This is just an example of the real table. Now what I need is something like this:
ID DAY_INAC
1 1
2 1
I mean, I need to count only the null values present in the DATE column.
But when I execute my query
Select id, count(date)
from table
where date is null
group by Id
having count(date)>0
As a result I'm getting nothing. What do I need to with the date value in order to generate the corresponding counting.
Regards
Because your query is already filtering by date is null, you just need to use count(*)
Select id, count(*)
from table
where date is null
group by Id
having count(*) > 0
COUNT does not count NULL values. You can use CASE to change them:
Select id, count(CASE WHEN date IS NULL THEN 1 END) AS DAY_INAC
from table
where date is null
group by Id;
LiveDemo
Please do not name column as datatypes. Otherwise you may need to quote them.
A more condensed query:
Select id, count(nvl2(date_column,null, sysdate)) as cnt
from table
group by Id;
COUNT will not count NULL values - instead get it to count a literal value (i.e. 1) for those rows that are NULL:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( ID, "DATE" ) AS
SELECT 1, DATE '2015-08-02' FROM DUAL
UNION ALL SELECT 1, NULL FROM DUAL
UNION ALL SELECT 1, DATE '2014-06-02' FROM DUAL
UNION ALL SELECT 2, NULL FROM DUAL
UNION ALL SELECT 2, DATE '2013-02-06' FROM DUAL
Query 1:
SELECT id,
COUNT(1)
FROM table_name
WHERE "DATE" IS NULL
GROUP BY id
Results:
| ID | COUNT(1) |
|----|----------|
| 1 | 1 |
| 2 | 1 |

Select tree by leaf in Oracle Database

There is hierarchical queries in Oracle, using CONNECT BY PRIOR. Everybody knows, how to select children by parent, but I need to select parent by child.
Here is my table:
ID PID NAME TYPE
1 null EARTH PLANET
2 1 USA COUNTRY
3 2 CALIFORNIA STATE
4 3 Los_Angeles CITY
5 3 San_Francisco CITY
6 3 San_Diego CITY
In my app I have ID of San_Diego, and I need to know, in what country San_Diego is? I need to get USA (TYPE=COUNTRY) with my query? How to select it with oracle hierarchical structures?
Hierarchy means, that one row of a table is a "parent", and another one - a "child". PRIOR is used to show who is who. Clause CONNECT BY PRIOR EMPNO = MGR means, that if two rows have the same value, but one row in a column EMPNO, and the second - in a column MGR, then second is a "parent" and first is a "child". So, query
SELECT EMPNO,ENAME,MGR,LEVEL
FROM TMP_PCH
CONNECT BY PRIOR EMPNO = MGR
START WITH MGR = 'John'
returns all subordinates of John (and John itself), and query
SELECT EMPNO,ENAME,MGR,LEVEL
FROM TMP_PCH
CONNECT BY PRIOR MGR = EMPNO
START WITH MGR = 'John'
returns all bosses of John (and John itself).
You need to create correct condition for connect by and start with leaf 'San Diego':
select name
from (
select * from test
connect by id = prior pid
start with name='San_Diego')
where type='COUNTRY'
SQL Fiddle demo
SELECT * FROM places_table
WHERE type = 'COUNTRY'
START WITH id = 6 -- San Diego
CONNECT BY PRIOR pid = id;
There's no difference, you just have to use PRIOR in the parent side. For example to get the tree for the city of San Diego:
WITH your_table AS (
SELECT 1 id, NULL pid, 'EARTH' name, 'PLANET' type FROM dual
UNION
SELECT 2 id, 1 pid, 'USA' name, 'COUNTRY' type FROM dual
UNION
SELECT 3 id, 2 pid, 'CALIFORNIA' name, 'STATE' type FROM dual
UNION
SELECT 4 id, 3 pid, 'Los_Angeles' name, 'CITY' type FROM dual
UNION
SELECT 5 id, 3 pid, 'San_Francisco' name, 'CITY' type FROM dual
UNION
SELECT 6 id, 3 pid, 'San_Diego' name, 'CITY' type FROM dual
)
SELECT id, name, level
FROM your_table
CONNECT BY id = PRIOR pid
START WITH id = 6
If you just wanted to get the country, you could filter by level:
WITH your_table AS (
SELECT 1 id, NULL pid, 'EARTH' name, 'PLANET' type FROM dual
UNION
SELECT 2 id, 1 pid, 'USA' name, 'COUNTRY' type FROM dual
UNION
SELECT 3 id, 2 pid, 'CALIFORNIA' name, 'STATE' type FROM dual
UNION
SELECT 4 id, 3 pid, 'Los_Angeles' name, 'CITY' type FROM dual
UNION
SELECT 5 id, 3 pid, 'San_Francisco' name, 'CITY' type FROM dual
UNION
SELECT 6 id, 3 pid, 'San_Diego' name, 'CITY' type FROM dual
)
SELECT id, name, level
FROM your_table
WHERE LEVEL = 3
CONNECT BY id = PRIOR pid
START WITH id = 6

Resources