rowcount query in Oracle 8i - sql

I have a table Department_history and here is the count of records for each department.
select department_name, Id, count(1) total_rows_COUNT from Department_history
where
group by Department_history,id
order by 2 desc
result:
department_name ID total_rows_COUNT
Accounting 4564 556
Finance 3434 671
Marketing 4353 234
IT 1233 454
I want to keep only the 10 records for each department in the table.
if run this below query for each department like this, it works.
delete from Department_history a1
where
and a1.report_runtime NOT IN
(
select report_runtime
from (
select a.*, rank() over ( partition by department_name, id order by report_runtime desc) r
from Department_history a
) rs
where r <= 10 and department_name = 'Accounting'
)
and department_name = 'Accounting'
But I don't want to individually run this deletion for each department.
how can I run one query that deletes the data for each department_name (if it is >10 records). I tries this. but it doesn't work.
delete from Department_history a1
where
and a1.report_runtime NOT IN
(
select report_runtime
from (
select a.*, rank() over ( partition by department_name, id order by report_runtime desc) r
from Department_history a
) rs
where r <= 10
)
Can someone please advise?

test sample:
create table tst as select owner, view_name from all_views;
delete from tst
where owner||'::'||view_name in
(
select owner||'::'||view_name from (
select owner, view_name, rank() over (partition by owner order by view_name) r from tst
) where r > 10
)
your updated sql:
delete from Department_history
where id NOT IN
(
select id
from (
select id, rank() over ( partition by department_name
order by report_runtime desc) rnk
from Department_history
) s
where s.rnk <= 10
)

Try this. It's similar to what you already tried, but the not in clause should be checking against all 3 identifying columns, department_name, id, report_runtime, not just report_runtime. Otherwise, you might accidentally delete the wrong rows.
I also used row_number instead of rank. I think it's the better choice for your requirement. Though based on your description of the data, I don't think it actually makes a difference in this case.
delete from department_history
where (department_name, id, report_runtime)
not in (select department_name, id, report_runtime
from (select department_name, id, report_runtime,
row_number() over (partition by department_name, id order by report_runtime desc) as rn
from department_history)
where rn <= 10)

Related

SQL oracle: Need to display a query.

so i have 3 tables linked together named office, employee, and dependent.
office: Oid (PK), officeName
employee: EID(PK), Fname, Lname, JobTitle, Salary, DOH, Gender, DOB, OID(FK1), Supervisor(FK2)
Dependent: DID(PK), Fname, Lname, Gender, EID(FK1)
Here is the link to the picture of the tables:
http://classweb2.mccombs.utexas.edu/mis325/class/hw/hw12a.jpg
I need to display concatenated name and EID of 5 employees with the largest number of dependents, if there is a tie for the five largest, then I need to display all of the tying employees.
I am confused on how to begin. please help :)
thank you in advance
Just break down the problem:
How many dependents an EID has:
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
Add a rank
SELECT EID, C, RANK() OVER (ORDER BY C DESC)
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
We want the first 5
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <= 5
Now ask for what you want:
SELECT * -- or whatever
FROM Employee
WHERE EID IN (
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <=5
) S3
I suggest you run each step and make sure it gives you the expected results.
Ummm I would try something like this:
Select TOP 5
a.FNAME,
a.LNAME,
a.EID,
Count(b.EID) as Dependents
FROM employee a
LEFT JOIN dependent b on a.EID = b.EID
group by 1,2,3 order by Dependents desc

Query to get the "MAX COUNT"

