Need sql query to get expected output for the below, - sql

Tried the below query, but it works only for the first and second records.
Select
name,
dept,
sal,
(
coalesce(sal, 0) + coalesce(saltodrop)
) as running total (
SELECT
name,
dept,
sal,
LAG(Sal, 1, 0) OVER(
PARTITION BY [dept]
ORDER BY
[name],
[dept] ASC
) AS [saltodrop]
FROM
dataset
) as data_set_extract
Input
Name dept sal
John sales 10000
Tom sales 8000
Tim sales 5000
George finance 6000
Dane finance 4000
Mike hr 5000
Meme hr 6000
Ark it 5000
Output
Name dept sal
John sales 1000
Tom sales 18000
Tim sales 23000
George finance 29000
Dane finance 33000
Mike hr 38000
Meme hr 44000
Ark it 49000
Using the Oracle database, I need to add a consecutive row of the
first two records, later the sum of the first record and second record
with that of the third record and so on.

Assuming you have already ordered the results then use the SUM analytic function and order by ROWNUM to keep the current ordering:
SELECT t.*,
SUM(sal) OVER (ORDER BY ROWNUM) AS cumulative_sal
FROM table_name t;
Which, for the sample data:
CREATE TABLE table_name (Name, dept, sal) AS
SELECT 'John', 'sales', 10000 FROM DUAL UNION ALL
SELECT 'Tom', 'sales', 8000 FROM DUAL UNION ALL
SELECT 'Tim', 'sales', 5000 FROM DUAL UNION ALL
SELECT 'George', 'finance', 6000 FROM DUAL UNION ALL
SELECT 'Dane', 'finance', 4000 FROM DUAL UNION ALL
SELECT 'Mike', 'hr', 5000 FROM DUAL UNION ALL
SELECT 'Meme', 'hr', 6000 FROM DUAL UNION ALL
SELECT 'Ark', 'it', 5000 FROM DUAL;
Outputs:
NAME
DEPT
SAL
CUMULATIVE_SAL
John
sales
10000
10000
Tom
sales
8000
18000
Tim
sales
5000
23000
George
finance
6000
29000
Dane
finance
4000
33000
Mike
hr
5000
38000
Meme
hr
6000
44000
Ark
it
5000
49000
db<>fiddle here

Related

Oracle Analytic Function.. OVER PARTITION BY

Trying to calculate Total Sales like below with the following query, But getting not a group by error.
select country,month,sales,sum(sales) over (partition by country order by month)
from check2
group by country,month,sales
Data
Expected Output
If you're using OVER..PARTITION BY, then you don't need the GROUP BY.
Just this should be sufficient
select country,month,sales,sum(sales) over (partition by country order by month)
from check2
See example here on LiveSL
Don't use GROUP BY and, if you want the total for the entire partition then, don't use ORDER BY in the analytic function:
select country,
month,
sales,
sum(sales) over (partition by country) As total_sales
from check2
Which, for the sample data:
CREATE TABLE check2(country, month, sales) AS
SELECT 'US', 202204, 2000 FROM DUAL UNION ALL
SELECT 'US', 202205, 3000 FROM DUAL UNION ALL
SELECT 'US', 202206, 5000 FROM DUAL UNION ALL
SELECT 'Canada', 202204, 8000 FROM DUAL UNION ALL
SELECT 'Canada', 202205, 2000 FROM DUAL UNION ALL
SELECT 'Canada', 202206, 1000 FROM DUAL;
Outputs:
COUNTRY
MONTH
SALES
TOTAL_SALES
Canada
202205
2000
11000
Canada
202204
8000
11000
Canada
202206
1000
11000
US
202205
3000
10000
US
202204
2000
10000
US
202206
5000
10000
fiddle

List the branch that monthly pays the most in salaries

