Why does Create table show ORA-00957: duplicate column name - oracle

Does anyone know why this select statement on this query runs just fine but when i add cte as in front of the same select statement it gives this error:
SQL Error: ORA-00957: duplicate column name)
CREATE TABLE t1 AS
SELECT *
FROM NS_F3
LEFT JOIN NS_FA2
ON NS_F3.PI_CANDIDATE_NUM = NS_FA2.PI_CANDIDATE_NUM
WHERE REGEXP_LIKE(NS_F3.TITLE, 'intern($|ship|[^a-z])', 'i');

It is because tables NS_F3 and NS_FA2 contain columns with the same name - in that case, you should use column alias to avoid duplicate column names.
Here's an example: I'm creating a simple table, as extract of several columns from Scott's EMP table:
SQL> create table t_first as select deptno, empno, ename from emp where rownum < 5;
Table created.
Join it to DEPT table:
SQL> select * from t_first e join dept d on e.deptno = d.deptno;
DEPTNO EMPNO ENAME DEPTNO DNAME LOC
---------- ---------- ---------- ---------- -------------- -------------
20 7369 SMITH 20 RESEARCH DALLAS
20 7566 JONES 20 RESEARCH DALLAS
30 7521 WARD 30 SALES CHICAGO
30 7499 ALLEN 30 SALES CHICAGO
^^^^^^^^^ ^^^^^^^^
this is DEPTNO column ... ... and here's another one
As long as it works in SELECT, it won't work in CREATE TABLE:
SQL> create table test as
2 select * from t_first e join dept d on e.deptno = d.deptno;
select * from t_first e join dept d on e.deptno = d.deptno
*
ERROR at line 2:
ORA-00957: duplicate column name
The solution is to use a column alias, such as:
SQL> create table test as
2 select e.deptno emp_deptno, --> first alias
3 e.empno,
4 e.ename,
5 d.deptno, dept_deptno --> second alias
6 d.dname,
7 d.loc
8 from t_first e join dept d on e.deptno = d.deptno;
Table created.
SQL> select * From test;
EMP_DEPTNO EMPNO ENAME DEPT_DEPTNO DNAME LOC
---------- ---------- ---------- ----------- -------------- -------------
20 7369 SMITH 20 RESEARCH DALLAS
20 7566 JONES 20 RESEARCH DALLAS
30 7521 WARD 30 SALES CHICAGO
30 7499 ALLEN 30 SALES CHICAGO
SQL>

Related

Comparing Performance in Oracle

I would like to compare two SQL statements which produce the same result. For example
SELECT
id, name,
(SELECT street || ' ' || town from addresses WHERE addresses.id=customers.addressid) AS address
FROM customers;
-- vs
SELECT
id, name,
street || ' ' || town AS address
FROM customers c LEFT JOIN addresses a ON c.id=a.customerid;
Here I want to compare the performance of the subquery compared to using a join. I know about the other advantages and disadvantages of subqueries and joins, but I’m more interested in comparing their performance.
How can I do a performance comparison? Is there some sort of timing test?
Is there some sort of timing test?
Yes, in SQL*Plus, do it as
SQL> set timing on
and then run queries, each of them several times (to avoid caching issues) and compare time needed for each query to complete. Note that on small data sets you won't notice any difference, so - whichever you use, it'll be OK.
SQL> select e.deptno, (select d.dname from dept d where d.deptno = e.deptno) dname, e.ename
2 from emp e
3 where e.deptno = 20;
DEPTNO DNAME ENAME
---------- -------------- ----------
20 RESEARCH SMITH
20 RESEARCH JONES
20 RESEARCH SCOTT
20 RESEARCH ADAMS
20 RESEARCH FORD
Elapsed: 00:00:00.04
SQL> select e.deptno, d.dname, e.ename
2 from emp e join dept d on e.deptno = d.deptno
3 where e.deptno = 20;
DEPTNO DNAME ENAME
---------- -------------- ----------
20 RESEARCH SMITH
20 RESEARCH JONES
20 RESEARCH SCOTT
20 RESEARCH ADAMS
20 RESEARCH FORD
Elapsed: 00:00:00.03
SQL>
Other than that, did you compare explain plans? Did you collect statistics on tables and indexes (and do it regularly)? Are there any indexes (should be on columns used in joins, most probably)?