Guys I have the following query:
select count(*) AS num_items
from desc_look
group by dept
This query returns the number of items in each department. However I can't get ONLY the department with the higher number of items.
I've been trying to use this to retrieve the name and id of the department with most items
select dept, desc_up
from desc_look
where (select count(*) AS num_items
from desc_look
group by dept)
However I keep getting an error ORA-00936 and I don't know why.
I know I can't user MAX(COUNT(*)) but is there a way to workaround this?
select * from
(
select count(*) AS num_items
from desc_look
group by dept
order by count(*) desc
) tmp
WHERE ROWNUM = 1;
Also have a look on howto limit the records in Oracle.
This version is basically the same as juergen's, but using an analytic function instead of an aggregate (GROUP BY) for counting:
SELECT t.dept, t.desc_up FROM
(SELECT dept, desc_up,
COUNT(*) over (partition BY dept) dept_count
FROM desc_look
ORDER BY dept_count DESC
) t
WHERE rownum = 1
If you're on Oracle 12, the inline view is not needed because you can use the row-limiting clause (FETCH FIRST ...):
SELECT dept, desc_up,
COUNT(*) over (partition BY dept) dept_count
FROM desc_look
ORDER BY dept_count DESC
FETCH FIRST 1 ROW ONLY
You might try something like this:
SELECT dept, num_items FROM (
SELECT dept, COUNT(*) AS num_items
, ROW_NUMBER() OVER ( ORDER BY COUNT(*) DESC ) AS rn
FROM desc_look
GROUP BY dept
) WHERE rn = 1;
i think this may help you
select count(*) AS num_items
from desc_look
group by dept
order by count(*) desc
limit 1

Finding department having maximum number of employee

I have a table employee
id name dept
1 bucky shp
2 name shp
3 other mrk
How can i get the name of the department(s) having maximum number of employees ? ..
I need result
dept
--------
shp
SELECT cnt,deptno FROM (
SELECT rank() OVER (ORDER BY cnt desc) AS rnk,cnt,deptno from
(SELECT COUNT(*) cnt, DEPTNO FROM EMP
GROUP BY deptno))
WHERE rnk = 1;
Assuming you are using SQL Server and each record representing an employee. So you can use window function to get the result
WITH C AS (
SELECT RANK() OVER (ORDER BY dept) Rnk
,name
,dept
FROM table
)
SELECT TOP 1 dept FROM
(SELECT COUNT(Rnk) cnt, dept FROM C GROUP BY dept) t
ORDER BY cnt DESC
With common table expressions, count the number of rows per department, then find the biggest count, then use that to select the biggest department.
WITH depts(dept, size) AS (
SELECT dept, COUNT(*) FROM employee GROUP BY dept
), biggest(size) AS (
SELECT MAX(size) FROM depts
)
SELECT dept FROM depts, biggest WHERE depts.size = biggest.size
Based on one of the answer, Let me try to explain step by step
First of all we need to get the employee count department wise. So the firstly innermost query will run
select count(*) cnt, deptno from scott.emp group by deptno
This will give result as
Now out of this we have to get the one which is having max. employee i.e. department 30.
Also please note there are chances that 2 departments have same number of employees
The second level of query is
select rank() over (order by cnt desc) as rnk,cnt,deptno from
(
select count(*) cnt, deptno from scott.emp group by deptno
)
Now we have assigned ranking to each department
Now to select rank 1 out of it. we have a simplest outer query
select * from
(
select rank() over (order by cnt desc) as rnk,cnt,deptno from
(
select count(*) cnt, deptno from scott.emp group by deptno
)
)
where rnk=1
So we have the final result where we got the department which has the maximum employees. If we want the minimum one we have to include the department table as there are chances there is a department which has no employees which will not get listed in this table
You can ignore the scott in scott.emp as that is the table owner.
The above SQL can be practised at Practise SQL online

Top 2 Salary Grouped By Department

Below is the table I am referring to.
I want to find ou the 2 Employees in each department with highest salary.
Further to the above answer, if there are ties (multiple employees sharing the same salary), you can use the following to bring them all through instead of just picking two at random (which is what the ROW_NUMBER clause will do)
SELECT *
FROM (
SELECT *, DENSE_RANK() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rn
FROM MyTable ) t
WHERE t.rn <= 2
Use ROW_NUMBER() to get the top salaries per Department, then select the first two records from each departmental partiton:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rn
FROM MyTable ) t
WHERE t.rn <= 2

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;