Subtract 2 measures as Grand Total in SSAS Cube Browser - aggregate-functions

I guess it's a common and basic issue. I'm trying to get the "net value" of a measure depending on a dimension. Let me explain..
I have a fact table factTicket and a dimension called Operation who have 2 values: Opened and Closed. The goal is to get the number of ticket opened and closed for each month.
In the Cube Browser, I have a Distinct Count Measure of the TicketID according to the Operation dimension, but I would like the Grand Total to be Opened minus Closed instead of Opened + Closed
The factTable has a record with the date for every opened ticket, and a second record is added when the ticket is closed (So a Ticket can only have a maximum of 2 records in the fact table)
Is it possible ? I can't find a way to do it.. Maybe the Operation Dimension is a bad idea and I should have 1 record per ticket, with an OpenedDate and ClosedDate field ? I don't believe it will fixe the probleme since Distinct Count always return positive value, so the Grand Total will still be Opened + Closed.
Any ideas is welcome !
Thx

The scope function is what I needed:
SCOPE([Dim Operation].[OpenClose].[All], [Measures].[TicketCount]);
THIS = [Dim Operation].[OpenClose].&[OPEN] - [Dim Operation].[OpenClose].&[CLOSE]
END SCOPE;

Related

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 to determine trial booking conversion - google sheets

