Attribute summing in CRM entity hierarchies
I’ve implemented some rather hefty Reporting Services (RS) reports lately, with some of the requirements including recursive summing af attribute values through hierarchies of CRM accounts. This sort of aggregation may be possible in RS, but I dislike that tool with a vengeance and prefer doing math in the database.
My first attempt (and the one that is now running at the client) used recursive SQL-functions. The scoping rules for recursive functions are highly non-intuitive however and when I look at the functions now, I have only a vague idea of why — let alone how – they work. Further, functions have to be created in the database independently of uploading the reports that use them, a minor deployment headache. Clearly there must be a better way…
Enter Common Table Expressions, a new feature introduced in SQL Server 2005. The syntax and exactly how the recursion works is somewhat opaque, the best explanation I’ve found is this article. You’ll probably need to read it if you want to grok this bit of SQL that computes the total number of employees in the parent/child hierarchy of each account:
with num_employees as ( select fa.accountid, accountid as original_id, fa.[name] as original_name, isnull(fa.numberofemployees,0) as numberofemployees from filteredaccount fa union all select fa.accountid, ne.original_id, ne.original_name, isnull(fa.numberofemployees,0) as numberofemployees from filteredaccount fa inner join num_employees ne on fa.parentaccountid = ne.accountid ) select sum(numberofemployees) as numberofemployees, original_name from num_employees group by original_id,original_name
Here’s similar code for a prefilterable report dataset:
with num_employees as ( select accountid, accountid as original_id, name as original_name, isnull(numberofemployees, 0) as numberofemployees from filteredAccount as CRMAF_fa union all select fa.accountid, ne.original_id, ne.original_name, isnull(fa.numberofemployees, 0) as numberofemployees from filteredAccount as fa inner join num_employees as ne on fa.parentaccountid = ne.accountid ) select sum(numberofemployees) as numberofemployees, original_name from num_employees as num_empl_1 group by original_id, original_name
The most elegant formulation I’ve come up with is based on this example however:
with num_employees as ( select accountid, sum(numberofemployees) as numberofemployees from filteredaccount group by accountid union all select fa.parentaccountid, y.numberofemployees from filteredaccount as fa inner join num_employees as y on y.accountid = fa.accountid ) select sum(numberofemployees),accountid from num_employees group by accountid
I challenge you, the reader, to come up with a more concise example :-).
More resources: