Calculating an Avg in SQL excluding the current row - sql

I have a DB where certain records are tagged with an ID and I want create a view that contains the Average of all those records with the same ID, EXCLUDING the current record. For example, if my data looks like this:
ROW - ID - Value
1 1 20
2 1 30
3 1 40
4 2 60
5 2 80
6 2 40
7 3 50
8 3 20
9 3 40
My view needs to calculate the average of every row with the same ID, EXCLUDING the row it's on, so my output would look something like this:
ROW - ID - Value AVG
1 1 20 35
2 1 30 30
3 1 40 25
4 2 60 60
5 2 80 50
6 2 40 70
7 3 50 30
8 3 20 55
9 3 40 35
So, in the case of row 3, it's extracted rows 1 and 2, as they have the same ID and given me the avg of their values - 25.
I'm gone round the houses on this for a while now, but can't seem to nail it. Any help would be appreciated.

One Option if you have window functions
Declare #YourTable table (ROW int,ID int,Value int)
Insert Into #YourTable values
(1, 1, 20),
(2, 1, 30),
(3, 1, 40),
(4, 2, 60),
(5, 2, 80),
(6, 2, 40),
(7, 3, 50),
(8, 3, 20),
(9, 3, 40)
Select *
,Avg = (sum(value) over (Partition By ID)-Value)/NullIf((sum(1) over (Partition By ID)-1),0)
From #YourTable
Another Option is a OUTER APPLY
Select A.*
,B.*
From #YourTable A
Outer Apply (Select Avg=avg(value)
From #YourTable
where ID=A.ID and Row<>A.Row
) B
Both Return

SELECT t1.gid, AVG(t2.value)
FROM table1 as t1 INNER JOIN
table1 as t2 ON (t1.gid != t2.gid)
GROUP BY t1.gid;
Basically, join the table to itself on your condition and then group the results based on the first table's key.
This solution should work regardless of what database system you are usimg; there may be minor syntax details to change.
A table like this:
ID | Value
1 | 4
2 | 6
3 | 5
Becomes (when joined):
t1.ID | t2.ID | t1.Value | t2.Value
1 | 2 | 4 | 6
1 | 3 | 4 | 5
2 | 1 | 6 | 4
2 | 3 | 6 | 5
3 | 1 | 5 | 4
3 | 2 | 5 | 6
And, then the aggregate of the grouped rows yields the wanted values.

This query works for me:
select t1.row, t1.id, t1.value, (select avg(value) from test_table as t2 where t1.id = t2.id and t1.row != t2.row) as avg from test_table as t1;
Data in table created by me (i assume is simmilar to Yours):
mysql> select * from test_table;
+-----+------+-------+
| row | id | value |
+-----+------+-------+
| 1 | 1 | 20 |
| 2 | 1 | 30 |
| 3 | 1 | 40 |
| 4 | 2 | 60 |
| 5 | 2 | 80 |
| 6 | 2 | 40 |
| 7 | 3 | 50 |
| 8 | 3 | 20 |
| 9 | 3 | 40 |
+-----+------+-------+
Result of query:
+-----+------+-------+---------+
| row | id | value | avg |
+-----+------+-------+---------+
| 1 | 1 | 20 | 35.0000 |
| 2 | 1 | 30 | 30.0000 |
| 3 | 1 | 40 | 25.0000 |
| 4 | 2 | 60 | 60.0000 |
| 5 | 2 | 80 | 50.0000 |
| 6 | 2 | 40 | 70.0000 |
| 7 | 3 | 50 | 30.0000 |
| 8 | 3 | 20 | 45.0000 |
| 9 | 3 | 40 | 35.0000 |
+-----+------+-------+---------+

Related

How to sum 2 columns and add it with the previous summed columns in sql?

