-- dropping the vProducts view (cleaning after) --DROP VIEW IF EXISTS [Production].[vProducts] -- creating the vProducts view CREATE VIEW [Production].[vProducts] AS SELECT p.[ProductID] , p.ProductNumber , p.[Name] , IsNull(p.Size, '') + IsNull(' ' + p.SizeUnitMeasureCode, '') Size , p.Color , P.Style , p.ProductModelID , pm.[Name] AS [ProductModel] , p.StandardCost , P.ListPrice , P.SafetyStockLevel , P.ReorderPoint , p.SellStartDate , p.SellEndDate , p.ProductSubcategoryID , PPS.Name Subcategory , PPS.ProductCategoryID , PPC.Name Category , P.MakeFlag , P.FinishedGoodsFlag FROM [Production].[Product] p LEFT JOIN [Production].[ProductModel] pm ON p.[ProductModelID] = pm.[ProductModelID] LEFT JOIN Production.ProductSubcategory PPS ON P.ProductSubcategoryID = PPS.ProductSubcategoryID LEFT JOIN Production.ProductCategory PPC ON PPS.ProductCategoryID = PPC.ProductCategoryID GO -- reviewing the data SELECT * FROM [Production].[vProducts] -- checking the view for internal data consistency SELECT count(*) FROM [Production].[Product] p LEFT JOIN [Production].[ProductModel] pm ON p.[ProductModelID] = pm.[ProductModelID] LEFT JOIN Production.ProductSubcategory PPS ON P.ProductSubcategoryID = PPS.ProductSubcategoryID LEFT JOIN Production.ProductCategory PPC ON PPS.ProductCategoryID = PPC.ProductCategoryID
-- dropping the vProductInventory view (cleaning after) --DROP VIEW IF EXISTS Production.vProductInventory -- creating the view CREATE VIEW Production.vProductInventory AS SELECT PPI.ProductId , PPD.ProductNumber , PPD.Name ProductName , PPD.ProductModel , PPD.Size , PPD.Category , PPD.Subcategory , PPD.Style , PPD.StandardCost , PPD.ListPrice , PPD.StandardCost * PPI.Quantity InventoryValue , PPD.ListPrice * PPI.Quantity SalesValue , PPD.MakeFlag , PPI.Locationid , PPL.Name Location , PPI.Shelf , PPI.Bin , PPI.Quantity FROM [Production].[ProductInventory] PPI JOIN [Production].[vProducts] PPD ON PPI.ProductID = PPD.ProductID JOIN [Production].[Location] PPL ON PPI.LocationID = PPL.LocationID -- reviewing the data SELECT * FROM Production.vProductInventory -- checking the view for internal data consistency SELECT count(*) FROM [Production].[ProductInventory] PPI JOIN [Production].[vProducts] PPD ON PPI.ProductID = PPD.ProductID JOIN [Production].[Location] PPL ON PPI.LocationID = PPL.LocationID
Note:
It's important to check the internal consistency of the views or queries used, on whether the logic removes or duplicates data. For this one can run the query for the uppermost table, and add repeatedly one more join for each run to see whether the number of records remains the same. One can shortcut the validation by checking only the number of records from the base table and for the whole query, and only if there are differences use the previously mentioned approach. (This is how I observed that the Production.vProductDetails view is not usable, because it considers only the Products having a valid Model.)
Creating the Report
We can now use the Production.vProductInventory view to create the Product Inventory by Location report based on the following query:
-- Product Inventory by Location SELECT PPI.Category , PPI.Subcategory , PPI.ProductNumber , PPI.ProductName , PPI.ProductModel , PPI.Size , PPI.Style , PPI.StandardCost , PPI.ListPrice , PPI.Location , PPI.Quantity , PPI.InventoryValue , PPI.SalesValue FROM Production.vProductInventory PPI ORDER BY PPI.Category , PPI.Subcategory , PPI.ProductNumber
Note:
The attributes can be provided in the order in which they should be displayed in the report, reducing thus the overhead in the further steps.
Using the Reporting Wizard via the Add New Report select in the first step the data source, while in the next step provide the above query:
Design the Query |
In the next step select the "Matrix" Report Type:
Select the Report Type |
Within the "Design the Matrix" section assign the fields as follows (all the fields except the ones considered as Columns and Details will be considered as Rows):
Design the Matrix |
Into the last step give the report a meaningful name (e.g. Product Inventory by Location):
Completing the Wizard |
In theory the report is ready to run, however before doing that change the formatting by aligning the headers to the center and eventually change their size from 11 to 10 pixels, respectively rename the dataset (e.g. Inventory). To obtain the same information about the grouping as below change into the "Advanced Mode".
Design View |
And here's the output (I had to scroll through the pages to find meaningful values, therefore part of the Details header is not shown):
Preview |
Restructuring the Grouping
As can be seen into the Design Mode, the wizard created a grouping for each attribute provider into the Details (see matrix1_Category, matrix1_Subcategory, etc.). Therefore, the values will not be repeated for each row, which is typically desirable for visualizations but not when exporting the data to Excel for further processing. I prefer the latter version, therefore to obtain this behavior one can go on and delete all the grouping via "Delete group only" except the matrix1_Category:
This action deleted unfortunately all the Detailed headers except Category. To bring them back into the grouping double click on the and add each field into the Group expressions as below:
Group Properties |
As final change before running the report one can add header names for the Detail attributes. After these changes reports' design looks as follows:
Report Design with one grouping |
And here's the final report with the values repeating for each row:
Preview Report without formatting |
Note:
To avoid removing the groupings, I prefer to add only one Detail field into the query, typically the field which will make the row unique into the output (e.g. Product Number) and add the further fields (actually replace the below query with the one above) after the Wizard created the report. One still needs to add the columns manually into the report. In the end the effort is similar.
-- Product Inventory by Location SELECT PPI.ProductNumber , PPI.Location , PPI.Quantity , PPI.InventoryValue , PPI.SalesValue FROM Production.vProductInventory PPI ORDER BY PPI.Category , PPI.Subcategory , PPI.ProductNumber
Changing the Design
Report's design can be slightly improved by adding various formatting of the cells or values. One can use similar formatting as the ones consider in the previous post. The only thing difficult to implement will be a ranking function (see Ranking Rows in Reports). After the design changes here's the report:
Final Report |
Note:
Of course, together with parameters one can also add totals after each Category or Subcategory to the report if needed, though the latter is more appropriate for design purposes and not for further data consumption.
Happy coding!