Select both row number and count from oracle - sql

I'm trying to select records with pagination, and I need the total number of records so that I can display the number of records and pages on the UI.
The query I'm using is as below but it always returning the totalcount as 1.
WITH cteEmp AS
(SELECT e.empid, e.empname, d.deptid, d.deptname
FROM hr.Emp e
INNER JOIN hr.dept d ON e.deptid = d.deptid)
Select * from (SELECT row_number() over (order by hr.empid desc) rn, Count(*) totalcount,
C.empName FROM CTEPO C
LEFT JOIN hr.emphistory ON C.empid=hr.empid
GROUP BY c.empid,hr.empid) where rn>0 and rn<= 100

You can try this maybe it'll work for you:
(SELECT e.empid, e.empname, d.deptid, d.deptname
FROM hr.Emp e
INNER JOIN hr.dept d ON e.deptid = d.deptid)
Select * from (SELECT row_number() over (order by hr.empid desc) rn,
count(*) OVER (ORDER BY hr.empid desc ) AS totalcount
C.empName FROM CTEPO C
LEFT JOIN hr.emphistory ON C.empid=hr.empid
GROUP BY c.empid,hr.empid) where rn>0 and rn<= 100

Related

FETCH/ROWNUM() first n percent from each BRANCH (BRANCH_NO). I am trying to retrieve top 10 percent of each branch

SELECT e.EMPLOYEE_NO, e.FNAME, e.LNAME, b.BRANCH_NO, o.SUBTOTAL,
PERCENT_RANK() OVER ( partition by e.EMPLOYEE_NO ORDER BY e.EMPLOYEE_NO ASC) AS percent
FROM EMPLOYEE e
INNER JOIN BRANCH b
ON e.BRANCH_NO = b.BRANCH_NO
INNER JOIN ORDERS o
ON o.BRANCH_NO = b.BRANCH_NO
ORDER BY b.BRANCH_NO
FETCH FIRST 10 PERCENT ROWS ONLY;
I am trying to retrieve top 10 percent of each branch.
PL SQL
You can use analytical functions as following:
Select employee_no,
Fname,
Lname,
employee_total_order,
Branch_no
From
(SELECT e.EMPLOYEE_NO, e.FNAME, e.LNAME, b.BRANCH_NO,
SUM(o.SUBTOTAL) AS employee_total_order,
Count(distinct e.employee_no)
over (partition by b.branch_no) as total_emp,
Row_number()
over (partition by b.branch_no order by SUM(o.SUBTOTAL) desc nulls last) as rn
FROM EMPLOYEE e
INNER JOIN BRANCH b
ON e.BRANCH_NO = b.BRANCH_NO
INNER JOIN ORDERS o
ON o.BRANCH_NO = b.BRANCH_NO
Group by e.EMPLOYEE_NO, e.FNAME, e.LNAME, b.BRANCH_NO)
Where rn/total_emp <= 0.1
or rn = 1 -- this condition is used to fetch atleast one employee
-- if branch has less than 10 employees
Cheers!!

Aliasing a table in a window function?

I am trying to alias a table in a window function, but not sure what I am doing wrong as when I alias it gives error that the columns cannot be resolved
SELECT e.city,
e.time,
e.day,
e.id,
m.id
FROM
(SELECT *,
rank() OVER (PARTITION BY e.id,
e.bin
ORDER BY e.time ASC) rnk
FROM table e
JOIN table2 m
on m.id = e.id
WHERE e.status = 'YES'
AND e.day BETWEEN date '2019-05-06' and date '2019-05-08')
WHERE rnk = 1
You have used the e alias in the outermost select. However, there is nothing in scope with that alias. The inner from doesn't "reach out" like that (scopes do "reach in" the other way though).
So:
SELECT e.city, e.time, e.day, e.id
FROM (SELECT e.*,
rank() OVER (PARTITION BY e.id, e.bin ORDER BY e.time ASC) as rnk
FROM table e
WHERE e.status = 'YES' AND
e.day BETWEEN date '2019-05-06' and date '2019-05-08'
) e
-------^ here
WHERE rnk = 1

calculating the first three HIGHEST GPA of each school