I have a table with these rows:
+------+--------+---------+---------+
| ID | Date | Amount1 | Amount2 |
+------+--------+---------+---------+
| 1 | 13 Nov | 8 | 3 |
| 2 | 11 Nov | 5 | 1 |
| 3 | 15 Nov | 0 | 3 |
| 4 | 18 Nov | 5 | 7 |
| 5 | 20 Nov | 10 | 0 |
+------+--------+---------+---------+
Would like to query with these result with the formula
Total = (Amount1 - Amount2) + Previous Row's Total
+------+--------+---------+---------+---------+
| ID | Date | Plus | Minus | Total |
+------+--------+---------+---------+---------+
| 2 | 11 Nov | 5 | 1 | 4 |
| 1 | 13 Nov | 8 | 3 | 9 |
| 3 | 15 Nov | 0 | 3 | 6 |
| 4 | 18 Nov | 5 | 7 | 4 |
| 5 | 20 Nov | 10 | 0 | 14 |
+------+--------+---------+---------+---------+
Is there any way to query this without binding the Total to a column on temporary table?
To get a running total, you can use SUM(columnname) OVER (ORDER BY sortedcolumnname).
To me it's actually a little counterintuitive compared to most windowed functions, as it doesn't have a partition but produces different results over the set of rows. However, it does work.
Here is some somewhat-obfuscated documentation from Microsoft about it.
I think you can therefore use
SELECT mt.[ID],
mt.[Date],
mt.[Amount1] AS [Plus],
mt.[Amount2] AS [Minus],
SUM(mt.[Amount1] - mt.[Amount2]) OVER (ORDER BY mt.[Date], mt.[ID]) AS Total
FROM mytable mt
ORDER BY mt.[Date],
mt.[ID];
And here are the results - they match yours.
ID Date Plus Minus Total
2 2020-11-11 5 1 4
1 2020-11-13 8 3 9
3 2020-11-15 0 3 6
4 2020-11-18 5 7 4
5 2020-11-20 10 0 14
Demo
You can acheive this using CTE first followed by self join. For amount1 - amount2, for id=3, you will be getting 0 -3 = -3. So, for id 3, the result below will be different for id=3
DECLARE #t table(id int, dateval date, amount1 int, amount2 int)
INSERT INTO #t
values
(1 ,'2020-11-13', 8, 3),
(2 ,'2020-11-11', 5, 1),
(3 ,'2020-11-15', 0, 3),
(4 ,'2020-11-18', 5, 7),
(5 ,'2020-11-20',10, 0);
;WITH CTE_First AS
(
SELECT id, dateval, amount1 as plus, amount2 as minus, (amount1-amount2) as total ,
ROW_NUMBER() OVER (ORDER BY dateval) as rnk
FROM #t
)
SELECT c.ID, c.DATEVAL, c.plus,c.minus,c.total + isnull(c1.total,0) as new_total
FROM CTE_First AS c
left outer join CTE_First AS C1
on C1.rnk = c.rnk- 1
+----+------------+------+-------+-----------+
| ID | DATEVAL | plus | minus | new_total |
+----+------------+------+-------+-----------+
| 2 | 2020-11-11 | 5 | 1 | 4 |
| 1 | 2020-11-13 | 8 | 3 | 9 |
| 3 | 2020-11-15 | 0 | 3 | 2 |
| 4 | 2020-11-18 | 5 | 7 | -5 |
| 5 | 2020-11-20 | 10 | 0 | 8 |
+----+------------+------+-------+-----------+

Is there a way to check if one table has all the records from an answer table for one specific id in one column?

