ANALYTICAL FUNCTION:
(i).Analytical functions, also known as window functions.
(ii).Analytical functions calculate an aggregate value based on a group of rows and
return multiple rows for each group.
Aggregate Function or Group Function:
Group function process the values of multiple rows to return one result per group.
Analytical Function:
It process the vaues of multiple rows to return multiple rows for each set of
values.
Multiple rows it return one row     --Aggregate
Each rows it return one row.        --Analytical
select department_id, MAX(salary) from employees GROUP BY department_id;
select department_id, MAX(salary) OVER() FROM employees;
PARTITION BY,ORDER BY   --optional clause
select department_id, MAX(salary) OVER(PARTITION BY department_id ORDER BY salary
desc) FROM employees;
with A as
(select employee_id,first_name,department_id,salary, ROW_NUMBER() OVER(PARTITION BY
department_id ORDER BY salary Desc) RNK from employees
) select * from A where RNK=1;
RANK
DENSE_RANK
ROW_NUMBER
LEAD
LAG
FIRST_VALUE
LAST_VALUE
CUBE
ROLLUP
RANK()
(i). It accept one arg.
(ii). It is used to provide rank for a column value.
(iii). If two records are same then it give same rank for both records, and next
records will be (n+2) rank.
SYNTAX:
RANK() OVER(PARTITION BY CLAUSE ORDER BY CLAUSE)
ie: 1
    1
    3
select Employee_id,First_name,salary, RANK() OVER(ORDER BY SALARY DESC) RNK from
employees;
select employee_id,first_name,department_id,salary, RANK() OVER(PARTITION BY
department_id ORDER BY salary Desc) RNK from employees;
select employee_id,first_name,department_id,salary, RANK() OVER(PARTITION BY
department_id ORDER BY SALARY DESC) RNK from employees where RNK=1; --RNK: invalid
identifier
Oracle Execution Order             Query order
        FROM                             Select
        WHERE                            From
        GROUP BY                         Where
        HAVING                                 Group by
        SELECT                                 Having
        ORDER BY                         Order by
WITH clause(Common Table Expression (CTE)): is a named subquery(or temp table)
that you can reference within your main SQL query to make your code more organized
and easier to understand.
WITH A AS
(select Employee_id,First_name,salary, RANK() OVER(ORDER BY SALARY DESC) RNK from
employees)
select * from A where RNK=14;
WITH A AS
(select Employee_id,First_name,salary, RANK() OVER(ORDER BY SALARY DESC) RNK from
employees)
select * from A where RNK between 14 and 20;
WITH A AS
(select Employee_id,First_name,salary, RANK() OVER(ORDER BY SALARY DESC) RNK from
employees where salary between 10000 and 15000)
select * from A;
DENSE_RANK()
(i). It accept one arg.
(ii). It is used to provide rank for a column value.
(iii). If two records are same then it give same rank for both records, and next
records will be (n+1) rank.
(If multiple rows have the same values and are assigned the same rank, the next
rank will be consecutive, without any gaps)
ie: 1
    1
    2
SYNTAX:
DENSE_RANK() OVER(PARTITION BY CLAUSE ORDER BY CLAUSE)
select Employee_id,First_name,salary,
DENSE_RANK() OVER(ORDER BY SALARY DESC) RNK from employees;
select employee_id,first_name,department_id,salary, DENSE_RANK() OVER(PARTITION BY
department_id ORDER BY salary Desc) RNK from employees
WITH B AS
(select employee_id,first_name,department_id,salary, DENSE_RANK() OVER(PARTITION BY
department_id ORDER BY salary Desc) RNK from employees)
select * from B where RNK between 3 and 6;
ROW_NUMBER()
select Employee_id,First_name,salary, ROW_NUMBER() OVER(ORDER BY SALARY DESC) RNK
from employees;
with B as
(select Employee_id,First_name,salary, ROW_NUMBER() OVER(ORDER BY SALARY DESC) RNK
from employees)
select * from B where RNK between 90 and 95;
LEAD()
(i) It accept one to three Args.
(ii) It is used to print next row value in current record.
SYNTAX:
LEAD(expr, offset, default) OVER(PARTITION BY CLAUSE ORDER BY CLAUSE)
select employee_id,first_name,salary from employees order by salary desc;
select employee_id,first_name,salary, row_number() over(order by salary desc) rnk
from employees;
select employee_id,first_name,salary, rank() over(order by salary desc) rnk from
employees;
select employee_id,first_name,salary, dense_rank() over(order by salary desc) rnk
from employees;
LEAD()
LEAD(expr, offset, default) OVER(PARTITION BY CLAUSE ORDER BY CLAUSE)
select employee_id,first_name,salary,   lead(salary,1,99) over(order by salary desc)
from employees;
select employee_id,first_name,salary,   lead(salary,2,500) over(order by salary desc)
from employees;
select employee_id,first_name,salary,   lead(salary,1) over(order by salary desc)
from employees;--2 arg
select employee_id,first_name,salary,   lead(salary) over(order by salary desc) from
employees; --1 arg
select employee_id,first_name,salary, lead(salary,1,0) over(order by employee_id)
nxt_emp_sal,
                            salary - lead(salary,1,0) over(order by employee_id)
