SQL Nested select in From caluse - sql

I am confuse, can we write SELECT statement in FROM clause and if yes why can it be.
SELECT v.employee_id, v.last_name, v.lev
FROM
(SELECT employee_id, last_name, LEVEL lev
FROM employees v
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id) v
WHERE (v.employee_id, v.lev) IN
(SELECT employee_id, 2 FROM employees);

The answer is yes, you can use. The select clause in the from will act as a inline view(consider it as a temporary table that databse creates to hold the results).
For example:
SELECT sdt sdat
FROM (SELECT SYSDATE sdt FROM dual);
In the above query, SELECT SYSDATE sdt FROM dual is executed first, and output would be like:
sdt
---
08-Dec-2016 16:20:56
Then, using this as a temp table(which is called an inline view in such cases), oracle will execute your outer select on this data. Hence SELECT sdt FROM... executes, giving the final output as:
sdat
----
08-Dec-2016 16:20:56

I think you are looking for a recursive cte in sql server which would be something like.....
WITH X (employee_id, last_name, lev )
AS (
SELECT employee_id, last_name, 0 AS lev
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.last_name , lev + 1
FROM employees e
INNER JOIN x ON x.employee_id = e.manager_id
)
SELECT v.employee_id, v.last_name, v.lev
FROM X
WHERE lev = 2

Related

get items from one-level tree postgresql [duplicate]

I have a table with the structure:
Employee_ID Employee_Name Manager_ID
And, for each employee, I need to show the top manager ID. I mean, if for example, I have the EmployeeID 2 whose manager is 3 and, therefore, the number 3 has the manager number 5, I would have to show:
Empoyee_ID--Top_Manager
2 5
I need to do this with a Recursive CTE in Postgres.
Something like (for the level 2 manager) :
WITH RECURSIVE T AS
(
SELECT EMPLOYEE_ID, EMPLOYEE_NAME, MANAGER_ID, 1 AS MANAGER_LEVEL
FROM MyTable
UNION ALL
SELECT T.EMPLOYEE_ID, T.EMPLOYEE_NAME, E.MANAGER_ID, MANAGER_LEVEL + 1
FROM MyTable AS E
JOIN T ON T.MANAGER_ID = E.EMPLOYEE_ID
WHERE T.MANAGER_LEVEL = 1 --> limiting to level 2 - 1
)
SELECT EMPLOYEE_ID, EMPLOYEE_NAME, MANAGER_ID
FROM T
WHERE MANAGER_LEVEL = 2 --> retrieving only level 2, not level 1 and 2
That's a typical recursive query. Here is one way to do it in Postgres:
with recursive cte as (
select 1 lvl, employee_id, manager_id from mytable
union all
select c.lvl + 1, c.employee_id, t.manager_id
from cte c
inner join mytable t on t.employee_id = c.manager_id
)
select distinct on (employee_id) employee_id, manager_id top_manager
from cte c
order by employee_id, lvl desc
The cte climbs up the hierarchy while keeping track of the original employee id and of the relationship level. The outer query filters on the top manager per employee.

How to solve this error - ORA-22818: subquery expressions not allowed?

SELECT first_name, (select min(salary) from hr.employees where department_id = 103), (select max(salary) from hr.employees where department_id = 103)
from hr.employees where hr.employees.department_id = 103;
But it shows an error:
subquery expressions not allowed here
Do you know how to solve the error?
LEFT JOIN a derived table (aka inline view) that returns each department's min and max salary:
SELECT e.first_name,
e2.min_sal,
e2.max_sal
from hr.employees e
left join (select department_id, min(salary) min_sal, max(salary) max_sal
from hr.employees
group by department_id) e2
on e.department_id = e2.department_id
where e.department_id = 103;
The topic is kinda old but I've found neat "hack" for this oracle limitation.
If you create a normal view and then create a materialized view using that view then oracle will allow it.
Example1 (this will throw error):
DROP MATERIALIZED VIEW VW_TEST2;
CREATE MATERIALIZED VIEW VW_TEST2 AS
SELECT ROWNUM AS rowNumber, vw.* from (
SELECT 1 as ID, 'Test1' as Txt from dual
union all
select (select 2 from dual) as ID, 'Test2' as Txt from dual) vw;
Example2 (this will not throw error)
CREATE OR REPLACE VIEW VW_TEST1 AS
SELECT ROWNUM AS rowNumber, vw.* from (
SELECT 1 as ID, 'Test1' as Txt from dual
union all
select (select 2 from dual) as ID, 'Test2' as Txt from dual) vw;
DROP MATERIALIZED VIEW VW_TEST2;
CREATE MATERIALIZED VIEW VW_TEST2 AS
SELECT * FROM VW_TEST1;