I am trying to compare two tables: a table that has results, and a table that has the answer/key. I want the result table to have records that match exactly what the answer table has for a specific column id. This result table has:
I am using SQL Server 2008 and this is my query:
select id
from Answer
left outer join Result on Answer.mappingId = Result.mappingId
and Answer.answerValue = Result.answerValue
left outer join Check on Result.checkId = Check.checkId
Here are the tables I am using:
Result table -- checkId = 100 is what I want in this example
id | mappingId | checkId | answerValue
---+-------------+----------+---------------
1 | 15 | 100 | 1
2 | 16 | 100 | 1
3 | 17 | 100 | 1
4 | 18 | 100 | 1
5 | 15 | 200 | 1
6 | 16 | 200 | 1
7 | 17 | 200 | 2
8 | 18 | 200 | 2
Answer table:
id | mappingId | answerValue
---+-------------+------------
1 | 15 | 1
2 | 16 | 1
3 | 17 | 1
4 | 18 | 1
The result table, notice that there are the same id's for checkId (4 of id 100 and 4 of id 200). I want to be able to know if the answer value is 1 for all of one specific checkId. So the result table for checkId= 100 is what I want the query to find the existence of, since it has all of the correct answers for that single id value (4 records for that checkId = 100, which is what I want because the answer table has 4 answers. The mapping Id's also need to match, which they do: 15, 16, 17, 18). But for 200, it doesn't have all of the answers. It only has the correct answer for mapping id 15, 16.
Example of result table which is not what I want but still appears to pass my query
Result table - still passes even though it's not supposed to
id | mappingId | checkId | answerValue
---+-------------+----------+---------------
1 | 15 | 100 | 1
2 | 16 | 100 | 1
3 | 17 | 100 | 2
4 | 18 | 100 | 2
5 | 15 | 200 | 2
6 | 16 | 200 | 2
7 | 17 | 200 | 1
8 | 18 | 200 | 1
This should be incorrect, since only two of the questions have the correct answer value of 1--for mappingId 15/16 for checkId = 100. But the issue is that since checkId = 200 has the remaining correct values-- for mappingId 17/18, my query still regards this as correct, even though I want mappingId: 15, 16, 17, 18 with answer values of 1 for all for one specific checkId= 100. Note: it just has to be for any one specific checkId so the below is still fine and what I would like:
id | mappingId | checkId | answerValue
---+-------------+----------+---------------
1 | 15 | 100 | 2
2 | 16 | 100 | 2
3 | 17 | 100 | 2
4 | 18 | 100 | 2
5 | 15 | 200 | 1
6 | 16 | 200 | 1
7 | 17 | 200 | 1
8 | 18 | 200 | 1
Because checkId 200 has mappingId: 15, 16, 17, 18 with all answerValues as 1's.
This is what I want to return
id | mappingId | checkId | answerValue
---+-------------+----------+---------------
5 | 15 | 200 | 1
6 | 16 | 200 | 1
7 | 17 | 200 | 1
8 | 18 | 200 | 1
OR:
id | mappingId | checkId | answerValue
---+-------------+----------+---------------
1 | 15 | 100 | 1
2 | 16 | 100 | 1
3 | 17 | 100 | 1
4 | 18 | 100 | 1
If the either of the above aren't true, it would return nothing at all. It has to have all the correct answers for one specific checkId. An all or nothing deal, basically.
What I am actually returning and is incorrect since it spans 2 checkId's
id | mappingId | checkId | answerValue
---+-------------+----------+---------------
1 | 15 | 100 | 1
2 | 16 | 100 | 1
3 | 17 | 200 | 1
4 | 18 | 200 | 1
Thanks for the help everyone! I am new to stack overflow, so let me know if there's anything I could have done better. I couldn't figure out how to color the SQL query, so forgive me and I hope it is readable.
One conceptually easy way to handle this is to join the two tables, and then aggregate by checkId, asserting that every answer matches:
SELECT
c.checkId
FROM [Check] c
LEFT JOIN Answer a
ON c.mappingId = a.mappingId AND c.answerValue = a.answerValue
GROUP BY
c.checkId
HAVING
COUNT(*) = COUNT(a.mappingId);
Demo

SQL server rank rows by group and condition

