100% found this document useful (3 votes)
22 views

SQL Server Analytical Toolkit: Using Windowing, Analytical, Ranking, and Aggregate Functions for Data and Statistical Analysis 1st Edition Angelo Bobak 2024 Scribd Download

Angelo

Uploaded by

prietlvarm
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (3 votes)
22 views

SQL Server Analytical Toolkit: Using Windowing, Analytical, Ranking, and Aggregate Functions for Data and Statistical Analysis 1st Edition Angelo Bobak 2024 Scribd Download

Angelo

Uploaded by

prietlvarm
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 66

Download Full Version ebookmass - Visit ebookmass.

com

SQL Server Analytical Toolkit: Using Windowing,


Analytical, Ranking, and Aggregate Functions for
Data and Statistical Analysis 1st Edition Angelo
Bobak
https://ebookmass.com/product/sql-server-analytical-toolkit-
using-windowing-analytical-ranking-and-aggregate-functions-
for-data-and-statistical-analysis-1st-edition-angelo-bobak/

OR CLICK HERE

DOWLOAD NOW

Discover More Ebook - Explore Now at ebookmass.com


Instant digital products (PDF, ePub, MOBI) ready for you
Download now and discover formats that fit your needs...

Practical Graph Structures in SQL Server and Azure SQL:


Enabling Deeper Insights Using Highly Connected Data 1st
Edition Louis Davidson
https://ebookmass.com/product/practical-graph-structures-in-sql-
server-and-azure-sql-enabling-deeper-insights-using-highly-connected-
data-1st-edition-louis-davidson-2/
ebookmass.com

Practical Graph Structures in SQL Server and Azure SQL:


Enabling Deeper Insights Using Highly Connected Data 1st
Edition Louis Davidson
https://ebookmass.com/product/practical-graph-structures-in-sql-
server-and-azure-sql-enabling-deeper-insights-using-highly-connected-
data-1st-edition-louis-davidson/
ebookmass.com

Fixed Income Mathematics: Analytical and Statistical


Techniques, 5th Edition Frank J. Fabozzi

https://ebookmass.com/product/fixed-income-mathematics-analytical-and-
statistical-techniques-5th-edition-frank-j-fabozzi/

ebookmass.com

Tietz fundamentos de química clínica e diagnóstico


molecular 7ª Edition Carl A. Burtis

https://ebookmass.com/product/tietz-fundamentos-de-quimica-clinica-e-
diagnostico-molecular-7a-edition-carl-a-burtis/

ebookmass.com
Big Data in Astronomy: Scientific Data Processing for
Advanced Radio Telescopes 1st Edition Linghe Kong (Editor)

https://ebookmass.com/product/big-data-in-astronomy-scientific-data-
processing-for-advanced-radio-telescopes-1st-edition-linghe-kong-
editor/
ebookmass.com

Fortran for Scientists and Engineers 4th Edition Stephen


J. Chapman

https://ebookmass.com/product/fortran-for-scientists-and-
engineers-4th-edition-stephen-j-chapman/

ebookmass.com

On The Origin of Evolution : Tracing ‘Darwin’s Dangerous


Idea’ From Aristotle to DNA John Gribbin

https://ebookmass.com/product/on-the-origin-of-evolution-tracing-
darwins-dangerous-idea-from-aristotle-to-dna-john-gribbin/

ebookmass.com

Process Safety and Big Data Sagit Valeev

https://ebookmass.com/product/process-safety-and-big-data-sagit-
valeev/

ebookmass.com

Shopping and the Senses, 1800-1970 Serena Dyer

https://ebookmass.com/product/shopping-and-the-
senses-1800-1970-serena-dyer/

ebookmass.com
Calculus: Early Transcendentals 8th Edition eBook

https://ebookmass.com/product/calculus-early-transcendentals-8th-
edition-ebook/

ebookmass.com
SQL Server
Analytical
Toolkit
Using Windowing, Analytical, Ranking,
and Aggregate Functions for Data and
Statistical Analysis

Angelo Bobak
SQL Server Analytical
Toolkit
Using Windowing, Analytical,
Ranking, and Aggregate Functions
for Data and Statistical Analysis

Angelo Bobak
SQL Server Analytical Toolkit: Using Windowing, Analytical, Ranking, and Aggregate
Functions for Data and Statistical Analysis
Angelo Bobak
Hastings On Hudson, NY, USA

ISBN-13 (pbk): 978-1-4842-8666-1 ISBN-13 (electronic): 978-1-4842-8667-8


https://doi.org/10.1007/978-1-4842-8667-8

Copyright © 2023 by Angelo Bobak


This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the
material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation,
broadcasting, reproduction on microfilms or in any other physical way, and transmission or information
storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now
known or hereafter developed.
Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with
every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an
editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the
trademark.
The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not
identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to
proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of publication,
neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or
omissions that may be made. The publisher makes no warranty, express or implied, with respect to the
material contained herein.
Managing Director, Apress Media LLC: Welmoed Spahr
Acquisitions Editor: Joan Murray
Development Editor: Laura Berendson
Coordinating Editor: Gryffin Winkler
Cover image designed by Freepik (www.freepik.com)
Distributed to the book trade worldwide by Springer Science+Business Media LLC, 1 New York Plaza,
Suite 4600, New York, NY 10004. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail orders-ny@springer-
sbm.com, or visit www.springeronline.com. Apress Media, LLC is a California LLC and the sole member
(owner) is Springer Science + Business Media Finance Inc (SSBM Finance Inc). SSBM Finance Inc is a
Delaware corporation.
For information on translations, please e-mail [email protected]; for reprint,
paperback, or audio rights, please e-mail [email protected].
Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and
licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales
web page at http://www.apress.com/bulk-sales.
Any source code or other supplementary material referenced by the author in this book is available to
readers on GitHub.
Paper in this product is recyclable
I would like to dedicate this book to my wife, Cathy, for all her support
and patience throughout my career and all my book projects. I would
like to thank Apress for this opportunity, specifically Joan Murray, the
acquisition editor, who gave me this chance and Laura Berendson
and Gryffin Winkler for their valuable help and suggestions.
Last but not least, I thank all the technical reviewers for their
suggestions, tips, and corrections. What’s good about this book is
because of them. What’s not so good is entirely due to me!
Table of Contents
About the Author�����������������������������������������������������������������������������������������������������xv

About the Technical Reviewer�������������������������������������������������������������������������������xvii


Introduction������������������������������������������������������������������������������������������������������������xix

Chapter 1: Partitions, Frames, and the OVER( ) Clause��������������������������������������������� 1


What Are Partitions and Window Frames?������������������������������������������������������������������������������������ 1
What Is an OVER( ) Clause?����������������������������������������������������������������������������������������������������������� 2
History of the OVER( ) Clause and Window Functions������������������������������������������������������������������� 2
The Window Functions������������������������������������������������������������������������������������������������������������������ 3
The OVER( ) Clause������������������������������������������������������������������������������������������������������������������������ 4
Syntax������������������������������������������������������������������������������������������������������������������������������������������� 4
Partitions and Frames������������������������������������������������������������������������������������������������������������������� 6
ROWS Frame Definition����������������������������������������������������������������������������������������������������������������� 8
RANGE Frame Definition������������������������������������������������������������������������������������������������������������� 16
Example 1����������������������������������������������������������������������������������������������������������������������������������� 19
ROWS and RANGE Default Behavior�������������������������������������������������������������������������������������������� 23
Scenario 1����������������������������������������������������������������������������������������������������������������������������� 24
Scenario 2����������������������������������������������������������������������������������������������������������������������������� 24
ROWS and RANGE Window Frame Examples������������������������������������������������������������������������������ 25
Data Set��������������������������������������������������������������������������������������������������������������������������������� 25
Example 2������������������������������������������������������������������������������������������������������������������������������ 29
Example 3������������������������������������������������������������������������������������������������������������������������������ 32
Example 4������������������������������������������������������������������������������������������������������������������������������ 34
Example 5������������������������������������������������������������������������������������������������������������������������������ 38
Summary������������������������������������������������������������������������������������������������������������������������������������ 40

v
Table of Contents

Chapter 2: Sales DW Use Case: Aggregate Functions��������������������������������������������� 43


Sales Data Warehouse���������������������������������������������������������������������������������������������������������������� 43
Sales Data Warehouse Conceptual Model����������������������������������������������������������������������������������� 45
A Word About Performance Tuning���������������������������������������������������������������������������������������������� 50
Aggregate Functions������������������������������������������������������������������������������������������������������������������� 60
COUNT( ), MAX( ), MIN( ), AVG( ), and SUM( ) Functions����������������������������������������������������������� 61
With OVER( )��������������������������������������������������������������������������������������������������������������������������� 63
GROUPING( ) Function������������������������������������������������������������������������������������������������������������ 67
GROUPING: Performance Tuning Considerations������������������������������������������������������������������� 71
STRING_AGG Function����������������������������������������������������������������������������������������������������������� 77
STDEV( ) and STDEVP( ) Functions����������������������������������������������������������������������������������������� 80
STDEV: Performance Tuning Considerations�������������������������������������������������������������������������� 85
VAR( ) and VARP( ) Functions�������������������������������������������������������������������������������������������������� 91
SQL Server 2022: Named Window Example�������������������������������������������������������������������������������� 95
Summary���������������������������������������������������������������������������������������������������������������������������������� 103

Chapter 3: Sales Use Case: Analytical Functions������������������������������������������������� 105


Analytical Functions������������������������������������������������������������������������������������������������������������������ 105
CUME_DIST( ) Function�������������������������������������������������������������������������������������������������������� 106
Performance Considerations����������������������������������������������������������������������������������������������� 112
PERCENT_RANK( ) Function������������������������������������������������������������������������������������������������� 117
Performance Considerations����������������������������������������������������������������������������������������������� 124
High-Performance Strategy������������������������������������������������������������������������������������������������� 127
LAST_VALUE( ) and FIRST_VALUE( )������������������������������������������������������������������������������������� 134
Performance Considerations����������������������������������������������������������������������������������������������� 137
LAG( ) and LEAD( )���������������������������������������������������������������������������������������������������������������� 140
Performance Considerations����������������������������������������������������������������������������������������������� 142
PERCENTILE_CONT( ) and PERCENTILE_DISC( )������������������������������������������������������������������� 147
Performance Considerations����������������������������������������������������������������������������������������������� 152
Using a Report Table������������������������������������������������������������������������������������������������������������ 157
Summary���������������������������������������������������������������������������������������������������������������������������������� 163

vi
Table of Contents

Chapter 4: Sales Use Case: Ranking/Window Functions�������������������������������������� 165


Ranking/Window Functions������������������������������������������������������������������������������������������������������ 165
RANK( ) vs. PERCENT_RANK( )��������������������������������������������������������������������������������������������� 171
Performance Considerations����������������������������������������������������������������������������������������������� 175
RANK( ) vs. DENSE_RANK( )������������������������������������������������������������������������������������������������� 179
Performance Considerations����������������������������������������������������������������������������������������������� 183
NTILE( ) Function Revisited�������������������������������������������������������������������������������������������������� 185
Performance Considerations����������������������������������������������������������������������������������������������� 188
ROW_NUMBER( ) Function��������������������������������������������������������������������������������������������������� 190
Performance Considerations����������������������������������������������������������������������������������������������� 194
Islands and Gaps Example��������������������������������������������������������������������������������������������������� 201
Summary���������������������������������������������������������������������������������������������������������������������������������� 209