using join and group by...having giving error

SELECT d.DEPARTMENT_NAME
FROM Department d,
Student s
WHERE d.DEPARTMENT_ID = s.DEPARTMENT_ID
GROUP BY d.DEPARTMENT_NAME
HAVING COUNT(s.STUDENT_ID) < MAX(COUNT(s.STUDENT_ID));
The code is for joining student and department table. The department_id is key from department to student. Need to find departments with not the max number of students. Error is group function nested too deeply. Isn't nesting allowed up to 3?
Here is the exact error
ORA-00935: group function is nested too deeply
upd. Oh, shi~! I just mentioned the question's related to Oracle. I don't know its syntax for rank() function, but I think it should be really close to Sql Server.
Here it is:
;with Department(DEPARTMENT_ID, DEPARTMENT_NAME) as (
select 1, 'first' union all
select 2, 'second' union all
select 3, 'third'
)
, Student(STUDENT_ID, DEPARTMENT_ID) as (
select 1, 1 union all
select 2, 2 union all
select 3, 2 union all
select 4, 2 union all
select 5, 3 union all
select 6, 3 union all
select 7, 3
)
, DepOrdered as (
select
d.DEPARTMENT_ID,
d.DEPARTMENT_NAME,
s.StudentCnt,
-- rank departments by the number of students
rank() over (order by s.StudentCnt desc) as Rnk
from Department d
cross apply (
-- for every department count its students
select
count(s.STUDENT_ID) StudentCnt
from Student s
where
d.DEPARTMENT_ID = s.DEPARTMENT_ID
) s
)
select
DEPARTMENT_ID,
DEPARTMENT_NAME,
StudentCnt
from DepOrdered
where
-- Rnk = 1 would have all departments with max number of students
Rnk > 1

how to select even records from a table in oracle?

