Repeat a sum as a column in SQL - sql-server

I have a table
WO# Seg# Part# QTY TotSale FlatSale
1 1 1 5 35 159
1 1 2 2 100 159
1 2 3 3 50 50
I need to calculate the FlatSale/SUM(TotSale) for each Seq# & WO# but do not group Seg# into one row.
I need this
WO# Seg# Part# QTY TotSale FlatSale Calc
1 1 1 5 35 159 1.177
1 1 2 2 100 159 1.177
1 2 3 3 50 50 1
With my code I am able to only do the division on each individual line like this:
select *, FlatSale/TotSale as Calc from table
WO# Seg# Part# QTY TotSale FlatSale Calc
1 1 1 5 35 159 4.54
1 1 2 2 100 159 1.59
1 2 3 3 50 50 1
I wouldn't mind leaving my Calc column and adding another column if that's the easiest way to do it.

Maybe something like this:
SELECT
[WO#],[Seg#],[Part#],[QTY],[TotSale],[FlatSale]
((FlatSale*100)/(SUM([TotSale]) OVER(PARTITION BY [Seg#] ORDER BY [Seg#])))/100 AS Calc
FROM SomeTable

You can use a lateral join. Here's something quick (not tested as I don't have access to mssql at the moment):
select *, x.CalcPrice as Calc
from table t
outer apply (
select t.FlatSale/SUM(ix.TotSale) CalcPrice
from table ix where ix.[WO#] = t.[WO#]
and ix.[Seg#] = t.[Seg#]) x
Something like that.

Related

How to calculate moving avarage within array

I have a table with two columns, id and for each id an array with values. I want to calculate the moving avarage within the id over the moving 3 elements.
id
v
1
{210,200,180,120,150,200}
2
{230,180,140,100,170,210}
create table series(id int, v _int4);
insert into series
values(1,array[210,200,180,120,150,200])
,(2,array[230,180,140,100,170,210]);
If i use the following query it works for one id
select id, nr, "elemV", avg("elemV") over (order by nr rows between 3 PRECEDING AND CURRENT ROW) "movingAvgOver3elements"
from series t, unnest("v") with ordinality as a("elemV", nr)
where id = 1 ;
id
nr
elemV
movingAvgOverLast4Elements
1
1
210
210.0000000000000000
1
2
200
205.0000000000000000
1
3
180
196.6666666666666667
1
4
120
177.5000000000000000
1
5
150
162.5000000000000000
1
6
200
162.5000000000000000
How does it works for all id's within the id ?
The problem is in that case the 4 elements moving over the id 1 to 2
select id, nr, "elemV", avg("elemV") over (order by id, nr rows between 3 PRECEDING AND CURRENT ROW) "movingAvgOver3elements"
from series t, unnest("v") with ordinality as a("elemV", nr)
id
nr
elemV
movingAvgOver3elements
1
1
210
210.0000000000000000
1
2
200
205.0000000000000000
1
3
180
196.6666666666666667
1
4
120
177.5000000000000000
1
5
150
162.5000000000000000
1
6
200
162.5000000000000000
2
1
230
175.0000000000000000
2
2
180
190.0000000000000000
2
3
140
187.5000000000000000
2
4
100
162.5000000000000000
2
5
170
147.5000000000000000
2
6
210
155.0000000000000000
If I understand correctly, I think you just need to add a PARTITION BY clause to make each id a separate frame. With that clause in place, you can also remove the sort by id, although that's optional.
select id, nr, "elemV", avg("elemV") over (PARTITION BY id order by nr rows between 3 PRECEDING AND CURRENT ROW) "movingAvgOver3elements"
from series t, unnest("v") with ordinality as a("elemV", nr);

Calculating the running total

I want to calculate the running total using a Stored Procedure. The base Table is ~10.000 rows and is as follows:
nWordNr nBitNr tmTotals
------------------------
5 14 86404
5 14 146
2 3 438
10 2 3319
5 12 225
2 3 58
.... .... .....
.... .... .....
I want this to be GROUPED BY nWordNr, NBitNr and have the total tmTotals. To do this is started of with the following:
SELECT TOP 10
[nWordNr] as W,
[nBitNr] as B,
SUM([tmTotals]) as total,
COUNT(*) as Amount
FROM Messages_History
GROUP BY nWordNr, nBitNr
ORDER BY total desc
This results in:
W B total Amount
-----------------------
2 3 3578775 745
3 3 3557975 395
5 4 2305229 72
5 3 2183050 33
5 12 2022401 825
5 14 1673295 652
48 12 1658862 302
4 3 1606454 215
48 13 1541729 192
5 9 1463256 761
Now I want to calculate the running total on the column total like this:
W B total Amount running
-------------------------------
2 3 3578775 745 3578775
3 3 3557975 395 7136750
5 4 2305229 72 9441979
5 3 2183050 33 11625029
5 12 2022401 825 etc.
5 14 1673295 652 etc.
48 12 1658862 302 etc.
4 3 1606454 215 etc.
48 13 1541729 192 etc.
5 9 1463256 761 etc.
so what I found was:
COUNT([tmTotals]) over (ORDER BY [nWordNr], [nBitNr]) as Running
But here I get the error that is discussed in this question: Column invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause and I just can't figure out how to solve it in this case
it should be SUM ( SUM ( tmTotals) ) OVER ( ... )
SELECT TOP 10
[nWordNr] as W,
[nBitNr] as B,
SUM([tmTotals]) as total,
COUNT(*) as Amount,
SUM(SUM([tmTotals])) OVER (ORDER BY [nWordNr], [nBitNr]) as Running
FROM Messages_History
GROUP BY nWordNr, nBitNr
ORDER BY total desc
EDIT :
Looking at your expected result, the Running should be
SUM(SUM([tmTotals])) OVER (ORDER BY SUM([tmTotals]) DESC) as Running
if the above is a bit difficult to grasp, then you can use a CTE or derived table and perform the running total on the outer query
; with CTE as
(
SELECT
[nWordNr] as W,
[nBitNr] as B,
SUM([tmTotals]) as total,
COUNT(*) as Amount
FROM Messages_History
GROUP BY nWordNr, nBitNr
)
SELECT TOP 10 *,
SUM(total) OVER (ORDER BY total desc) as Running
FROM CTE
ORDER BY total desc

SQL select joined 2 tables same as one column

SQL table Authority is:
AuthorNo Price PrePay(bit)
----------------------------
1 250$ 1
2 120$ 0
3 300$ 0
4 112$ 1
5 25$ 0
Table Order is:
AuthorNo OrderNo
-----------------
1 33
1 34
2 33
2 38
3 41
3 82
4 55
4 21
5 21
5 66
I want the result is:
Select from Authority.AuthorNo where AuthorNo same in Order.OrderNo and at least one of the AuthorNo.Prepay is 1
AuthorNo
--------
1
2
4
5
How to select this?
If you need to find the authors that have orders that were also ordered by authors with PrePay?
Then you could use an EXISTS for this.
SELECT auth.AuthorNo
FROM Authority auth
JOIN [Order] ord ON ord.AuthorNo = auth.AuthorNo
WHERE EXISTS
(
SELECT 1
FROM [Order] ord_pp
JOIN Authority auth_pp
ON auth_pp.AuthorNo = ord_pp.AuthorNo
AND auth_pp.Prepay = 1
WHERE ord_pp.OrderNo = ord.OrderNo
)
GROUP BY auth.AuthorNo;
A test here
Result:
AuthorNo
--------
1
2
4
5
I am guessing you just want to see the AuthorNo in the result? Try this
Select distinct a.AuthorNo
From Authority a
join Order b on a.AuthorNo=b.AuthorNo
where a.Prepay=1

SQL Server 2016 - Calculating remaining stock quantity

I have a table like this:
As you can see, I have a column called remaining_stock that is correct for the first line of each item but NOT for the subsequent lines. The first line is straight forward as you can simply subtract the order-quantity from initial_stock..
What I want to achieve is to get a remaining_stock column that looks like this:
I though of using row_number and then joining back to the same table using the row numbers.. but that doesn't quite work either. can someone point me in the right direction please?
select 1 as line, 123 as item, 5 as order_quantity,10 as intial_stock
union all
select 2 as line, 123 as item, 3 as order_quantity,10 as intial_stock
union all
select 3 as line, 123 as item, 1 as order_quantity,10 as intial_stock
union all
select 4 as line, 234 as item, 5 as order_quantity,15 as intial_stock
union all
select 5 as line, 234 as item, 3 as order_quantity,15 as intial_stock
union all
select 6 as line, 234 as item, 1 as order_quantity,15 as intial_stock
Small matter using the window function Sum() over
Example
Select *
,Remaining_Stock = intial_stock - sum(Order_Quantity) over (Partition By Item Order by Line)
from YourTable
Returns
line item order_quantity intial_stock Remaining_Stock
1 123 5 10 5
2 123 3 10 2
3 123 1 10 1
4 234 5 15 10
5 234 3 15 7
6 234 1 15 6

Sqlserver group by pending days period

I have table structure as below,
State Application_count Pending_Days
_________________________________________
TN 10 0
TN 20 1
TN 60 2
TN 10 3
MH 40 1
MH 50 3
MH 20 5
MH 30 8
I want to sum Application_count based on State and Pending_Days period.
I have to group Pending_days 0 to 1 Days, 1 to 3 days, morethan 3 days
Expected Output:
State Application_count
_________________________
TN 30
TN 70
MH 40
MH 50
MH 50
Give an additional column, group_num using a CASE expression based on the condition of Pending_Days column.
Then find the sum group by group_num and state columns.
Query
select t.[state], sum(t.[Application_Count]) as [Application_Count] from(
select [group_num] = (
case when [Pending_Days] between 0 and 1 then 1
when [Pending_Days] between 2 and 3 then 2
when [Pending_Days] > 3 then 3 else 4 end
), *
from [your_table_name]
)t
group by t.[group_num], t.[state];
Find demo here
Note:
For Pending_Days condition, 0 to 1 Days I have taken 0 and 1
for 1 to 3 days I have taken 2 and 3 , for morethan 3 days I have taken the value greater than 3.

Resources