How can add the cumulative sum from bottom to top? - database

Create a tmp table and add the num column from top till bottom::
WITH data (num) AS (
VALUES( 1),
( 5),
( 3)
)
SELECT num, sum(num) OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM data;
All the num added:
num | sum
-----+-----
1 | 1
5 | 6
3 | 9
How can add all the num from bottom till top such as:
num | sum
-----+-----
1 | 9
5 | 8
3 | 3

First of all, there needs to be a second column which provides the ordering you seem to think exists in your table. Note that SQL tables are based on unordered sets of tuples.
WITH data (id, num) AS (
VALUES ROW(1, 1),
ROW(2, 5),
ROW(3, 3)
)
SELECT num, SUM(num) OVER (ORDER BY id DESC) AS sum
FROM data
ORDER BY id;
Here we are taking a rolling sum in the reverse order.
Demo

Related

Using multiple row results on a formula, based by group

Is there a way to use the results from a multiple rows on a formula, divided by each group.
I have the followin formula:
result = (1st vfg ) / (1 + (1st vfg / 2nd vfg) + (1st vfg / 3rd vfg) + ... + (1st vfg / *nth* vfg) )
vfg = value from group
For example, the table bellow:
Group | Value
---------------
1 | 1000
1 | 280
1 | 280
2 | 1000
Note: I guarantee that there will be no 0 (zero) or NULLs in the value for the first table
Should give me the following result:
Group | Result
---------------
1 | 122.85
2 | 1000 -> If there is only one value on the group, the result will be the value itself
You need a column that indicates the row order within a group (timestamps, the sequence number, identity column, etc.). Rows in a database table have no implicit order. Once you have that, you can use a CTE and window functions to solve the problem:
;WITH
cte AS
(
SELECT [Group]
, [Value]
, FIRST_VALUE([Value]) OVER (PARTITION BY [Group] ORDER BY RowOrder) AS FirstValue
, FIRST_VALUE([Value]) OVER (PARTITION BY [Group] ORDER BY RowOrder) / [Value] AS Subtotal
FROM MyTable
)
SELECT [Group]
, AVG(FirstValue) / SUM(Subtotal) AS Result
FROM cte
GROUP BY [Group]

Get top X percentage based on cumulative sum

My table looks like this:
ID | ItemID | ItemQualityID | Amount | UnitPrice
My goal is to find the top x% rows for each ItemID + ItemQualityID pair based on Amount cumulative sum and ordered by UnitPrice.
For example:
ID | ItemID | ItemQualityID | Amount | UnitPrice
1 1 1 18 2
2 1 1 1 1
3 1 1 1 1
4 2 1 18 2
5 2 1 1 1
6 2 1 1 1
7 1 1 1 3
and I want the top 10%, then the resulting table should contain row #2, 3, 5, 6. Since the total amount for ItemID 1 and 2 are 21 and 20 respectively, thus 10% would be 2 items each. If I want the top 20%, the resulting table should still be the same since if I include row 1 and 4 it would make it 100%. Row #7 has unit price > row #1 so if row #1 is not included then row #7 shouldn't be included as well.
Ideally I want the table with all the filtered rows for some other calculations but I will be happy even if I can only get the sum of Amount * UnitPrice of the filtered table. Something like
ItemID | ItemQualityID | Sum
1 1 2
2 1 2
for the above example.
You can use SUM OVER :
DECLARE #percent DECIMAL(5, 2) = .1
;WITH CteSum AS(
SELECT *,
TotalSum = SUM(Amount) OVER(PARTITION BY ItemID, ItemQualityID),
CumSum = SUM(Amount) OVER(PARTITION BY ItemID, ItemQualityID ORDER BY UnitPrice, ID)
FROM tbl
)
SELECT
ItemID,
ItemQualityID,
[Sum] = SUM(Amount * UnitPrice)
FROM CteSum
WHERE CumSum <= #percent * TotalSum
GROUP BY ItemID, ItemQualityID
ONLINE DEMO

SQL Server SUM based on subsequent records