i'm using below query to retrieve even numbered records.but in reslut it is displaying no rows
select ename,job from emp where mod(rownum,2)=0;
why mod(rownum,2) is not working in where conditiom
can u please also give the query to select the odd number records
Is there anything wrong with that query?
suggetions please..
It is not working because: for the first row ROWNUM is 1 and, in this case, MOD(ROWNUM,2) is 1 and since your WHERE statement is MOD(ROWNUM,2)=0 then this reduces to 1=0 and the row is discarded. The subsequent row will then be tested against a ROWNUM of 1 (since the previous row is no longer in the output and will not have a row number), which will again fail the test and be discarded. Repeat, ad nauseum and all rows fail the WHERE test and are discarded.
If you try to get the odd rows this way using WHERE MOD(ROWNUM,2)=1 then it will return the first row only and the second, and subsequent, rows will fail the test and will never be included in the query.
As Vijaykumar Hadalgi suggests, you need to select the ROWNUM in a sub-query (where it can number all the rows without a where clause to restrict it) and then in the outer query perform the test to restrict the rows:
SELECT ename, job
FROM (
SELECT ename,
job,
ROWNUM AS row_id -- Generate ROWNUM second.
FROM (
SELECT ename, job
FROM Emp
ORDER BY ename -- ORDER BY first.
)
)
WHERE MOD( row_id, 2 ) = 0; -- Filter third.
SQLFIDDLE
Try this
To find the EVEN number of row details you can use this code.
This one is comfortable in oracle SQL as well as MySQL.
select * from (select ename,job, ROWNUM AS rn from emp) where mod(rn, 2) = 0;
To find the ODD number of row details you can use this code.
select * from (select ename,job, ROWNUM AS rn from emp) where mod(rn, 2) <> 0;
-- for selecting rows 1,3,5,7....
SELECT EMPLOYEE_ID,FIRST_NAME, LAST_NAME FROM
(
SELECT DENSE_RANK OVER(ORDER BY EMPLOYEE_ID)AS RANK, EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM EMPLOYEES
)
WHERE MOD(RANK,2)=1
-- for selecting rows 2,4,6,8....
SELECT EMPLOYEE_ID,FIRST_NAME, LAST_NAME FROM
(
SELECT DENSE_RANK OVER(ORDER BY EMPLOYEE_ID)AS RANK, EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM EMPLOYEES
)
WHERE MOD(RANK,2)=0
select * from emp where empid in (select decode(mod(rownum,2),0, empid,null) from emp); --Alternate record Even numbered
Fetch even records from the table
Or You can try this:
Here The inner query will fetch all the even records primary key value and based on that we can get all those record details.
SELECT * FROM EMP WHERE EMPNO IN
(
SELECT CASE MOD(ROWNUM,2)
WHEN 0 THEN EMPNO
END
FROM EMP
);
This will fetch all the odd records
SELECT * FROM EMP WHERE EMPNO IN
(
SELECT CASE MOD(ROWNUM,2)
WHEN 1 THEN EMPNO
END
FROM EMP
);
this will do :
Select * from (Select rownum as No_of_Row, E.* from emp E)
Where mod(No_of_Row,2)=0;
Use the below query u will get the result:
SELECT empno,ename,slno
FROM ( SELECT empno,ename,ROW_NUMBER() OVER
(ORDER BY empno desc) AS slno FROM emp ) result WHERE mod(slno,2) = 1;
Use the below query,
select * from (select ename,job, ROWNUM as row_id from emp) where mod(row_id, 2) = 0;
Select ename, job from emp where mod(id, 2) =0 ;
You can Try the id column intead of rownum if table has an identity column
We can use with clause
Example:
WITH Tab AS(select mod(rownum,2) AS R ,EMPLOYEES.* from employees)
SELECT * FROM Tab WHERE R = 0;
If you want odd rows then R = 1.
Example:
WITH Tab AS(select mod(rownum,2) AS R ,EMPLOYEES.* from employees)
SELECT * FROM Tab WHERE R = 1;
row num represents row number in the results table not in the original table.
So, first assign it to row_id or any variable and use that variable.
Please try :
select * from emp where (rowid,0) in (select rowid, mod(rownum,2) from emp)
Output:-
2
4
6
Select * from emp where (rowid,1) in (select rowid, mod(rownum,2) from emp);
Output: 1,3,5..
Or this will work
this :
odd :
select * from
(
SELECT col1, col2, ROW_NUMBER() OVER(ORDER BY col1 DESC) AS 'RowNumber',
FROM table1
) d
where (RowNumber % 2) = 1
even :
select * from
(
SELECT col1, col2, ROW_NUMBER() OVER(ORDER BY col1 DESC) AS 'RowNumber',
FROM table1
) d
where (RowNumber % 2) = 0

ORACLE sql query for getting top 3 salaries rownum greater than