Chapter 5: Finance Use Case: Aggregate Functions��������������������������������������������� 211


Aggregate Functions����������������������������������������������������������������������������������������������������������������� 211
COUNT( ) and SUM( ) Functions�������������������������������������������������������������������������������������������� 217
Performance Considerations����������������������������������������������������������������������������������������������� 226
SUM( ) Function������������������������������������������������������������������������������������������������������������������� 234
Performance Considerations����������������������������������������������������������������������������������������������� 238
MIN( ) and MAX( ) Functions������������������������������������������������������������������������������������������������� 244
Performance Considerations����������������������������������������������������������������������������������������������� 250
AVG( ) Function�������������������������������������������������������������������������������������������������������������������� 258
Performance Considerations����������������������������������������������������������������������������������������������� 264
GROUPING Function������������������������������������������������������������������������������������������������������������� 267
Performance Considerations����������������������������������������������������������������������������������������������� 272
STRING_AGG( ) Function������������������������������������������������������������������������������������������������������ 277
STDEV( ) and STDEVP( ) Functions��������������������������������������������������������������������������������������� 278
Performance Considerations����������������������������������������������������������������������������������������������� 286
VAR( ) and VARP( ) Functions������������������������������������������������������������������������������������������������ 297
Ticker Analysis�������������������������������������������������������������������������������������������������������������������������� 302

vii
Table of Contents

More Non-statistical Variance��������������������������������������������������������������������������������������������� 305


Even More Statistical Variance�������������������������������������������������������������������������������������������� 308
Summary���������������������������������������������������������������������������������������������������������������������������������� 311

Chapter 6: Finance Use Case: Ranking Functions������������������������������������������������ 313


Ranking Functions�������������������������������������������������������������������������������������������������������������������� 313
RANK( ) Function������������������������������������������������������������������������������������������������������������������ 314
DENSE_RANK( ) Function����������������������������������������������������������������������������������������������������� 341
NTILE( ) Function������������������������������������������������������������������������������������������������������������������ 355
ROW_NUMBER( ) Function��������������������������������������������������������������������������������������������������� 370
The Data Gaps and Islands Problem����������������������������������������������������������������������������������������� 377
Step 1: Create the First CTE������������������������������������������������������������������������������������������������� 383
Step 2: Set Up the Second CTE to Label Gaps��������������������������������������������������������������������� 386
Step 3: Set Up the Third CTE and Identify Start/Stop Dates of Gaps����������������������������������� 388
Step 4: Generate the Report������������������������������������������������������������������������������������������������ 390
Performance Considerations����������������������������������������������������������������������������������������������� 392
Islands Next������������������������������������������������������������������������������������������������������������������������������ 395
Step 1: Create the First CTE Using LAG( ) and LEAD( )��������������������������������������������������������� 395
Step 2: Create the Second CTE That Labels Islands and Gaps�������������������������������������������� 397
Step 3: Identify Island Start/Stop Dates������������������������������������������������������������������������������� 402
Step 4: Create the Final Report�������������������������������������������������������������������������������������������� 404
Summary���������������������������������������������������������������������������������������������������������������������������������� 408

Chapter 7: Finance Use Case: Analytical Functions���������������������������������������������� 409


Analytical Functions������������������������������������������������������������������������������������������������������������������ 409
CUME_DIST( ) Function�������������������������������������������������������������������������������������������������������� 410
Performance Considerations����������������������������������������������������������������������������������������������� 416
FIRST_VALUE( ) and LAST_VALUE( ) Functions��������������������������������������������������������������������� 420
Performance Considerations����������������������������������������������������������������������������������������������� 424
LAG( ) and LEAD( ) Functions������������������������������������������������������������������������������������������������ 431
LAG( ) Function��������������������������������������������������������������������������������������������������������������������� 431
Performance Considerations����������������������������������������������������������������������������������������������� 435
LEAD( ) Function������������������������������������������������������������������������������������������������������������������ 440

viii
Table of Contents

Performance Considerations����������������������������������������������������������������������������������������������� 442


Memory-Optimized Strategy����������������������������������������������������������������������������������������������� 445
PERCENT_RANK( ) Function������������������������������������������������������������������������������������������������� 450
Performance Considerations����������������������������������������������������������������������������������������������� 453
PERCENTILE_CONT( ) and PERCENTILE_DISC( )������������������������������������������������������������������� 455
PERCENTILE_CONT( )����������������������������������������������������������������������������������������������������������� 455
Performance Considerations����������������������������������������������������������������������������������������������� 459
PERCENTILE_DISC Function������������������������������������������������������������������������������������������������ 462
Performance Considerations����������������������������������������������������������������������������������������������� 465
Multi-memory-enhanced-table Strategy����������������������������������������������������������������������������� 471
Performance Considerations����������������������������������������������������������������������������������������������� 476
Summary���������������������������������������������������������������������������������������������������������������������������������� 482

Chapter 8: Plant Use Case: Aggregate Functions������������������������������������������������� 483


Aggregate Functions����������������������������������������������������������������������������������������������������������������� 484
Data Model�������������������������������������������������������������������������������������������������������������������������������� 485
Data Dictionaries����������������������������������������������������������������������������������������������������������������������� 489
Entity Data Dictionary���������������������������������������������������������������������������������������������������������� 489
Entity Attribute Data Dictionary������������������������������������������������������������������������������������������� 491
Entity Relationship Data Dictionary: Equipment Failure Subject Area��������������������������������� 498
Entity Relationship Data Dictionary: Equipment Status History������������������������������������������� 500
Entity Relationship Data Dictionary: Plant Expense������������������������������������������������������������� 500
COUNT( ) Function��������������������������������������������������������������������������������������������������������������������� 501
AVG( ) Function��������������������������������������������������������������������������������������������������������������������� 512
MIN( ) and MAX( ) Functions������������������������������������������������������������������������������������������������� 514
GROUPING( ) Function���������������������������������������������������������������������������������������������������������� 526
STRING_AGG( ) Function������������������������������������������������������������������������������������������������������ 530
STDEV( ) and STDEVP( ) Functions���������������������������������������������������������������������������������������� 534
VAR( ) and VARP( ) Functions������������������������������������������������������������������������������������������������������ 543
Example 1: Rolling Variance������������������������������������������������������������������������������������������������ 544
Example 2: Variance by Quarter������������������������������������������������������������������������������������������� 547
Example 3: Variance by Year������������������������������������������������������������������������������������������������ 550

ix
Table of Contents

Performance Considerations����������������������������������������������������������������������������������������������������� 553


Memory-Optimized Table Approach������������������������������������������������������������������������������������� 559
Seven-Million-Row Query: Performance Tuning����������������������������������������������������������������������� 570
Summary���������������������������������������������������������������������������������������������������������������������������������� 582

Chapter 9: Plant Use Case: Ranking Functions����������������������������������������������������� 583


Ranking Functions�������������������������������������������������������������������������������������������������������������������� 583
RANK( ) Function������������������������������������������������������������������������������������������������������������������ 584
Performance Considerations����������������������������������������������������������������������������������������������� 588
Performance Considerations����������������������������������������������������������������������������������������������� 594
Performance Considerations����������������������������������������������������������������������������������������������� 600
DENSE_RANK( ) Function����������������������������������������������������������������������������������������������������� 606
Performance Considerations����������������������������������������������������������������������������������������������� 611
NTILE Function��������������������������������������������������������������������������������������������������������������������� 616
Performance Considerations����������������������������������������������������������������������������������������������� 622
ROW_NUMBER( ) Function��������������������������������������������������������������������������������������������������� 626
Performance Considerations����������������������������������������������������������������������������������������������� 630
Summary���������������������������������������������������������������������������������������������������������������������������������� 633

Chapter 10: Plant Use Case: Analytical Functions������������������������������������������������ 635


Analytical Functions������������������������������������������������������������������������������������������������������������������ 635
CUME_DIST( ) Function�������������������������������������������������������������������������������������������������������� 637
Performance Considerations����������������������������������������������������������������������������������������������� 643
FIRST_VALUE( ) and LAST_VALUE( ) Functions��������������������������������������������������������������������� 648
Performance Considerations����������������������������������������������������������������������������������������������� 651
LAG( ) Function��������������������������������������������������������������������������������������������������������������������� 652
Performance Considerations����������������������������������������������������������������������������������������������� 656
LEAD( ) Function������������������������������������������������������������������������������������������������������������������ 665
Performance Considerations����������������������������������������������������������������������������������������������� 667
PERCENT_RANK( ) Function������������������������������������������������������������������������������������������������� 669
Performance Considerations����������������������������������������������������������������������������������������������� 671
PERCENTILE_CONT Function����������������������������������������������������������������������������������������������� 677
Performance Considerations����������������������������������������������������������������������������������������������� 680

x
Table of Contents

PERCENTILE_DISC( ) Function���������������������������������������������������������������������������������������������� 685


Performance Considerations����������������������������������������������������������������������������������������������� 688
Our Usual Report Table Solution������������������������������������������������������������������������������������������ 692
SQL Server Analysis Services��������������������������������������������������������������������������������������������������� 697
Summary���������������������������������������������������������������������������������������������������������������������������������� 714

Chapter 11: Inventory Use Case: Aggregate Functions���������������������������������������� 717


The Inventory Database������������������������������������������������������������������������������������������������������������ 717
The Inventory Data Warehouse������������������������������������������������������������������������������������������������� 719
Loading the Inventory Data Warehouse������������������������������������������������������������������������������������ 721
Aggregate Functions����������������������������������������������������������������������������������������������������������������� 735
COUNT( ), SUM( ), MAX( ), MIN( ), and AVG( ) Functions��������������������������������������������������������� 735
Performance Considerations����������������������������������������������������������������������������������������������� 739
AVG( ) Function�������������������������������������������������������������������������������������������������������������������� 743
Performance Considerations����������������������������������������������������������������������������������������������� 745
Data Warehouse Query�������������������������������������������������������������������������������������������������������� 747
Performance Considerations����������������������������������������������������������������������������������������������� 750
STDEV( ) Function���������������������������������������������������������������������������������������������������������������� 754
Performance Considerations����������������������������������������������������������������������������������������������� 758
Data Warehouse Query�������������������������������������������������������������������������������������������������������� 760
Performance Considerations����������������������������������������������������������������������������������������������� 764
VAR( ) Function��������������������������������������������������������������������������������������������������������������������� 766
Performance Considerations����������������������������������������������������������������������������������������������� 769
Enhancing the SSIS Package���������������������������������������������������������������������������������������������������� 772
Summary���������������������������������������������������������������������������������������������������������������������������������� 783

Chapter 12: Inventory Use Case: Ranking Functions�������������������������������������������� 785


Ranking Functions�������������������������������������������������������������������������������������������������������������������� 786
RANK( ) Function������������������������������������������������������������������������������������������������������������������ 786
Performance Considerations����������������������������������������������������������������������������������������������� 791
Querying the Data Warehouse��������������������������������������������������������������������������������������������� 796
DENSE_RANK( ) Function����������������������������������������������������������������������������������������������������� 802
Performance Considerations����������������������������������������������������������������������������������������������� 805
xi
Table of Contents

NTILE( ) Function������������������������������������������������������������������������������������������������������������������ 809


