{"id":85,"date":"2010-02-14T09:15:00","date_gmt":"2010-02-14T09:15:00","guid":{"rendered":"\/lisa\/post\/2010\/02\/14\/YAPS-on-Dynamic-PageBreaks-Mixing-up-the-Groups.aspx"},"modified":"2010-02-14T09:15:00","modified_gmt":"2010-02-14T09:15:00","slug":"yaps-on-dynamic-pagebreaks-mixing-up-the-groups","status":"publish","type":"post","link":"https:\/\/spacefold.com\/lisa\/2010\/02\/14\/yaps-on-dynamic-pagebreaks-mixing-up-the-groups\/","title":{"rendered":"YAPS on Dynamic PageBreaks: Mixing up the Groups"},"content":{"rendered":"<p><a title=\"Karthik's request as a comment on a blog post\" href=\"\/lisa\/2009\/03\/08\/Dynamic-Page-Breaks-in-SSRS-Going-to-Eleven#id_68c75b71-d808-4e25-9b63-87169c837813\" target=\"_parent\" rel=\"noopener\">Karthik asks<\/a><\/p>\n<blockquote>\n<p>My actual task is to display totals of each group at the end of page breaks which are further grouped on count of 1000. I don&#8217;t know how to proceed with this issue. I have also queried the same at MSDN forums at the following links but haven&#8217;t been getting any responses at all.<\/p>\n<p>social.technet.microsoft.com\/&#8230;\/b3ea0253-bb5a-463d-82e8-4e9d1d9eed3a<\/p>\n<p>Could you please provide any tips\/suggestions on the way to deal with this task?<\/p>\n<\/blockquote>\n<p>This is actually a tough one, but luckily I brought grenades.&nbsp; Today&#8217;s Karthik&#8217;s day in TechSpoken Court&#8230;<\/p>\n<h2>Why is this so hard?<\/h2>\n<p>Let&#8217;s &nbsp;quickly recap the problem.&nbsp; I will demonstrate Karthik&#8217;s scenario using the City table in my standard SqlWorld sample db.&nbsp;<\/p>\n<p class=\"code\"><span style=\"color: #0000ff; \">SELECT <\/span>id, countrycode, district, name, LEFT(name,1) AS NameInitial, population<br \/><span style=\"color: #0000ff;\">FROM <\/span>city <br \/><span style=\"color: #0000ff;\">ORDER BY<\/span>countrycode,district,name<\/p>\n<p>Karthik has three &#8220;real&#8221; groupings and aggregation levels in his report, which we will model using CountryCode, District, and the first initial of the city name (that&#8217;s why the ORDER BY clause).<\/p>\n<p>Typically, you put a conditional or dynamic page break instruction on an outer group.&nbsp; In this case Karthik has used <strong>CEILING(RowNumber(NOTHING)\/1000)<\/strong> as his outermost group instruction.&nbsp;<\/p>\n<p>When an outer group breaks, each inner group breaks too; they are &#8220;child&#8221; groups, or nested aggregates.&nbsp;&nbsp;Karthik&#8217;s problem occurs when one of his &#8220;real&#8221; groups has more than 1000 rows. &nbsp;Karthik doesn&#8217;t want to see his sums or other aggregates until the &#8220;real&#8221; groups are actually finished.<\/p>\n<p>Since my sample doesn&#8217;t really have more than 1000&nbsp;rows in any one set, and to test properly, I&#8217;ve made the &#8220;Break on&#8221; figure configurable, with a default value of 3 rows.&nbsp;&nbsp;I&#8217;ve illustrated the problem like this:<\/p>\n<p>&nbsp;<img decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/2010\/2\/K1.PNG\" alt=\"\" \/><\/p>\n<p>The <strong>AGO<\/strong> country code grouping that starts on page 2 doesn&#8217;t finish on page 2.&nbsp; Therefore, even though a group break is forced by the outer group every 3 detail rows, we shouldn&#8217;t have totals for AGO on page 2.<\/p>\n<p>The report is doing what we said, but it isn&#8217;t doing what we meant.<\/p>\n<h2>What not to try<\/h2>\n<p>I first tried to solve this problem using a &#8220;remove the groups&#8221; strategy, which I&#8217;ve <a title=\"blog post on when not to use groups\" href=\"\/lisa\/2009\/03\/08\/Dynamic-Page-Breaks-in-SSRS-Going-to-Eleven\/\" target=\"_parent\" rel=\"noopener\">used successfully in other scenarios <\/a>before.&nbsp; It quickly turned into a nightmare.&nbsp; I&#8217;ll cut to the chase and say&#8230; don&#8217;t bother.<\/p>\n<h2>Inner dynamic group breaks<\/h2>\n<p>I realized that the right thing to do was to move the dynamic break group inside the ones that might have more members and shouldn&#8217;t show aggregates until they legitimately ended.&nbsp; This is the right solution, but it turned out to be a little more complicated than expected.<\/p>\n<p class=\"NB\">Before I explain, the usual caveats.&nbsp; In this case, there are two things to keep in mind:<\/p>\n<p>1. My analysis may be better than my solution. Read what&#8217;s involved, because I&#8217;ve done this part right. Maybe you&#8217;ll think of a better way to handle what needs to be done.<\/p>\n<p>2. I&#8217;m only moving one level of grouping inwards, because that&#8217;s all that&#8217;s necessary to show you what&#8217;s involved &#8212; even though, as you&#8217;ll see, the District group could also &#8220;overflow&#8221; the test break value&nbsp;of three rows&nbsp;that I&#8217;m using in these screen shots&nbsp;is&nbsp;so small. However, if Karthik or you have more than one additional level that could have more rows than the explicit page breaks you want to create, it doesn&#8217;t change the problem. Whatever solution you use &#8212; whether mine or your improved version &#8212; the thing-to-fix, and how it works, remain exactly the same.<\/p>\n<h3>The&nbsp;unkindest cut<\/h3>\n<p>We start, as explained&nbsp;&nbsp;by moving the outermost group with the special &#8220;CEILING&#8221; expression one level inward.&nbsp; You can try taking Karthik&#8217;s expression and just moving it, as-is, if you want to play along.&nbsp; Here&#8217;s the error you&#8217;ll get:<\/p>\n<blockquote>\n<p style=\"color:red;\">A group expression for the grouping &#8216;Standard Page Break&#8217; uses the RowNumber function with a scope that is not valid.&nbsp; When used in a group expression, the value of the scope parameter of RowNumber must equal the name of the group directly containing the current group.<\/p>\n<\/blockquote>\n<p>Ouch.&nbsp;Note: this is the error message I get in RS 2008 using the Report Designer; it might be slightly less explicit using ReportBuilder or RS 2005, but I imagine the engine rules are the same.<\/p>\n<p>You can try to do the obvious thing and use the scope suggested in this error message (in my case, that would be <strong>RowNumber(&#8220;table1_CountryCode&#8221;)<\/strong>).&nbsp; This may seem to work for you &#8212; for me, it didn&#8217;t have the desired results.&nbsp;&nbsp;&nbsp;Maybe I should have perservered, but I think that different sort orders, on different levels, may interfere. So, instead, I thought about how I could mimic the desired behavior of <strong>RowNumber(Nothing)<\/strong> without actually using the forbidden syntax.<\/p>\n<h3>The second cut<\/h3>\n<p>I did a number of things with Code functions, counting rows myself, which seemed to sort-of-work.&nbsp; But the behavior seemed a bit flakey, especially when rendering to HTML and flipping back and forth between pages.&nbsp;<\/p>\n<p>In the end, I took the more reliable route of creating my own row counter in SQL, like this:&nbsp;<\/p>\n<p class=\"code\"><span style=\"color: #0000ff;\">SELECT<\/span> <br \/>Name,CountryCode, District, Population, ID,<br \/><span style=\"color:#ff00ff;\">ROW_NUMBER() <\/span><span style=\"color: #0000ff;\">ORDER BY<\/span> CountryCode,District,Name) <br \/><span style=\"color: #0000ff;\">FROM<\/span> City<br \/><span style=\"color: #0000ff;\">ORDER BY<\/span> CountryCode,District,Name<br \/><span style=\"color:green;\"><br \/>&#8212; the new group break expression is: <br \/>&#8212; =CEILING(Fields!RowNum.Value\/Parameters!BreakOn.Value)<\/span><\/p>\n<p>&#8230; and that sort-of worked. I mean, it worked for most pages.<\/p>\n<p>But now I had a new problem. On pages where the CountryCode (outer) group break and the pagebreak limit (Parameters!BreakOn.Value) coincided exactly, no page break occurred.&nbsp; Apparently, the fact that the outer group said &#8220;no page break&#8221; countermanded the inner group&#8217;s explicit page break instructions.&nbsp;<\/p>\n<p style=\"TEXT-ALIGN: center\"><img decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/2010\/2\/K2.PNG\" alt=\"\" \/><\/p>\n<p>This behavior was consistent in different renderers, and seemed to have nothing to do with margins, sort orders, or anything else I could tweak.&nbsp; So, clearly, more effort was required.<\/p>\n<h3>Giving myself a break<\/h3>\n<p>By the time I figured out the pattern of the mysterious pages that didn&#8217;t work as expected, I wanted to solve this in a very literal-minded fashion and get it over with already.&nbsp; I already had a way to say &#8220;do a page breaks without unwarranted group header and footers&#8221;, that was inner.&nbsp; But now I needed to say &#8220;Also break at the same time as group headers and footers are warranted&#8221;.&nbsp; So, I realized I needed a second way to break &#8212; outermost, where it would be the highest-level authority on whether a page break was called for.<\/p>\n<p>&nbsp;<\/p>\n<p align=\"center\"><img decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/2010\/2\/K3.PNG\" alt=\"\" \/><\/p>\n<p>What would be the proper group break expression for the new group, though?<\/p>\n<p>I knew I wanted to to give the group these instructions: &#8220;Only break when (a) you&#8217;ve hit the right number of rows and (b) you&#8217;ve also hit the CountryCode group break&#8221;.&nbsp;<\/p>\n<p>Again, thinking literally, I knew that the second condition could be satisfied by checking the current CountryCode against the previous row&#8217;s CountryCode.&nbsp; But, in using the Previous function,&nbsp;I ran into similar limitations in group expressions as I&#8217;d faced with the RowNumber() function:<\/p>\n<blockquote>\n<p style=\"color:red;\">A group expression includes the aggregate function &#8216;Previous&#8217;.&nbsp; Previous cannot be used in group expressions.<\/p>\n<\/blockquote>\n<p>Ouch squared.<\/p>\n<p>I tried a lot of ways to get around this expression, as I did earlier (because I am stubborn), by writing code to compare the values myself, but in the end I took the somewhat more controllable path of adding the value directly into my SQL query, like this:<\/p>\n<p class=\"code\"><span style=\"color:#0000ff\">SELECT&nbsp;<\/span>curr<span style=\"color:#808080\">.*,<\/span> prev<span style=\"color:#808080\">.<\/span>CountryCode <span style=\"color:#0000ff\">AS<\/span> PrevCountryCode <br \/><span style=\"color:#0000ff\">FROM&nbsp;<br \/>&nbsp;&nbsp; <\/span><span style=\"color:#808080\">(<br \/>&nbsp;&nbsp;&nbsp; <span style=\"color: #0000ff\">S<\/span><\/span><span style=\"color:#0000ff\">ELECT<\/span> <span style=\"color:#0000ff\">TOP<\/span> 100 <span style=\"color:#0000ff\">PERCENT<\/span> <span style=\"color:#ff00ff\">ROW_NUMBER<\/span><span style=\"color:#808080\">()<\/span> <span style=\"color:#0000ff\">Over<\/span> &nbsp;<br \/><span style=\"color:#808080\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (<\/span><span style=\"color:#0000ff\">ORDER<\/span> <span style=\"color:#0000ff\">BY<\/span> CountryCode<span style=\"color:#808080\">,<\/span>District<span style=\"color:#808080\">,<\/span>Name<span style=\"color:#808080\">)<\/span> <span style=\"color:#0000ff\">AS<\/span> RowNum<span style=\"color:#808080\">,<\/span>&nbsp;<br \/><span style=\"color:#ff00ff\">&nbsp;&nbsp;&nbsp;&nbsp;RTRIM<\/span><span style=\"color:#808080\">(<\/span>Name<span style=\"color:#808080\">)<\/span> <span style=\"color:#0000ff\">AS<\/span> Name<span style=\"color:#808080\">,<\/span>CountryCode<span style=\"color:#808080\">,<\/span> District<span style=\"color:#808080\">,<\/span> <span style=\"color:#0000ff\">Population<\/span><span style=\"color:#808080\">,<\/span> ID &nbsp;<br \/><span style=\"color:#0000ff\">&nbsp;&nbsp;&nbsp; FROM<\/span> City&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:#0000ff\">ORDER<\/span> <span style=\"color:#0000ff\">BY<\/span> countrycode<span style=\"color:#808080\">,<\/span>district<span style=\"color:#808080\">,<\/span>name<br \/>&nbsp;&nbsp; <span style=\"color:#808080\">)<\/span> curr<br \/><span style=\"color:#808080\">LEFT<\/span> <span style=\"color:#808080\">JOIN <br \/>&nbsp;&nbsp; (<br \/><\/span><span style=\"color:#0000ff\">&nbsp;&nbsp; SELECT<\/span> <span style=\"color:#0000ff\">TOP<\/span> 100 <span style=\"color:#0000ff\">PERCENT<\/span> <span style=\"color:#ff00ff\">ROW_NUMBER<\/span><span style=\"color:#808080\">()<\/span> <span style=\"color:#0000ff\">Over<\/span> <br \/><span style=\"color:#808080\">&nbsp;&nbsp;&nbsp;&nbsp; (<\/span><span style=\"color:#0000ff\">ORDER<\/span> <span style=\"color:#0000ff\">BY<\/span> CountryCode<span style=\"color:#808080\">,<\/span>District<span style=\"color:#808080\">,<\/span>Name<span style=\"color:#808080\">)<\/span> <span style=\"color:#0000ff\">AS<\/span> RowNum<span style=\"color:#808080\">,<\/span> CountryCode&nbsp;<br \/><span style=\"color:#0000ff\">&nbsp;&nbsp; FROM<\/span> City &nbsp;<br \/><span style=\"color:#0000ff\">&nbsp;&nbsp; ORDER<\/span> <span style=\"color:#0000ff\">BY<\/span> countrycode<span style=\"color:#808080\">,<\/span>district<span style=\"color:#808080\">,<\/span>name<br \/>&nbsp;&nbsp; <span style=\"color:#808080\">)<\/span> prev<br \/><span style=\"color:#0000ff\">ON <\/span>curr<span style=\"color:#808080\">.<\/span>RowNum<span style=\"color:#808080\">&#8211;<\/span>1 <span style=\"color:#808080\">=<\/span> prev<span style=\"color:#808080\">.<\/span> RowNum<\/p>\n<p align=\"center\"><img decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/2010\/2\/K4.PNG\" alt=\"\" \/><\/p>\n<p>&#8230; and, while it may be possible to handle the resulting evaluation in a direct group break expression, I found it easiest to set up a function to do it, like this:<\/p>\n<p align=\"center\"><img decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/2010\/2\/K5.PNG\" alt=\"\" \/><\/p>\n<p>Ignore the Intellisense failure (annoying isn&#8217;t it?) which just indicates that Intellisense isn&#8217;t very&#8230; intelligent&#8230; about custom code.&nbsp;<\/p>\n<p>And you can ignore the ShowIssue parameter, which I only needed to show you the problem that occurs when this break behavior isn&#8217;t included in&nbsp;my sample report.<\/p>\n<p>The report script looks like this (as you can see it&#8217;s very simple and literal-minded):<\/p>\n<p class=\"code\"><span style=\"color:#0000ff;\">Dim<\/span> CurrBreakNum <span style=\"color:#0000ff;\">As <\/span><span style=\"color:#0000ff;\">Integer<\/span> = 0&nbsp;&nbsp;<br \/><span style=\"color:#0000ff;\">Dim<\/span> CurrCeiling <span style=\"color:#0000ff;\">As <\/span><span style=\"color:#0000ff;\">Integer<\/span> = 0&nbsp;&nbsp;<br \/>&nbsp;<br \/><span style=\"color:#0000ff;\">Function<\/span> GetBreak( _&nbsp;&nbsp;<br \/><span style=\"color:#0000ff;\">&nbsp;&nbsp; ByVal<\/span> showIssue <span style=\"color:#0000ff;\">As <\/span><span style=\"color:#0000ff;\">Boolean<\/span>, <span style=\"color:#0000ff;\">ByVal<\/span>&nbsp;thisCeiling <span style=\"color:#0000ff;\">As <\/span><span style=\"color:#0000ff;\">Integer<\/span> , _&nbsp;&nbsp;<br \/><span style=\"color:#0000ff;\">&nbsp;&nbsp; ByVal<\/span> currCode <span style=\"color:#0000ff;\">As <\/span><span style=\"color:#0000ff;\">String<\/span>, <span style=\"color:#0000ff;\">ByVal<\/span>&nbsp;prevCode <span style=\"color:#0000ff;\">As <\/span><span style=\"color:#0000ff;\">String<\/span>) <span style=\"color:#0000ff;\">As <\/span><span style=\"color:#0000ff;\">Integer<\/span><br \/>&nbsp;<br \/><span style=\"color:#0000ff;\">&nbsp;&nbsp; If<\/span> showIssue <span style=\"color:#0000ff;\">Then<\/span><br \/><span style=\"color:#008000;\"><br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8216; never break, we want to show the issue<\/span><br \/><span style=\"color:#0000ff;\"><br \/>&nbsp;&nbsp; ElseIf<\/span>&nbsp;prevCode <span style=\"color:#0000ff;\">Is <\/span><span style=\"color:#0000ff;\">Nothing <\/span><span style=\"color:#0000ff;\">OrElse<\/span> Len(prevCode) = 0 <span style=\"color:#0000ff;\">Then<\/span><br \/><span style=\"color:#008000;\"><br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8216; first row, there is no previous value<\/span><br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CurrBreakNum = 1<br \/><span style=\"color:#0000ff;\"><br \/>&nbsp;&nbsp; ElseIf<\/span> (CurrCeiling &lt;&gt; thisCeiling) <span style=\"color:#0000ff;\">AndAlso<\/span> (currCode &lt;&gt; prevCode) <span style=\"color:#0000ff;\">Then<br \/><\/span><br \/><span style=\"color:#008000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8216; if we&#8217;ve hit the special situation where<\/span><br \/><span style=\"color:#008000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8216; a break is called for and the &#8220;outer&#8221; group<\/span><br \/><span style=\"color:#008000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8216; breaks on the same row, we have to force&nbsp;<\/span><br \/><span style=\"color:#008000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8216; an external break&#8230;<\/span><br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CurrBreakNum += 1<br \/><span style=\"color:#0000ff;\"><br \/>&nbsp;&nbsp; End <\/span><span style=\"color:#0000ff;\">If<\/span><\/p>\n<p>&nbsp;&nbsp; CurrCeiling =&nbsp;thisCeiling<\/p>\n<p><span style=\"color:#0000ff;\">&nbsp;&nbsp; Return<\/span> CurrBreakNum&nbsp;&nbsp;<\/p>\n<p><span style=\"color:#0000ff;\">End <\/span><span style=\"color:#0000ff;\">Function<\/span><\/p>\n<h2>See?<\/h2>\n<p align=\"center\"><img decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/2010\/2\/K6.PNG\" alt=\"\" \/><\/p>\n<p>Simple, literal-minded, and rather brute-force-ish.&nbsp; And of course I tried all kinds of ways to be clever first.<\/p>\n<p>But&#8230; when you think about it,&nbsp;you&#8217;ll see that this approach&nbsp;makes sense and fits &#8220;what&#8217;s really going on&#8221; in the engine. And, more importantly, it works.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Karthik asks My actual task is to display totals of each group at the end of page breaks which are further grouped on count of 1000. I don&#8217;t know how to proceed with this issue. I have also queried the same at MSDN forums at the following links but haven&#8217;t been getting any responses at<a class=\"more-link\" href=\"https:\/\/spacefold.com\/lisa\/2010\/02\/14\/yaps-on-dynamic-pagebreaks-mixing-up-the-groups\/\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,6,12],"tags":[],"class_list":["post-85","post","type-post","status-publish","format-standard","hentry","category-reporting","category-sql-server","category-yaps"],"_links":{"self":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/posts\/85","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/comments?post=85"}],"version-history":[{"count":0,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/posts\/85\/revisions"}],"wp:attachment":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/media?parent=85"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/categories?post=85"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/tags?post=85"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}