Calculating the running total - sql-server

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

Related

Repeat a sum as a column in SQL

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.

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.

Get Unmatched records from the 3 table

I have 3 tables. The first table 'Status_Mapping' has following columns
Status_original Status_Site
accepted Call Verified
duplicate Duplicate Leads
dq DQ
'Lead_transaction' has the columns:
Lead_transaction_id Rate Status
11 0.01 accepted
12 0.02 accepted
13 0.01 newstatus
'Lead_Instance' table:
Lead_Instance_id Lead_transaction_id product_id affiliate_id
1 11 6 10
2 12 7 11
3 13 6 10
What I want to do is get the count(lead_instance_id) and sum(rate) for status which are not present in status_mapping table and should display status as "other", with product_id = 6 and affiliate_id = 10 My End result should be like
Total Sum Status
1 0.01 Other
you can start with this query:
select count(distinct a.Lead_Instance_id), sum(b.Rate)
from
Lead_Instance as a
inner join
Lead_transaction as b
on (a.Lead_transaction_id = b.Lead_transaction_id)
where
b.Status not in (select distinct Status_original from Status_Mapping)
and a.product_id = 6
and a.affiliate_id = 10

How to split a numeric field into smaller segments in Sql Server

I have a table in SQL Server with two fields.
Total Group
35645 24
12400 55
30000 41
I want to split each group into smaller segments of fixed size 7000, with the remainder of each group into the last segment. So, the output should look like below.
Segment Total Group
1 7000 24
2 7000 24
3 7000 24
4 7000 24
5 7000 24
6 645 24
1 7000 55
2 5400 55
1 7000 41
2 7000 41
3 7000 41
4 7000 41
5 2000 41
This should do it:
declare #t table (Total int,[Group] int)
insert into #t(Total,[Group]) values
(35645,24 ),
(12400,55 ),
(30000,41 )
;With Numbers as (
select ROW_NUMBER() OVER (ORDER BY number)-1 n
from master..spt_values
)
select
n.n+1 as Segment,
CASE WHEN (n.n+1)*7000 < t.Total THEN 7000
ELSE t.Total - (n.n*7000) END as Total,
t.[Group]
from
#t t inner join
Numbers n on n.n*7000 < t.Total
(If you already have a Numbers table you can eliminate that part. I'm using spt_values just as a table that I know has plenty of rows in it, so that the ROW_NUMBER() expression should generate all of the necessary numbers)
Results:
Segment Total Group
-------------------- -------------------- -----------
1 7000 24
2 7000 24
3 7000 24
4 7000 24
5 7000 24
6 645 24
1 7000 55
2 5400 55
1 7000 41
2 7000 41
3 7000 41
4 7000 41
5 2000 41
I prepared following SELECT statement using SQL CTE expression and SQL numbers table function
declare #divisor int = 7000
;with CTE as (
select
Total,
[Group],
#divisor divisor,
(Total / #divisor) quotient,
(Total % #divisor) reminder
from t
), NT as (
SELECT i FROM dbo.NumbersTable(1, (select max(quotient) from CTE) ,1)
)
select
case when i = 0 then reminder else divisor end as Total,
[Group]
from (
select *
from CTE, NT
where quotient >= i
union all
select *, 0 as i
from CTE
where reminder >= 0
) t
order by [Group], i desc

Rolling up values in SQL Server

This is the result of my first sql statement:
SELECT
count(*) countQuarter, Hour, Quarter,
ROW_NUMBER() OVER(ORDER BY Hour, Quarter ASC) AS rownum
FROM
(SELECT [ID] ,[simulationID] ,[time],
replace(str(time/3600,len(ltrim(time/3600))+abs(sign(time/359999)-1)) + ':' + str((time/60)%60,2) + ':' + str(time%60,2),' ','0') dtString,
(time/3600) Hour, (time/60)%60 Minute, case when (time/60)%60<15 then 15 when
(time/60)%60<30 then 30 when (time/60)%60<45 then 45 when (time/60)%60<60 then 60 end
Quarter ,[person] ,[link] ,[vehicle] FROM [TEST].[dbo].[evtLinks]
WHERE simulationID=#simulationID) B
GROUP BY Hour, Quarter
which gives the following results:
Count Hour Quarter Rownum
497 0 15 1
842 0 30 2
1033 0 45 3
1120 0 60 4
1235 1 15 5
1267 1 30 6
1267 1 45 7
1267 1 60 8
1267 2 15 9
1267 2 30 10
I desire a result, where the column fullCount is the sum of the Count of the actual row and the next 3!
Count Hour Quarter Rownum Fullcount
497 0 15 1 3492
842 0 30 2 4230
1033 0 45 3 4655
1120 0 60 4 ...
1235 1 15 5
1267 1 30 6
1267 1 45 7
1267 1 60 8
1267 2 15 9
1267 2 30 10
How can this be done with grouping or analytical functions in SQL Server?
For SQL Server 2012, yes this can be done:
declare #t table ([Count] int,[Hour] int,[Quarter] int,Rownum int)
insert into #t([Count],[Hour],[Quarter],Rownum) values
(497 , 0 , 15 , 1 ),
(842 , 0 , 30 , 2 ),
(1033 , 0 , 45 , 3 ),
(1120 , 0 , 60 , 4 ),
(1235 , 1 , 15 , 5 ),
(1267 , 1 , 30 , 6 ),
(1267 , 1 , 45 , 7 ),
(1267 , 1 , 60 , 8 ),
(1267 , 2 , 15 , 9 ),
(1267 , 2 , 30 , 10 )
select *,SUM([Count]) OVER (
ORDER BY rownum
ROWS BETWEEN CURRENT ROW AND
3 FOLLOWING)
from #t
Here I'm using #t as your current result set - you may be able to adapt this into your current query or may have to place your current query in a CTE.
Unfortunately, the ROWS BETWEEN syntax is only valid on 2012 and later.
Tested the logical scenario and it works, but I don't have your data, so in your case it should look roughly like this:
;WITH CTE as (SELECT count(*) countQuarter,Hour,Quarter,
ROW_NUMBER() OVER(ORDER BY Hour, Quarter ASC) AS rownum
FROM
(SELECT [ID] ,[simulationID] ,[time],
replace(str(time/3600,len(ltrim(time/3600))+abs(sign(time/359999)-1)) + ':' + str((time/60)%60,2) + ':' + str(time%60,2),' ','0') dtString,
(time/3600) Hour, (time/60)%60 Minute, case when (time/60)%60<15 then 15 when
(time/60)%60<30 then 30 when (time/60)%60<45 then 45 when (time/60)%60<60 then 60 end
Quarter ,[person] ,[link] ,[vehicle] FROM [TEST].[dbo].[evtLinks]
WHERE simulationID=#simulationID) B
GROUP BY Hour, Quarter)
SELECT *, CA.Fullcount
FROM CTE
CROSS APPLY (SELECT SUM(countQuarter) Fullcount FROM CTE C WHERE C.ID BETWEEN CTE.ID AND CTE.ID+3) CA

Resources