Performance Considerations����������������������������������������������������������������������������������������������� 813
ROW_NUMBER( ) Function��������������������������������������������������������������������������������������������������� 818
Performance Considerations����������������������������������������������������������������������������������������������� 823
Create an SSRS Report������������������������������������������������������������������������������������������������������������� 824
Report Builder Mini Tutorial������������������������������������������������������������������������������������������������� 828
Create a Power BI Report���������������������������������������������������������������������������������������������������� 855
Summary���������������������������������������������������������������������������������������������������������������������������������� 867

Chapter 13: Inventory Use Case: Analytical Functions����������������������������������������� 869


Analytical Functions������������������������������������������������������������������������������������������������������������������ 869
CUME_DIST( ) Function�������������������������������������������������������������������������������������������������������� 870
Performance Considerations����������������������������������������������������������������������������������������������� 876
FIRST_VALUE( ) and LAST_VALUE( ) Functions��������������������������������������������������������������������� 878
Performance Considerations����������������������������������������������������������������������������������������������� 883
LAG( ) Function��������������������������������������������������������������������������������������������������������������������� 885
Performance Considerations����������������������������������������������������������������������������������������������� 889
LEAD( ) Function������������������������������������������������������������������������������������������������������������������ 894
Performance Considerations����������������������������������������������������������������������������������������������� 900
PERCENT_RANK( ) Function������������������������������������������������������������������������������������������������� 907
Performance Considerations����������������������������������������������������������������������������������������������� 912
PERCENTILE_CONT( ) Function�������������������������������������������������������������������������������������������� 914
Performance Considerations����������������������������������������������������������������������������������������������� 919
PERCENTILE_DISC( ) Function���������������������������������������������������������������������������������������������� 925
Performance Considerations����������������������������������������������������������������������������������������������� 929
Overall Performance Considerations����������������������������������������������������������������������������������� 935
Report Builder Examples����������������������������������������������������������������������������������������������������������� 939
Summary���������������������������������������������������������������������������������������������������������������������������������� 947

Chapter 14: Summary, Conclusions, and Next Steps�������������������������������������������� 949


Summary���������������������������������������������������������������������������������������������������������������������������������� 949
Our Journey������������������������������������������������������������������������������������������������������������������������������ 949
About the Code�������������������������������������������������������������������������������������������������������������������������� 950
xii
Table of Contents

About the Database Folders������������������������������������������������������������������������������������������������������ 952


Data Used in the Examples������������������������������������������������������������������������������������������������������� 952
The Toolkit��������������������������������������������������������������������������������������������������������������������������������� 953
SQL Server�������������������������������������������������������������������������������������������������������������������������������� 954
SSMS���������������������������������������������������������������������������������������������������������������������������������������� 956
The Window Functions�������������������������������������������������������������������������������������������������������������� 959
The Visual Studio Community License�������������������������������������������������������������������������������������� 960
SSAS Projects���������������������������������������������������������������������������������������������������������������������� 962
SSIS Projects����������������������������������������������������������������������������������������������������������������������� 963
Power BI Web Scorecards, Dashboards, and Reports��������������������������������������������������������������� 964
Microsoft Excel Spreadsheets�������������������������������������������������������������������������������������������������� 965
SSAS Server������������������������������������������������������������������������������������������������������������������������������ 966
SSRS Server and Website��������������������������������������������������������������������������������������������������������� 968
Report Builder��������������������������������������������������������������������������������������������������������������������������� 970
Performance Analysis Tools������������������������������������������������������������������������������������������������������ 971
Estimated Query Plans�������������������������������������������������������������������������������������������������������� 972
Live Query Plans������������������������������������������������������������������������������������������������������������������ 973
DBCC������������������������������������������������������������������������������������������������������������������������������������ 974
IO and TIME Statistics���������������������������������������������������������������������������������������������������������� 974
STATISTICS PROFILE������������������������������������������������������������������������������������������������������������ 975
Where to Get the Tools�������������������������������������������������������������������������������������������������������������� 977
SQL Server Developer���������������������������������������������������������������������������������������������������������� 977
Visual Studio Community����������������������������������������������������������������������������������������������������� 978
SQL Server Data Tools��������������������������������������������������������������������������������������������������������� 979
SQL Server SSAS Project Support��������������������������������������������������������������������������������������� 980
SQL Server SSIS Project Support���������������������������������������������������������������������������������������� 981
SQL Server SSRS Project Support��������������������������������������������������������������������������������������� 982
Report Builder���������������������������������������������������������������������������������������������������������������������� 983
Power BI Desktop���������������������������������������������������������������������������������������������������������������� 984
Power BI Server������������������������������������������������������������������������������������������������������������������� 985

xiii
Table of Contents

Microsoft Excel�������������������������������������������������������������������������������������������������������������������� 986


SSMS����������������������������������������������������������������������������������������������������������������������������������� 987
Next Steps��������������������������������������������������������������������������������������������������������������������������������� 988
Thank You!�������������������������������������������������������������������������������������������������������������������������������� 988

Appendix A: Function Syntax, Descriptions���������������������������������������������������������� 989

Appendix B: Statistical Functions����������������������������������������������������������������������� 1009

Index������������������������������������������������������������������������������������������������������������������� 1035

xiv
About the Author
Angelo R. Bobak is a published author with more than three
decades of experience and expertise in the areas of business
intelligence, data architecture, data warehouse design, data
modeling, master data management, and data quality using
the Microsoft BI Stack across several industry sectors such as
finance, telecommunications, engineering, publishing, and
automotive.

xv
About the Technical Reviewer
Alicia Moniz is a leader in Data & AI at Microsoft, an
organizer for Global AI Bootcamp – Houston Edition, and
a #KafkaOnAzure Evangelista and prior was a three-time
Microsoft AI MVP. She is an active supporter of women in
technology and volunteers her time at events that help make
AI technology accessible to the masses. She is a co-author of
the Apress publication Beginning Azure Cognitive Services:
Data-Driven Decision Making Through Artificial Intelligence
along with fellow Microsoft MVPs Matt Gordon, Ida Bergum,
Mia Chang, and Ginger Grant. With over 14 years of experience in data warehousing
and advanced analytics, Alicia is constantly upskilling and holds more than 12 in-
demand IT certifications including AWS, Azure, and Kafka. She is active in the Microsoft
User Group community and enjoys speaking on AI, SQL Server, #KafkaOnAzure, and
personal branding for women in technology topics. Currently, she authors the blog
HybridDataLakes.com, a blog focused on cloud data learning resources, and produces
content for the YouTube channel #KafkaOnAzure.

xvii
Introduction
Welcome to my book, SQL Server Analytical Toolkit.
What’s this book about?
This is a book on applying Microsoft SQL Server aggregate, analytical, and ranking
functions across various industries for the purpose of statistical, reporting, analytical,
and historical performance analysis using a series of built-in SQL Server functions
affectionately known as the window functions!
No, not window functions like the ones used in the C# or other Microsoft Windows
application programming. They are called window functions because they implement
windows into the data set generated by a query. These windows allow you to control
where the functions are applied in the data by creating partitions in the query data set.
“What’s a partition?” you might ask. This is a key concept you need to understand to
get the most out of this book. Suppose you have a data set that has six rows for product
category A and six rows for product category B. Each row has a column that stores sales
values that you wish to analyze. The data set can be divided into two sections, one for
each product category. These are the partitions that the window functions use. You can
analyze each partition by applying the window functions (more on this in Chapter 1).
We will see that the window in each partition can be further divided into smaller
windows. The mechanism of a window frame allows you to control which rows in
the partition are submitted to the window function relative to the current row being
processed. For example, apply a function like the SUM() function to the current row being
processed and any prior rows in the partition to calculate running totals by month. Move
to the next row in the partition and it behaves the same.
The book focuses on applying these functions across four key industries: sales,
finance, engineering, and inventory control. I did this so that readers in these industries
can find something they are familiar with in their day-to-day job activities. Even if you
are not working across these industries, you can still benefit by learning the window
functions and seeing how they are applied.
Maybe you want to interview for a developer role in the finance sector? Or maybe
you work in engineering or telecommunications or you are a manufacturer of retail
products. This book will help you acquire some valuable skills that will help you pass the
job interview.
xix
Introduction

Although you could perform these functions with tools like Power BI, performing
these functions at the SQL level precalculates results and improves performance so that
reporting tools use precalculated data.
By the way, there are many books out there on SQL Server and window (or
windowing) functions. What’s so different about this book?

Approach
This book takes a cookbook approach. Not only are you shown how to use the functions,
but you are shown how to apply them across sales, finance, inventory control, and
engineering scenarios.
These functions are grouped into three categories, so for each industry use case we
look at, we will dedicate a chapter to each function category:

• Aggregate functions

• Analytical functions

• Ranking functions

For each function, a query is created and explained. Next, the results are examined
and analyzed.
Where applicable the results are used to generate some interesting graphs with
Microsoft Excel spreadsheets, like creating normal distribution charts for sales data.
Appendix A contains descriptions and syntax for these functions in case you are not
familiar with them, so feel free to examine them before diving into the book.
Key to mastering the concepts in this book is understanding what the OVER() clause
does. Chapter 1 starts off by defining what the OVER() clause is and how it is used with
the window functions.
Several diagrams clearly explain what data sets, partitions, and window frames are
and how they are key to using the window functions.
Each of the industries we identified earlier has three dedicated chapters, one for each
of the window function categories. Each chapter provides a specification for the query to be
written, the code to satisfy the specification, and then one or more figures to show the results.
The book is unique in that it goes beyond just showing how each function works; it
presents use case scenarios related to statistical analysis, data analysis, and BI (BI stands
for business intelligence by the way).

xx
Introduction

The book also makes available all code examples including code to create and load
each of the four databases via the publisher's Google website.
Lastly, just enough theory is included to introduce you to statistical analysis in case
you are not familiar with terms like standard deviation, mean, normal distribution, and
variance. These are important as they will supply you with valuable skills to support your
business users and enhance your skills portfolio. Hey, a little business theory can’t hurt!
Appendix B has a brief primer on statistics, so make sure to check it out in case these
topics are new to you. It discusses standard deviation, variance, normal distribution,
other statistical calculations, and bell curves.
Back to the window functions. These functions generate a lot of numerical data. It’s
great to generate numbers with decimal points but even more interesting to graph them
and understand what they mean. A picture is worth a thousand words. Seeing a graph
that shows sales decreasing month by month is certainly worth looking at and should
raise alarms!
You can also use the Excel spreadsheets to verify your results by using the
spreadsheets’ built-in functions to make sure they match the results of your queries.
Always test your data against a set of results known to be correct (you might just learn
a little bit about Microsoft Excel too!). The spreadsheets used in this book will also be
available on the publisher's Google website.
The book includes tips and discussions that will take you through the process of
learning the SQL Server aggregate, ranking, and analytical functions. These are delivered
in a step-by-step approach so you can easily master the concepts. Data results are
analyzed so that you can understand what the function does and how the windows are
used to analyze the data work.

Expectations
Now that you know what you are in for, what do I expect from you?
Not much really, at a high level.
I expect you to be an intermediate to advanced SQL Server developer or data
architect who needs to learn how to use window functions. You can write ­medium-­
complexity queries that use joins, understand what a CTE (common table expression) is,
and be able to create and load database tables.
You could also be a tech-savvy business analyst who needs to apply sophisticated
data analysis for your business users or clients.

xxi
Introduction

