How to convert semicolon separated column into a row in Oracle? - oracle

Source Table: EMP_LOCATION
NAME LOCATION
-------------------------------
SMITH NY;CA;IL;GA
JAMES MO;AZ;RI
FORD NJ
SCOTT TX;VA;WA;NH
MARTIN MD;CT
Required Output:
NAME LOCATION
-------------------
FORD NJ
JAMES AZ
JAMES MO
JAMES RI
MARTIN CT
MARTIN MD
SCOTT NH
SCOTT TX
SCOTT VA
SCOTT WA
SMITH CA
SMITH GA
SMITH IL
SMITH NY

Some people will ask you to show some code, but when I needed this I spent a lot of time creating a function then I realize that I could do it with a connect by. So what you need is this:
SELECT name, REGEXP_SUBSTR (location, '[^;]+', 1, LEVEL) AS location
FROM emp_location
CONNECT BY
LEVEL <= LENGTH(REGEXP_REPLACE (location, '[^;]*')) + 1
GROUP BY name, REGEXP_SUBSTR (location, '[^;]+', 1, LEVEL)
ORDER BY name

Related

What is the use of + in oracle join [duplicate]

This question already has answers here:
Difference between Oracle's plus (+) notation and ansi JOIN notation?
(8 answers)
Is there an Oracle official recommendation on the use of explicit ANSI JOINs vs implicit joins?
(2 answers)
Closed 17 days ago.
What is meant by + sign right after column name while join in oracle .
Example :
select a,d,f,c
From table1, table 2
Where table1.x(+) = table2.y:
The (+) is used to indicate an outer join. It is placed on the side where the row in the table may be missing. That is old Oracle syntax I have known since Oracle 7. Presently, even Oracle encourages using ANSI syntax for joins.
That's the old Oracle's outer join operator.
Old:
SQL> SELECT d.deptno, d.dname, e.ename
2 FROM dept d, emp e
3 WHERE e.deptno (+) = d.deptno
4 ORDER BY d.deptno, e.ename;
DEPTNO DNAME ENAME
---------- -------------- ----------
10 ACCOUNTING CLARK
10 ACCOUNTING KING
10 ACCOUNTING MILLER
20 RESEARCH ADAMS
20 RESEARCH FORD
20 RESEARCH JONES
20 RESEARCH SCOTT
20 RESEARCH SMITH
30 SALES ALLEN
30 SALES BLAKE
30 SALES JAMES
30 SALES MARTIN
30 SALES TURNER
30 SALES WARD
40 OPERATIONS
15 rows selected.
Nowadays, we do it as
SQL> SELECT d.deptno, d.dname, e.ename
2 FROM dept d LEFT JOIN emp e ON e.deptno = d.deptno
3 ORDER BY d.deptno, e.ename;
DEPTNO DNAME ENAME
---------- -------------- ----------
10 ACCOUNTING CLARK
10 ACCOUNTING KING
10 ACCOUNTING MILLER
20 RESEARCH ADAMS
20 RESEARCH FORD
20 RESEARCH JONES
20 RESEARCH SCOTT
20 RESEARCH SMITH
30 SALES ALLEN
30 SALES BLAKE
30 SALES JAMES
30 SALES MARTIN
30 SALES TURNER
30 SALES WARD
40 OPERATIONS
15 rows selected.
SQL>

Why break command didnt work in sql oracle?

