Get sum of consecutive rows in one row - sql

I have a table as:
Emp_id Emp_Name Department Score
123 Raju D1 300
124 Ravi D2 400
125 Annie D3 600
126 Ajay D4 200
127 Amey D5 500
128 Akil D6 100
I need output as
Sum of Score of row1 and row2 in row1
Sum of Score of row2 and row3 in row2,
and so on
So the output should be:
700
1000
800
700
600
I need the output through a SQL query and not a procedure or something else.

It is very easy to do this with an analytic function that uses a sliding window from the current row to the next one (ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING):
SELECT Emp_id, Emp_Name, Department, Score, sum(Score)
OVER (ORDER BY Emp_id ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) sum
FROM score;
When executing this query on your data the result is as follows:
123 Raju D1 300 700
124 Ravi D2 400 1000
125 Annie D3 600 800
126 Ajay D4 200 700
127 Amey D5 500 600
128 Akil D6 100 100
See Database SQL Language Reference, Analytic Functions for further details.

You need Lead function, which will show second row with first row and so on. Name it nxt_score. Then you can add score and nxt_score to get your output. You will also need nvl as for last row, the nxt_score will be null. So in that case, it will add the score with 0.
Remove other columns from select clause if you want.
SELECT
t1.*,
score + nvl(nxt_score, 0) AS cum_score
FROM
(SELECT
t.*,
LEAD(score, 1) OVER (ORDER BY emp_id) AS nxt_score
FROM table1 t
) t1

Related

SQL Oracle to select a column that displays the highest value in a result set

I have an existing query that loads a specific dataset. Please see sample table for illustration
Select I.Invoice_ID, I.Invoice_Date, CI.Unit_Rate
FROM Invoice I, ChargeInvoice CI
Invoice_ID Invoice_Date Unit_Rate
A1 05/08/2018 100
A2 04/08/2018 200
A3 03/08/2018 300
B6 04/06/2018 150
C5 04/15/2018 2000
What I need to add a calculated column which displays the MAX or highest value of one field in the result set, that can be named as MAX_UNIT_RATE.
The expected result set is something like this
Invoice_ID Invoice_Date Unit_Rate Max_Unit_Rate
A1 05/08/2018 100 2000
A2 04/08/2018 200 2000
A3 03/08/2018 300 2000
B6 04/06/2018 150 2000
C5 04/15/2018 2000 2000
I tried this, but It is not getting the desired result
select IV.INVOICE_ID, IV.INVOICE_DATE , ICV.UNIT_RATE, MAX(ICV.UNIT_RATE) AS MAX_UNIT_RATE
FROM INVOICE_V IV,
INVOICE_CHARGE_V ICV
GROUP BY IV.INVOICE_ID, IV.INVOICE_DATE, ICV.UNIT_RATE
You should be writing your query with correct join conditions. The solution to your problem are window functions:
SELECT I.Invoice_ID, I.Invoice_Date, CI.Unit_Rate,
MAX(CI.Unit_Rate) OVER () as MAX_Unit_Rate
FROM Invoice I JOIN
ChargeInvoice CI
ON I.Invoice_Id = CI.Invoice_ID -- this is a guess

Select rows where value changed in column

Currently I have this table in sql database sorted by Account#.
Account# Charge_code PostingDate Balance
12345 35 1/18/2016 100
**12345 35 1/20/2016 200**
12345 61 1/23/2016 250
12345 61 1/22/2016 300
12222 41 1/20/2016 200
**12222 41 1/21/2016 250**
12222 42 1/23/2016 100
12222 42 1/25/2016 600
How do I select last row prior to the change in the charge_code column for each Account#. I highlighted the rows that I am trying to return.
The query should execute quickly with the table having tens of thousands of records.
In SQL Server 2012+, you would use lead():
select t.*
from (select t.*,
lead(charge_code) over (partition by account order by postingdate) as next_charge_code
from t
) t
where charge_code <> next_charge_code;
In earlier versions of SQL Server, you can do something similar with apply.

Select statement with multiple rows from condition on values in single column affecting more than one column

I have the table below.Using salary as condition I want to get multiple rows. Below is current table call it employee.
empid | name | salary
-----------------------------------
1 A1 alex 20000
2 B2 ben 4500
3 C1 carl 14000
compare the salary to certain fixed values, and every time the salary is larger than the fixed value, show a record in output.Also output a calculated tax column.Below is a step closer to my final result
select e.*,tax= (case when salary<6000 then tax=0.06 *salary,when salary between 6000 and 18000 then tax= 0.06 *(salary -6000),else tax =0 ),m.incometype,
from employee e
left join
(
select 0 as threshold, 101 as incometype
union
select 5999 as threshold, 102 as incometype
union
select 17999 as threshold, 103 as incometype
) m
on e.salary > m.threshold
order by e.empid
Desired ouput would be:
empid | name | salary | incometype | tax
----------------------------------------------
1 A1 alex 20000 101 360
2 A1 alex 20000 102 720
3 A! alex 20000 103 0
4 B2 ben 4500 101 270
5 C1 carl 14000 101 360
6 C1 carl 14000 102 480
this is a question further to Select statement with multiple rows from condition on values in single column
this may help you
select e.*,
case
when salary<6000 then (0.06*salary)
when salary between 6000 and 1800 then (0.06*(salary -6000))
when m.incometype=103 then 0
end as tax
,m.incometype,
from employee e
left join
(
select 0 as threshold, 101 as incometype
union
select 5999 as threshold, 102 as incometype
union
select 17999 as threshold, 103 as incometype
) m
on e.salary > m.threshold
order by e.empid

Select statement with multiple rows from condition on values in single column