Lastly, you could be a technology manager who wants to understand what your
development team does in their roles as developers. All will benefit from this book.
In conclusion, you need

• A keen interest in learning data analysis skills

• A basic knowledge of relational database technology and SQL skills

• A basic understanding of mathematical calculations like calculating


the average of values and performing basic arithmetic operations like
addition, subtraction, division, and multiplication

• Lastly, a working knowledge of SQL Server Management Studio


(SSMS), the tool we will use to create and execute the queries

In case you do not know how to use SSMS, there are many excellent YouTube videos
and sites that can show you how to use this tool in a short amount of time.
You can also check out my podcast “GRUMPY PODCAST 01 NAVIGATING SSMS” at
www.grumpyolditguy.com under the TSQL Podcasts menu selection in the menu bar.

What’s in It for You?


You, my dear reader, will learn how to use the Microsoft SQL Server analytical, aggregate,
and ranking functions. These are valuable skills that will enhance your capability to
develop solutions for your company role and the business users you support or will
support.

What Else Do You Get?


There are tons of code examples that you can access and play around with to become
familiar with the workings of the window functions. Practice makes perfect. Break the
code, modify it, and experiment. This is the best way to learn.

Note You can download the code from the publisher’s Google website at
https://github.com/Apress/SQL-Server-Analytical-Toolkit.

xxii
Introduction

One Final Note


Besides the queries discussed in the chapters, DDL (data declaration language) code is
included to create the four practice databases and load the tables in each. These scripts
clearly identify the steps and the sequence you need to take to create and load all the
data objects (some will generate millions of rows).
Once you create the databases and load the tables, you can practice by executing
the supplied queries as you read along in each of the chapters. You can also practice
performance tuning by creating indexes and examining the query plans that can be
generated with SSMS.
Lastly, I will also touch upon performance tuning a bit to ensure that the queries
you create run fast and efficient. The functions you will learn are resource intensive, so
we need to write queries that will not tie down server resources, like CPU, memory, and
disk! (Or have your users pull their hair when a query runs for hours or days….)
As added value, you will be shown how to apply good coding standards to improve
code legibility. Code that is easy to read is easy to maintain, fix, and modify. We want
to be good teammates in case your code is handed to another developer once you are
promoted (or get a better job!). For these reasons, we will use the coding standards
suggested by Microsoft Corporation for SQL Server.
These are easy to learn and adopt. All TSQL commands and keywords are in
uppercase, and data objects referenced are named with one or more words that describe
the data object. The first letter of the word that makes up the data object name is in
uppercase, and the remaining letters are lowercase, for example, DeptId for department
identifier.
A sample query that follows this coding standard is

SELECT DeptId, MgrId, MgrLastName


FROM Department
GO

Very simple and easy to read. It is clear by the names used that the query retrieves
departmental information, specifically the department identifier, the manager identifier,
and the manager’s last name. Notice the name of the table. There is no doubt as to what
the table contains.
That’s it! Let’s begin our journey into window functions.

xxiii
CHAPTER 1

Partitions, Frames, and


the OVER( ) Clause
The goal of this chapter is to describe the OVER() clause, its various configurations
in terms of how partitions and window frames are created, and how data is sorted
in the partition so that the window function can operate on the values. (The OVER()
clause together with partitions and window frames is what gives power to the window
functions.)
We will cover window frames and how they are defined to present a set of partition
rows that are processed by the window functions.
Several diagrams illustrate the concepts, and then several examples are shown to
illustrate the various ways partitions and window frames work on real data sets using
window functions. We will discuss ROWS and RANGE clauses and how they operate on data
in the partition.
We will also look at a case where we use subqueries in the ORDER BY clause instead of
columns so as to eliminate expensive sort steps in a query plan.
A final short example is presented to show the new named window feature in SQL
Server 2022.

What Are Partitions and Window Frames?


A TSQL query will generate an initial data result set. The result set can be divided
into sections called partitions, like a partition for each set of rows by specific years.
The window frame is like a smaller window into the partition defined by some row
boundaries or ranges, for example, rows prior to and including the current row being
processed or all rows after and including the current row within the partition. The entire

1
© Angelo Bobak 2023
A. Bobak, SQL Server Analytical Toolkit, https://doi.org/10.1007/978-1-4842-8667-8_1
Chapter 1 Partitions, Frames, and the OVER( ) Clause

data set can also be a partition by itself, and a window can be defined that uses all rows
in the single partition. It all depends on how you include and define the PARTITION BY,
ORDER BY, and ROWS/RANGE window frame clauses.
These conditions can be specified with the OVER() clause. Let’s see how this works.

What Is an OVER( ) Clause?


As stated earlier, the OVER() clause allows you to create partitions and windows into a
data set generated by a query. It allows you to divide the data set into sections called
partitions. The windows allow you to control how the window functions are applied in
terms of the data they will operate on.
Smaller windows called window frames can be created to further carve up the
larger window defined by the PARTITION BY clause using ROWS and RANGE frame clauses.
These windows grow or move (as rows are processed) based on the boundaries defined
by ROWS and RANGE frame specifications included in the OVER() clause. You can also
specify how the rows are sorted via an ORDER BY clause so that the window function can
process them.
This capability allows you to create queries such as three-month rolling averages and
year-to-date, quarter-to-date, and month-to-date totals. Each of the functions we discuss
in this book can utilize the OVER() clause in this manner.
This is why they are called window functions!

History of the OVER( ) Clause and Window Functions


The following is a brief history of the window functions:

• Aggregate/ranking window functions without the ORDER BY clause


support were introduced in 2005.

• Seven years later, aggregate functions with support for the ORDER BY
clause were introduced in 2012.

• Support for window frames (which we will discuss shortly) was also
introduced in 2012.

• Ranking functions and some window capability were introduced


in 2015.

2
Chapter 1 Partitions, Frames, and the OVER( ) Clause

• The batch-mode window aggregate operator was introduced in 2016.

• The STRING_AGG function was introduced in 2017.

• The named WINDOW capability was introduced in SQL Server 2022.

The capability of the window functions has grown over the years and delivers a rich
and powerful set of tools to analyze and solve complex data analysis problems.

The Window Functions


The window functions (which are the focus of this book) that can be used with the
OVER() clause are assigned to three categories and are listed in Table 1-1.

Table 1-1. Aggregate, Analytical, and Ranking Functions


Aggregate Functions Analytical Functions Ranking Functions

COUNT( ) CUME_DIST( ) RANK( )


COUNT_BIG( ) FIRST_VALUE( ) DENSE_RANK( )
SUM( ) LAST_VALUE( ) NTILE( )
MAX( ) LAG( ) ROW_NUMBER( )
MIN( ) LEAD( )
AVG( ) PERCENT_RANK( )
GROUPING( ) PERCENTILE_CONT( )
STRING_AGG( ) PERCENTILE_DISC( )
STDEV( )
STDEVP( )
VAR( )
VARP( )

Each of the subsequent chapters will create and discuss queries for these categories
for four industry-specific databases that are in scope for this book. Please refer to
Appendix A for syntax and descriptions of what each of the preceding functions does if
you are unfamiliar with them or need a refresher on how to use them in a query.

3
Chapter 1 Partitions, Frames, and the OVER( ) Clause

The OVER( ) Clause


The OVER() clause appears right after the window function in the SELECT clause. Our
first example in Listing 1-1 uses the SUM() function to aggregate sales amounts by year
and month.

Listing 1-1. SUM() Function with the OVER() Clause

SELECT OrderYear,OrderMonth,SalesAmount,
      SUM(SalesAmount) OVER(
            PARTITION BY OrderYear
            ORDER BY OrderMonth ASC
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
            ) AS AmountTotal
FROM OverExample
ORDER BY OrderYear,OrderMonth
GO

Between a set of parentheses after the OVER keyword, three other clauses can be
included such as PARTITION BY, ORDER BY, and ROWS or RANGE clauses (to define the
window frame that presents the rows to the function for processing).
Even if you have an ORDER BY clause in the OVER() clause, you can also include the
usual ORDER BY clause at the end of the query to sort the final processed result set in any
order you feel is appropriate to the business requirements the query solves.

Syntax
The following are three basic syntax templates that can be used with the window
functions. Reading these syntax templates is easy. Just keep in mind keywords between
square brackets mean they are optional. The following is the first syntax template
available for the OVER() clause:
Syntax 1

<Window Function> OVER (


       [ <PARTITION BY expression> ]
       [ <ORDER BY expression ASC | DESC > ]
       [ <ROWS or RANGE expression > ]
      )
4
Chapter 1 Partitions, Frames, and the OVER( ) Clause

Most of the window functions use this first syntax, and it is composed of three
main clauses, the PARTITION BY clause, the ORDER BY clause, and a ROWS or RANGE
specification. You can include one or more of these clauses or none. These combinations
will affect how the partition is defined. For example, if you do not include a PARTITION
BY clause, the entire data set is considered a one large partition. The expression is usually
one or more columns, but in the case of the PARTITION BY and ORDER BY clauses, it could
also be a subquery (refer to Appendix A).
The Window Function is one of the functions identified in Table 1-1.
This first syntax is pretty much the same for all functions except for the
PERCENTILE_DISC() and PERCENTILE_CONT() functions that use a slight variation:
Syntax 2

PERCENTILE_DISC (numeric literal ) WITHIN GROUP (


                ORDER BY expression [ ASC | DESC ]
      )  OVER ( [ <PARTITION BY expression> ] )

These functions are used to calculate the percentile discrete and percentile
continuous values in a data set column. The numeric literal can be a value like .25, .50,
or .75 that is used to specify the percentile you wish to calculate. Notice that the ORDER
BY clause is inserted between the parentheses of the WITHIN GROUP command and the
OVER() clause just includes the PARTITION BY clause.
Don’t worry about what this does for now. Examples will be given that make the
behavior of this code clear. For now, just understand that there are three basic syntax
templates to be aware of.
In our chapter examples, the expression will usually be a column or columns
separated by commas although you can use other data objects like queries. Please
refer to the Microsoft SQL Server documentation to check out the detailed syntax
specification or Appendix A.
Lastly, our third syntax template applies to SQL Server 2022 (release 16.x). The
window capability has been enhanced that allows you to specify window options in a
named window that appears at the end of the query:
Syntax 3

WINDOW <window name> AS (


       [ <PARTITION BY clause> ]
       [ <ORDER BY clause> ]
       [ <ROWS or RANGE clause> ]
      )
5
Chapter 1 Partitions, Frames, and the OVER( ) Clause

As of this writing, SQL Server 2022 is available for evaluation only. In Listing 1-2 is an
example TSQL query that uses this new feature.

Listing 1-2. SQL Server 2022 Named Window Feature

SELECT OrderYear,OrderMonth,SalesAmount,
      SUM(SalesAmount) OVER SalesWindow AS SQPRangeUPCR
FROM OverExample
WINDOW SalesWindow AS (
            PARTITION BY OrderYear
            ORDER BY OrderMonth
            RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
            );
GO

The name of the window is SalesWindow, and it is used right after the OVER operator
instead of the PARTITION BY, ORDER BY, and RANGE clauses as used in the first syntax
template we discussed.
Probably a good feature in case you have multiple window functions in your SELECT
clause that need to use this partition and window frame configuration. This would avoid
repeating the partition code in each column of the SELECT clause.
The PARTITION BY, ORDER BY, and RANGE clauses are declared at the end of the
query between parentheses after the WINDOW keyword instead of right after the OVER
keyword.
If you want to play around with this, download and install the 2022 evaluation
license and try it out on the example code available with the book or on your own
queries. The setup and download are fast and simple. Make sure you get the latest
version of SSMS. These are available on Microsoft’s download website.

