Advanced hierarchy in PowerPivot - hierarchy

I am building a hierarchy in PowerPivot and have an issue that I want to solve.
The hierarchy has 6 levels and view 4 columns of data. The two lowest levels is ordernumber and product groups (on the ordernumber).
Issue:
When viewing the the order number level (level 5), the values should show the full order value, even though some product groups are filter out.
Does anyone know how to solve this?

Honestly, this isn't a particularly well written question but I think I know what you are trying to do.
Lets say you have a table called 'SalesData' with columns; Order_Number, Product_Category, Product_Code and Sales.
The following measure would allow you to slice your data by Product_Category and see sales for all transactions that contained a product in that category:
=
CALCULATE (
SUM ( 'SalesData'[Sales] ),
ALL ( 'SalesData'[Product_Category], 'SalesData'[Product_Code] ),
VALUES ( 'SalesData'[Order_Number] )
)
Effectively what it does is opens up the product stuff so that the result isn't restricted to the thing you have sliced on but then filters your SUM() by a list of the order_ids that were included in the original selection.
Post back more details of your specific case and I can try and tighten it up....

Related

How to use an ifnull() inside a case

I am writing a query for a SQLite database in which I need to find the best selling product for each region in a list of 6 regions. However, some of the regions don't have any product sold in which case I am supposed to output 'No Product Sold'. I am trying to use an ifnull() statement, but can't get it working.
Currently, my query is as follows
SELECT area.name AS region,
CASE ifnull(sales.area_id, 'No Product Sold')
END AS most_sales
FROM product
JOIN sales ON product.rank = sales.rank
GROUP BY area name
I also know I will likely need to use a nested query, but I'm not sure how yet.
Unfortunately I cannot base this off of rank, it has to be the item with the highest sales in the region. Does anyone know what I am doing wrong?

Invisible graphs cause report to slow

