QlikSense expression to only show the products selected in the codes - qliksense

I just started QlikSense a few weeks ago, and am currently stuck on counting fields with more than 1 criteria, I've searched around in the discussion forums and can't seem to find any solution to this.
Basically, I wanted to generate an expression that only shows the my New Customers in 2017, for my targeted products, the end table should look like this
For this, i have thought of an expression that takes in only customers that had bought from us in 2017(invoice amount > 0), and not in 2016(invoice amount=0), for the targeted products, but I cant seem to go about coding the expression for it.
The tables which i currently use is:
-Invoice details table(which includes all the invoice details of all customers buying, for all products,across years 2015-2017, along with the amount$ paid in the invoice)
-Targeted Products table(products which we have to look at, which is "Product A", "Product B", "Product C")
The following is the expression which I have done up so far, but instead of showing new customers, it's also showing customers that are not buying from us.
count(
aggr(
sum(
{$<[Invoice Date.autoCalendar.Year]={"2017"},
[Product-Product Name (Finance File)]={
"Product A", "Product B", "Product C"
}
>}
[Amount$]
)
, CUSTOMER_CODE
)>0
AND
aggr(
sum(
{$<[Invoice Date.autoCalendar.Year]={"2016"},
[Product-Product Name (Finance File)]={
"Product A", "Product B", "Product C"
}
>}
[Amount$]
)
, CUSTOMER_CODE
)=0
)

I didn't get a good idea of your table structure. I hope you are using Master Calendar in script and your invoice date is linked to that of the Master Calendar.
To keep things simple, I created an example dataset
Our target product is B and we want to capture its sales for new customer C. I used the expression:
Sum({
<
Customer = {"=Sum({<Year = {2017}>}Sales)"}
, Product = {'B'}
>
}Sales)
This expression can be used in a straight table such as the below one:
I used A,B,C for both customers and products but they are not related - my sloppiness!
If you want to know who are the new customers that bought Product 'B' in 2017, then you can use the following expression:
Count({
<
Customer = {"=Sum({<Year = {2017}>}Sales)"}
, Product = {'B'}
>
-
<
Customer = {"=Sum({<Year = {2016}>}Sales)"}
>
}Distinct Customer)

Related

How to parameterize a column for aggregation in Power BI desktop?

I have users who would like to be able to modify what columns a table aggregates by. My issue is that I seem unable to do this in Power BI. I basically want to be able to do the following in SQL:
SELECT
<OrgLevel1>,
<OrgLevel2>,
SUM([Revenue])
FROM [Data]
GROUP BY
<OrgLevel1>,
<OrgLevel2>
;
where the user can change <OrgLevel1> and/or <OrgLevel2> to be any of { "(All)", [Department], [Product] }.
The issue may be related to this post: https://community.powerbi.com/t5/Desktop/Calculated-Column-Table-Change-Dynamically-According-to-Slicer/m-p/655991#M314800
Here's a link to a workbook that illustrates this issue, TestParameterizeGroupby.pbix (hosted by Google Drive). I've also included field definitions below with screenshots. Thanks for any help.
TestParameterizeGroupby.pbix
Link: TestParameterizeGroupby.pbix (hosted by Google Drive)
Problem
[Org Level 1] and [Org Level 2] fields are not recalculating from the users' selection. Only the default values are shown.
Expected result in table
"Org Level 1", "Org Level 2", "Revenue"
"(All)", "(All)", 28
Note
The purpose is to have parameterizable organization level fields so that the report user can aggregate by all, department, product, or both in either order.
Table and column definitions
'Data' = DATATABLE(
"Department",
STRING,
"Product",
STRING,
"Revenue",
DOUBLE,
{
{"DeptA", "ProdX", 5.0},
{"DeptA", "ProdY", 6.0},
{"DeptB", "ProdX", 10.0},
{"DeptB", "ProdY", 7.0}
}
)
'Data'[Org Level 1] = SWITCH(
'Org Level 1 Parameter'[Org Level 1 Parameter Value],
0,
"(All)",
1,
[Department],
2,
[Product]
)
// Problem: [Org Level 1] and [Org Level 2] fields are not recalculating from the users' selection. Only the default values are shown.
'Org Level 1' = DATATABLE(
"Org Level 1",
STRING,
"Org Level 1 Parameter",
INTEGER,
{
{"(0) (All)", 0},
{"(1) Department", 1},
{"(2) Product", 2}
}
)
'Org Level 1 Parameter'[Org Level 1 Parameter] = GENERATESERIES(0, 2, 1)
'Org Level 1 Parameter'[Org Level 1 Parameter Value] = SELECTEDVALUE('Org Level 1 Parameter'[Org Level 1 Parameter], 1)
Table 'Org Level 1' has a 1-1 relationship with 'Org Level 1 Parameter' on column [Org Level 1 Parameter].
The user selects the value for 'Data'[Org Level 1] by selecting the value for 'Org Level 1'[Org Level 1].
Tables and columns for [Org Level 2] are defined in the same way as [Org Level 1].
Screenshots
Report view:
Data view:
Model view:
Cross-reference to post in Power BI forum:
Power BI Forum: How to parameterize a column for aggregation
One solution to this is to add two list values parameters and use their values in Power Query M code to modify the database query. Lets assume that you have a table Data with columns Department, Product and Revenue. For simplicity I will add one more column, named Dummy Column, with all rows having the same value (e.g. null). I will explain why later in this post. So the table looks like this:
Then in your report specify a query when adding this table to your model (lets assume we will import it, but in general you can do this in DirectQuery too):
Now if you look the M code you will see the above query there:
Source = Sql.Database(".", "StackOverflow", [Query=" select ....
Now define couple of parameters, that the end-user can use to select how the data should be aggregated. Lets name them Level 1 and Level 2:
The value of a parameter can be used in M by parameter name, and & is used to concatenate strings. So if there is a parameter Name with value Samuel, the expression "Hello, " & Name & "!" will be evaluated as Hello, Samuel!. The idea is to check the value of our parameters and modify the database query accordingly.
In the select part, we will replace the name of the field selected, or we will put '' (empty string) in case of <All> (I surrounded parameter values with brackets to be more easily to distinguish parameter values from database field names). So the expression should look like:
"select " & (if #"Level 1" = "<Department>" then "Department" else ..." (and so on)
Because there is a space in our parameter's name, we need to surround it with #" and ", so Level1 can be referenced simply as Level1 in the code, but Level 1 becomes #"Level 1".
The group by part is a bit trickier. We should add a comma between field names, add or not field name, or even omit the group by at all (in case both parameters are set to <All>). To simplify this, I added one dummy column, with all rows having the same value (e.g. null) and always group by this column. This way building the group by clause is way more simpler - in case the parameter value is not <All>, we should add , fieldname. So the code could look like this:
"group by DummyColumn" & (if #"Level 1" = "<Department>" then ", Department" else ..." (and so on)
So the final M code is this:
let
Source = Sql.Database(".", "StackOverflow", [Query="select#(lf) " & (if #"Level 1" = "<Department>" then "Department" else if #"Level 1" = "<Product>" then "Product" else "''") & " as [Org Level 1]#(lf) , " & (if #"Level 2" = "<Department>" then "Department" else if #"Level 2" = "<Product>" then "Product" else "''") & " as [Org Level 2]#(lf) , SUM(Revenue) as Revenue#(lf)from Data#(lf)group by DummyColumn" & (if #"Level 1" = "<Department>" then ", Department" else if #"Level 1" = "<Product>" then ", Product" else "") & (if #"Level 2" = "<Department>" then ", Department" else if #"Level 2" = "<Product>" then ", Product" else "")])
in
Source
Now the end-user can change parameter values, by clicking Edit Queries -> Edit Parameters:
And select how to group the data:
By default, Power BI Desktop will warn you first time, when particular query is executed:
If you want to turn this off, go to File -> Options and settings -> Options -> (GLOBAL) Security and make sure Require user approval for new native database queries is not selected:
When the end-user changes parameter values, the data will change too, e.g.:
Or:
And so on...
This trick works well in Power BI Desktop when every user has its own copy of the .pbix file. However, if you publish it, first changing parameter values is not very convenient (you must go to datasat's settings) and more important, changing parameter values affects all users, which are looking at this report. You can also use it to modify Table.Group statements generated by Power Query Editor, in case you want to aggregate the data in Power BI, but changing the database query is easier and more flexible.
If you want to enable this scenario for concurrent multi-users scenarios for published reports, you can use slicers and What-if parameters. Unfortunately, What-if parameters can be numeric (you can't define the list of values there), so you can use measures to "decode" the int value of the parameter and write some DAX code to perform different aggregations accordingly. It is more work, but if it is needed, it can be made too.

Accessing the ATTR field troubleshooting in Tableau?

I am working on Tableau server but I believe the problem I am facing does not correspond to tableau server specifically.
I am using two data sources ds1 and ds2 which are joined using the dimension Id . ds1 has a field city and ds2 has a field district. There is only 1 city corresponding to each Id but there can be multiple district corresponding to an Id .
I have created a calculated field Points in ds2 which is described in the code segment.
I have researched from different sites and blogs (including tableau support). I came to a close possible reason behind this and I might be wrong . The ATTR function which works on row level and identify if a row is unique then it outputs the dimension otherwise it outputs '*' . I think when I joined those two tables the district dimension in ds2 might have the '*' instead of actual district values, so it might not be able to compare the conditions in if statements of Point .
//Point//
IF [city] == "Delhi"
AND [district] == "Dist1"
AND [district] == "Dist2"
THEN "100 Section"
ELSEIF [city] == "Mumbai"
AND [district] == "Dist11"
AND [district] == "Dist12"
THEN "200 Section"
ELSE "Other Section"
END
When I insert data which satisfy the conditions in calculated field, it is going in Other section of the Point .I want it to go in desired section.
For instance
Id = 19
city = Delhi
district = Dist1
district = Dist2
district = Dist3
It should go in 100 Section but it is going in Other Section . What modifications should I do or add to make the Point work properly ?

Adding Columns heading to report if no data in a given period

I have a dataset for each record it has a CompanyID, RevenueMonth, RevenueYear, Revenue
When I create the report, I am grouping each CompanyID and showing their monthly revenue for a given year.
But in a given year, not all companies have any revenues for a particular month.
Example:
A sample record would look like:
CompanyID, RevenueMonth, RevenueYear, Revenue
1,05,2013,5.00
1,08,2013,6.00
1,03,2013,3.00
End Result, I would like my report to look like this with CompanyID 1.
Company ID|01|02|03|04|05|06|07|08|09|10|11|12
1 0.00|0.00|3.00|0.00|5.00|0.00|0.00|6.00|0.00|0.00|0.00|0.00
In my current Report, it will only fill column headings with March (03), May (05) and August (08).
Company ID|03|05|08
1 3.00|5.00|6.00
How do I get my Report to add the missing months for the year?
I hope my questions is clear.
Database level
Since you're only returning a year at a time, you can create a calendar table and add this to your result set:
Keeping it as simple as possible, with the date table coming from a CTE:
with months as -- get required year/months
(
select RevenueYear = 2013
, RevenueMonth = 1
union all
select RevenueYear = 2013
, RevenueMonth = RevenueMonth + 1
from months
where RevenueMonth < 12
)
select CompanyID = coalesce(r.CompanyID, c.companyID)
, RevenueMonth = coalesce(r.RevenueMonth, m.RevenueMonth)
, RevenueYear = coalesce(r.RevenueYear, m.RevenueYear)
, Revenue = isnull(r.Revenue, 0.0)
from months m
cross join (select distinct CompanyID from records) c -- make sure all companies included
left join records r on m.RevenueYear = r.RevenueYear
and m.RevenueMonth = r.RevenueMonth
SQL Fiddle with demo.
This will return a year/month for each company in the result set.
In the long run it would be better to move from a CTE to a permanent calendar table in the database.
You can then implement this in the report using a matrix style tablix.
Report level
If you'd prefer to do this at the report level, you can set up a table-style tablix with 12 permanent columns, one for each month, then populate the month revenue cells with expressions like:
=Sum(IIf(Fields!RevenueMonth.Value = 2, Fields!Revenue.Value, Nothing)
For the February column.
This would work with your existing dataset without any database code changes.

Crystal Report - Conditional selection of record

I'm using Crystal Reports XI.
My data is coming from a dataset.
I have 2 tables which are related as follows:
Product(ProdID(PK), ProdName)
ProdPC(ProdPCID(PK), ProdID(FK), PCType, ProdCode)
The 'PCType' field determins the type of barcode format the 'ProdCode' represents. (E.g. EAN13, EAN8).
In crystal reports one 'Product' can have more than one kind of barcode which means my tables end up looking like this:
Product: ("1", "Example Product 1")
ProdPC: ("0", "1", "EAN8", "01234567"), ("1", "1", "EAN13", "012345678910")
In crystal reports I only want to print 1 barcode label for per product. However because they're are 2 records in the 'ProdPC' table, I will get 2 labels being printed for this 1 product.
What I want to do is place a condition in crystal reports which states, "If EAN13 is NULL then display EAN8, ELSE display EAN13"
I do not have access to the dataset and cannot prevent the application which calls Crystal Reports to create the barcode labels from sending more than 1 record for the 'ProdPC' table.
How can I create my conditional statement, purely in 'Crystal Reports 2008'?
What I have tried so far is:
IF {PartPC.PCType} = "EAN-13" AND {PartPC.ProdCode} <> "" THEN
{PartPC.ProdCode}
ELSE
/* DISPLAY PartPC.ProdCode containing EAN8 value */
;
But I am unsure how to then tell Crystal Reports to display the 'ProdCode' value where 'PCType' is equal to 'EAN8'
Group your report by Product ID.
Order your report by PC Type descending (within Product ID).
Include your report details in the Product ID footer (not the details section).
Option I: create two columns: one for each bar code. Do this in Crystal Reports.
Remove the PartPC table, replacing it with two SQL Expression fields:
// {%EAN-8}
(
SELECT ProdCode
FROM PartPC
WHERE ProdID=Product.ProdID
AND PCType='EAN-8'
)
// {%EAN-13}
(
SELECT ProdCode
FROM PartPC
WHERE ProdID=Product.ProdID
AND PCType='EAN-13'
)
Then create a formula field to display the appropriate one:
// {#barcode}
If Not(Isnull({%EAN-13})) Then
{%EAN-13}
Else
{%EAN-8}
Option II: alter the SQL to create to scalar-valued fields. Do this in your dataset or in a Command object (Crystal Reports).
SELECT Product.*,
(
SELECT ProdCode
FROM PartPC
WHERE ProdID=Product.ProdID
AND PCType='EAN-8'
) EAN_8,
(
SELECT ProdCode
FROM PartPC
WHERE ProdID=Product.ProdID
AND PCType='EAN-13'
) EAN_13
FROM Product
...

MDX: Calculated Dimensions?

I don't know if this is possible or not, or if my limited knowledge of MDX is pushing me in the wrong direction...
The cube I'm dealing with has two different dimensions for dates, [Statement Dates] and [Premium Dates]. Further in the hierarchy of each looks like this:
[Statement Dates].[Statement Year].[2008]
[Payment Dates].[Payment Year].[2008]
For the business logic I'm implementing I need to do something like:
select
({ [Measures].[Commission] }) on columns,
({[Products].[Product Category]}) on rows
from [Cube]
where
(
IIF( [Products].[Product Category].CurrentMember.Name = "Some Category",
[Statement Dates].[Statement Year].[2008],
[Payment Dates].[Payment Year].[2008] )
)
So I need it to discriminate what dimension to use for filtering the year based on what product category is being used.
This parses ok and the query runs, but the numbers seem to suggest that the IIF statement is always returning false.
Because the WHERE clause gets evaluated first the .CurrentMember function in the IIF will only be seeing "All Product Cateogories". In which case the [Products].[Product Category].CurrentMember.Name will never be equal to "Some Category" as the only product category in context is "All Product Cateogories".
One possible work around would be to do a calculation like the following:
WITH MEMBER Measures.Commission2 as
SUM(
{[Products].[Product Category].[Product Category].Members}
, IIF( [Products].[Product Category].CurrentMember.Name = "Some Category"
, ([Statement Dates].[Statement Year].[2008],[Measures].[Commission])
, ([Payment Dates].[Payment Year].[2008].[Measures].[Commission]) )
)
select
({ [Measures].[Commission2] }) on columns
, ({[Products].[Product Category]}) on rows
from [Cube]
You could also do a scoped assignement in the calculation script in your cube to do this sort of thing.