I need help with ranking of rows in one table.
+-----+-------+-------------+------------+-------+------+
| ID | group | typeInGroup | rankOfType | score | Rank |
+-----+-------+-------------+------------+-------+------+
| 1 | a | type1 | 1 | 40 | |
| 2 | a | type2 | 2 | 55 | |
| 3 | a | type1 | 1 | 20 | |
| 4 | b | type3 | 3 | 80 | |
| 5 | b | type2 | 2 | 60 | |
| 6 | b | type1 | 1 | 70 | |
| 7 | b | type1 | 1 | 70 | |
+-----+-------+-------------+------------+-------+------+
I am basically looking for solution which would give me order for last column "Rank".
Each "group" has up to 9 "typeInGroup" which are ranked by 1-9 in column "rankOfTypes". Each "typeInGroup" has "score". When i am calculating last column "Rank" i look at the "score" and "rankOfType" column.
The row with the higgest score should be ranked first unless there is row with "rankOfType" column that has lower value and score that is <= 15 than the score we have been looking at. Order of rows with same "score" and "rankOfType" is not important.
I should do this check for every single row in group and in the end end with something like this:
+-----+-------+-------------+------------+-------+------+
| ID | group | typeInGroup | rankOfType | score | Rank |
+-----+-------+-------------+------------+-------+------+
| 1 | a | type1 | 1 | 40 | 1 |
| 2 | a | type2 | 2 | 55 | 2 |
| 3 | a | type1 | 1 | 20 | 3 |
| 4 | b | type3 | 3 | 80 | 3 |
| 5 | b | type2 | 2 | 60 | 4 |
| 6 | b | type1 | 1 | 70 | 1 |
| 7 | b | type1 | 1 | 70 | 2 |
+-----+-------+-------------+------------+-------+------+
Any idea how to do this?
the CROSS APPLY query, checks for any rows that meet your special requirement, if exists, than that row will have higher priority
try it out with larger data set and verify the result
declare #tbl table
(
ID int,
Grp char,
typeInGrp varchar(5),
rankOfType int,
score int
)
insert into #tbl select 1, 'a', 'type1', 1, 40
insert into #tbl select 2, 'a', 'type2', 2, 55
insert into #tbl select 3, 'a', 'type1', 1, 20
insert into #tbl select 4, 'b', 'type3', 3, 80
insert into #tbl select 5, 'b', 'type2', 2, 60
insert into #tbl select 6, 'b', 'type1', 1, 70
insert into #tbl select 7, 'b', 'type1', 1, 70
select *,
[rank] = row_number() over (partition by Grp
order by case when cnt > 0 then 1 else 2 end,
score desc)
from #tbl t
cross apply
(
select cnt = count(*)
from #tbl x
where x.Grp = t.Grp
and x.ID <> t.ID
and x.rankOfType > t.rankOfType
and x.score - t.score <= 15
) s
order by ID

MS-SQL Grouping and counting query

So I have a table and the columns are Product and ProductGroupID.
Every Product can be in 1 or more groups as shown in this example:
+-------+--------------+
|product|ProductGroupId|
+-------+--------------+
| 10 | 2 |
| 10 | 9 |
| 10 | 4 |
| 10 | 7 |
| 20 | 7 |
| 30 | 4 |
| 40 | 1 |
| 50 | 11 |
| 50 | 12 |
| 60 | 2 |
| 70 | 9 |
| 80 | 11 |
| 90 | 12 |
| 100 | 13 |
+-------+--------------+
For every product I need to get it's group or groups and to bring the number of product which are in those groups.
For example product 10 is in groups 2,4,9,7 so I need to count all the products that are in those groups, in this case 5 (for count of products 10,60,70,30,20).
I attach the full desired outcome for this example.
https://i.stack.imgur.com/XTa4R.png
Any suggestion how to do this in ms-sql?
Thnaks!
If I understood it correctly this will work for you.
Schema from your image:
CREATE TABLE #PRODUCTS (PRODUCT INT, PRODUCTGROUP_ID INT)
INSERT INTO #PRODUCTS
SELECT 10,2
UNION ALL
SELECT 10,9
UNION ALL
SELECT 10,4
UNION ALL
SELECT 10,7
UNION ALL
SELECT 20,7
UNION ALL
SELECT 30,4
UNION ALL
SELECT 40,1
UNION ALL
SELECT 50,11
UNION ALL
SELECT 50,12
UNION ALL
SELECT 60,2
UNION ALL
SELECT 70,9
UNION ALL
SELECT 80,11
UNION ALL
SELECT 90,12
UNION ALL
SELECT 100,13
Now do a Self Join with GroupId on condition
SELECT P.PRODUCT, COUNT(DISTINCT G.PRODUCT) Linked_GroupProducts
FROM #PRODUCTS P
INNER JOIN #PRODUCTS G ON P.PRODUCTGROUP_ID = G.PRODUCTGROUP_ID
GROUP BY P.PRODUCT
And the result will be
+---------+----------------------+
| PRODUCT | Linked_GroupProducts |
+---------+----------------------+
| 10 | 5 |
| 20 | 2 |
| 30 | 2 |
| 40 | 1 |
| 50 | 3 |
| 60 | 2 |
| 70 | 2 |
| 80 | 2 |
| 90 | 2 |
| 100 | 1 |
+---------+----------------------+