I have a report with a parameter where the end user chooses a practice name that corresponds to a group of people. Most of these groups have fewer than 10 people, but a small number of them have as many as 150. When there are more than 15 people in a given group, they want separate graphs, each with no more than 15 people. So for most of the groups, we only need one graph. For a few, we need a lot of graphs.
Behind the scenes, I created a graph for each multiple of 15 people, and set them to only be visible if there are actually that many people in the group. This does what I need it to, but it makes the report super slow. As close as I can tell, behind the scenes when an end user runs the report it's still somehow rendering the hidden graphs and slowing it all to heck. (I did find this link which I think suggests this is a known bug.
I need to have one report where the end user selects the practice name, so I can't make two reports, "My practice is normal" and "My practice is ginormous". I thought maybe I could make a conditional sub-report split into those two reports based on the practice name parameter, but that doesn't appear to be possible; you can play around with visibility but I'm guessing that will still cause the invisible graph rendering problem and not help my speed.
Are there any other cool tips I can try to speed up my report, or is this just a case of too many graphs spoiling the broth?
The easiest way would be to generate a group number for every 15 people and then use a list control to repeat the chart for each group.
Here's a very quick example of this in action. I just used some sample data from one of the Adventure Works sample database.
Here's my query that returns every person in each selected department. Note that I have commented out the DELCAREs as these were just in there for testing.
--DECLARE #Department varchar(50) = ''
--DECLARE #chartMax int = 5
SELECT
GroupName, v.Department, v.FirstName, v.LastName
, ChartGroup = (ROW_NUMBER() OVER(PARTITION BY Department ORDER BY LastName, FirstName)-1) / #chartMax -- calc which chart number the person belongs to
, Salary = ((ABS(CHECKSUM(NewId())) % 100) * 500) + (ABS(CHECKSUM(NewId())) % 1000) + 10000 -- Just some random number to plot
FROM [HumanResources].[vEmployeeDepartment] v
WHERE Department IN (#Department)
ORDER BY Department
The key bit is the ChartGroup column
ChartGroup = (ROW_NUMBER() OVER(PARTITION BY Department ORDER BY LastName, FirstName)-1) / #chartMax
This will give the first 5 rows in each department a ChartGroup of 0 the next 15 1 and so on. I used 5 rather than 15 just so it's easier to demo.
Here's the dataset results
Now, in your report, add a List, set it's dataset property to your dataset containing your main data (the query above in my case).
Now edit the 'details' rowgroup properties and add a grouping by Practice and ChartGroup (Department and ChartGroup in this example)
In the list box's textbox, right-click then insert a chart.
Set the chart up as required, in my example, I used salary as the values on a pie chart and the employee names as the labels.
Here's the final design ..
Note that I set the department as a multi-value parameter and also set the number of persons per chart (chartMax) as a report parameter.
When I preview the report I get this for 'Engineering' which has 6 employees
Sales has 18 employees so we get this
.... and so on, it will generate a new chart for every 15 people or part thereof.

How do I create a running count of outcomes sequentially by date and unique to a specific person/ID?

I have a list of unique customers who have made transactions over a year (Jan – Dec). They have bought products using 3 different methods (card, cash, check). My goal is to build a multi-classification model to predict the method pf payment.
To do this I am engineering some Recency and Frequency features into my training data, but am having trouble with the following frequency count because the only way I know how to do it is in Excel using the Countifs and SUMIFs functions, which are inhibitingly slow. If someone can help and/or suggest another solution, it would be very much appreciated:
So I have a data set with 3 columns (Customer ID, Purchase Date, and Payment Type) that is sorted by Purchase Date then Customer ID. How do I then get a prior frequency count of payment type by date that does not include the count of the current row transaction or any future transactions that are > the Purchase Date. So basically I want to do a running count of each payment option, based on a unique Customer ID, and a date range that is < purchase date of that training row. In my head I see it as “crawling” backwards through the transactions and counting. Simplified screenshot of data frame is below with the 3 prior count columns I am looking to generate programmatically.
Screenshot
This gives you the answer as a list of CustomerID, PurchaseDate, PaymentMethod and prior counts
SELECT CustomerID, PurchaseDate, PaymentMethod,
(
select count(CustomerID) from History T
where
T.CustomerID=History.CustomerID
and T.PaymentMethod=History.PaymentMethod
and T.PurchaseDate<History.PurchaseDate
)
AS PriorCount
FROM History;
You can save this query and use it as the source for a crosstab query to get the columnar format you want
Some notes:
I assumed "History" as the source table name - you can change the query above to use the correct source
To use this as a query, open a new query in design view. Close the window that asks what tables the query is to be built on. Open the SQL view of the query design - like design view, but it shows the SQL instead of the normal design interface. Copy the above into the SQL view.
You should now be able to switch to datasheet view and see the results
When the query is working to your satisfaction, save it with any appropriate name
Open a new query in design view
When you get the list of tables to include, switch to the list of queries and include the query you just saved
Change the query type to crosstab and update the query as needed to select rows, columns and values - look up "access crosstab queries" if you need more help.
Another tip to see what is happening here:
You can take the subquery - the parts inside the () above - and make
just that statement into it's own query, excluding the opening and closing (). Then you can look at it's design view to see what it does
Save it with an appropriate name and put it into the query above in place of the statement in () - then you can look at the design view.
Sometimes it's easier to visualize and learn from 2 queries strung together this way than to work with sub queries.

Query on use of aggregate functions over recursive groups in microsoft report designer

I have to point out that I'm fairly new to reporting outside of Microsoft Access, and new to the site, so please bear with me!
Stripped down to essential items, my data object has:
CategoryID, ParentCategoryID, TransactionID, TransactionDate, SplitID, CurrencyID and Value.
I don't think this is relevant, but just in case -
A Split has a Category and a Value, with one to many belonging to a Transaction.
Multiple Splits may exist for the same Category & Transaction with
different, or the same, Value (to support different combinations of the other data
items I haven't listed).
A Transaction has a TransactionDate and a CurrencyID, so all Splits
belonging to a Transaction are for the same Currency.
A Category belongs to a Category recursively.
A Split may be assigned a Category at any level in the recursive hierarchy and the crux of my problem is to report Transaction / Split detail under the appropriate Category heading, with a sub-total to include all those details AND the totals of all child Categories.
So, I have a Detail row group holding all the ancilliary data items that aren't relevant and a TransactionIDGroup row group on the same row. I then have a CategoryGroup row group based on CategoryID with a Parent of ParentCategoryID to handle the recursive nature of the data and a CurrencyIDGroup column group to handle the possible multiple currencies involved.
Also in the CategoryIDGroup row group is a total row with the Value cell holding an expression.
If I leave that expression as =Sum(Fields!AccountValue.Value), the report quite nicely totals the Value for each Currency column for all the details specifically in each Category (the default scope), so I thought I needed to make the Sum 'Recursive'. However, you don't seem able to specify the optional Recursive parameter without specifying the scope as well.
If I specify scope as CategoryIDGroup, I get all zero sub-totals. If I use CurrencyIDGroup I get each one being the same report total for the Currency. Anything else either gets me a build error or a combined-currency report total.
The other issue I have is that the recursive child Category groups are reported sequentially underneath the parent Category group (so, outside the header row, detail rows and total row, and not within the group. However, if I can get the total to reflect the children as well as the details at that level, I'd be happy enough, even though it wouldn't seem to add up until you realised what was going on.
What I have in mind is something like:
Category A
Transaction 1 10/02/2011 ...................... £100.00
---------------------- £14.50
Transaction 2 18/03/2011 ...................... $159.34
Category Ai
Transaction 3 18/06/2011 ---------------------- £295.60
Total Category Ai £295.60
Total Category A £410.10 $159.34*
But what I get is this:
Category A
Transaction 1 10/02/2011 ...................... £100.00
---------------------- £14.50
Transaction 2 18/03/2011 ...................... $159.34
Total Category A £114.50 $159.34*
Category Ai
Transaction 3 18/06/2011 ---------------------- £295.60
Total Category Ai £295.60
I guess the fundamental question is - am I asking the impossible? Do I need to take a different approach, perhaps with sub-reports for the details? I've wondered about including a Sum of the values of the child Categories within the data object at each Category level, but is there something simple I'm missing?
Any pointers in the right direction would be greatly appreciated after several days tearing my hair out :)
I have no idea whether there was something simple I missed, but resolved the issue to my satisfaction by including another property in the data object, being the sum of all child categories for each currency, and including a new row to print the sum of that field. Just in case someone else hits just the same question!

LINQ to SQL grouping and passing onto a view

I am new to Asp.Net, MVC3, Linq, and everything else related to it. I'm very used to PHP and ColdFusion so pardon my ignorance! Essentially what I am trying to do is re-create the situation in ColdFusion where I can perform the equivalent of a cfoutput's group attribute. I'm so used to just calling a stored procedure and then doing
<cfoutput group="id">
and then another inner cfoutput for any columns that have non-distinct data. Works like a charm! Not so much in Asp.Net.
I would like to stay with using my stored procedure, which is returning a join from two tables with a one-to-many relationship. For example's sake let's say I have 3 columns: a full name, a title, and a graduation year. The graduation year is the column from the joined table, so my result from the stored procedure looks like this:
Jim Professor 2005
Jim Professor 2008
Jim Professor 2011
I am sending this to the View. I am assuming it's the View's job to then group the data based on one of the columns (probably the full name). I want to output an HTML table with 3 columns and in this situation I would have ONE row:
Jim Professor 2005, 2008, 2011
I have googled tons of examples that use this thing called a group key. This does not seem to help me because I'm not interested in just outputting one value "Jim" (or whatever the grouped value is), I need both "Jim" and "Professor" values to be output for each row. My thinking is I would need 2 foreach loops, the outer loop displaying the fullname and title and the inner loop going through all possible matches for the graduation years. I cannot seem to get the graduation years in a group, especially with this IGrouping syntax. The key can only store one value and I need every value on that row, I only really need one or two values to be iterated over. Should I try and create a custom view model after I perform a secondary linq grouping and then send that to a strongly typed view?
EDIT:
Ok, I have code that works but it seems very inefficient as I basically have to re-define all of the columns/values that I have from my stored procedure. It almost makes me want to forget stored procedures and just use LINQ for everything. It seems what I was asking for is a kind of "group on multiple columns" and link helped immensely.
var records = db.getRecords();
var groups = from r in records
group r by new
{
r.id
}
into row
select new ListVM()
{
id = row.Key.id,
fullname = row.Select(x => x.fullname).First(),
title = row.Select(x => x.title).First(),
degrees = row.Select(x => x.degree_name).ToList(),
majors = row.Select(x => x.major_name).ToList()
};
return View(groups);
I of course had to create a ViewModel for this to work. In my view then I can use for loops to iterate over the degrees and majors lists. Is this the best way to do this? I just generally need more than just the group key to display my entire row of information, and only want to iterate over lists once or twice in a 20 column row, as opposed to only displaying the group key once and iterating over everything in most examples I see.
I'm not that big specialist with Linq and MVC, but faced with your problem I would:
Deal with data preparation in controller/model, after being taught that view should be concerned with displaying things only.
I would use knowledge from these topics to solve your particular problem:
a) grouping by multiple columns:
Group By Multiple Columns
b) Concatenation as an aggregate function:
Using LINQ to concatenate strings
c) Using aggregates and grouping by multiple columns
How to write a LINQ query combining group by and aggregates?
Once you have data in your view model, just display it.
I believe I've finally found out how to solve what I was looking for. A "group join" seems to solve my problem with ease. The information I found on this page solved it: http://geekswithblogs.net/WillSmith/archive/2008/05/28/linq-joins-and-groupings.aspx

Resources