I have this table, the expected output should be B003 since it's pays 54,000
STAFF
SALARY
BRAN
SL21
30000
B005
SG37
12000
B003
SG14
18000
B003
SA9
9000
B007
SG5
24000
B003
SL41
9000
B005
So far I only have this subquery, which isn't working how I expected.
SELECT BRANCHNO
FROM STAFF
WHERE (SALARY) IN (SELECT MAX(SUM(SALARY))
FROM STAFF
GROUP BY BRANCHNO);
This works but I want a subquery that returns the branchno
SELECT MAX(SUM(SALARY))
FROM STAFF
GROUP BY BRANCHNO;
select BRANCHNO max(sum_sal)
from (SELECT BRANCHNO, SUM(SALARY) sum_sal
FROM STAFF
GROUP BY BRANCHNO) q1
group by BRANCHNO ;
The column used to group the rows can be displayed. So, add BRANCHNO to your select clause.
One option is to use rank analytic function which ranks branches by sum of their salaries in descending order; you'd then return the one(s) that rank as the highest (rnk = 1).
Sample data:
SQL> with staff (staff, salary, bran) as
2 (select 'SL21', 30000, 'B005' from dual union all
3 select 'SG37', 12000, 'B003' from dual union all
4 select 'SG14', 18000, 'B003' from dual union all
5 select 'SA9' , 9000, 'B007' from dual union all
6 select 'SG5' , 24000, 'B003' from dual union all
7 select 'SL41', 9000, 'B005' from dual
8 )
Query:
9 select bran
10 from (select bran, rank() over (order by sum(salary) desc) rnk
11 from staff
12 group by bran
13 )
14 where rnk = 1;
BRAN
----
B003
SQL>

SQL Joining transactions on Date Range

In SQL Server 2014, I'm working with two tables, an EMPLOYEE and a SALES table:
EMPID EMPNAME HIRE_DATE
---------------------------
1234 JOHN SMITH 2021-05-01
1235 JANE DOE 2021-08-05
1236 JANE SMITH 2021-07-31
EMPID SALE_DATE PRODUCT
-------------------------------------
1234 2021-05-05 VPN
1234 2021-05-10 VPN Basic
1234 2021-07-15 Cloud Storage Bronze
1234 2021-07-05 Cloud Storage Gold
1235 2021-10-01 Antivirus
I need to write a query that will produce all rows/columns from the EMPLOYEE table, with a column showing their (aggregated) sales, but ONLY sales that were triggered within 30 days of the hire date.
This query works, but will pull in ALL sales completed until present:
SELECT EMP.*, SALES_30_DAYS
FROM EMP
LEFT JOIN
(SELECT EMPID, COUNT(*)
FROM SALES_30_DAYS
GROUP BY EMPID) ON EMP.EMPID = SALES.EMPID
In this other attempt, HIRE_DATE is not recognized in the sub-query.
SELECT EMP.*, SALES_30_DAYS
FROM EMP
LEFT JOIN
(SELECT EMPID, COUNT(*) SALES_30_DAYS
FROM SALES
WHERE DATEDIFF(DD, HIRE_DATE, SALE_DATE) < 30
GROUP BY EMPID) ON EMP.EMPID= SALES.EMPID
How can I re-write this query, so that the second table will provide the aggregated sales ONLY if the sale took place up to 30 days after the hire date?
Desired outcome:
EMPID EMPNAME HIRE_DATE SALES_30_DAYS
-----------------------------------------
1234 JOHN SMITH 2021-05-01 2
1235 JANE DOE 2021-08-05 1
1236 JANE SMITH 2021-07-31 NULL
WITH EMPLOYEES(EMPID, EMPNAME, HIRE_DATE)AS
(
SELECT 1234, 'JOHN SMITH', '2021-05-01' UNION ALL
SELECT 1235, 'JANE DOE' , '2021-08-05' UNION ALL
SELECT 1236, 'JANE SMITH' ,'2021-07-31'
),
SALES(EMPID, SALE_DATE, PRODUCT) AS
(
SELECT 1234, '2021-05-05' ,'VPN' UNION ALL
SELECT 1234 , '2021-05-10' ,'VPN Basic' UNION ALL
SELECT 1234 , '2021-07-15' ,'Cloud Storage Bronze' UNION ALL
SELECT 1234 , '2021-07-05' ,'Cloud Storage Gold' UNION ALL
SELECT 1235 , '2021-10-01', 'Antivirus'
)
SELECT E.EMPID,E.EMPNAME,E.HIRE_DATE,SALE_QUERY.CNTT
FROM EMPLOYEES E
OUTER APPLY
(
SELECT COUNT(*)CNTT
FROM SALES AS S WHERE E.EMPID=S.EMPID AND
S.SALE_DATE BETWEEN E.HIRE_DATE AND DATEADD(DD,30,E.HIRE_DATE)
)SALE_QUERY
Could you please try if the above is suitable for you

How to get records for the values when there was increase in salary

