{"id":16050,"date":"2015-07-27T14:01:06","date_gmt":"2015-07-27T21:01:06","guid":{"rendered":"https:\/\/devwww.3cloudsolutions.com\/post\/ssrs-using-multiple-axes-in-an-mdx-query-2\/"},"modified":"2024-06-18T09:02:37","modified_gmt":"2024-06-18T16:02:37","slug":"ssrs-using-multiple-axes-in-an-mdx-query","status":"publish","type":"post","link":"https:\/\/3cloudsolutions.com\/resources\/ssrs-using-multiple-axes-in-an-mdx-query\/","title":{"rendered":"SSRS: Using Multiple Axes in an MDX Query"},"content":{"rendered":"<p>MDX is made for producing pivot tables. \u00a0In SQL Server Management Studio, someone will write MDX queries all day that produce pivot tables naturally. \u00a0However, when using some of these MDX queries in a SQL Server Reporting Services report, they\u2019ll often run across this error:<\/p>\n<p><span class=\"hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_rich_text\" data-hs-cos-general-type=\"meta_field\" data-hs-cos-type=\"rich_text\"><span class=\"hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_rich_text\" data-hs-cos-general-type=\"meta_field\" data-hs-cos-type=\"rich_text\"><!--more--><\/span><\/span><\/p>\n<p><em>The query cannot be prepared: The query must have at least one axis. The first axis of the query should not have multiple hierarchies, nor should it reference any dimension other than the Measures dimension.<\/em><\/p>\n<p>SSRS can ONLY have measures in the first dimension. \u00a0That\u2019s not how MDX queries are normally written. \u00a0Dimensions usually appear both in the rows and columns, and the measure is selected in the WHERE clause. \u00a0Previous methods have used cross joins in the rows or a pass-through query in SQL Server. \u00a0Both potentially degrade performance. \u00a0However, there is another method that can be used with SSRS, and it\u2019s deceptively simple.<\/p>\n<p>Use a third axis in your query.<\/p>\n<p>While SSMS cannot display a third axis, SSRS can use a third axis in a dataset. \u00a0To select your typical pivot table data, simply select your desired measures on the first axis, your desired columns on the second and desired rows on the third. \u00a0If your original query looks like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"width: 378px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/mdxaxis.png\" alt=\"Text Example\" width=\"378\" height=\"153\" data-constrained=\"true\" \/><\/p>\n<p>Then your revised query will look like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"width: 368px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/mdxaxis1.png\" alt=\"Text Example\" width=\"368\" height=\"150\" data-constrained=\"true\" \/><\/p>\n<p>Again, SSMS will not be able to display the results of the revised query, but it will work properly in Reporting Services.<\/p>\n<h3>Walkthrough<\/h3>\n<p>To demonstrate the technique, we will recreate the output from the original query in a SSRS report using a 3-axis query. Here are the results of the original query in SSMS:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"width: 372px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/mdxaxis2.png\" alt=\"the original query in SSMS\" width=\"372\" height=\"169\" data-constrained=\"true\" \/><\/p>\n<p>In SSRS, we will duplicate those results with the 3-axis query. \u00a0Select New Dataset and enter the 3-axis query in design mode.<\/p>\n<p><strong><strong><img loading=\"lazy\" decoding=\"async\" style=\"width: 288px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Screen_Shot_2015-07-24_at_2.21.03_PM.png\" alt=\"Select New Dataset\" width=\"288\" height=\"225\" data-constrained=\"true\" \/><br \/>\n<\/strong><\/strong><\/p>\n<p>The fields show up in the dataset.<\/p>\n<p><strong><strong><img loading=\"lazy\" decoding=\"async\" style=\"width: 269px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Screen_Shot_2015-07-24_at_2.22.23_PM-1.png\" alt=\"Dataset Example\" width=\"269\" height=\"266\" data-constrained=\"true\" \/><br \/>\n<\/strong><\/strong><\/p>\n<p>Place the fields in a simple matrix<\/p>\n<p><strong><strong><img loading=\"lazy\" decoding=\"async\" style=\"width: 141px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Screen_Shot_2015-07-24_at_2.24.50_PM.png\" alt=\"Place the fields in a simple matrix\" width=\"141\" height=\"84\" data-constrained=\"true\" \/><br \/>\n<\/strong><\/strong><\/p>\n<p>Here\u2019s the final report, duplicating the original SSMS query results.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"width: 355px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Screen_Shot_2015-07-24_at_2.24.57_PM.png\" alt=\"Here\u2019s the final report\" width=\"355\" height=\"257\" data-constrained=\"true\" \/><\/p>\n<h3>Performance<\/h3>\n<p>Whither performance? \u00a0Let\u2019s compare execution times of the 3-axis query to the original 2-axis query and to a 2-axis query that is SSRS compatible. \u00a0First, the SSRS compatible 2-axis query:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"width: 357px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Screen_Shot_2015-07-24_at_2.27.19_PM.png\" alt=\"Text Example\" width=\"357\" height=\"145\" data-constrained=\"true\" \/><\/p>\n<p>Here\u2019s some execution times as captured by SQL Profiler:<\/p>\n<table>\n<tbody>\n<tr>\n<td><img loading=\"lazy\" decoding=\"async\" style=\"width: 644px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Screen_Shot_2015-07-24_at_2.27.32_PM.png\" alt=\"execution times as captured by SQL Profiler\" width=\"589\" height=\"112\" data-constrained=\"true\" \/><\/td>\n<td colspan=\"2\"><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We can see \u00a0the execution of the 3-axis query retains the favorable performance of the original. However, this dataset is just too small to give meaningful information. \u00a0If we increase the size by swapping FiscalYear to DateKey, we\u2019ll get a little bit more information.<\/p>\n<p><strong><strong><img loading=\"lazy\" decoding=\"async\" style=\"width: 658px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Screen_Shot_2015-07-24_at_2.30.22_PM.png\" alt=\"increase the size by swapping FiscalYear to DateKey\" width=\"621\" height=\"115\" data-constrained=\"true\" \/><br \/>\n<\/strong><\/strong><\/p>\n<p>When that translates to our report, we see the following. \u00a0Frankly, the query in this case is not the major limiting factor, and the average improvement was a mere half-second. \u00a0More demanding queries should show a larger delta.<\/p>\n<p><strong><strong><img loading=\"lazy\" decoding=\"async\" style=\"width: 454px;\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Screen_Shot_2015-07-24_at_2.31.47_PM.png\" alt=\"When that translates to our report, we see the following\" width=\"454\" height=\"96\" data-constrained=\"true\" \/><br \/>\n<\/strong><\/strong><\/p>\n<h3>Conclusion<\/h3>\n<p>What can we conclude from all of this? \u00a0We can develop something more akin to \u201cnatural\u201d MDX queries for use in SSRS using a third axis. \u00a0We can realize some performance benefits and better flexibility in our queries. \u00a0Finally, we can do that without any additional security or configuration hassles. \u00a0It should be a technique to keep in your mind when developing MDX based SSRS reports.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A look at how to use a third axis in your MDX query.<\/p>\n","protected":false},"author":21,"featured_media":14914,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":""},"categories":[297],"tags":[304,346],"class_list":["post-16050","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-platform","tag-modern-data-platform","tag-ssrs","topics-blog"],"acf":[],"_links":{"self":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts\/16050","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/comments?post=16050"}],"version-history":[{"count":0,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts\/16050\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/media\/14914"}],"wp:attachment":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/media?parent=16050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/categories?post=16050"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/tags?post=16050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}