I have the table below.Using salary as condition I want to get multiple rows.
Below is current table call it employee.
empid name salary
-----------------------------------
1 A1 alex 20000
2 B2 ben 4500
3 C1 carl 14000
compare the salary to certain fixed values, and every time the salary is larger than the fixed value, show a record in output.My attempt condition case is close to this:
incometype= case When salary<6000 then 101 When salary Between 6000 And 18000 Then
102 Else 103 End
Desired ouput would be:
empid name salary incometype
------------------------------------------
1 A1 alex 20000 101
2 A1 alex 20000 102
3 A! alex 20000 103
4 B2 ben 4500 101
5 C1 carl 14000 101
6 C1 carl 14000 102
I have tried using union but union will give me 3 rows for each record even when value meets 1st condition.
Your question is unclear, because your logic implies that you should only have 3 output rows for 3 input rows. Your output however implies that you want to compare the salary to certain fixed values, and every time the salary is larger than the fixed value, show a record in output.
If the former is the case, Minh's query is all you need. In the latter case, you can do something like this:
select e.*, m.incometype
from employee e
left join
(
select 0 as threshold, 101 as incometype
union
select 5999 as threshold, 102 as incometype
union
select 17999 as threshold, 103 as incometype
) m
on e.salary > m.threshold
order by e.empid
If you want to add a calculate column i.e. one with values calculated using columns in this query, you can simply add it as a column in the select clause, like so:
select e.*,
m.incometype,
case
when <first condition> then <business logic here>
....
else <handle default case>
end as yourcomputedcolumn
from
...
This returns 3 rows and enough for your need:
SELECT empid, name, salary,
case When salary<6000 then 101
When salary Between 6000 And 18000 Then 102
Else 103 End as incometype
FROM employee;
Not very clear on the requirement, however the following worked for me:
Select
EmpId,Name,Sal,101 IncomeType
from Emp
Union all
Select
EmpId,Name,Sal,102
from Emp
Where Sal > 6000
union all
Select
EmpId,Name,Sal,103
from Emp
Where Sal > 18000;

Query to display largest n% of values and group the rest as "other"

I see someone posted something very similar to what I am looking to do in Access 2010.
Grouping of top 80% categories
I saw the response but am confused as to the nomenclature used and the titles assigned. I have 5 vendors that supply product. I only care about the top 80% as a pareto distribution and the remainder can be grouped as "Other"
4 vendors as Field [vendors]: A1, A2, A3, A4
4 values as Field [Lbs]: 4000, 5000, 200, 800
Query returns: A1, A2, Other
Thanks for any help anyone can provide.
When performing calculations like this we need to be mindful of what happens when there is a tie, so let's use the following [VendorData]
vendors lbs
------- ----
A1 2000
A2 3000
A3 200
A4 800
A5 2000
A6 2000
We can start by creating the following saved query named [VendorPct] in Access
SELECT
vendors,
lbs,
lbs_sum,
lbs / lbs_sum * 100 AS lbs_pct
FROM
(
SELECT vendors, lbs, lbs_sum
FROM
VendorData,
(
SELECT Sum(lbs) AS lbs_sum FROM VendorData
)
)
It gives us
vendors lbs lbs_sum lbs_pct
------- ---- ------- -------
A1 2000 10000 20
A2 3000 10000 30
A3 200 10000 2
A4 800 10000 8
A5 2000 10000 20
A6 2000 10000 20
Now we can create a saved query in Access named [VendorPctCumulative]
SELECT
vendors,
Max(lbs) AS lbs_,
Max(lbs_pct) as lbs_pct_,
Sum(lbs_pct_other) AS lbs_pct_cumulative_
FROM
(
SELECT
vendors,
lbs,
lbs_pct,
lbs_pct AS lbs_pct_other
FROM VendorPct
UNION ALL
(
SELECT
v1.vendors,
v1.lbs,
v1.lbs_pct,
v2.lbs_pct AS lbs_pct_other
FROM
VendorPct v1
INNER JOIN
VendorPct v2
ON (v2.lbs = v1.lbs AND v2.vendors < v1.vendors)
OR v2.lbs > v1.lbs
)
)
GROUP BY vendors
ORDER BY Sum(lbs_pct_other), vendors
That produces
vendors lbs_ lbs_pct_ lbs_pct_cumulative_
------- ---- -------- -------------------
A2 3000 30 30
A1 2000 20 50
A5 2000 20 70
A6 2000 20 90
A4 800 8 98
A3 200 2 100
Now one more saved query named [VendorPctCumulativeThreshold] to find the first cumulative percent that meets or exceeds the 80% threshold:
SELECT TOP 1 lbs_pct_cumulative_
FROM
(
SELECT lbs_pct_cumulative_
FROM VendorPctCumulative
WHERE lbs_pct_cumulative_ >= 80
ORDER BY lbs_pct_cumulative_
)
i.e.,
lbs_pct_cumulative_
-------------------
90
and we can put it all together with
SELECT
vendors,
lbs_ AS lbs,
lbs_pct_ AS lbs_pct
FROM
VendorPctCumulative vpc
INNER JOIN
VendorPctCumulativeThreshold vpct
ON vpc.lbs_pct_cumulative_ <= vpct.lbs_pct_cumulative_
UNION ALL
SELECT
"other" AS vendors,
Sum(lbs_) AS lbs,
Sum(lbs_pct_) AS lbs_pct
FROM
VendorPctCumulative vpc
INNER JOIN
VendorPctCumulativeThreshold vpct
ON vpc.lbs_pct_cumulative_ > vpct.lbs_pct_cumulative_
ORDER BY 3 DESC, 1
producing
vendors lbs lbs_pct
------- ---- -------
A2 3000 30
A1 2000 20
A5 2000 20
A6 2000 20
other 1000 10