I want to check if the salary of an employee has salary increased between 100 and 500.
Employee Salary Serial No ID Criteria
James 500 1 110 Inc
James 800 2 110 NA
James 900 3 110 NA
James 1200 4 110 Inc
James 1100 5 110 NA
James 1500 6 110 NA
Jim 1000 1 112 Inc
Jim 1100 2 112 NA
Jim 1300 3 112 NA
Jim 1500 4 112 NA
Jim 1900 5 112 Inc
Jim 1800 6 112 NA
Jim 2200 7 112 NA
--ID is unique to each employee and serial no is the sequence of events
occurrence for the employee in terms of salary increase or decrease. I need to find the serial number which had previous criteria as Inc ( does not necessarily have to be previous row, as long as it satisfies the criteria of 100 and 500) and salary increase between 100 and 500. Please note we might have multiple records satisfying the criteria but I need only one which ever is the first one which had increase. Also, we may have salary decrease as well ,I don't need to display it rather display the next record which has satisfying criteria. We need to look only we have criteria as Inc and then look for values which satisfy the range between 100 and 500, and get the first value.
--Desired Output
Employee Salary Serial No ID Criteria
James 800 2 110 NA
James 1500 6 110 NA
Jim 1100 2 112 NA
Jim 2200 7 112 NA
You could do this by incrementally adding information to your records via several entries in a with clause.
In the first select I just reproduced your example data. The end result will produce all the intermediary information so you can see the logic that has been applied:
with salary(Employee, Salary, SerialNo, ID, Criteria) as (
select 'James', 500, 1, 110, 'Inc' union all
select 'James', 800, 2, 110, 'NA' union all
select 'James', 900, 3, 110, 'NA' union all
select 'James', 1200, 4, 110, 'Inc' union all
select 'James', 1100, 5, 110, 'NA' union all
select 'James', 1500, 6, 110, 'NA' union all
select 'Jim', 1000, 1, 112, 'Inc' union all
select 'Jim', 1100, 2, 112, 'NA' union all
select 'Jim', 1300, 3, 112, 'NA' union all
select 'Jim', 1500, 4, 112, 'NA' union all
select 'Jim', 1900, 5, 112, 'Inc' union all
select 'Jim', 1800, 6, 112, 'NA' union all
select 'Jim', 2200, 7, 112, 'NA'
),
extended as (
select salary.*,
count(case Criteria when 'Inc' then 1 end) over
(partition by Employee order by SerialNo) incGroup
from salary
),
extended2 as (
select extended.*,
first_value(Salary) over
(partition by Employee, incGroup order by SerialNo) incSalary
from extended
),
extended3 as (
select extended2.*,
row_number() over
(partition by Employee, incGroup order by SerialNo) rn
from extended2
where Salary - incSalary between 100 and 500
)
select * from extended3 where rn = 1;
See it run on rextester.com
NB/ You might want to partition by ID where I did it by Employee if indeed the ID is the Employee's key.

how to retrieve highest and lowest salary from following table?