Partitions and Frames


Finally, we get to discuss what a partition looks like and what frames or window
frames are.
Basically, a query will generate a data result set, which you can carve up into sections
called partitions by including the PARTITION BY clause inside the OVER() clause. For
each partition you can further define smaller windows to fine-tune how the window
functions will be applied.
6
Chapter 1 Partitions, Frames, and the OVER( ) Clause

A picture is worth a thousand words, so let’s look at one now. Please refer to
Figure 1-1.

Figure 1-1. A simple data set with three partitions and an example frame

Here we have a simple data set composed of eight rows. There are three example
partitions in this data set. One can include all eight rows of the data set; the other two
include rows identified by the TYPE column. There are only two type values, type A and
type B, so each of these partitions will have four rows. By the way, you cannot include
multiple PARTITION BY clauses in an OVER() clause.
You can define only one partition per OVER() clause although you can have more
than one column in the SELECT clause of the query that uses a partition. You can specify
different column combinations to define the partitions.
Where the power of this architecture comes in is that we can create smaller window
frames against the partition by using the ROWS or RANGE operator. These will allow you to
specify how many rows before and/or after the current row being processed will be used
by the window function.

7
Chapter 1 Partitions, Frames, and the OVER( ) Clause

In our preceding example snapshot, the current row is row 3, and the window frame
is defined so it includes only the prior row, the current row, and the next row relative
to the current row. If we apply the SUM() function to this window frame and add all the
values, we get the result 60 (15 + 20 + 25). (Remember this is within the first partition,
which contains only four rows.)
If processing continues on the next row, row 4, only rows 3 and 4 are available to
the SUM() function, and the result is 45 (20 + 25). I neglected to mention that if we start
at row 1, then only rows 1 and 2 are available to the SUM()function because there is no
prior row. The function returns the value 25 (10 + 15).
How do we control this type of processing? All we need to do is add a ROWS or RANGE
specification to the query if required. We could also include an ORDER BY clause to
specify how to order the rows within the partition so that the window function is applied
as needed. For example, generate rolling totals by month, starting of course at month 1
(January) and ending at month 12 (December).
Sounds easy, but we need to be aware of a few scenarios around default processing
when we leave the ORDER BY clause and/or the PARTITION clause out. We will discuss
these shortly.

ROWS Frame Definition


The ROWS clause operates on the physical set of rows belonging to the partition. Because
the ROWS clause operates on the rows in the partition, it is considered a physical
operation.
The ORDER BY clause allows you to specify the logical order of the rows in the
partition so the window function can evaluate them. For example, if you have sales data
by year and month, you would set the logical order of the rows in the partition by month
so that the SUM() function can generate rolling year-to-date totals for each month. You
can specify optional ascending and descending sort orders by using the keywords ASC
and DESC.
The ROWS clause allows you to define the window frame into the partition. There are
several variations of the ROWS clause that we need to be aware of. The following are two
variations that generate the same window frame:

ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW


ROWS UNBOUNDED PRECEDING

8
Chapter 1 Partitions, Frames, and the OVER( ) Clause

This clause tells the function to operate on the current row and all rows preceding
the current row if there are any in the partition. A simple diagram in Figure 1-2 makes it
all clear.

Figure 1-2. Include the current row and all preceding rows

If we start at row 1, since there are no prior rows in the partition before this row, the
SUM() function returns the value 10.
Moving on to row 2, the SUM() function will include the only available prior row
(row 1), so the result is 25 (10 + 15).
Next (shown in the preceding figure), the current row to be processed is row 3. The
SUM() function will evaluate row 3 plus rows 1 and 2 in order to generate the total. The
result is 45 (10 + 15 + 20).
Lastly, moving to row 4, the function will include the current row and all prior rows
in its calculation and return 70 (10 + 15 + 20 + 25). Processing now concludes for this
partition.
Moving to partition B, the processing repeats itself, and only rows from partition B
are included. All rows in partition A are ignored.

9
Chapter 1 Partitions, Frames, and the OVER( ) Clause

Our next ROWS clause takes us in the opposite direction:

ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING


ROWS UNBOUNDED FOLLOWING (will not work, not supported)

The first clause is legal but the second is not. It is not supported. One would think
that if there is a ROWS UNBOUNDED PRECEDING, there should be a ROWS UNBOUNDED
FOLLOWING, but it is not supported at this time. Go figure!
As stated earlier, this clause takes us in the opposite direction than the prior scenario
we just discussed. It will allow the aggregate or other window functions to include the
current row and all succeeding rows until all rows in the partition are exhausted. Our
next diagram in Figure 1-3 shows us how this works.

Figure 1-3. Process the current row and all succeeding rows

Remember rows are processed one by one in the partition.


If processing starts at row 1, then all four values are included to calculate a sum of 70
(10 + 15 + 20 +25).

10
Chapter 1 Partitions, Frames, and the OVER( ) Clause

Next, if the current row being processed is row 2 as in the preceding example, then
the SUM() function will include rows 2–4 to generate the total value. It will generate a
result of 60 (15 + 20 + 25).
Moving on to row 3, it will only include rows 3 and 4 and generate a total value of 45
(20 + 25).
Once processing gets to row 4, only the current row is used as there are no more rows
available in the partition. The SUM() function calculates a total of 25.
When processing resumes at the next partition, the entire scenario is repeated.
What if we do not want to include all prior or following rows but only a few before or
after? The next window frame clause will accomplish the trick for limiting the number of
following rows:

ROWS BETWEEN CURRENT ROW AND n FOLLOWING

Including this clause in the OVER() clause will allow us to control the number of
rows to include relative to the current row, that is, how many rows after the current row
are going to be used from the available partition rows. Let’s examine another simple
example where we want to include only one row following the current row in the
calculation.
Please refer to Figure 1-4.

11
Chapter 1 Partitions, Frames, and the OVER( ) Clause

Figure 1-4. Current row and one row following

Here is the window frame clause to include in the OVER() clause:

ROWS BETWEEN CURRENT AND 1 FOLLOWING

Processing starts at row 1. I think by now you understand that only rows 1 and 2 are
used and the result is 25 (10 + 15).
Next, in the preceding example, row 2 is the current row. If only the next row is
included, then the SUM() function will return a total of 35 (15 + 20).
Moving to row 3 (the next current row), the SUM() function will return 45 as the sum
(20 + 25).
Finally, when processing gets to the last row in the partition, then only row 4 is used
and the SUM() function returns 25.
When processing continues to the next partition, the sequence repeats itself ignoring
the values from the prior partition.
We can now see how this process creates windows into the partition that change
as the rows are processed one by one by the window function. Remember, the order
in which the rows are processed is controlled by the ORDER BY clause used in the
OVER() clause.

12
Chapter 1 Partitions, Frames, and the OVER( ) Clause

The next example takes us in the opposite direction. We want to include the current
row and the prior two rows (if there are any) in the calculation.
The window frame clause is

ROWS BETWEEN n PRECEDING AND CURRENT ROW

The letter n represents an unsigned integer value specifying the number of rows. The
following example uses 2 as the number of rows.
Please refer to Figure 1-5.

Figure 1-5. Include two prior rows and the current row

The window frame for this scenario is

ROWS BETWEEN 2 PRECEDING AND CURRENT ROW

Starting at row 1 (the current row), the SUM() function will only use row 1 as there are
no prior rows. The value returned by the window function is 10.
Moving to row 2, there is only one prior row so the SUM() function returns 25
(10 + 15).

13
Chapter 1 Partitions, Frames, and the OVER( ) Clause

Next, the current row is row 3, so the SUM() function uses the two prior rows and
returns a value of 45 (10 + 15 +20).
In the preceding figure, the current row being processed is row 4 and the preceding
two rows are included; the SUM() function when applied will return a total value of 60 (15
+ 20 + 25).
Since all rows of the first partition have been processed, we move to partition B, and
this time only row 5 is used as there are no prior rows. We are at the beginning of the
partition. The SUM() function returns a total value of 30.
Processing continues at row 6, so the SUM function processes rows 5 and 6 (the
current and prior rows). The total value calculated is 65 (30 + 35).
Next, the current row is 7 so the window function will include rows 5, 6, and 7. The
SUM() function returns 105 (30 + 35 + 40).
Finally, processing gets and ends at row 8 of the partition. The rows used by the
SUM() function are rows 6, 7, and 8. The SUM() function() returns 120 (35 + 40 + 45).
There are no more partitions so the processing ends.
What if we want to specify several rows before and after the current row? The next
clause does the trick. This was one of the example in the chapter, but let’s review it again
and make one change:

ROWS BETWEEN n PRECEDING AND n FOLLOWING

In this case we want to include the current row, the prior row, and two following
rows. We could well specify two rows preceding and three rows following or any
combination within the number of rows in the partition if we had more rows in the
partition.
Please refer to Figure 1-6.

14
Chapter 1 Partitions, Frames, and the OVER( ) Clause

Figure 1-6. Rows between n = 1 preceding and n = 2 following

Here is the ROWS clause for this scenario:

ROWS BETWEEN 1 PRECEDING AND 2 FOLLOWING

Starting at row 1 of the partition, the SUM() function can only use rows 1, 2, and 3
as there are no rows in the partition prior to row 1. The result calculated by the SUM()
function is 45 (10 + 15 + 20).
Moving to the next row, row 2 of the partition, the SUM() function can use rows 1, 2
(the current row), 3, and 4. The result calculated by the SUM() function is 70 (10 + 15 +
20 + 25).
Next, the current row is row 3. This window frame uses row 2, 3, and only 4 so the
SUM() function will calculate a total sum of 60 (15 + 20 + 25).
Finally, moving to row 4 (last row of the partition), the SUM() function can only use
rows 3 and 4 as there are no more available rows following in the partition. The result is
45 (20 + 25).
Processing at the next partition continues in the same fashion, ignoring all rows from
the prior partition.

15
Chapter 1 Partitions, Frames, and the OVER( ) Clause

We have pretty much examined most of the configurations for the ROWS clause. Next,
we look at window frames defined by the RANGE clause, which works at a logical level. It
considers values instead of physical row position. Duplicate ORDER BY values will yield a
strange behavior.

RANGE Frame Definition


We discussed how the ROWS clause works at the physical level by using values relative
to the row positions they belong to. The RANGE clause operates at the logical level. It
considers the values of the column instead of physical row position within the partition.
It displays a strange (in my opinion) behavior. If it encounters duplicate values in the row
sort column, it will add them all up and display the total in all rows with the duplicate
ORDER BY column. Any values like moving totals will go out the window! (Pardon
the pun.)
An example illustrates this scenario.
Suppose you have a small table with five columns: Row, Year, Month, Amount, and
Running Total. The table is loaded with 12 rows for each year, let’s say 2010 and 2011,
plus a duplicate month row giving us a total of 13 rows. Each row represents a month in
the year, but for the month of March, two rows are inserted for the first year (that’s why
we have 13 rows and not 12 rows). In other words, an extra amount value exists for the
same month, resulting in duplicate month numbers.
The RANGE clause will use all the rows with duplicate current month values to apply
the window function to (in addition to any other rows specified in the RANGE clause).
Check out the partial table, Table 1-2.

