Is this a right query? If it is what does it mean - oracle

I was given a query to explain. Could someone please explain it to me:
select j.ip_num from
jobs j, address a
where j.jobtype='C' and
a.sel_code(+)='H' and
j.ip_num=a.ip_num and
a.ip_num is null order by a.ip_num

That query selects every JOB.IP_NUM which doesn't have a matching ADDRESS record or where the matching ADDRESS record has a SEL_CODE not equal to 'H'.
The (+) is Oracle's old outer join syntax. It is the only OUTER JOIN syntax supported in versions of Oracle before 9i.
In this query we get one row for every row in EMP which matches a department, plus a row for the DEPTNO=40, which has no employees:
SQL> select d.dname
2 , e.ename
3 from dept d
4 , emp e
5 where d.deptno = e.deptno(+)
6 /
DNAME ENAME
-------------- ----------
ACCOUNTING SCHNEIDER
ACCOUNTING BOEHMER
ACCOUNTING KISHORE
RESEARCH ROBERTSON
RESEARCH KULASH
RESEARCH GASPAROTTO
RESEARCH RIGBY
RESEARCH CLARKE
SALES HALL
SALES CAVE
SALES SPENCER
SALES BILLINGTON
SALES PADFIELD
SALES VAN WIJK
SALES KESTELYN
SALES LIRA
OPERATIONS PSMITH
HOUSEKEEPING VERREYNNE
HOUSEKEEPING FEUERSTEIN
HOUSEKEEPING PODER
HOUSEKEEPING TRICHLER
COMMUNICATIONS
22 rows selected.
SQL>
Now, if we put an additional filter on the EMP table like this, we simply get one record for each Department, because only one record in EMP now matches:
SQL> select d.dname
2 , e.ename
3 from dept d
4 , emp e
5 where d.deptno = e.deptno(+)
6 and e.ename(+) = 'CAVE'
7 /
DNAME ENAME
-------------- ----------
ACCOUNTING
RESEARCH
SALES CAVE
OPERATIONS
HOUSEKEEPING
COMMUNICATIONS
6 rows selected.
SQL>
/
To convert this query into the ANSI SQL syntax we have to do this:
SQL> select d.dname
2 , e.ename
3 from dept d
4 left outer join emp e
5 on ( d.deptno = e.deptno
6 and e.ename = 'CAVE' )
7 /
DNAME ENAME
-------------- ----------
ACCOUNTING
RESEARCH
SALES CAVE
OPERATIONS
HOUSEKEEPING
COMMUNICATIONS
6 rows selected.
SQL>
Note that if we don't include the additonal clause in the JOIN but leave it in the WHERE clause we get a different result:
SQL> select d.dname
2 , e.ename
3 from dept d
4 left outer join emp e
5 on ( d.deptno = e.deptno )
6 where e.ename = 'CAVE'
7 /
DNAME ENAME
-------------- ----------
SALES CAVE
SQL>
This is the equivalent of omitting the (+) in the second old skool query.

The query is joining the 2 tables jobs, and address. These tables are joining on the field ip_num but you are looking for the records that exist in the jobs table but do not exist in the address table.
This is a LEFT OUTER JOIN. This query could also be written
SELECT j.ip_num
FROM jobs j
LEFT OUTER JOIN address a
ON j.ip_num=a.ip_num
WHERE j.jobtype='C' AND
a.sel_code(+)='H' AND
a.ip_num is null
ORDER BY a.ip_num
It might be useful to see a visual picture joins http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

Related

I am trying to update a table on joining them in order to give 2% bonus to the person who hasn't received at all

2 tables employee_1 and bonus_1 joined and trying to update but gives me the error -
ERROR REPORT UNKNOWN COMMAND
UPDATE(
SELECT e.first_name,
sum(b.bonus_amount) as bon
from employee_1 e
LEFT join bonus_1 b
on e.employee_id=b.employee_id
group by e.first_name
)
set bon=0.2*e.salary
where bon IS NULL;
Please help me update this join query to give 2% bonus to employees whose bonus amount will be null in bonus_amount.
It would help if you posted sample data.
With tables I imagine you have:
SQL> select * from employee_1;
EMPLOYEE_ID SALARY
----------- ----------
1 100
2 200
SQL> select * From bonus_1;
EMPLOYEE_ID BONUS_AMOUNT
----------- ------------
1 20
2 --> no bonus for this employee, so their salary should be raised by 2%
One option might be merge:
SQL> merge into employee_1 e
2 using (select b.employee_id,
3 sum(b.bonus_amount) as bon
4 from bonus_1 b
5 group by b.employee_id
6 ) x
7 on (x.employee_id = e.employee_id)
8 when matched then update set
9 e.salary = e.salary * 1.02
10 where x.bon is null;
1 row merged.
SQL> select * from employee_1;
EMPLOYEE_ID SALARY
----------- ----------
1 100
2 204
Another might be update:
SQL> rollback;
Rollback complete.
SQL> merge into employee_1 e
2 using (select b.employee_id,
3 sum(b.bonus_amount) as bon
4 from bonus_1 b
5 group by b.employee_id
6 ) x
7 on (x.employee_id = e.employee_id)
8 when matched then update set
9 e.salary = e.salary * 1.02
10 where x.bon is null;
1 row merged.
SQL> select * From employee_1;
EMPLOYEE_ID SALARY
----------- ----------
1 100
2 204
SQL>
If you just want to display the amount then do not use UPDATE, just use SELECT and COALESCE:
SELECT MAX(e.first_name) AS first_name,
COALESCE(
SUM(b.bonus_amount),
0.2*MAX(e.salary)
) as bon
FROM employee_1 e
LEFT JOIN bonus_1 b
ON e.employee_id=b.employee_id
GROUP BY e.employee_id;
Note: do not GROUP BY e.first_name as you will aggregate together people with the same first name; which is almost certainly incorrect.
If you want to modify the bonus_1 table to add a bonus when there are no bonuses for an employee then you want an INSERT statement and not an UPDATE:
INSERT INTO bonus_1 (employee_id, bonus_amount)
SELECT employee_id, 0.2*salary
FROM employee_1 e
WHERE NOT EXISTS (SELECT 1 FROM bonus_1 b WHERE b.employee_id = e.employee_id);
Or a MERGE ... WHEN NOT MATCHED THEN INSERT ... statement:
MERGE INTO bonus_1 b
USING employee_1 e
ON (b.employee_id = e.employee_id)
WHEN NOT MATCHED THEN
INSERT (employee_id, bonus_amount)
VALUES (e.employee_id, 0.2*e.salary);
Note: your title states a 2% bonus, if that is the case then 0.02 = 2% whereas 0.2 = 20%.
Once you have performed the insert then:
SELECT MAX(e.first_name) AS first_name,
sum(b.bonus_amount) as bon
FROM employee_1 e
LEFT JOIN bonus_1 b
ON e.employee_id=b.employee_id
GROUP BY e.employee_id;
Will have a row for all employees to display the bonuses.
fiddle

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)?

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 )