I have employee table
EMP_ID | F_NAME | L_NAME | SALARY | JOINING_DATE | DEPARTMENT
-----------------------------------------------------------------------------------
101 | John | Abraham | 100000 | 01-JAN-14 09.15.00.000000 AM | Banking
102 | Michel | Clarke | 800000 | | Insaurance
102 | Roy | Thomas | 70000 | 01-FEB-13 12.30.00.000000 PM | Banking
103 | Tom | Jose | 600000 | 03-FEB-14 01.30.00.000000 AM | Insaurance
105 | Jerry | Pinto | 650000 | 01-FEB-13 12.00.00.000000 PM | Services
106 | Philip | Mathew | 750000 | 01-JAN-13 02.00.00.000000 AM | Services
107 | TestName1 | 123 | 650000 | 01-JAN-13 12.05.00.000000 PM | Services
108 | TestName2 | Lname% | 600000 | 01-JAN-13 12.00.00.000000 PM | Insaurance
i want to find highest and lowest salary from above table in oracle sql.
if i do
select max(salary) from (select * from (select salary from employee) where rownum <2);
it returns MAX(SALARY) = 100000 where it should return 800000
If I do
select max(salary)
from (select * from (select salary from employee)
where rownum <3);
it returns MAX(SALARY) = 800000
If I do
select min(salary)
from (select * from(select salary from employee)
where rownum < 2);
it will return MIN(SALARY) = 100000 where it should return 70000.
What is wrong in this query?
what should be the correct query?
You don't need all these subqueries:
SELECT MAX(salary), MIN(salary)
FROM employee
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE employee ( EMP_ID, F_NAME, L_NAME, SALARY, JOINING_DATE, DEPARTMENT ) AS
SELECT 101, 'John', 'Abraham', 100000, TIMESTAMP '2014-01-01 09:15:00', 'Banking' FROM DUAL
UNION ALL SELECT 102, 'Michel', 'Clarke', 800000, NULL, 'Insurance' FROM DUAL
UNION ALL SELECT 102, 'Roy', 'Thomas', 70000, TIMESTAMP '2013-02-01 12:30:00', 'Banking' FROM DUAL
UNION ALL SELECT 103, 'Tom', 'Jose', 600000, TIMESTAMP '2014-02-03 01:30:00', 'Insurance' FROM DUAL
UNION ALL SELECT 105, 'Jerry', 'Pinto', 650000, TIMESTAMP '2013-02-01 12:00:00', 'Services' FROM DUAL
UNION ALL SELECT 106, 'Philip', 'Mathew', 750000, TIMESTAMP '2013-01-01 02:00:00', 'Services' FROM DUAL
UNION ALL SELECT 107, 'TestName1', '123', 650000, TIMESTAMP '2013-01-01 12:05:00', 'Services' FROM DUAL
UNION ALL SELECT 108, 'TestName2', 'Lname%', 600000, TIMESTAMP '2013-01-01 12:00:00', 'Insurance' FROM DUAL;
Query 1 - To find the highest-n salaries:
SELECT *
FROM (
SELECT salary
FROM employee
ORDER BY salary DESC
)
WHERE rownum <= 3 -- replace with the number of salaries you want to retrieve.
Results:
| SALARY |
|--------|
| 800000 |
| 750000 |
| 650000 |
Query 2 - To find the lowest-n salaries:
SELECT *
FROM (
SELECT salary
FROM employee
ORDER BY salary ASC
)
WHERE rownum <= 3 -- replace with the number of salaries you want to retrieve.
Results:
| SALARY |
|--------|
| 70000 |
| 100000 |
| 600000 |
For each row returned by a query, the ROWNUM pseudocolumn returns a number indicating the order in which Oracle selects the row from a table or set of joined rows. The first row selected has a ROWNUM of 1, the second has 2, and so on.
So in your case :
select max(salary) from (select * from (select salary from employee) where rownum <2);
This query will return
101 John Abraham 100000 01-JAN-14 09.15.00.000000 AM Banking
only this row as output... and hence the max value will be 100000 only.
select max(salary) from (select * from (select salary from employee) where rownum <3);
This query will tak first 2 rows from your table, i.e.,
101 John Abraham 100000 01-JAN-14 09.15.00.000000 AM Banking
102 Michel Clarke 800000 Insaurance
and hence the max salary will be 800000.
Similarly,
select min(salary)from (select * from(select salary from employee)where rownum<2);
will only select 1st row
select min(salary)from (select * from(select salary from employee)where rownum<2);
so min salary will be 100000.
P.S. : You could simply write your queries like this :
select max(salary) from employee where rownum<[n];
where n will be ROWNUM to which you want to limit the number of rows returned by your query
Try it:
select *
from (
select T.*, rownum RRN
from (
select salary
from employee
order by salary desc) T)
where RRN < 3
so you want the 2nd highest and 2nd lowest salary? Check this out
select max(salary), min(salary) from employee
where salary < (select max(salary) from employee)
and salary > (select min(salary) from employee)
;
1) For lowest salary.
select * from (
select empno,job,ename,sal
from emp order by sal)
where rownum=1;
2) For Highest salary.
select * from (
select empno,job,ename,sal
from emp order by sal desc)
where rownum=1;
i don't know why you make complicated queries you can simply write this and get the same result:
select salary
from employees
where rownum <=3
order by salary desc;
you can solve your problem with following queries:
Highest salary:
Select * from Employee(Select salary from Employee ORDER BY salary DISC) where rownum=1;
Lowest salary:
Select * from Employee(Select salary from Employee ORDER BY salary) where rownum=1;
Second highest salary:
Select MAX(Salary) from Employee
Where Salary < (Select MAX(Salary) from employee);
Second Lowest salary :
Select MIN(Salary) from Employee
Where Salary > (Select MIN(Salary) from employee);