Table 1-2. Partial RANGE Running Totals


Row Year Month Amount Running Total

1 2010 1 100.00 100.00


2 2010 2 100.00 200.00
3 2010 3 200.00 600.00
4 2010 3 200.00 600.00

16
Chapter 1 Partitions, Frames, and the OVER( ) Clause

When we get to row 3, the first of two duplicate months, the window function (SUM()
in this case) will include all prior rows and add the values in row 3 and the next row 4
to generate a total value of 600.00. This is displayed for both rows 3 and 4. Weird! One
would expect a running total value of 400.00 for row 3.
Let’s try another one. If we apply the following RANGE clause to calculate
running totals

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

or

RANGE UNBOUNDED PRECEDING

we get interesting results. Check out the partial results in Figure 1-7.

Figure 1-7. Sales by year and month

Everything works as expected until we get to the duplicate rows with a value of 5
(May) for the month. The window frame for this partition includes rows 1–4 and the
current row 5, but we also have a duplicate month value in row 6, which calculates the
rolling total value 60. This value is displayed in both rows 5 and 6. Aggregations continue
for the rest of the months (not shown).

17
Chapter 1 Partitions, Frames, and the OVER( ) Clause

Let’s process rows in the opposite direction. Here is our next RANGE clause:

RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING


RANGE UNBOUNDED FOLLOWING (will not work)

By the way, the second RANGE clause is not supported, but I included it so you are
aware that it will not work and generate an error. Please refer to Figure 1-8.

Figure 1-8. RANGE between current row and unbounded following

Rows 5 and 6 represent two sales figures for the month of May. Since these are
considered duplicates, row 5 displays a rolling value of 90 and row 6 also shows 90
instead of 80 as one would expect if they did not understand the behavior of this window
frame declaration.
Notice, by the way, how the rolling sum values decrease as the row processing
advances from row 1 onward. We started with 130 and ended with 10 – moving totals in
reverse.
Putting it all together, here is a conceptual view that illustrates the generation of
window frames as rows are processed when the following ROWS clause is used:

ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING

18
Chapter 1 Partitions, Frames, and the OVER( ) Clause

This was one of the example in the chapter. Only the partition for type A rows is
considered. Please refer to Figure 1-9.

Figure 1-9. Window frame and processed rows

Both partitions are shown so you can see how the frame resets when it gets to the
next partition.
The generated window frames, as processing goes row by row, show which values
are included for the window function to process within the partition. The first window
and last window only have two rows to process, but the second and third both have three
rows to process, the prior, current, and next rows. The same pattern repeats itself for the
second partition.
Let’s put our knowledge to the test by looking at a simple query based on the figures
we just examined.

Example 1
We will start by creating a small test temporary table for our analysis.
The following listing shows the test table CREATE TABLE DDL (data declaration
language) statement created as a temporary table and one INSERT statement to load all
the rows we wish to process.

19
Random documents with unrelated
content Scribd suggests to you:
Whether he was to be trusted to return or not was left an open
question. One thing was plain—he must leave India now. He
reached Bombay by easy stages, and completely restored by the
sea voyage, landed at Southampton a month later, after an absence
from England of nearly three years.
CHAPTER IV.
MONKSWOOD.

Monkswood was the original family place of the Fairfaxes. It was


from Monkswood that a Fairfax sallied forth, booted and spurred, to
ride with Prince Rupert; and owing to having espoused that side,
many a fair acre was shorn away from him and his descendants.
Nothing, in fact, was left to the next generation but the house and
demesne.
A succession of lucky speculations and prudent marriages had
restocked the Fairfax purse, and Sir Reginald’s grand-father, instead
of gambling and squandering at Arthur’s, Crockford’s, Boodle’s, or
White’s, as was the fashion in his day—being, on the contrary, of a
thrifty turn of mind—purchased Looton, which a card-playing owner
had brought to the hammer, and it became the family seat. Still all
Fairfaxes were at least buried at Monkswood, and during the season
it was generally visited for woodcock-shooting, for which its thick
woods were famous.
Monkswood was a good-sized red-brick house, hideous and
rambling and inconvenient to the last degree. It was a rare collection
of architecture on a small scale, as a room had been added here, a
window knocked out there, according to the sweet will of the reigning
Fairfax. It was approached by a long drive, skirted on one side by a
thick laurel cover, and on the other by a broad open demesne, dotted
about with some splendid timber, oak and copper beech in particular.
The house was entered by a shallow flight of steps and heavy
portico, leading into a lofty oak-panelled hall, opening on one side
into the drawing-room and tea-room, and on the other into the
dining-room and library.
The drawing-room side looked out on a grand old-fashioned
pleasure-ground; the dining-room “gave”—oh horror!—on the yard—
a yard large enough for a barrack square, with a long range of loose-
boxes and deserted stalls and coach-houses. A couple of saddle-
horses, and Miss Saville’s fat ponies, Tweedle Dum and Tweedle
Dee, revelled at least in plenty of room. Upstairs the house was still
more old-fashioned than below; fireplaces in corners abounded;
cupboards broke out in the strangest places; and there were various
passages leading everywhere in general and nowhere in particular,
as you angrily discover when, having followed one down to its
source as you flatter yourself, you open a fine promising-looking
door, and find a set of empty shelves staring you in the face! On the
other hand, you are disagreeably surprised when, on bursting open
the door of what you take to be a cupboard, you find yourself
precipitated headlong down three steps into a large room. Huge four-
post beds and furniture to correspond were de rigueur, and there
was an old-world feeling about the place altogether, as if it had gone
to sleep one hundred years ago, and awoke, greatly surprised to find
itself in the present century. Everything was antiquated, with the
exception of new carpets and curtains in the sitting-room, a few
fashionable chairs and tea-tables, Alice’s piano, and the furniture of
her bedroom, where a modern brass construction relieved the time-
honoured four-poster, and a writing-table, wardrobe, and lounge took
the place of furniture that would have been the ne plus ultra of luxury
in the reign of Queen Elizabeth.
Need I here mention that the maiden monarch slept a night at
Monkswood? According to the number of places which boast of this
honour, her majesty can have rarely passed a night at home.
The house was overrun with old china, and there were a good
many family portraits, simpering and scowling, about the walls. The
best—the beauties and the handsome cavaliers—were all at Looton;
but frosty-faced old divines and plain elderly matrons had been left
undisturbed. There was some Chippendale furniture too, and all
kinds of queer old ornaments, odds and ends, and even clothes,
stowed away carefully among the venerable wardrobes; in fact,
enough unappreciated bric-à-brac to turn a collector’s head.
The pleasure-grounds opened through a rustic gate into the
plantations, which skirted the whole demesne inside a high wall.
Through the plantations ran a walk just wide enough for two. A
dense growth of underwood gave cover to thousands of rabbits, and
where the ground was visible it was one mass of blue-bells and
primroses in the season.
Opening also out of the pleasure-grounds was a large old-
fashioned garden, chiefly devoted to fruit and vegetables, though the
broad gravel walks that intersected it were lined with wallflowers,
carnations, lavender, and hollyhocks. Its four gray walls did not look
down upon a “wealth of flowers,” but they were covered with very
excellent fruit trees, and they overlooked the best beds of asparagus
within a radius of ten miles.
CHAPTER V.
WAITING FOR AN ANSWER.

Alice had found all prepared for her reception at Monkswood. A