Solutions for outer join operator (+) not allowed in operand like OR or IN

I have tried the following query but I still get this error and I am not able to find a solution to resolve it. I want to be able to get one of the three dates (LOAD,LAST_MODIFIED,ORDER_ITEM_LAST_UPDATE) according to the situation. However, I need also to use the actual calendar date to use a specific column inside. It is why I do the join (+) with the LOAD_DATE. Now, I try to find a way not to get the error ORA-01719, Someone can help me?
ORA-01719: outer join operator (+) not allowed in operand of OR or IN
01719. 00000 - "outer join operator (+) not allowed in operand of OR or IN"
*Cause: An outer join appears in an or clause.
*Action: If A and B are predicates, to get the effect of (A(+) or B),
try (select where (A(+) and not B)) union all (select where (B)).
Error at Line: 17 Column: 35
CODE:
SELECT A.PRODUCT_ID AS KEY,
TO_CHAR(A.ORDER_DATE, 'MM/DD/YYYY') AS ORDER_CREATION_DATE,
TO_CHAR(B.LOAD_DATE, 'MM/DD/YYYY') AS LOAD_DATE,
TO_CHAR(B.LAST_MODIFIED_DATE, 'MM/DD/YYYY') AS LAST_MODIFIED_DATE,
TO_CHAR(B.ORDER_ITEM_LAST_UPDATED, 'MM/DD/YYYY') AS ORDER_ITEM_LAST_UPDATED,
A.ORDER_STATUS AS ORDER_STATUS,
A.ORDER_ITEM_STATUS AS ORDER_ITEM_STATUS,
A.ORDER_ACTION AS ORDER_ACTION,
NVL(B.ORDER_ITEM_ACTION, 'NOT APPLICABLE') AS ORDER_ITEM_ACTION,
NVL(B.CEASE_REASON, 'NOT APPLICABLE') AS ORDER_CEASE_REASON,
A.PRO_SYSTEM AS PRO_SYSTEM,
CASE WHEN (A.PRO_SYSTEM = 'X') THEN 'Y' ELSE 'Z' END AS FLOW
FROM PART1 A, PART2 B,DATA_REP_CALENDAR CAL
WHERE A.ORDER_SEQ = B.ORDER_SEQ
AND TRUNC(B.LOAD_DATE) = CAL.ACTUAL_CALENDAR_DATE (+)
AND TRUNC(B.LOAD_DATE) BETWEEN ADD_MONTHS( TO_DATE('07/01/2019', 'MM/DD/YYYY'),- 6) and LAST_DAY( TO_DATE('07/01/2019', 'MM/DD/YYYY'))
OR TRUNC(B.LAST_MODIFIED_DATE) BETWEEN ADD_MONTHS( TO_DATE('07/01/2019', 'MM/DD/YYYY'),- 6) and LAST_DAY( TO_DATE('07/01/2019', 'MM/DD/YYYY'))
OR TRUNC(B.ORDER_ITEM_LAST_UPDATED) BETWEEN ADD_MONTHS( TO_DATE('07/01/2019', 'MM/DD/YYYY'),- 6) and LAST_DAY( TO_DATE('07/01/2019', 'MM/DD/YYYY'));
A simple example based on Scott's EMP and DEPT tables; there's department 40, and nobody works in it. If you want to display it (while joining those tables), use outer join. The "old" Oracle outer join operator is (+) which has its ... drawbacks. If you use outer join, many things (that won't work with (+)) will now work.
This is what you have now:
SQL> select d.deptno, d.dname, e.ename
2 from dept d,
3 emp e
4 where d.deptno = e.deptno (+)
5 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>
This is how you should rewrite it:
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>

How to use a rowcount in select statement to modify the query to fetch data for 10 days , if rowcount is 0 for 5 days?

I need to modify my script using rowcount to check if the data in table or not?. Here, i write the query to select a data for last 5 days from current system date. But sometimes there is no data in table for 5 days. So i need to fetch for 10 day or more.
Query:
Select ep.ENTERPRISE_NAME||'|'||s.id||'|'||s.SUBMISSION_DATE||'|'||E.VALUE
from JOB_SUMMARY_EXT e, ob_summary s, enterprise ep
where e.id = s.id and e.name_res_key = 'Model'
and s.job_id in (select id from job_summary where
trunc(start_date) > trunc(sysdate) -10 and service_name ='Model2' )
I don't know how to modify my Query using rowcount. If rowcount is 0 then i want select data for 10 days.Otherwise it should to fetch for 5 days automatically. I want this to be done as single query.
It looks that you want to select the last 5 "days" from that table. So, why would you anchor to SYSDATE if there aren't rows for each of those days? I'd suggest another approach: literally, select last 5 days. Here's how.
As I don't have your tables, I'm using Scott's EMP table which contains information about employees. It is an ancient one so HIREDATE column is set to 1980s, but never mind that. Sorting employees by HIREDATE in descending order shows:
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> select ename, hiredate from emp order by hiredate desc;
ENAME HIREDATE
---------- ----------
ADAMS 12.01.1983 1.
SCOTT 09.12.1982 2.
MILLER 23.01.1982 3.
FORD 03.12.1981 4.
JAMES 03.12.1981 4.
KING 17.11.1981 5. --> I want to fetch rows up to KING
MARTIN 28.09.1981
TURNER 08.09.1981
CLARK 09.06.1981
BLAKE 01.05.1981
JONES 02.04.1981
WARD 22.02.1981
ALLEN 20.02.1981
SMITH 17.12.1980
14 rows selected.
SQL>
As you can see, the 4th date is shared by two employees so I want to include them both. DENSE_RANK analytic function helps:
SQL> with last5 as
2 (select ename,
3 job,
4 sal,
5 hiredate,
6 dense_rank() over (order by hiredate desc) rnk
7 from emp
8 )
9 select ename, job, sal, hiredate
10 from last5
11 where rnk <= 5;
ENAME JOB SAL HIREDATE
---------- --------- ---------- ----------
ADAMS CLERK 1100 12.01.1983
SCOTT ANALYST 3000 09.12.1982
MILLER CLERK 1300 23.01.1982
JAMES CLERK 950 03.12.1981
FORD ANALYST 3000 03.12.1981
KING PRESIDENT 5000 17.11.1981
6 rows selected.
SQL>
What does it do? The LAST5 CTE sorts employees (as above), DENSE_RANK ranks them; finally, the last SELECT (which begins at line #9) fetches desired rows.
In your case, that might look like this:
with last5 as
(select id,
dense_rank() over (order by start_date desc) rnk
from job_summary
where service_name = 'Model2'
)
select ep.enterprise_name,
s.id,
s.submission_date,
e.value
from job_summary_ext e
join ob_summary s on e.id = s.id
join last5 t on t.id = s.id
join enterprise ep on <you're missing join condition for this table>
where e.name_res_key = 'Model';
Note that you're missing join condition for the ENTERPRISE table; if that's really so, no problem - you'd use cross join for that table, but I somehow doubt that you want that.
Finally, as you use SQL*Plus, perhaps you don't need to concatenate all columns and separate them by the pipe | sign - set it as a column separator, e.g.
SQL> set colsep '|'
SQL>
SQL> select deptno, dname, loc from dept;
DEPTNO|DNAME |LOC
----------|--------------|-------------
10|ACCOUNTING |NEW YORK
20|RESEARCH |DALLAS
30|SALES |CHICAGO
40|OPERATIONS |BOSTON
SQL>
If you want to
return 10 last days if select count(*) returns 0, or
return 5 last days if select count(*) returns a positive number
then something like this might help (again based on Scott's EMP table):
with
tcnt as
-- count number of rows; use your own requirement, I'm checking
-- whether someone got hired today. In Scott's EMP table, nobody was
-- so CNT = 0
(select count(*) cnt
from emp
where hiredate >= trunc(sysdate)
)
select e.ename, e.job, e.sal, e.hiredate
from emp e cross join tcnt c
where e.hiredate >= case when c.cnt = 0 then trunc(sysdate) - 10
else trunc(sysdate) - 5
end;
Apply it to your tables; I don't know which of those 3 tables' count you want to check.
Tried to add in comments but it was too long for comments and Not clear on count based on but here is case in where clause substitute your count statement with nvl function
SELECT ep.ENTERPRISE_NAME||'|'||s.id||'|'||s.SUBMISSION_DATE||'|'||E.VALUE
FROM JOB_SUMMARY_EXT e,
ob_summary s,
enterprise ep
WHERE e.id = s.id
AND e.name_res_key = 'Model'
AND s.job_id IN
(SELECT id
FROM job_summary
WHERE service='Model'
AND trunc(start_date) >
CASE WHEN
(WRITE your SELECT COUNT criteria WITH NVL FUNCTION)<=0 THEN
trunc(sysdate) -10
ELSE trunc(sysdate)-5
END )

Reduction columns are not working for group by expression in oracle

I tried to concat two columns and using group by expression, but it is not work. how can I grouped multiple columns in oracle. first_name and last_name are reduction data.
SELECT employee_id,
employee_name,
employee_unique
FROM
(SELECT a.id AS employee_id,
(a.first_name
|| a.last_name) AS employee_name,
b.employee_unique
FROM A a
INNER JOIN b
ON a.id=b.employee_id
GROUP BY a.id,
b.employee_unique,
(a.first_name
|| a.last_name)
);
What does "not work" mean? It works for me (though, as I don't have your tables, I used Scott's EMP and DEPT, but everything else is more or less the same). If it isn't correct, you should explain what is wrong with it. If you want us to work with your data, please, provide CREATE TABLE and INSERT INTO sample data.
SQL> select employee_id,
2 employee_name,
3 employee_unique
4 from
5 (select a.empno as employee_id,
6 a.ename || a.job as employee_name,
7 b.dname as employee_unique
8 from emp a
9 inner join dept b
10 on a.deptno=b.deptno
11 group by a.empno,
12 b.dname,
13 a.ename || a.job
14 );
EMPLOYEE_ID EMPLOYEE_NAME EMPLOYEE_UNIQU
----------- ------------------- --------------
7654 MARTINSALESMAN SALES
7876 ADAMSCLERK RESEARCH
7566 JONESMANAGER RESEARCH
7698 BLAKEMANAGER SALES
7844 TURNERSALESMAN SALES
7369 SMITHCLERK RESEARCH
7788 SCOTTANALYST RESEARCH
7900 JAMESCLERK SALES
7902 FORDANALYST RESEARCH
7782 CLARKMANAGER ACCOUNTING
7934 MILLERCLERK ACCOUNTING
7499 ALLENSALESMAN SALES
7521 WARDSALESMAN SALES
7839 KINGPRESIDENT ACCOUNTING
14 rows selected.
SQL>
Though, as there's nothing really to be grouped (no aggregation here), you could have used distinct (without group by clause) and get the same result:
select employee_id,
employee_name,
employee_unique
from
(select distinct
a.empno as employee_id,
a.ename || a.job as employee_name,
b.dname as employee_unique
from emp a
inner join dept b
on a.deptno=b.deptno
);

SELECT DISTINCT on one column and return multiple other columns in Oracle/TOAD

My goal is to get a distinct for Clm_Pd_Amt column only and return all other columns:
SELECT CLM_AMT, PAID_DATE, MBR, DISTINCT CLM_PD_AMT
FROM MY_CLAIMS
WHERE DATE >= '20200101
AND STATUS = 'CURRENT'
A GROUP BY is equivalent to a distinct, for example, the distinct list of departments in the EMP table can be found with (say)
SQL> select deptno, min(sal)
2 from emp
3 group by deptno
4 /
DEPTNO MIN(SAL)
---------- ----------
30 951
10 1300
20 800
But what if I want to know which employee had that minimum salary. Then you can use the KEEP clause to gather that as well, eg
SQL> select deptno, min(sal), min(empno) KEEP ( dense_rank FIRST order by sal) empno
2 from emp
3 group by deptno
4 /
DEPTNO MIN(SAL) EMPNO
---------- ---------- ----------
10 1300 7934
20 800 7369
30 951 7900
So using that approach, you should be able to adapt your query to get the distinct CLM_PD_AMT and then pick up the other columns with KEEP. This only works if you have a definition for which distinct CLM_PD_AMT means, ie, the smallest? the largest? etc

Resources