converting correlated oracle subquery to single query - oracle

Hi I have two tables EMP and Dept( data as normal emp and dept tables of oracle)
I want to find the number of employees earning more than the avg(sal) of their own dept without use of correlated subquery. I wrote the query as below
SELECT * from emp e JOIN
(SELECT avg(sal) avgsal,deptno
FROM emp group by deptno )avgsal_tab
on e.sal > avgsal_tab.avgsal where e.deptno =avgsal_tab.deptno
order by e.deptno
This gets me the output but how can I rewrite this with a single query without inline query as shown above.

You can use analytic window functions:
SELECT *
from (
SELECT
e.*
,avg(sal)over(partition by deptno) avgsal
from emp e
)
where avgsal>sal

Related

Cursor with multiple queries in oracle not compiling

I have created a cursor that has two queries joined with inner join, but query is not compiling their is error at the end of first query but the same query is getting executed without cursor.
cursor data is
select * from
select rid,id, order from table1
inner join
select pid, name, order from table2
on table1.order = table2.order
original query is much bigger and complicated but end result would be this.
Their are compilation errors at the end of first query and those are generic nature, I guess may be syntax for creating a two joined queries is wrong (this is a wild guess though)
Error:
SQL statement ignored //at select word of first query
Missing right parenthesis //at the last word of first query
Example based on Scott's schema:
SELECT should contain column aliases if columns returned by those inline views share the same name; otherwise, you won't know which one you're using
inline views should have their own aliases; basically, that's always a good idea - prefix columns with table aliases, otherwise you'll soon forget which column belongs to which table
SQL> declare
2 cursor data is
3 select a.empno a_empno, b.ename b_ename
4 from (select empno, ename, deptno from emp) a
5 inner join
6 (select empno, ename, deptno from emp) b
7 on a.deptno = b.deptno
8 where rownum < 5;
9 begin
10 for data_r in data loop
11 dbms_output.put_line(data_r.b_ename);
12 end loop;
13 end;
14 /
SMITH
JONES
SCOTT
ADAMS
PL/SQL procedure successfully completed.
SQL>
You have to put your subqueries in parenthesis and add aliases for the subqueries:
cursor data is
select * from
(select rid,id, order from table1) table1
inner join
(select pid, name, order from table2) table2
on table1.order = table2.order
Here is another answer for you, with just small differences and with an example:
CREATE OR REPLACE PROCEDURE p_test(n_test in number)
AS
CURSOR data
IS
SELECT *
FROM
(SELECT rid
, id
, "order" or1
FROM table1) tab1
INNER JOIN
(SELECT pid
, name
, "order" or1
FROM table2 ) tab2
ON tab1.or1 = tab2.or1;
BEGIN
FOR data_i IN data LOOP
DBMS_OUTPUT.PUT_LINE(data_i.rid);
END LOOP;
END p_test;
Here is the DEMO

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.

how to get a row number for each group in report?

i am making a report that getting employees for each group and i need to get a row number for each employee in each department group
select rownum,e.empno, e.ename, e.sal, e.comm, e.deptno, d.dname
from emp e
left join dept d on emp.deptno = dept.deptno
order by deptno;
We can try using ROW_NUMBER here:
SELECT
ROW_NUMBER() OVER (PARTITION BY emp.deptno ORDER BY emp.ename) rn,
emp.empno,
emp.ENAME,
emp.SAL,
emp.COMM,
emp.DEPTNO,
dept.dname
FROM emp
LEFT JOIN dept
ON emp.deptno = dept.deptno
ORDER BY
emp.deptno;
Note that you never provided logic for what should decide the ordering of each employee within a department. In the absence of this, I have used the employee name. If you want some other ordering, then just modify the ORDER BY clause in the call to ROW_NUMBER.

Oracle select random rows matching a join condition

My objective is simple, I have to create a temporary table with some random values from a employee table whenever the department is in some particular department (say 2). For the rest of departments I don't care the value, it can be NULL.
Currently I have the following :
create table test
as
select s.DEPTNAME,
cast (
(case when s.DEPTID in (2) then
(SELECT a.ENAME FROM
(SELECT b.ENAME, b.DEPTID FROM EMPLOYEE b
WHERE b.DEPTID IS NOT NULL
ORDER BY DBMS_RANDOM.VALUE) a
WHERE a.DEPTID = s.DEPTID AND ROWNUM = 1
)
END)
AS VARCHAR2(30)) "ENAME" from DEPARTMENT s;
But the main issue here is related to performance. For every department value in 2 we do a sort of EMPLOYEE table to get a single random ENAME.
Is there a better way to do this ? I know sample might work but I want to achieve more randomness.
First idea - join randomly numbered enames:
with
e as (select ename, deptid, row_number() over (order by dbms_random.value) rn
from employee where deptid = 2),
c as (select count(1) cnt from e),
d as (select deptname, deptid, round(dbms_random.value(1, c.cnt)) rn from department, c)
select d.deptname, e.ename from d left join e using (rn, deptid)
SQLFiddle demo
Second possible solution, which worked for me, is to create function returning random ename from table employee
and use it in your query, but it would be probably slower.
Edit - according to comment:
If, for some reason, the first part of your statement is "fixed", then you could use this syntax:
create table test as
select deptname, ename from (
with
e as (select ename, deptid, row_number() over (order by dbms_random.value) rn
from employee where deptid = 2),
c as (select count(1) cnt from e),
d as (select deptname, deptid, round(dbms_random.value(1, c.cnt)) rn
from department cross join c)
select d.deptname, e.ename from d left join e using (rn, deptid));

How to use maximum select queries in hive

I have two tables emp and dept in oracle. Have imported it to hive. The same structure is in hive. I need a query where I can select max no of empno coloumn in hive. Can I use ORDER BY EMPNO instead of select max(empno)?
This is the query for Oracle Database that I am using.
select a.empno,
a.ename,
a.hiredate,
a.mgr,
a.job,
a.sal,
a.comm,
a.deptno,
b.deptno,
b.dname,
b.loc
from emp2 a,
dept1 b
where a.deptno=b.deptno
and a.empno=(select max(empno) from emp2);
How can I select max empno in hive?
This should work:
SELECT a.empno,a.ename,a.hiredate,a.mgr,
a.job,a.sal,a.comm,a.deptno,b.dname,b.loc
FROM emp2 a, JOIN dept1 b
ON (a.deptno=b.deptno )
WHERE a.empno = max(b.empno)
GROUP BY a.empno,a.ename,a.hiredate,a.mgr,
a.job,a.sal,a.comm,a.deptno,b.dname,b.loc
;

Resources