moderate staff of servants, culled from Looton, was awaiting her
arrival. They accorded her a cold, not to say sullen, welcome; as
they unanimously blamed her, and her alone, for their master’s
sudden freak of shutting up Looton and sailing for India. Their
attitude of dignified disapproval was entirely thrown away on their
young mistress, who spent most of her time out of doors, and quickly
accustomed herself to a life of complete solitude. In company with
her dog Tory, a fox-terrier, given her by her husband before she was
married, she would spend hours roaming through the garden and
pleasure-grounds, and, above all, the woods. They had a special
attraction for her—she liked their aromatic piny smell, and they were
leafless, deserted, and dreary, and seemed exactly to match her own
frame of mind. Here, in utter solitude and silence, only broken by the
snapping of a twig beneath her feet, the flutter of a falling leaf, or the
short sharp barks of Tory in hot pursuit of a rabbit, she could think
without interruption.
To Tory these woods were Elysium itself, and his most happy
hunting-grounds. Although always baffled by the agile bunny, he
returned to the chase each day with renewed enthusiasm. As he sat,
much out of breath, on his haunches directly in front of his mistress,
seated on a log, his eyes rolling, his tongue lolling, and his sides
palpitating, perhaps he wondered in his own mind what could be the
matter with her. Why did those great round drops roll down her
cheeks and go splash on her sealskin coat and small clasped
hands? Why did she take him up, and hug him, and kiss him, and
say: “Tory, no one in all the world loves me as well as you do”?
Although Alice had spoken to Geoffrey of her husband’s departure
with easy indifference, her indifference was assumed. Her heart
quailed when she thought of India, sickness, and the field of action.
Each day, instead of deadening, only intensified her grief. It will be
seen that her feelings towards her husband had undergone a
revulsion, and since she had been out of the hearing of Miss Fane’s
oracular sayings, her opinion of his misdeeds had become greatly
modified. If he was utterly innocent, as in her secret heart she began
to believe, what was to be her fate? Twice he had given her an
opportunity to make amends, and twice she had declined the olive
branch. She would never have another chance, that was very
certain.
As she looked down the dreary path before her, strewn with fallen
leaves and branches, at the bare, gaunt, gray and brown trees
interlaced overhead, it was not a cheerful prospect; and yet a far
more dismal vista presented itself to her mind’s eye. A long, solitary,
monotonous life at Monkswood, where youth and beauty would alike
fade away unnoticed and unregretted; her husband implacable,
following with ardour his beloved profession; her friends indifferent
and forgetful; what a miserable existence seemed to be in store for
her! Could the haughty stern man, who had so bitterly upbraided her
on Southsea Pier, and bidden her such a cold and almost
contemptuous farewell, have been the bridegroom who had
sauntered by her side through the deep green glades of the forest of
Fontainebleau? It seemed impossible. What delightful mornings they
had spent among those old trees—she with her work, he lying at her
feet reading aloud Tennyson, Punch, Galignani, whatever came first;
what rambles they had taken among French farms and fields,
exchanging tastes, opinions, confidences; what delightful drives and
excursions they had made in the neighbourhood, exploring the
country in every direction, losing their way, stopping to dine at little
out-of-the-way villages, and meeting with numerous amusing
adventures.
Then there had been that short trip through Normandy, and home
by the Channel Islands; and what a welcome she had received at
Looton!—rich and poor testified their regard for its master by the
reception they gave his bride. How proud he had seemed of her in
those days, as, dressed in one of Worth’s gowns, which he had
helped to choose in Paris, he led her up to the Duchess of Dover,
who was giving a ball in their honour—the very last she had been at.
How she had enjoyed it too, although Reginald never danced with
her once, telling her, when she remonstrated with him as they went
home in the brougham, “That he did not approve of bride and
bridegroom dancing together, as they had quite enough of each
other’s company, and might spare a few hours to the claims of
society;” and he had cut short all her arguments with a kiss. She
remembered saying to him the day that Geoffrey had been expected:
“I suppose we may consider our honeymoon over now?” “No,” he
had replied, “I hope ours will last as long as we live, and that, no
matter what happens, we shall never love each other less than we
do at present. I can answer for myself, at any rate,” he had said
emphatically.
Rash promise! Three months of unutterable happiness, and all
was over! That he had loved was certain. Never a very
demonstrative lover; yet a look, a word, a caress from him were ten
times more precious from their rarity, and because they bore the
stamp of a tender, almost reverent affection, than if another man of
more shallow feelings had overwhelmed her with perpetual
adoration.
Such thoughts as these, and such happy recollections, only made
the contrast between past and present trebly painful. Day by day,
Alice became more miserably unhappy. She spent her time aimlessly
wandering about the woods or sitting indoors before the fire, with
Tory on her lap, talking half to him and half to herself. Society she
had none: with the exception of the clergyman’s family, the
neighbours and county held completely aloof, and left her entirely to
her own devices. They knew that Sir Reginald had gone abroad, that
Looton was shut up. “There is something very mysterious about the
whole thing,” they said, “and we will not be in a hurry to call on Lady
Fairfax.”
Consequently Lady Fairfax was left entirely to herself.
At last Alice made up her mind to write to her husband. She could
no longer believe in that false marriage certificate; it was all a wicked
lie from first to last. Oh that she had thought so before! She had
determined to abase herself before him and entreat his pardon.
These feelings came to a climax one dim spring afternoon, and,
hastily glancing at the paper, she saw that it was mail-day. She had
just half an hour before post time, and so she hurriedly sat down and
wrote a short but truly penitent and loving letter to Sir Reginald (the
fate of which will afterwards be disclosed).
“What a change in her life that single sheet of foreign paper might
make,” she thought, as she kissed it and folded it, and enclosed in it
two or three violets taken from a little bunch in front of her dress. Ere
the letter had gone out of the house a load seemed lifted off her
mind. In eight weeks at most the answer would come back; and the
foolish girl sat down on the hearth-rug and began to reckon up the
days!
“He will come back himself,” she whispered to Tory, as he laid his
head on her arm and blinked his eyes sagaciously. “And how glad
we shall be to see him, Tory, you and I! He will sit between us here,
at the fire, and he will scold me. He will lecture me dreadfully, Tory,
but he is sure to be very pleased with you. I will tell him what a good
boy you have been, and how you have kept me company.”
In vain she watched and waited for an answer to her letter. Every
morning, wet or dry, accompanied by Tory, she walked to the
avenue-gates, and herself received the post-bag. How she looked
out for the arrivals of the mails viâ Brindisi, and reckoned up the
days and hours till her much-desired letter could come! When the
allotted two months had elapsed, and it did not appear, hope, instead
of being silent, told a still more flattering tale.
“He is coming himself; he may be here any day,” it said. For days,
and even weeks, Alice deluded herself with this idea. A step, the
sudden opening of a door, made her start and flush crimson. But
time went on, her boy was born, and still no letter; so her heart
hardened once more. Not only was she herself slighted and
despised, but what outraged her feelings in their most sensitive
point, her child was ignored. “He might have sent me even one little
line; he is barbarous, cruel, unnatural,” were some of her bitter
reflections.
Miss Saville, a good-tempered, sensible, elderly lady, very fond of
her niece, had come to Monkswood, and with her a new régime
commenced; no more untouched meals, no more “moping,” as she
called it, permitted. But now that Alice had her baby to engross her
mind, she was not so much inclined to live in the past as in the
present. When she did think of her husband, it was with an
indescribable mixture of remorse, indignation, and regret. The
“confessions” from Cheetapore were duly forwarded to Alice, and
were safely locked up in her dressing-case; but as he had not
deigned to take any notice of her abject apology before the matter
had been cleared up, it was unnecessary to trouble him with another
appeal, even supposing her own pride would have permitted a
second abasement, which it would not.
When not occupied in the nursery, Alice spent a good deal of time
in taking long rides in the neighbourhood. In company with Martin,
the old family groom, she scoured the country for miles far and near,
very much to her own enjoyment and greatly to the indignation of the
surrounding élite, who had no idea that a young woman sent to
Monkswood by her husband in the deepest disgrace should be
permitted so much relaxation and amusement. Her horses were first-
rate, her riding undeniable, and once in the saddle she half forgot
her troubles, and seemed more like herself once more. The perfect
equanimity with which she met the cold hard stare of the county
people, and the inimitable grace with which she managed her
thoroughbred, made them feel—the ladies especially—more
wickedly disposed towards her than ever.
The whisper of scandal was busy with her name in a way that she,
poor girl, had little idea of; and stories were circulated that would
have made her absent husband’s blood boil had he only known. The
accepted legend was, “that she had been on the point of eloping with
her cousin, Mr. Saville, during her husband’s temporary absence;
that he had fortunately returned just in time to frustrate their plans,
and, to save a public ésclandre and the Fairfax good name, had
relegated his erring wife to Monkswood, and had himself volunteered
for the East.”
“But she is all the same as a divorcée. He has left her for ever,”
her kind neighbours whispered over their five-o’clock tea; “and she is
not to be tolerated in Steepshire society.”
The Mayhews occasionally sent Sir Reginald’s missives to his
wife, and she observed that, although her boy was often alluded to
with interest and affection, her own name was never mentioned. She
had done violence to her pride in sending him Maurice’s photograph,
and he had treated it with the same disdain as her letter.
When the Afghan war broke out, all his epistles to Mark or Helen
were regularly forwarded to her, and she received the news of his
having gained the Victoria Cross with a pride that she did not attempt
to conceal; but her fears and anxieties far outweighed any pleasure
the intelligence afforded her. It did not delight her to hear that he had
gained the sobriquet of “Fighting Fairfax”—far from it; and when
Captain Vaughan’s letter arrived her agony was beyond description.
How she bore the miserable week that intervened before the next
mail was only known to herself. She endured in silence, opening her
heart to no one—taking no one into her confidence; not shedding a
single tear, but going about her usual duties with a white set face
that fairly frightened her aunt. “If he is dead,” she would say to
herself as she paced her room, “he has gone without forgiving me.
As I stand here he may be already weeks in his lonely foreign grave,
and I, without knowing it, am his widow. If this is the case, I believe it
will kill me.” Never very robust at any time, she looked now so worn,
so thin, so altered, even with the suspense of less than a week, that
it seemed as if it would not take much to snap her hold on life.
She heard from the Mayhews of her husband’s approaching
return, and saw by his letters how very reluctant he was to come
home.
He little knew that his wife’s eyes would rest on the lines he was
penning when he said:
“I have no wish to return to England; I am ten times happier out
here than I shall be at home; and excepting to see you and Helen,
and my son and heir, I do not wish to set foot in my native land for
years. All my interests and all I care about most are bound up in the
fortunes of the Seventeenth Royal Hussars. I hope to get command
of the regiment ere long, and if I do I would not change places with
any king or emperor you could name.”
Alice read the above with apparent composure and handed it back
to Helen, to whom she was paying a short visit. Indignation and
disappointment were depicted in her face, in spite of her heroic
efforts to appear indifferent. She went and stood at the window, to
hide the tears that would come into her eyes.
“He does not mean it, Alice,” said Helen soothingly.
“It is nothing to me whether he does or not,” replied Alice hotly,
“but he does mean it; at any rate we will not talk about him.” Then
continued, with womanly consistency: “I can read between the lines
of that letter. I am the cause of his reluctance to come home; he
does not wish to be in the same country with me; he hates to
remember that he is a married man; he is afraid that we shall meet;
but he need not be. England is wide enough for both of us, and I
have no wish to see a husband who has completely ignored me for
nearly three years.” So saying, and rapidly collecting her hat,
umbrella, and gloves (having just come in from the park), she swept
indignantly out of the room.
CHAPTER VI.
THE RETURN OF THE NATIVE.

Three years had made a wonderful change in Alice: she was a


very different Alice to what she had been when we first saw her at
Malta. Her naturally high spirits and elastic temperament had been
almost totally subdued and crushed by the life of retirement and
isolation she had led. She felt, although barely twenty-one, as if she
had already lived her life: the happiness, gaiety, and domestic
sunshine, the common lot of girls of her age, was not for her, an
outcast from society, a deserted wife. Sometimes her youth and
natural buoyancy would assert themselves, and she would find
herself singing and laughing as of old, especially as she played with
Maurice, and allowed him to drive her as his willing steed up and
down the passages and round the garden; but such were rare
occasions.
The mistress of Monkswood was a tall, slight, dignified young lady,
who often inspired her aunt with awe by the gravity of her
demeanour, and who found it hard to realise that she and the
madcap child of former years were one and the same individual. She
utterly refused to leave Monkswood, and, with the exception of a
flying visit to the Mayhews, had never been away from home for one
night. Nor did she encourage people to stay with her, saying she had
no inducement to offer, and that it was much too stupid at
Monkswood to repay anyone the trouble of coming so far.
At length her aunt, Miss Saville, greatly concerned by her niece’s
listlessness and dejection, took upon herself to invite Miss Ferrars,
one of Alice’s former companions, on a long visit. “The young,” she
rightly argued, “like the young; her former schoolfellow will cheer her
up. After all, an old woman like myself is no companion for a girl from
one year’s end to another.”
Miss Ferrars duly arrived at Monkswood. She was a year older
than Lady Fairfax, a clever, warm-hearted girl, with untiring spirits
and energy. She was tall and well developed, and looked twice as
much the matron as her slim girlish hostess. She had a pleasant,
intelligent, rather than handsome face, with sparkling brown eyes,
and quantities of beautiful bronze-coloured hair. She was
unaffectedly surprised at the change in her former schoolfellow.
Could this silent, grave, melancholy-looking young lady be indeed
the bright Alice of Rougemont, who used to keep them all alive with
her bright face and gay sallies?
Soon they relapsed into their old groove, however, going over their
former experiences with mutual pleasure. Professors, schoolfellows,
examinations, places, and people were reviewed and discussed, and
Alice took her friend into her confidence on every subject save one.
Her Bluebeard’s closet, her sealed book, was her husband’s name,
and that she always most scrupulously avoided. To her friend’s
inquiries about him her answers were cold and brief; her short
married career she never touched upon, and Mary Ferrars having
indirectly heard that Sir Reginald did not “get on” with his wife, and
was anything but a highly-domesticated animal, seeing that he had
been abroad for nearly three years, never alluded to him again.
Miss Ferrars and Alice shared the same room, and though they
would lie awake talking for hours in the most approved young-lady
fashion, nothing had escaped Alice’s lips that gave her friend any
clue to the mystery which enshrouded her husband. She roused
herself for the entertainment of her schoolfellow, and became every
day more like her old self. She purchased a tame sedate steed for
her use, and gave her riding lessons, and together they explored the
neighbourhood. They got up a lawn-tennis in the pleasure-grounds,
where they played half their mornings, making Maurice very useful in
fetching the balls.
Maurice was now a young gentleman in belted blouse, sturdy and
well-made. He had a fair broad forehead, dark eyes, dark lashes,
and dark curls. He already possessed a very decided will of his own,
and was absolute master of all the womenkind on the premises, from
Alice to the cook inclusive.
The two young ladies had effected a great change in the interior of
the house. The drawing-room was now a thing of beauty and a joy
for ever. They had routed out old pictures and hung them on the
walls; the Chippendale furniture had been brought to the front, and
some beautiful old china had been arranged on a venerable black
buffet that had been discovered in the laundry; more plates and
dishes were affixed to the walls on velvet shields; in fact, the
drawing-room and tea-room were their mutual hobby, and became
two of the most charming apartments possible to see, with polished
floors and Persian rugs.
June and July passed—a vision of hot, sweet-scented, languid
summer days. Then came August; and August brought a visitor to
Monkswood.