Introduction
Many sites use WooCommerce as a plugin for their WordPress site and so do we :). We've linked all purchases to google sheets, so I can do some analyses.
Our goal is get a many children physically active as we can and we have gym classes for very young children with they parents. To teach them the basics of the fun of physical activity
What I would like to do
I would like to know, how many free trial classes actually convert to paying customers and what the average timespan is between booking a trial class and becoming a member
The data that I have
I have the following columns which are necessary for this, I believe:
Datestamp
paymentID (is empty when booking a free trial class)
Price (is 0,00 whem booking a free trial class)
childsName (Unique in combination with parentsEmailadress, but recurs every month in the list once a membership is active)
parentsEmailadress (may have several children)
OrderName (has the string "trial" or "Membership")
I've made some dummy data in the following sheet:
https://docs.google.com/spreadsheets/d/1lWzQbXMU4qRLp_2qiQ_qsq57nPMy2RG8AHDMGKW626E/edit?usp=sharing
Possible solution
My guess is that I should:
make a column in which I combine the childs name and the emailadress
Make a TRUE of FALSE column to check if order is trial class or not
Make a column to find the first Unique child-emailadres combination in previous orders (How do I do that?! - Vlookup?)
and than
if this is found than check again if this is a trial class order.
If it is a trial class order than it should determine the amount of days between the trial class order and the non-trial class order and display the amount of days
if this is another normal order than leave empty(it's just a membership order)
if the emailadres is not found than display "direct" (it's a directly bought membership)
I did 1 and 2 and tried 3 with:
=ALS(H2=0;VERT.ZOEKEN(G2;A:G;1;ONWAAR);) (in Dutch)
=IF(H2=0;V.LOOKUP(G2;A:G;1;FALSE);) (possible translation)
But this doesn't work.
Really hope some can point me in the right direction!
Thank you very much in advance!
Given that trial classes have a price of 0, there's no need to create another column to identify those cases–just check the price. To the source data we'll add the "Client ID" column that you created in Column G of your sample sheet. (Ideally, you'll come up with an client ID system, but this works.) Now, create a new sheet that will be your dashboard and let's add a few columns:
Client ID This grabs only the unique values from the Client IDs in Sheet2 as we don't want users to be repeated in our dashboard. (Column A, row 1... for all others place the formulas in row 2).
=UNIQUE(Sheet2!G:G)
Did they trial? This will tell you TRUE/FALSE if the client did a trial. (Column B).
=ISNUMBER(MATCH(Dashboard!A2, FILTER(Sheet2!G:G, Sheet2!C:C=0), 0))
Did they convert? This will tell you TRUE/FALSE if the client converted from trial to paid. (In cases where they did not do a trial, it will be blank.) (Column C).
=IF(Dashboard!B2, ISNUMBER(MATCH(Dashboard!A2, FILTER(Sheet2!$G:$G, Sheet2!$C:$C>0), 0)), "")
Date of First Trial The date of the first trial. If none exists, will be blank. (Column D).
=IFERROR(MIN(FILTER(Sheet2!$A:$A, Sheet2!$G:$G=Dashboard!A2, Sheet2!$C:$C=0)))
Date of First Paid Course The date of the first paid course. If none exists, will be blank. (Column E).
=IFERROR(MIN(FILTER(Sheet2!$A:$A, Sheet2!$G:$G=Dashboard!A2, Sheet2!$C:$C>0)))
Days from First Trial to First Paid The number of days between the first paid course and the first trial course. If one of those values doesn't exist, then will be blank. (Column F).
=IF(ISDATE(Dashboard!E2), Dashboard!E2-Dashboard!D2, "")
Now you can answer several questions:
How many clients used a free trial? =COUNTIF(Dashboard!B:B, TRUE)
How many free trials converted? =COUNTIF(Dashboard!C:C, TRUE)
Average number of days from first trial to first paid? =AVERAGE(Dashboard!F:F)

How do I show "NEXT" x items to the user? [duplicate]

This question already has answers here:
Paging & Sorting grids with ASP.Net MVC
(5 answers)
Closed 9 years ago.
I am learning MVC. I'm creating a simple website for demo, which stores products in Database and shows them to the user 10 per page. Now, how do I fetch "NEXT" 10/20 items from the database? I thought of adding auto-increment column to table and then fetching items on its basis. Is it the right way? Also I am keeping record of how many items have been shown to the user by getting an int value as parameter to the Controller function, Products(int id). Is it the right way? I mean will it work if user is on 5th page(hence id==5) and refreshes the page?(or will it set id back to 0?).
you can use linq queries to fetch number of items in a table. you can pass number of item, start index. then the query will be like this
var nextProduct = myProducts.Skip(100).Take(10);
it will return 10 items from 101 to 110.
Fetching data based on id is not a good idea. because if u delete any record there will be a difference in the count and id. so you can take using the above code concept

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!

oracle year change trigger

I m on a problem that I can t figure out. I m building an application in c++ builder 2009 and oracle 11g. I have some calculated data that depend on users age. What I want to do is to re-calculate these data every new year. I thought I could have a trigger to do this, but I don t know which event I should catch and I didn t find something in internet.
My table is :
ATHLETE (name, ......, birthdate, Max_heart_frequency)
Max_heart_frequency is the field that depends on age. In insertion I calculate athlete's age, but what about next year??????
Can anyone help????
How is the max_heart_frequence calculated?
If this is a simply formula, I would create a view that returns that information. No need to store values that can easily be calculated:
CREATE VIEW v_athlete
AS
select name,
case
-- younger than 20 years
when (MONTHS_BETWEEN(sysdate, birthday) / 12) < 20 then 180
-- younger than 40 years
when (MONTHS_BETWEEN(sysdate, birthday) / 12) < 40 then 160
-- younger than 60 years
when (MONTHS_BETWEEN(sysdate, birthday) / 12) < 60 then 140
-- everyone else
else 120
end as max_heart_frequency
from athlete
Then you only need to select from the view and it will always be accurate.
You can use oracle scheduler to run a procedure at specific intervals (can be minutes hours, daily, yearly etc .. any time span).
Check this linke: http://download.oracle.com/docs/cd/B19306_01/server.102/b14231/schedover.htm
You have two options:
Have a stored procedure that calculates and updates the Max_Heart_Frequency of all the athletes every 01st Jan (using the yearly scheduling of a procedure)
Have a stored procedure that runs daily and calculates and updates the Max_Heart_Frequency of all the athletes every day (using the daily scheduling of a procedure)
If Max_Heart_Frequency changes over time because the user is getting older, why are you storing it in the table in the first place? Why not just call the function that computes the maximum heart rate at runtime when you need the value? Potentially, it may make sense to have a view on top of the Athlete table that adds the computed Max_Heart_Frequency column to hide from the callers that this is a computed column.

Resources