I need to make a job application report, I need to produce a table where the duplicated job_id and job_name will be removed from the table
And I actually want to compute total applicants who apply for the job and then I need to get remaining job vacancies (no_of_vacancies - count()) and get the percentage by (count()/no_of_vacancies*100)
Applicant ID
Job ID
Job Name
No of Vacancies
Remaining Job Vacancies
Percentage(%)
A0001
Clinical Specialist
J0001
30
24
20
A0072
A0076
but I could only get this
Applicant ID
Job ID
Job Name
No of Vacancies
Remaining Job Vacancies
Percentage(%)
A0001
Clinical Specialist
J0001
30
29
3
A0072
Clinical Specialist
J0001
30
29
3
A0076
Clinical Specialist
J0001
30
29
3
The duplicated job id and name, no of vacancies and remaining vacancies is still there, and the percentage they shown is incorrect too
Here's the code:
SET pagesize 30
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY';
ACCEPT v_jobID CHAR FORMAT 'A5' PROMPT ' Enter job id: '
COLUMN job_id FORMAT A12 HEADING "Job ID";
COLUMN job_name FORMAT A20 HEADING "Job Name";
COLUMN applicant_id FORMAT A12 HEADING "Applicant ID";
COLUMN no_of_vacancies FORMAT 999 HEADING "No of Vacancies";
COLUMN Remaining_Job_Vacancies FORMAT 999 HEADING "Remaining Job Vacancies";
COLUMN Percentage FORMAT 999 HEADING "Percentage(%)";
BREAK on J.job_id on job_name skip2 on no_of_vacancies, Remaining_Job_Vacancies, Percentage;
COMPUTE number LABEL 'Total Applicants' ON A.applicant_id;
TTITLE CENTER 'Job Application Report for ' _DATE -
RIGHT 'Page No: ' FORMAT 999 SQL.PNO SKIP 2
SELECT A.applicant_id, J.job_id, job_name, no_of_vacancies, (no_of_vacancies - count(*)) AS Remaining_Job_Vacancies, (count(*)/no_of_vacancies*100) AS Percentage
FROM applicant A, job J, application AP
WHERE A.applicant_id = AP.applicant_id
AND AP.job_id = J.job_id
AND J.job_id LIKE '&v_jobID'
GROUP BY A.applicant_id , J.job_id, job_name, no_of_vacancies
ORDER BY J.job_id;
--CLEAR COLUMNS
--TTITLE OFF
That's because you don't break on table_alias.column_name
BREAK on J.job_id
--
^
|
this
but only on column name (or its alias):
BREAK on job_id
I don't have your tables nor data, so I'll use Scott's sample schema to illustrate it.
This is what you did:
SQL> break on e.deptno
SQL>
SQL> select e.deptno, e.ename from emp e order by e.deptno;
DEPTNO ENAME
---------- ----------
10 CLARK
10 KING
10 MILLER
20 JONES
20 FORD
20 ADAMS
20 SMITH
20 SCOTT
30 WARD
30 TURNER
30 ALLEN
30 JAMES
30 BLAKE
30 MARTIN
14 rows selected.
This is what you should have done:
SQL> break on deptno
SQL>
SQL> select e.deptno, e.ename from emp e order by e.deptno;
DEPTNO ENAME
---------- ----------
10 CLARK
KING
MILLER
20 JONES
FORD
ADAMS
SMITH
SCOTT
30 WARD
TURNER
ALLEN
30 JAMES
BLAKE
MARTIN
14 rows selected.
SQL>

Self table comparison

I Have a table emp which has
ename sal
Smith 1000
Mark 2000
Jack 500
The output should be(person earning lower salary on the left)
Jack Smith
Jack Mark
Smith Mark
Please help
Seems like a cross join with a filter.
select h1.ename as first, h2.ename as second
from have as h1
cross join have as h2
where h1.sal>h2.sal

Retrieve data based on condition oracle apex

I have the following question:
I would like to display all users who have similar names to a specified user.
To do this, I first fetched the data of the specified user and store them in page items.
In the second step, I have created a classic report and would like to list all users here who have a similar name.
How can I say that, for example, only the beginning of the value of this page item must be the same?
If "similarity" means "match first several letters", then you'd
select ...
from table_of_users u
where substr(:P1_USER_NAME, 1, 3) = substr(u.user_name, 1, 3) --> match first 3 letters
However, maybe you'd want to consider another approach and use UTL_MATCH package. For example (cross (self) join of Scott's EMP table):
SQL> SELECT a.ename,
2 b.ename,
3 UTL_MATCH.jaro_winkler_similarity (a.ename, b.ename) similarity
4 FROM emp a CROSS JOIN emp b
5 ORDER BY similarity DESC
6 /
ENAME ENAME SIMILARITY
---------- ---------- ----------
SMITH SMITH 100
MILLER MILLER 100
ALLEN ALLEN 100
FORD FORD 100
JAMES JAMES 100
<snip>
JAMES JONES 76
JONES JAMES 76
JAMES ADAMS 73
CLARK BLAKE 73
BLAKE CLARK 73
<snip>
SCOTT MARTIN 45
JAMES MARTIN 41
MARTIN JAMES 41
TURNER ALLEN 41
ALLEN TURNER 41
FORD JAMES 0
FORD MILLER 0
MILLER WARD 0
MILLER SCOTT 0
<snip>
In your example, that would be e.g.
select ...
from table_of_users u
where utl_match.jaro_winkler_similarity(:P1_USER_NAME, u.user_name) > 80; -- match more than 80%