I want to write a query to display employees getting top 3 salaries
SELECT *
FROM (SELECT salary, first_name
FROM employees
ORDER BY salary desc)
WHERE rownum <= 3;
But I dont understand how this rownum is calculated for the nested query
will this work or if it has problem ,request you to please make me understand:
SELECT *
FROM (SELECT salary, first_name
FROM employees
ORDER BY salary )
WHERE rownum >= 3;
I went through this link Oracle/SQL: Why does query "SELECT * FROM records WHERE rownum >= 5 AND rownum <= 10" - return zero rows ,but it again points to a link, which does not gives the answer
a_horse_with_no_name's answer is a good one,
but just to make you understand why you're 1st query works and your 2nd doesn't:
When you use the subquery, Oracle doesn't magically use the rownum of the subquery, it just gets the data ordered so it gives the rownum accordingly, the first row that matches criteria still gets rownum 1 and so on. This is why your 2nd query still returns no rows.
If you want to limit the starting row, you need to keep the subquery's rownum, ie:
SELECT *
FROM (SELECT * , rownum rn
FROM (SELECT salary, first_name
FROM employees
ORDER BY salary ) )sq
WHERE sq.rn >= 3;
But as a_horse_with_no_name said there are better options ...
EDIT: To make things clearer, look at this query:
with t as (
select 'a' aa, 4 sal from dual
union all
select 'b' aa, 1 sal from dual
union all
select 'c' aa, 5 sal from dual
union all
select 'd' aa, 3 sal from dual
union all
select 'e' aa, 2 sal from dual
order by aa
)
select sub.*, rownum main_rn
from (select t.*, rownum sub_rn from t order by sal) sub
where rownum < 4
note the difference between the sub rownum and the main rownum, see which one is used for criteria
The "rownum" of a query is assigned before an order by is applied to the result. So the rownumw 42 could wind up being the first row.
Generally speaking you need to use the rownum from the inner query to limit your overall output. This is very well explained in the manual:
http://docs.oracle.com/cd/E11882_01/server.112/e26088/pseudocolumns009.htm#i1006297
I prefer using row_number() instead, because you have much better control over the sorting and additionally it's a standard feature that works on most modern DBMS:
SELECT *
FROM (
SELECT salary,
first_name,
row_number() over (order by salary) as rn
FROM employees
)
WHERE rn <= 3
ORDER BY salary;
You should understand that the derived table in this case is only necessary to be able to apply a condition on the generated rn column. It's not there to avoid the "rownum problem" as the value of row_number() only depends on the order specifiy in the over(...) part (it is independent of any ordering applied to the query itself)
Note this would not return employees that have the same salary and would still fall under the top three. In that case using dense_rank() is probably more approriate.
if you want to select the people with the top 3 salaries.. perhaps you should consider using analytics.. something more like
SELECT *
FROM (
SELECT salary, first_name, dense_rank() over(order by salary desc) sal_rank
FROM employees
)
WHERE sal_rank <= 3
ie ALL people with the 3rd highest(ranked) salary amount(or more)
the advantage of this over using plain rownum is if you have multiple people with the same salary they will all be returned.
Easiest way to print 5th highest salary.
SELECT MIN(SALARY) FROM (SELECT SALARY FROM EMPLOYEES ORDER BY DESC) WHERE ROWNUM BETWEEN 1 AND 5
according to same if u want to print 3rd or 4th highest salary then just chage last value.(means instead of 5 use 3 or 4 you will get 3rd or 4th highest salary).
SELECT MIN(SALARY) FROM (SELECT SALARY FROM EMPLOYEES ORDER BY DESC) WHERE ROWNUM BETWEEN 1 AND 4
SELECT MIN(SALARY) FROM (SELECT SALARY FROM EMPLOYEES ORDER BY DESC) WHERE ROWNUM BETWEEN 1 AND 3
SELECT EMPNO,
SAL,
(SELECT SUM(E.SAL) FROM TEST E WHERE E.EMPNO <= T.EMPNO) R_SAL
FROM (SELECT EMPNO, SAL FROM TEST ORDER BY EMPNO) T
Easiest way to find the top 3 employees in oracle returning all fields details:
SELECT *
FROM (
SELECT * FROM emp
ORDER BY sal DESC)
WHERE rownum <= 3 ;
select *
from (
select emp.*,
row_number() over(order by sal desc)r
from emp
)
where r <= 3;
SELECT Max(Salary)
FROM Employee
WHERE Salary < (SELECT Max(salary) FROM employee WHERE Salary NOT IN (SELECT max(salary) FROM employee))
ORDER BY salary DESC;