SQL Server Pagination with different line number per page

I have a table in SQL Server database containing :
int value (column's name : Value)
datetime value (column's name : Date)
bit value (column's name : LastLineOfPage)
I would like to make a pagination query over this table. The logic of the pagination is the following :
The query must return lines corresponding to a given page (parameter #PageNumber), after sorting lines by the Date column
Also, the query must give the SUM of all the previous pages lines
The line number per page is not fixed : by default it's 14 lines per page, but if the bit LastLineOfPage is true, then the page contain only lines until the one with the true value
Here is a synthetic view of the process :
Here is the data in text :
ID DATE VALUE LASTLINEOFPAGE
1 07/10/2006 10 0
2 14/10/2006 12 0
3 21/10/2006 4 1
4 28/10/2006 6 0
5 04/11/2006 8 1
6 25/11/2006 125 0
7 02/12/2006 1 0
8 09/12/2006 5 0
9 16/12/2006 45 0
10 30/12/2006 1 1
So, the query receiving #PageNumber, and also #DefaultLineNumberPerPage (which will be equal to 14 but maybe one day that will change).
Could you help me in the design of this query or SQL function ?
Thanks !
Sample data
I added few rows to illustrate how it works when there are more rows per page than #DefaultLineNumberPerPage. In this example I'll use #DefaultLineNumberPerPage=5 and you'll see how extra pages were generated.
DECLARE #T TABLE (ID int, dt date, VALUE int, LASTLINEOFPAGE bit);
INSERT INTO #T(ID, dt, VALUE, LASTLINEOFPAGE) VALUES
(1 , '2006-10-07', 10 , 0),
(2 , '2006-10-14', 12 , 0),
(3 , '2006-10-21', 4 , 1),
(4 , '2006-10-28', 6 , 0),
(5 , '2006-11-04', 8 , 1),
(6 , '2006-11-25', 125, 0),
(7 , '2006-12-02', 1 , 0),
(8 , '2006-12-09', 5 , 0),
(9 , '2006-12-16', 45 , 0),
(10, '2006-12-30', 1 , 1),
(16, '2007-01-25', 125, 0),
(17, '2007-02-02', 1 , 0),
(18, '2007-02-09', 5 , 0),
(19, '2007-02-16', 45 , 0),
(20, '2007-02-20', 1 , 0),
(26, '2007-02-25', 125, 0),
(27, '2007-03-02', 1 , 0),
(28, '2007-03-09', 5 , 0),
(29, '2007-03-10', 5 , 0),
(30, '2007-03-11', 5 , 0),
(31, '2007-03-12', 5 , 0),
(32, '2007-03-13', 5 , 1),
(41, '2007-10-07', 10 , 0),
(42, '2007-10-14', 12 , 0),
(43, '2007-10-21', 4 , 1);
Query
Run it step-by-step, CTE-by-CTE and examine intermediate results to understand what it does.
CTE_FirstLines sets the FirstLineOfPage flag to 1 for the first line of the page instead of the last.
CTE_SimplePages uses a cumulative SUM to calculate the simple page numbers based on FirstLineOfPage page breaks.
CTE_ExtraPages uses ROW_NUMBER divided by #DefaultLineNumberPerPage to calculate extra page numbers if there is a page that has more than #DefaultLineNumberPerPage rows.
CTE_CompositePages combines simple page numbers with extra page numbers to make a single composite page "Number". It assumes that there will be less than 1000 rows between original LASTLINEOFPAGE flags. If it is possible to have such long sequence of rows, increase the 1000 constant and consider using bigint type for CompositePageNumber column.
CTE_FinalPages uses DENSE_RANK to assign sequential numbers without gaps for each final page.
DECLARE #DefaultLineNumberPerPage int = 5;
DECLARE #PageNumber int = 3;
WITH
CTE_FirstLines
AS
(
SELECT
ID,dt, VALUE, LASTLINEOFPAGE
,CAST(ISNULL(LAG(LASTLINEOFPAGE)
OVER (ORDER BY dt), 1) AS int) AS FirstLineOfPage
FROM #T
)
,CTE_SimplePages
AS
(
SELECT
ID,dt, VALUE, LASTLINEOFPAGE, FirstLineOfPage
,SUM(FirstLineOfPage) OVER(ORDER BY dt
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS SimplePageNumber
FROM CTE_FirstLines
)
,CTE_ExtraPages
AS
(
SELECT
ID,dt, VALUE, LASTLINEOFPAGE, FirstLineOfPage, SimplePageNumber
,(ROW_NUMBER() OVER(PARTITION BY SimplePageNumber ORDER BY dt) - 1)
/ #DefaultLineNumberPerPage AS ExtraPageNumber
FROM CTE_SimplePages
)
,CTE_CompositePages
AS
(
SELECT
ID,dt, VALUE, LASTLINEOFPAGE, FirstLineOfPage, SimplePageNumber, ExtraPageNumber
,SimplePageNumber * 1000 + ExtraPageNumber AS CompositePageNumber
FROM CTE_ExtraPages
)
,CTE_FinalPages
AS
(
SELECT
ID,dt, VALUE, LASTLINEOFPAGE, FirstLineOfPage, SimplePageNumber, ExtraPageNumber
,CompositePageNumber
,DENSE_RANK() OVER(ORDER BY CompositePageNumber) AS FinalPageNumber
FROM CTE_CompositePages
)
,CTE_Sum
AS
(
SELECT
ID,dt, VALUE, LASTLINEOFPAGE, FirstLineOfPage, SimplePageNumber, ExtraPageNumber
,CompositePageNumber
,FinalPageNumber
,SUM(Value) OVER(ORDER BY FinalPageNumber, dt
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS SumCumulative
FROM CTE_FinalPages
)
SELECT
ID,dt, VALUE, LASTLINEOFPAGE, FirstLineOfPage, SimplePageNumber, ExtraPageNumber
,CompositePageNumber
,FinalPageNumber
,SumCumulative
FROM CTE_Sum
-- WHERE FinalPageNumber = #PageNumber
ORDER BY dt
;
Result with the final WHERE filter commented out
Here is the full result with all intermediate columns to illustrate how the query works.
+----+------------+-------+-----+-----+--------+-------+-----------+-------+------------+
| ID | dt | VALUE | Lst | Fst | Simple | Extra | Composite | Final | TotalValue |
+----+------------+-------+-----+-----+--------+-------+-----------+-------+------------+
| 1 | 2006-10-07 | 10 | 0 | 1 | 1 | 0 | 1000 | 1 | 10 |
| 2 | 2006-10-14 | 12 | 0 | 0 | 1 | 0 | 1000 | 1 | 22 |
| 3 | 2006-10-21 | 4 | 1 | 0 | 1 | 0 | 1000 | 1 | 26 |
| 4 | 2006-10-28 | 6 | 0 | 1 | 2 | 0 | 2000 | 2 | 32 |
| 5 | 2006-11-04 | 8 | 1 | 0 | 2 | 0 | 2000 | 2 | 40 |
| 6 | 2006-11-25 | 125 | 0 | 1 | 3 | 0 | 3000 | 3 | 165 |
| 7 | 2006-12-02 | 1 | 0 | 0 | 3 | 0 | 3000 | 3 | 166 |
| 8 | 2006-12-09 | 5 | 0 | 0 | 3 | 0 | 3000 | 3 | 171 |
| 9 | 2006-12-16 | 45 | 0 | 0 | 3 | 0 | 3000 | 3 | 216 |
| 10 | 2006-12-30 | 1 | 1 | 0 | 3 | 0 | 3000 | 3 | 217 |
| 16 | 2007-01-25 | 125 | 0 | 1 | 4 | 0 | 4000 | 4 | 342 |
| 17 | 2007-02-02 | 1 | 0 | 0 | 4 | 0 | 4000 | 4 | 343 |
| 18 | 2007-02-09 | 5 | 0 | 0 | 4 | 0 | 4000 | 4 | 348 |
| 19 | 2007-02-16 | 45 | 0 | 0 | 4 | 0 | 4000 | 4 | 393 |
| 20 | 2007-02-20 | 1 | 0 | 0 | 4 | 0 | 4000 | 4 | 394 |
| 26 | 2007-02-25 | 125 | 0 | 0 | 4 | 1 | 4001 | 5 | 519 |
| 27 | 2007-03-02 | 1 | 0 | 0 | 4 | 1 | 4001 | 5 | 520 |
| 28 | 2007-03-09 | 5 | 0 | 0 | 4 | 1 | 4001 | 5 | 525 |
| 29 | 2007-03-10 | 5 | 0 | 0 | 4 | 1 | 4001 | 5 | 530 |
| 30 | 2007-03-11 | 5 | 0 | 0 | 4 | 1 | 4001 | 5 | 535 |
| 31 | 2007-03-12 | 5 | 0 | 0 | 4 | 2 | 4002 | 6 | 540 |
| 32 | 2007-03-13 | 5 | 1 | 0 | 4 | 2 | 4002 | 6 | 545 |
| 41 | 2007-10-07 | 10 | 0 | 1 | 5 | 0 | 5000 | 7 | 555 |
| 42 | 2007-10-14 | 12 | 0 | 0 | 5 | 0 | 5000 | 7 | 567 |
| 43 | 2007-10-21 | 4 | 1 | 0 | 5 | 0 | 5000 | 7 | 571 |
+----+------------+-------+-----+-----+--------+-------+-----------+-------+------------+
To get only one given page uncomment the WHERE filter in the final SELECT.
Result with the final WHERE filter
+----+------------+-------+-----+-----+--------+-------+-----------+-------+------------+
| ID | dt | VALUE | Lst | Fst | Simple | Extra | Composite | Final | TotalValue |
+----+------------+-------+-----+-----+--------+-------+-----------+-------+------------+
| 6 | 2006-11-25 | 125 | 0 | 1 | 3 | 0 | 3000 | 3 | 165 |
| 7 | 2006-12-02 | 1 | 0 | 0 | 3 | 0 | 3000 | 3 | 166 |
| 8 | 2006-12-09 | 5 | 0 | 0 | 3 | 0 | 3000 | 3 | 171 |
| 9 | 2006-12-16 | 45 | 0 | 0 | 3 | 0 | 3000 | 3 | 216 |
| 10 | 2006-12-30 | 1 | 1 | 0 | 3 | 0 | 3000 | 3 | 217 |
+----+------------+-------+-----+-----+--------+-------+-----------+-------+------------+
The TotalValue in the last row gives you the total page value that you want to show at the bottom of the page. If you sum all values on this page (125+1+5+45+1 = 177) and subtract it from the last TotalValue (217-177 = 40) you'll get the total of previous pages that you want to show at the top of the page. You'd better do these calculations on the client.
I have a partial solution. Still doesnt count default page size, but can give you an idea. So let me know what you think. Hope you are familiar with CTE's. Test each step so you see what are the partial results.
SQL Demo
WITH cte as (
SELECT [ID], [DATE], [VALUE], [LASTLINEOFPAGE],
SUM([VALUE]) OVER (ORDER BY [ID]) as Total,
SUM([LASTLINEOFPAGE]) OVER (ORDER BY [ID]) as page_group
FROM Table1
),
pages as (
SELECT c1.[ID], c1.[Total],
CASE WHEN c1.[ID] = 1 THEN 0
WHEN c1.[ID] = m.[minID] THEN c1.[page_group] -1
ELSE c1.[page_group]
END as [page_group]
FROM cte as c1
JOIN (SELECT [page_group], MIN([ID]) as minID
FROM cte
GROUP BY [page_group]) m
ON c1.[page_group] = m.[page_group]
)
SELECT c.[ID], c.[DATE], c.[VALUE], c.[LASTLINEOFPAGE],
(SELECT MAX([Total])
FROM pages p2
WHERE p2.[page_group] = p.[page_group]) as [Total],
p.[page_group]
FROM cte c
JOIN pages p
ON c.[ID] = p.[id]
As you can see the total and the page are in the aditional column and you shouldnt display those on your app