Oracle where clause outer join

I am having trouble understanding how to do an outer join using the where clause for a particular query. I can accomplish the join using the JOIN keyword. The query I am trying to accomplish is:
-- display a list of all books in the books table. if a book has been ordered by a customer also list the corresponding order number and state the customer is from
here is the table structure
desc customers
Name Null Type
--------- -------- ------------
CUSTOMER# NOT NULL NUMBER(4)
LASTNAME NOT NULL VARCHAR2(10)
FIRSTNAME NOT NULL VARCHAR2(10)
ADDRESS VARCHAR2(20)
CITY VARCHAR2(12)
STATE VARCHAR2(2)
ZIP VARCHAR2(5)
REFERRED NUMBER(4)
REGION CHAR(2)
EMAIL VARCHAR2(30)
desc orders
Name Null Type
---------- -------- ------------
ORDER# NOT NULL NUMBER(4)
CUSTOMER# NUMBER(4)
ORDERDATE NOT NULL DATE
SHIPDATE DATE
SHIPSTREET VARCHAR2(18)
SHIPCITY VARCHAR2(15)
SHIPSTATE VARCHAR2(2)
SHIPZIP VARCHAR2(5)
SHIPCOST NUMBER(4,2)
desc orderitems
Name Null Type
-------- -------- ------------
ORDER# NOT NULL NUMBER(4)
ITEM# NOT NULL NUMBER(2)
ISBN VARCHAR2(10)
QUANTITY NOT NULL NUMBER(3)
PAIDEACH NOT NULL NUMBER(5,2)
desc books
Name Null Type
-------- -------- ------------
ISBN NOT NULL VARCHAR2(10)
TITLE VARCHAR2(30)
PUBDATE DATE
PUBID NUMBER(2)
COST NUMBER(5,2)
RETAIL NUMBER(5,2)
DISCOUNT NUMBER(4,2)
CATEGORY VARCHAR2(12)
using join I can get it to display what I believe is the correct results with the following:
SELECT b.title, c.state, order#
FROM customers c JOIN orders o USING (customer#)
JOIN orderitems oi USING (order#)
RIGHT OUTER JOIN books b USING (isbn);
TITLE STATE ORDER#
------------------------------ ----- ----------
HOW TO GET FASTER PIZZA
THE WOK WAY TO COOK
REVENGE OF MICKEY MI 1012
REVENGE OF MICKEY GA 1019
REVENGE OF MICKEY WA 1009
REVENGE OF MICKEY TX 1014
BODYBUILD IN 10 MINUTES A DAY FL 1003
HANDCRANKED COMPUTERS MI 1012
SHORTEST POEMS GA 1005
PAINLESS CHILD-REARING GA 1001
PAINLESS CHILD-REARING NJ 1004
PAINLESS CHILD-REARING FL 1016
PAINLESS CHILD-REARING MI 1012
PAINLESS CHILD-REARING GA 1011
COOKING WITH MUSHROOMS WY 1020
COOKING WITH MUSHROOMS ID 1008
COOKING WITH MUSHROOMS FL 1003
COOKING WITH MUSHROOMS WA 1000
COOKING WITH MUSHROOMS WA 1009
COOKING WITH MUSHROOMS FL 1018
COOKING WITH MUSHROOMS NJ 1015
HOLY GRAIL OF ORACLE TX 1007
BUILDING A CAR WITH TOOTHPICKS
BIG BEAR AND LITTLE DOVE FL 1017
BIG BEAR AND LITTLE DOVE TX 1007
BIG BEAR AND LITTLE DOVE MI 1012
DATABASE IMPLEMENTATION IL 1002
DATABASE IMPLEMENTATION TX 1007
DATABASE IMPLEMENTATION FL 1003
DATABASE IMPLEMENTATION WY 1013
DATABASE IMPLEMENTATION FL 1018
DATABASE IMPLEMENTATION NJ 1010
HOW TO MANAGE THE MANAGER GA 1001
E-BUSINESS THE EASY WAY TX 1007
E-BUSINESS THE EASY WAY FL 1006
35 rows selected
this is what I have tried for my where clause join:
-- using where clause
SELECT b.title, c.state, oi.order#
FROM customers c, orders o, orderitems oi, books b
WHERE c.customer# = o.customer#
AND o.order# = oi.order#
AND oi.isbn(+) = b.isbn;
but when I do this query I get the following
TITLE STATE ORDER#
------------------------------ ----- ----------
BODYBUILD IN 10 MINUTES A DAY FL 1003
REVENGE OF MICKEY GA 1019
REVENGE OF MICKEY TX 1014
REVENGE OF MICKEY MI 1012
REVENGE OF MICKEY WA 1009
DATABASE IMPLEMENTATION FL 1018
DATABASE IMPLEMENTATION WY 1013
DATABASE IMPLEMENTATION NJ 1010
DATABASE IMPLEMENTATION TX 1007
DATABASE IMPLEMENTATION FL 1003
DATABASE IMPLEMENTATION IL 1002
COOKING WITH MUSHROOMS WY 1020
COOKING WITH MUSHROOMS FL 1018
COOKING WITH MUSHROOMS NJ 1015
COOKING WITH MUSHROOMS WA 1009
COOKING WITH MUSHROOMS ID 1008
COOKING WITH MUSHROOMS FL 1003
COOKING WITH MUSHROOMS WA 1000
HOLY GRAIL OF ORACLE TX 1007
HANDCRANKED COMPUTERS MI 1012
E-BUSINESS THE EASY WAY TX 1007
E-BUSINESS THE EASY WAY FL 1006
PAINLESS CHILD-REARING FL 1016
PAINLESS CHILD-REARING MI 1012
PAINLESS CHILD-REARING GA 1011
PAINLESS CHILD-REARING NJ 1004
PAINLESS CHILD-REARING GA 1001
BIG BEAR AND LITTLE DOVE FL 1017
BIG BEAR AND LITTLE DOVE MI 1012
BIG BEAR AND LITTLE DOVE TX 1007
HOW TO MANAGE THE MANAGER GA 1001
SHORTEST POEMS GA 1005
32 rows selected
Here is a link to the sql that will build the structure if needed https://www.dropbox.com/s/7tpbpz1hbufj3qn/JLDB_Build_8.sql
I am having a hard time figuring out what I am doing wrong/different with the where clause join. Any help or direction is appreciated.
Thanks.
when using joins I recommend to do explicit left/right joins. For example..
Select A.*, B.*, C.*
from TableA A
left outer join TableB B
on A.field1 = B.fkfield1
and A.field2 0 B.fkfield2
...
left outer join TableC C
on A.field1 = C.fkfield1
and A.field2 0 C.fkfield2
...
In this case, the Table A records will be matched with the ones on Table B. If thereĀ“s no match on table B, then the columns from table B will be null. The second joins works loke the first one, this case will also show null if there is no matching value from field1 (on table A) in the Table C, fkfield1.
On the other hand, if you need to match all the records of the second table insteade of the first you need to do a "inner join". Just replace "left outer join" with "inner join" in the example above.
Thanks!
#leo
Try this:
SELECT b.title, o.state, o.order#
FROM books b
, (select o.order#, oi.isbn, o.customer#, c.state
from orders o, orderitems oi, customers c
where o.order# = oi.order#
and c.customer# = o.customer#
) o
WHERE
AND o.isbn(+) = b.isbn;
I found this after lots more digging
this is from http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries006.htm
If A and B are joined by multiple join conditions, then you must use
the (+) operator in all of these conditions. If you do not, then
Oracle Database will return only the rows resulting from a simple
join, but without a warning or error to advise you that you do not
have the results of an outer join.
The (+) operator does not produce an outer join if you specify one
table in the outer query and the other table in an inner query.
I was able to get it working with the following:
SELECT b.title, c.state, o.order#
FROM customers c, orders o, orderitems oi, books b
WHERE c.customer#(+) = o.customer#
AND o.order#(+) = oi.order#
AND oi.isbn(+) = b.isbn;

Resources