sal_diff from employees;
LAG()
(i) It accept one to three Args.
(ii) It is used to print next row value in current record.
SYNTAX:
LAG(expr,offset,default) OVER(PARTITION BY CLAUSE ORDER BY CLAUSE)
select employee_id,hire_date,salary, row_number() over(order by salary desc) from
employees;
select employee_id,hire_date,salary, rank()       over(order by salary desc) from
employees;
select employee_id,hire_date,salary, dense_rank() over(order by salary desc) from
employees;
select employee_id,first_name,salary, LAG(salary,1,0) OVER(order by salary
desc)pre_val from employees;
select employee_id,first_name,salary, LAG(salary,1,0) OVER(order by salary
desc)pre_val from employees;
select employee_id,first_name,salary, LAG(salary,2,0) OVER(order by salary
desc)pre_val from employees;
select employee_id,first_name,salary, LAG(salary,2) OVER(order by salary
desc)pre_val from employees;
select employee_id,first_name,department_id,salary, LAG(salary,1,0)
OVER(partition by department_id order by salary desc) pre_val from employees;
CREATE TABLE T_SALES(SALES_MONTH DATE,QUANTITY NUMBER);
INSERT ALL
INTO T_SALES VALUES('10-JAN-2021',100)
INTO T_SALES VALUES('15-FEB-2021',50)
INTO T_SALES VALUES('28-APR-2021',150)
INTO T_SALES VALUES('14-MAY-2021',200)
INTO T_SALES VALUES('05-SEP-2021',100)
INTO T_SALES VALUES('14-NOV-2021',70)
INTO T_SALES VALUES('10-DEC-2021',130)
SELECT * FROM DUAL;
SELECT * FROM T_SALES;
WITH A AS (select sales_month,quantity, LAG(QUANTITY,1,0) OVER(ORDER BY sales_month
ASC) pre_sales from T_SALES)
select sales_month,quantity,pre_sales,
CASE
when quantity > pre_sales then 'UP'
else 'DOWN' END ratio from A;
create table sales_data(sales_date date,daily_sales number);
insert   into   sales_data   (sales_date,daily_sales)   values   ('10-JAN-21',70);
insert   into   sales_data   (sales_date,daily_sales)   values   ('11-JAN-21',60);
insert   into   sales_data   (sales_date,daily_sales)   values   ('12-JAN-21',75);
insert   into   sales_data   (sales_date,daily_sales)   values   ('13-JAN-21',80);
insert   into   sales_data   (sales_date,daily_sales)   values   ('14-JAN-21',82);
insert   into   sales_data   (sales_date,daily_sales)   values   ('15-JAN-21',74);
insert   into   sales_data   (sales_date,daily_sales)   values   ('16-JAN-21',90);
insert   into   sales_data   (sales_date,daily_sales)   values   ('17-JAN-21',85);
select * from sales_data;
select sales_date, daily_sales,lag(daily_sales) over (order by sales_date) as
prev_day_sales,
                  daily_sales - lag(daily_sales) over (order by sales_date) as
sales_growth from sales_data order by sales_date;
SELECT RNK, e.*
FROM (
    SELECT e.*, RANK() OVER(PARTITION BY department_id ORDER BY SALARY DESC) RNK
    FROM employees e
) ranked_employees;