Trying to update table but i always get ora-01427

So i am trying to update my Vorschlagspakete table with some values i got from other tables. Precisely there are 3 values i want to write into the main table. Atm it looks like this:
update vorschlagspakete
set (paketid, verkaufsstelleid) = (
select k.paketid, k.verkaufsstelleid
from Konfiguration k, bewertung b
where k.konfigurationsid = b.konfigurationsid
group by k.paketid, k.verkaufsstelleid
having avg(b.sterne) >= 5);
But every time i tried this it results into ora-01427.
Error you got, ORA-01427, means too many rows (were returned by subquery). For example based on Scott's schema (as I don't have your tables), it looks like this:
SQL> update emp e set
2 (e.ename, e.job) = (select d.dname, d.loc from dept d);
(e.ename, e.job) = (select d.dname, d.loc from dept d)
*
ERROR at line 2:
ORA-01427: single-row subquery returns more than one row
Why wouldn't it work? Because subquery returns more than a single row!
SQL> select d.dname, d.loc from dept d;
DNAME LOC
-------------- -------------
ACCOUNTING NEW YORK
RESEARCH DALLAS
SALES CHICAGO
OPERATIONS BOSTON
SQL>
So, how would you put all those values into a single row of the EMP table? That won't work, obviously, so you have to do something to restrict number of rows. How? Well, it depends.
sometimes DISTINCT helps, e.g.
select distinct d.dname, d.loc from dept d
sometimes additional WHERE condition helps, e.g.
select d.dname, d.loc from dept d
where d.location = 'NEW YORK'
sometimes joining with the table to be updated helps, e.g.
select d.dname, d.loc from dept d where d.deptno = e.deptno
which leads to
SQL> update emp e set
2 (e.ename, e.job) = (select d.dname, d.loc from dept d where d.deptno = e.deptno);
14 rows updated.
What should you do? I don't know, we don't have your data. See whether something written above helps.

Creating temporary table without knowing the columns in oracle

How to create a temporary table in oracle without knowing the number and name of columns.
For example:
Select columnA,columnB,* into temp_table from tableA.
Here,tableA maynot be a simple tablename but maybe derived from many queries.
How can this be achieved?Is there any alternative to this?
In Oracle, you have to first create a table, then insert into it. Or, create it directly (as in my example).
Note that I've created a "normal" table; if it were temporary, you could have chosen between a global or private (depending on database version you use).
For this discussion, I guess that it is just fine:
SQL> create table temp_table as
2 select a.*
3 from (select d.deptno, d.dname, e.ename --> this SELECT is your "tableA"
4 from emp e join dept d
5 on e.deptno = d.deptno
6 where job = 'CLERK'
7 ) a;
Table created.
SQL> select * from temp_table;
DEPTNO DNAME ENAME
---------- -------------------- ----------
10 ACCOUNTING MILLER
20 RESEARCH SMITH
20 RESEARCH ADAMS
30 SALES JAMES
SQL>
Alternatively, create a view and work with it:
SQL> create or replace view v_temp as
2 select d.deptno, d.dname, e.ename
3 from emp e join dept d
4 on e.deptno = d.deptno
5 where job = 'CLERK'
6 ;
View created.
SQL> select * from v_temp;
DEPTNO DNAME ENAME
---------- -------------------- ----------
10 ACCOUNTING MILLER
20 RESEARCH SMITH
20 RESEARCH ADAMS
30 SALES JAMES
SQL>
This statement creates temp_table which contains all columns and data from tableA and two other empty columns, varchar and numeric.
create table temp_table as
select cast (null as varchar2(10)) columnA,
cast (null as number(6)) columnB,
tableA.*
from tableA
If you need only structure, no data, then add:
where 1 = 0
I am not sure why you want to have a temp table as you do not know columns, but you can think of dynamic SQL to create table depending on columns required during your process and then drop it again. From my point of view I think it is not a good design.
I can suggest to think on using collection with 'x' number of columns with datatype as VARCHAR2. During transaction you can populate and process according to you need and it will also remain for that session.

Resources