I have calculated the HIGHEST GPA scored by student from each school. But how can I get the list of top 3 GPA, I mean RANK 1, 2, and 3 scored by students from each school ?
SELECT A.*
FROM (
SELECT B.SCHOOL_NAME
,C.STUDENT_NAME
,A.SYMBOL_NO
,A.AVG_GPA
,MAX(A.AVG_GPA) OVER (PARTITION BY B.SCHOOL_NAME) AS MAX_GPA
FROM TBL_STUDENT_MARKS A
INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO
AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE A.AVG_GPA = MAX_GPA
ORDER BY A.AVG_GPA DESC;
You can use either RANK() or DENSE_RANK() or ROW_NUMBER() to achieve the result.
However, RANK() and DENSE_RANK() are preferable for this scenario.
RANK():
SELECT A.*
FROM (
SELECT B.SCHOOL_NAME
,C.STUDENT_NAME
,A.SYMBOL_NO
,A.AVG_GPA
,RANK() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC) AS SCHOOL_RANK
FROM TBL_STUDENT_MARKS A
INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE SCHOOL_RANK <= 3
ORDER BY SCHOOL_NAME, SCHOOL_RANK
DENSE_RANK():
SELECT A.*
FROM (
SELECT B.SCHOOL_NAME
,C.STUDENT_NAME
,A.SYMBOL_NO
,A.AVG_GPA
,DENSE_RANK() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC) AS SCHOOL_DENSE_RANK
FROM TBL_STUDENT_MARKS A
INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE SCHOOL_DENSE_RANK<= 3
ORDER BY SCHOOL_NAME, SCHOOL_DENSE_RANK
ROW_NUMBER():
SELECT A.*
FROM (
SELECT B.SCHOOL_NAME
,C.STUDENT_NAME
,A.SYMBOL_NO
,A.AVG_GPA
,ROW_NUMBER() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC) AS SCHOOL_ROW_NUMBER
FROM TBL_STUDENT_MARKS A
INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE SCHOOL_ROW_NUMBER <= 3
ORDER BY SCHOOL_NAME, SCHOOL_ROW_NUMBER
Please refer here for the difference between Rank, DenseRank and RowNumber
You can use DENSE_RANK() and PARTITION BY in combination:
DENSE_RANK() OVER (
PARTITION BY <expr1>[{,<expr2>...}]
ORDER BY <expr1> [ASC|DESC], [{,<expr2>...}]
)
In this case something like
DENSE_RANK() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY AVG_GPA desc) AS SCHOOL_RANK
and then in the outer query you add
WHERE SCHOOL_RANK in (1, 2, 3)
Also
Give Common Table Expressions a look! I find it often nicer than nested SELECT.
WITH ranked as (
SELECT
SCHOOL_ID
, SYMBOL_NO
, AVG_GPA
, DENSE_RANK() OVER (PARTITION BY SCHOOL_ID ORDER BY AVG_GPA DESC) AS SCHOOL_RANK
FROM TBL_STUDENT_MARKS
)
SELECT
SC.SCHOOL_NAME
, INFO.STUDENT_NAME
, ST.SYMBOL_NO
, ST.AVG_GPA
, ST.SCHOOL_RANK
FROM ranked ST
INNER JOIN TBL_SCHOOL SC ON R.SCHOOL_ID = SC.SCHOOL_ID
INNER JOIN TBL_STUDENT_INFO INFO ON ST.SYMBOL_NO = INFO.SYMBOL_NO AND SC.SCHOOL_ID = INFO.SCHOOL_ID
WHERE SCHOOL_RANK <= 3
ORDER BY SCHOOL_NAME, SCHOOL_RANK;
You can use ROW_NUMBER() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC)
SELECT A.*
FROM (
SELECT B.SCHOOL_NAME
,C.STUDENT_NAME
,A.SYMBOL_NO
,A.AVG_GPA
,ROW_NUMBER() OVER (PARTITION BY B.SCHOOL_NAME ORDER BY A.AVG_GPA DESC)
AS HIGHEST_GPA
FROM TBL_STUDENT_MARKS A
INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO
AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE HIGHEST_GPA <= 3
ORDER BY A.AVG_GPA DESC;
Use Dense_rank window function:
select *
from(SELECT A.*,DENSE_RANK()over(partition by school_name order by MAX_GPA
desc)as rankno
FROM (
SELECT B.SCHOOL_NAME
,C.STUDENT_NAME
,A.SYMBOL_NO
,A.AVG_GPA
,MAX(A.AVG_GPA) OVER (PARTITION BY B.SCHOOL_NAME) AS MAX_GPA
FROM TBL_STUDENT_MARKS A
INNER JOIN TBL_SCHOOL B ON A.SCHOOL_ID = B.SCHOOL_ID
INNER JOIN TBL_STUDENT_INFO C ON A.SYMBOL_NO = C.SYMBOL_NO
AND B.SCHOOL_ID = C.SCHOOL_ID
) A
WHERE A.AVG_GPA = MAX_GPA )B
WHERE rankno IN(1,2,3);

Get top one record of difference date

I try to get just one record of last Order of everysingle customer. ATM I have this idea but it giving me all of them Date of orders.
I work on dataBase AdventurerWorks2012
SELECT
H.CustomerID AS Customer,
H.SalesOrderID AS OrderNumber,
MAX(CAST(H.OrderDate AS DATE)) AS DateOrder
FROM
Sales.SalesOrderHeader H
JOIN
Sales.SalesOrderDetail D
ON H.SalesOrderID = D.SalesOrderID
GROUP BY
H.CustomerID,
H.SalesOrderID
ORDER BY
CustomerID;
You can use TOP 1 WITH TIES
select top 1 with ties
*
From
Sales.SalesOrderHeader H
INNER JOIN Sales.SalesOrderDetail D
ON H.SalesOrderID = D.SalesOrderID
ORDER BY row_number() over (partition by H.CustomerID order by H.OrderDate desc)
This applies and ordering with row_number() giving each customer's order an ID starting at 1 and going to N based off the OrderDate. The WITH TIES allows us to return the TOP 1 for each customer.
Another way, is using a CTE
;with cte as(
select top 1 with ties
*, RN = row_number() over (partition by H.CustomerID order by H.OrderDate desc)
From
Sales.SalesOrderHeader H
INNER JOIN Sales.SalesOrderDetail D
ON H.SalesOrderID = D.SalesOrderID)
select *
from cte
where RN = 1
I think you don't need to do JOIN:
SELECT h.*
FROM Sales.SalesOrderHeader h
WHERE OrderDate = (SELECT MAX(h1.OrderDate)
FROM Sales.SalesOrderHeader h1
WHERE h.CustomerID = h1.CustomerID
);
By this you will get customers with most recent order information.
select top 1 with ties
H.CustomerID AS Customer,
H.SalesOrderID as OrderNumber,
H.OrderDate As DataLast
From
Sales.SalesOrderHeader H
INNER JOIN Sales.SalesOrderDetail D
ON H.SalesOrderID = D.SalesOrderID
ORDER BY row_number() over (partition by H.CustomerID order by H.OrderDate desc)
This work like i need. Thanks!

What would be the result of the following query?

The following query I tried...
select d.deptID, max(tt.total)
from dept d,
(select d.deptID, d.deptName, sum(days) as total
from vacation v, employee e, dept d
where v.empId = e.empID
and d.deptID = e.deptID
group by d.deptID, d.deptName) tt
where d.deptID = tt.deptID
group by d.deptName;
--having max(tt.total);
Try using limit since your inner query already does the calculation.
select TOP 1 * from (
select d.deptID, d.deptName, sum(days) as total
from vacation v, employee e, dept d
where v.empId = e.empID
and d.deptID = e.deptID
group by d.deptID, d.deptName)
order by total desc;
Depends on the dbms you're using.. this is for mysql
In oracle use where rownum = 1
In sql server use SELECT TOP 1 *
Using Top:
Select top 1 with ties * from
(Select D.DepartmentName, sum(V.Days) as SumDays
from Vacations V
inner join Employee E on E.EmployeeID=V.EmployeeID
inner join Department D on D.DepartmentID=E.DepartmentID
group by D.DepartmentName)SumDays
Order by SumDays desc
Try like this,
SELECT TOP 1 d.departmentname,
Sum(v.days) AS vacations
FROM employee emp
INNER JOIN department d
ON d.departmentid = emp.departmentid
INNER JOIN vacations v
ON v.employeeid = emp.employeeid
GROUP BY d.departmentname
ORDER BY 2 DESC