Meanwhile Sir Reginald had landed at Southampton and made his


way to London, where he was rapturously received by the inmates of
Wessex Gardens. They thought him graver, thinner, and very much
sun-burnt from the voyage, but otherwise he was the same as ever.
The day following his arrival he produced presents for all the
Mayhew family—an Afghan matchlock and knife for Mark; a
Cashmere tea-set and shawl for Helen; toys, puzzles, and
sweetmeats for the children.
Helen, having tried on her shawl and viewed herself with much
complacency in all the mirrors and from every point of view, came
over to where Sir Reginald was explaining a puzzle to the children,
and, throwing herself into a chair opposite, said abruptly:
“And what have you brought Alice?”
“Alice!” he stammered, reddening even through the sunburn to the
roots of his crisp dark hair. Then immediately recovering himself,
replied, as he stooped to pick up a piece of the puzzle which had
fallen on the floor: “Oh, nothing.”
“Has he not brought her himself and his V.C.?” said Mark, giving
him a tremendous slap on the back. “What more could she desire?”
“I am not so humble as to consider myself nothing, whatever you
may think of me, Mark,” he returned, without raising his eyes from
the puzzle, which he had just completed in the neatest manner; and,
holding it out on the palm of his hand, he said: “Now, Hilda, if you put
this together before dinner this evening I’ll give you the biggest box
of chocolate you ever saw. I’m off to the club now,” he added,
standing up and preparing to depart, cleverly eluding the fire of cross
questions with which Helen was preparing to attack him.
For several days he evaded all her attempts to inveigle him into a
tête-à-tête; his engagements were so numerous that he was seldom
at home, for all his old friends flocked round him, and he was the
hero of the hour. Dozens of invitations came daily pouring in, and he
seemed to be fairly launched in London society, and carried away by
its current. Helen, like the hen whose duckling had taken to the
water, looked on in impotent despair. The highest in the land, the
beauties of the season, were all equally ready to engage his time. As
she saw him in the Row, the centre of a circle of former brother-
officers, then beckoned to the carriage of one of the belles of the
season, who engaged him in most animated and empressé
conversation, she said to herself: “This will never do; has he
forgotten that he has a home and a wife, or does he mean to ignore
both completely?” She sought in vain for opportunities to sound him
on the subject; he never was with her alone. All her little hints about
Alice, all her endeavours to bring her name into conversation, were
completely fruitless; he exhibited a skill in avoiding this one particular
theme, a dexterity that irritated and amazed her. At length, after he
had been nearly a fortnight in London, Helen made up her mind to
stand this state of affairs no longer. Accordingly, the evening when
he was dining at the Guards’ Club, she waited up for him in her
boudoir. Hearing him leisurely ascending the stairs between one and
two o’clock, she went out into the corridor and beckoned him into her
room, saying:
“Come in here, Regy; I want to speak to you.”
Strangling a yawn, and laying down his candlestick, he flung
himself into the nearest arm-chair with a mock tragic gesture, and
said: “Say on.”
It was all very well to say “Say on,” but how was she to begin?
Now that she had caged her bird she began to realise the delicate
task that lay before her. She well knew that it was a proverbially
thankless and dangerous mission to interfere between husband and
wife; and Regy, although he had often stood a little boy at her knee,
and come to her with all his grievances, was now a man, known to
be clever, distinguished, and thoroughly able to think and act, not
only for himself but for others. How well he looked in his mess-dress,
so bronzed, soldierlike, and handsomer than ever! He was leaning
back with his arms clasped behind his head, regarding her with lazy
amusement.
She must begin, she thought, somehow, and forthwith broke the
ice clumsily enough by saying: “Had you a pleasant evening, Regy?”
“A pleasant evening!” he echoed. “Why, you foolish old lady, you
never mean to say that you have sat up till nearly two o’clock to ask
me such a question?”
“No, not quite,” she replied, laughing nervously. “The truth is, Regy
—and don’t think I am inhospitable, or want to turn you out, or
anything——” And she paused.
“Well, and what is the truth, as you call it?” he asked brusquely.
“When are you going to Monkswood?”
“To Monkswood!” he repeated, suddenly sitting erect and looking
at her fixedly. “That is easily answered——never!”
“Oh Reginald, you can’t mean it! Do you not wish to see Alice or
your boy?”
“We will not speak of Alice, if you please,” he said gravely. “I have
nothing to say to her; but you must manage that I shall see the boy
somehow, Helen,” he added eagerly. “Could you get him up here for
a few days? I’m off to Norway with Fordyce the end of the month.”
“I am quite sure that Alice would never allow him out of her sight,
and I will never have him here without his mother. Do you mean me
to understand that you will not suffer me to speak to you about her?”
she asked hotly.
“I do. Not even with you, Helen, my more than sister, will I discuss
my wife—that was.”
“Then,” exclaimed Helen with rising indignation, “things are at a
deadlock. Alice will not speak of you to anyone, you will not suffer
me to mention her name, and neither of you will have anything to say
to the other. I know I could reconcile you both, were you not so
inconceivably proud and stiff-necked.”
“Look here, Helen,” he said, rising and beginning to pace about
the room, “I know you mean well and kindly, but take my advice and
leave us alone. We get on best apart. Our marriage was a
tremendous blunder; we both know that now. I have endeavoured to
forget that I have ever had a wife. Alice and I are utter strangers. As
her guardian, I have taken excellent care of her interests, and
studied her comfort and happiness as far as it is in my power; but as
her husband” (and he emphasized the word), “I have done with her.”
Hitherto he had been walking up and down the room, but as he
concluded he came to a full stop before Mrs. Mayhew, who, rising
and stretching out her plump white hands towards him with a gesture
of dismay, said:
“Are you mad, Reginald, to talk like this? You do not know what
you are saying. It is very easy to repudiate your wife to me; but when
you do it publicly what will people say? Have you thought of that?
What would you yourself say of a young couple who married for love,
separated almost in their honeymoon, the husband to go to India, the
wife to shut herself up in the country?”
“I would say nothing,” he interrupted. “Why should I?”
“Wait! I have not finished,” she continued hastily. “The husband,
after an absence of three years, returns; comes to London, mixes
freely in society, but never goes to see his young wife. You must
remember,” she pursued, literally button-holing him by his mess-
jacket, “that you are Alice’s guardian as well as her husband; she
has no father or mother, nor any relation in the world to protect her
good name except yourself and Geoffrey, and he is only a boy.”
“Geoffrey!” he exclaimed contemptuously.
“You don’t know what you are doing, Regy,” she pleaded. “If you
go abroad, as you have arranged, without seeing Alice, you will do
her a great injury in the eyes of the world. Your friends know that
there is an estrangement between you; at least for the sake of
appearances, patch up a truce at any rate.”
“I am not a hypocrite, and I will do nothing of the kind,” he
muttered angrily, drawing back and endeavouring to release himself
from his cousin’s grasp.
It was useless; she was a pertinacious woman, and she would be
heard.
“Do not go,” she entreated. “I never see you alone now, and I must
gain my point—I must indeed. You will hear me. It is all very well to
say you have ceased to think of Alice as your wife—which I do not
believe—but, at any rate, you cannot forget that she is the mother of
your child, can you?” she asked, with an air and emphasis that would
not have disgraced Mrs. Siddons.
No reply. “Silence gives consent, I see,” she nodded triumphantly
as she continued; “and as the mother of your child, surely you would
wish her to be honoured and respected, if not for her own sake at
least for his?”
An impatient gesture of assent was all his reply.
“Think of the life of retirement and seclusion she has led; surely
that has been punishment enough?”
“Who is talking of punishment?” he exclaimed, forcibly removing
Helen’s hand. “Alice is her own mistress, to come and go as she
pleases.”
“She has never left home nevertheless, in spite of all our
invitations, with the exception of a short visit this spring. You don’t
know the furore she created; we used to be quite mobbed walking in
the Row.”
A very unamiable scowl was the only notice he deigned to this
remark.
“You have no idea how lovely she is,” she urged impressively.
“Have I not?” he replied dryly.
“No; how can you?—you have not seen her for ages. She is
greatly changed in every way; no longer the giddy, impulsive girl you
remember. If you only knew how distracted she was when you were
so dangerously wounded!”
“Pray how can you tell?” he asked with raised brows and a certain
amount of sarcastic incredulity in his expression.
“I know all about it from Miss Saville. She told me that during the
week that followed Captain Vaughan’s letter Alice fretted away to
half her size, and that her grief and misery were painful to witness.”
Perceiving that he was gradually wavering, she urged:
“You will have to go down to Monkswood, my dear Regy, if only for
the sake of public opinion. Go as her guardian at any rate; putting
your wife aside, it is your duty to go and see your ward. You will go, if
only for a few days,” she entreated anxiously.
“Yes, I will go,” he replied slowly and with an evident effort. “I never
looked at the subject from your point of view before. I see that it is
necessary for me to study appearances, but I only go as her
guardian, recollect. You are very eager in the matter, Helen, and very
pressing,” he added with a smile, “but Alice is by no means so
anxious to see me as you imagine.”
“She is! she is!” cried Helen, in whose case the wish was father to
the thought. “And as for you,” laying her hand affectionately on his
shoulder, “you know you are very fond of her all the time, and that in
your heart you are dying to see her; now are you not?”
“What would be the good of telling you?” he replied evasively. “At
any rate, Alice does not care two straws about me. I know her far
better than you do, Helen, wise as you think yourself. I know her
private opinion of me; but confidences between married people are
sacred,” he added with a bitter smile. “I suppose she knows that I
have come home? he asked abruptly after a short silence.
“Oh yes; I wrote and told her of your safe arrival.”
“And what did she say?” he inquired with unconcealed eagerness.
“Well, strange to say, Regy, she never answered my letter. But
then, you know,” she added with an awkward laugh, “what a very
bad correspondent she is.”
“A very bad correspondent as you say,” he replied, with such
emphasis that Helen looked at him amazed.
“Tell me, Regy, has she never written to you?” she inquired with
solemn eyes.
“Then to-morrow or next day I shall start for Monkswood,” he
observed, coolly ignoring her question.
“Do, my dear boy,” returned Helen with effusion; “you don’t know
how glad I am to hear you say so. Mark and Geoffrey and I will follow
you the end of the week and pay a visit to Alice, which your arrival
has somewhat postponed.”
“Well, now I suppose I may go to bed?” said Reginald, taking up
his candle and looking at his cousin interrogatively. “You have said
your say, and carried your point, have you not? I am not at all sure
that you are not sending me on a fool’s errand, Helen.”
“I am very sure that I am not, Regy. You will be grateful to me
some day, though now I daresay you think me a meddlesome,
tiresome busybody. You look awfully tired and fagged, so I won’t
keep you up any longer. Good-night!” she concluded, holding up her
cheek to be kissed.
As the door closed on him, a triumphant smile broke over her face.
“He is all right, at any rate. If Alice were as easily managed or talked
over all would be as it ought to be in no time. I am only sorry I did not
make this opportunity before,” said Mrs. Mayhew aloud, as she
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

ebookmass.com

You might also like