Microsoft SQL Server 2012 (SP1) - 11.0.3156.0 (X64)
I am not sure of the best way to word this and have tried a few different searches with different combinations of words without success.
I only want to Sum Sequence = 1 when there are Sequence > 1, in the table below the Sequence = 1 lines marked with *. I don't care at all about checking that Sequence 2,3,etc match the same pattern because if they exist at all I need to Sum them.
I have data that looks like this:
| Sequence | ID | Num | OtherID |
|----------|----|-----|---------|
| 1 | 1 | 10 | 1 |*
| 2 | 1 | 15 | 1 |
| 3 | 1 | 20 | 1 |
| 1 | 2 | 10 | 1 |*
| 2 | 2 | 15 | 1 |
| 1 | 3 | 10 | 1 |
| 1 | 1 | 40 | 3 |
I need to sum the Num column but only when there is more than one sequence. My output would look like this:
Sequence Sum OtherID
1 20 1
2 30 1
3 20 1
I have tried grouping the queries in a bunch of different ways but really by the time I get to the sum, I don't know how to look ahead to make sure there are greater than 1 sequences for an ID.
My query at the moment looks something like this:
select Sequence, Sum(Num) as [Sum], OtherID
from tbl
where ID in (Select ID from tbl where Sequence > 1)
Group by Sequence, OtherID
tbl is a CTE that I wrapped around my query and it partially works, but is not really the filter I wanted.
If this is something that just shouldn't be done or can't be done then I can handle that, but if it's something I am missing I'd like to fix the query.
Edit:
I can't give the full query here but I started with this table/data (to get the above output). The OtherID is there because the data has the same ID/Sequence combinations but that OtherID helps separate them out so the rows are not identical (multiple questions on a form).
Create table #tmpTable (ID int, Sequence int, Num int, OtherID int)
insert into #tmpTable (ID, Sequence, Num, OtherID) values (1, 1, 10, 1)
insert into #tmpTable (ID, Sequence, Num, OtherID) values (1, 2, 15, 1)
insert into #tmpTable (ID, Sequence, Num, OtherID) values (1, 3, 20, 1)
insert into #tmpTable (ID, Sequence, Num, OtherID) values (2, 1, 10, 1)
insert into #tmpTable (ID, Sequence, Num, OtherID) values (2, 2, 15, 1)
insert into #tmpTable (ID, Sequence, Num, OtherID) values (3, 1, 10, 1)
insert into #tmpTable (ID, Sequence, Num, OtherID) values (1, 1, 40, 3)
The following will sum over Sequence and OtherID, but only when:
Either
sequence is greater than 1
or
there is something else with the same ID and OtherID, but a different sequence.
Query:
select Sequence, Sum(Num) as SumNum, OtherID from #tmpTable a
where Sequence > 1
or exists (select * from #tmpTable b
where a.ID = b.ID
and a.OtherID = b.OtherID
and b.Sequence <> a.Sequence)
group by Sequence, OtherID;
It looks like you are trying to sum by Sequence and OtherID if the Count of ID >1, so you could do something like below:
select Sequence, Sum(Num) as [Sum], OtherID
from tbl
where ID in (Select ID from tbl where Sequence > 1)
Group by Sequence, OtherID
Having count(id)>1

How to insert seven kind of ids in a column to all values

I have column data. I need to insert ids in another column. Total i have 7 ids. For first 7 values i have to insert these ids and next 7 values, i have to insert same ids and so on.. Can any one please help?
Pay_headID Pay_amount
16414 8000
16415 300
16416 0
16417 200
16418 500
16419 0
16420 0
16414 9000
16415 300
so on ...
you can use CTE and ROW_NUMBER, i have used ordering by Pay_headId:
WITH cte_myTable
AS (SELECT
*,
(ROW_NUMBER() OVER (ORDER BY Pay_headID)) - 1 AS num
FROM myTable)
UPDATE cte_myTable
SET [Pay_headID] =
CASE
WHEN num % 7 = 0 THEN 16414
WHEN num % 7 = 1 THEN 16415
WHEN num % 7 = 2 THEN 16416
WHEN num % 7 = 3 THEN 16417
WHEN num % 7 = 4 THEN 16418
WHEN num % 7 = 5 THEN 16419
WHEN num % 7 = 6 THEN 16420
END
GO
If you want use ordering on how it was inserted, you can set Pay_headIds to null:
update myTable set Pay_headID=null;
You should use RowNum() to give you an artificial incrementing number, divide it by 7 and then Round it.
SELECT FLOOR((ROW_NUMBER() OVER(ORDER BY Pay_HeadID DESC))/7) AS MyID
to get your ids

updating min value on the second column when the first column appears more then once

Im struggling with how to do this in one step.
I have a column with values which vary between 1 and +-20. Linked to this is a second value which is normally between 1 and 5.
what i want to do is when Number 1 values appears more then once then I need to update the value in column Number 2 to 99 but only the highest number in the Number 2 column.
I have added a pic to explain better.
Basically id is unique, if value 1 appears more then once I need to update value 2 for where the value in value 2 is the highest value.
You can use row_number() to find the row with the highest No2 value and you can use count() over() to check if there are more than one row present for a No1 value.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
create table YourTable
(
No1 int,
No2 int
);
insert into YourTable values
(1, 3),
(1, 2),
(2, 1);
Query 1:
with C as
(
select No2,
row_number() over(partition by No1 order by No2 desc) as rn,
count(*) over(partition by No1) as c
from YourTable
)
update C
set No2 = 99
where rn = 1 and
c > 1
Results:
Query 2:
select *
from YourTable
Results:
| NO1 | NO2 |
|-----|-----|
| 1 | 99 |
| 1 | 2 |
| 2 | 1 |

Resources