I have a total column that needs to follow the following criteria:
If the type = 1, then it needs to total all the rows that have a '1' and then add "1 - New" at the end, if the type = 2, then it needs to total all the rows that have a '2' and then add "2 - Reprint" at the end, and if the type = 50, then it needs to total all the rows that have a '50' and then add "50 - draft" at the end.
I want to total all my New, all my Reprint, and then drafts. I cannot find an expression that will allow me to do this. any assistance would be great! :-)
Insert a row below your details row that is inside the Type group, but outside the details row. Add an expression like this one into a cell in this new row:
=cStr(countrows()) + iif(Fields!Type.Value = "1", " 1 - New", iif(Fields!Type.Value = "2", " 2 - Reprint", iif(Fields!Type.Value = "50", " 50 - draft", "")))
This expression works because when used within the Type group, the function countrows() will return the number of rows within the group, not the number of rows in the full dataset. There are other aggregate expressions you could use if you were not grouping on Type in your table.
Related
I wonder how postgresql query can generate a column, say 'has_alarm1', that will have values "1", "0", or "null" whenever, respectively, i) any row of a certain GROUP of rows has value > 0 in an existing column, say 'alarm1'; ii) no row of the GROUP has 'alarm1' value > 0 and at least one row with 'alarm1' value = "0"; or all rows of the GROUP have 'alarm1' value = "null".
Let me further illustrate that with an example and images:
Here is the input table:
Here is the intended query output:
i) First and foremost, observe that the rows in 'table_name' (the input table: 1st figure) are at a level below the device_id-date (they are at, what I call, 'log level'), meaning there is more than 1 register for each device_id-date ( e.g. device_id = "1" AND date = "2022-01-16" has 2 rows or logs (log_id's = "3", "4"); device_id = "2" AND date = "2022-01-16" has 2 rows (log_id's = "7", "8") ). Meanwhile, rows in the intended query output (2nd figure) are at the device_id-date level, meaning each device_id-date has a unique row in the output table ( e.g. device_id = "1" AND date = "2022-01-16" has only 1 row (the 2nd register); device_id = "2" AND date = "2022-01-16" has only 1 row (the 4th register));
ii) Observe that the groups are formed by each 'device_id' value. So in the example, there are two groups: device_id = "1" and device_id = "2". I want to aggregate from log level (log_id) to group-date level (i.e. device_id-date) in the output table, as you can see in the 2nd figure.
iii) "Condition1": whenever the device_id-date has at least one log-row with column 'alarm_number' value > "0" (greater than zero), the query will output only one row for that device_id-date with new column 'has_alarm_number' = "1";
iv) "Condition2": whenever the device_id-date has all log rows with column 'alarm_number' value = "Null", the query will output only one row for that device_id-date with new column 'has_alarm_number' = "Null";
v) "Condition2.1": whenever the device_id-date has no log rows with column 'alarm_number' value > "0" AND at least one log row with column 'alarm_number' value = "0", the query will output only one row for that device_id-date with new column 'has_alarm_umber' = "0".
Example:
For example, observe in the 1st figure that device_id = "1" on date "2022-01-15" provides alarm1 = "55" (log_id = "1") and alarm1 = "0" (log_id = "2"). The query then outputs a single row with has_alarm1 = "1" for that device_id-date (see output), because "condition1" is met for that device_id-date.
However, when all log rows with device_id = "2" on date "2022-01-19" provide alarm1 = "Null" (log_id's = "13", "14"), the query outputs a single row with has_alarm1 = "Null" for that device_id-date, because "condition2" is met for that device_id-date.
Eventually, observe that device_id = "1" on "2022-01-16" provides alarm1 = 0" (log_id's = "3", "4"). The query returns a single row with has_alarm1 = "0" for that device_id-date, because now "condition2.1" is met for that device_id-date. Likewise, when device_id = "2" on "2022-01-17" provides alarm2 = "Null" (log_id = "9") and alarm2 = "0" (log_id = "10"), as we can see in column 'alarm2' of the input table, the query returns a single row with has_alarm2 = "0" for that device_id-date, because "condition2.1" is met again.
I hope I have made this case well structured and clear in this post, but please let me know if any further explanations are required. Any solutions or suggestions are truly appreciated. Sincerely,
Nigel.
Use sum() in groups by device_id and date.
select
device_id,
date,
(sum(alarm1) > 0)::int as has_alarm1,
(sum(alarm2) > 0)::int as has_alarm2
from my_table
group by 1, 2
order by 1, 2
Note, that sum() is null when all its arguments are null.
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.
I am fairly new to tableau and have searched in various online help forums but was unsuccessful in finding the one similar to mine. Hence posted this here. Not sure if this is a fairly straightforward one or complicated (as I think!)
I have 3 columns (2 dimensions and 1 measure) and I want to use the measure column based on some of the string occurances from the dimensions columns.
Let the columns be as 'Event', 'Screen' and 'Time'
Let the values be as in the following table (NOTE: There are many other values along with these, but I require only the ones in the lower cases i.e., NULLs and NAVIGATIONs are to be excluded)
I want a single calculated field with three steps that yields as below:
(2*count of "name submitted" occurances in Event) - (AVG time of corresponding "name submitted" (from Event) * count of "name submitted" occurances in Event)
+
(2*count of "address added" occurances in Event) - (AVG time of corresponding "Add address" (from screen) * count of "address added" occurances in Event)
+
(2*count of "order created" occurances in Event) - (AVG time of corresponding sum of "orders"+"order detail"+"order confirmation" (from screen) * count of "order created" occurances in Event)
My approach:
I have dragged Event and Screen dimensions to the filter pane and selected all the values including NAVIGATION AND NULL (as these fields correspond to the time that I need in the calculation) and it didn't quite work!
I have also created PARAMETERS for Event and Screen for each of the three steps of the calculation (above) and it didn't work either!
So, what would be a best way to achieve the above calculation?
Any help is much appreciated.
Something like this? Note, there are discrepancies in capitalization between the example data and your example calc (Name submitted vs name submitted), so you may need to adjust the below for that.
(
(2 * SUM(IIF([Event] = 'Name submitted',1,NULL)))
-
(
AVG(IIF([Event] = 'Name submitted',[Time],NULL))
* SUM(IIF([Event] = 'Name submitted',1,NULL))
)
)
+
(
(2 * SUM(IIF([Event] = 'Address added',1,NULL)))
-
(
AVG(IIF([Screen] = 'Add address',[Time],NULL))
* SUM(IIF([Event] = 'Address added',1,NULL))
)
)
+
(
(2 * SUM(IIF([Event] = 'order created',1,NULL)))
-
(
AVG(IIF([Screen] = 'orders'
OR [Screen] = 'order detail'
OR [Screen] = 'order confirmation'
,[Time],NULL))
* SUM(IIF([Event] = 'order created',1,NULL))
)
)
You can account for filters in calculations. So for your first part, it could be something like the following:
(2*count(if [Event]='name submitted' then [number of records] end)) - avg(if [Event]='name submitted' then [time] end)*count(if [Event]='name submitted' then [number of records] end)
I'm not sure about your order of operations but you can adjust as needed. Repeat this format for your other calcs.
I am trying to create a Crystal Report. One of the parameters that it has, is a Boolean flag which change the groupings of the Report.
What I'm trying to do is to add 3 levels of grouping from a formula.
The code that I wrote is:
if {?summarized_detailed} = true then
'Store Code : ' + {SNV_SP_ProfitabilityAndBreakEvenPerStore;1.WhsCode}
else
if {?season_supplier} = true then
'Store Code : ' + {SNV_SP_ProfitabilityAndBreakEvenPerStore;1.WhsCode} + ChrW(10) + 'Season : ' + {SNV_SP_ProfitabilityAndBreakEvenPerStore;1.SEASON} + ChrW(10) + 'Brand : ' + {SNV_SP_ProfitabilityAndBreakEvenPerStore;1.BRAND}
else
'Store Code : ' + {SNV_SP_ProfitabilityAndBreakEvenPerStore;1.WhsCode} + ChrW(10) + 'Supplier : ' + {SNV_SP_ProfitabilityAndBreakEvenPerStore;1.CardCode} + ChrW(10) + 'Brand : ' + {SNV_SP_ProfitabilityAndBreakEvenPerStore;1.BRAND}
{?summarized_detailed} is the parameter (the flag for grouping).
if he chooses true, the report must have the columns -> Store Code , Season or Supplier (it based on another flag-parameter) and Brand.
Output Layer that I have :
Name of Col1 Name of Col2 Name of Col3
Store: Value for Store Code, Season or Supplier: Value for Season or Supplier, Brand: Value for Brand | total Brand Col1 total Brand Col2 total Brand Col3 ....
With this Code, I take the result that I want. All database's rows are separated according to those groups.
The problem is, that I want to have total sum for every column that I have in my report. But I can't do this, because the above formula, created only ONE union group. So, I can have a summary only for the details within every brand.
Output Layer that I want :
Name of Col1 Name of Col2 Name of Col3
Store: Value for Store Code |
Seas or Sup: Value for Season or Supplier |
Brand: Value for Brand | total Brand Col1 total Brand Col2 total Brand Col3
//when supplier or season within all groups changes (not included in report)
--------------------------------------------------------------------------------------------
Total Supplier or Season: total Sup/Season Col1 total Sup/Season Col2 total Sup/Seas Col3
//when store within all groups changes (not included in report)
Total Store: total Store Col1 total Store Col2 total Store Col3
---------------------------------------------------------------------------------------------
With total Brand Col1 I want to do a summary for all rows of details for each field of the same brand.
With total Supplier Col1 I want to sum all total Brands for each field of the same supplier.
With total Store Col1 I want to sum all total Suppliers for each field for every shop.
How can I compute those totals and display them only when Season or Supplier changes, and when Store changes with no regarding the change of the union Group ?
Or is there an easier and better way to make those 3 groups from formula according to the parameter but let them be separated so that I can control them and do my summarizes ?
This is how I handle this type of requirement:
If you want a maximum of 3 groups, but potentially less, then you need to create two different formula fields. In the report design, you set grouping to group on Store_Code first, then the other two formula fields.
If the refresh/runtime parameter will be FALSE for when you want the three-level grouping, then the formulas should look something like this:
Group1_Formula1: if {?param} = TRUE then '' else {Season}
Then the next:
Group2_Formula: if {?param} = TRUE then '' else {Brand}
If you want totals/subtotal the just place them as summary fields in the group headers, with conditional display to suppress them as necessary.
The result will be that, even though grouping on all three levels is always taking place, for the subgroups below the always-active "Store_Code" each subgroup will have only a single group of all records if the {?Param} = TRUE, effectively meaning there is no grouping happening.
One caveat: This presumes you aren't using print-time evaluation, e.g. before/after printing, etc., in any of the related formulas necessary to perform your grouping.
I have a Crystal Report with a formula on the page header like this:
dim t as string
t = "DD Waiver Waitlist "
if {rpt_xtab_waitlist.CountyName} = "statewide" then
t = t + {rpt_xtab_waitlist.CountyName}
else
t = t + "for " + {rpt_xtab_waitlist.CountyName} + " County"
end if
formula = t
The problem is not all counties have data for the report, but I still want the page header to contain the county name.
Ultimately, other staff puts a front-end on the report with a combo box for the parameter listing all of the counties, so the parameter UI will not come from Crystal. I can't just change the parameter to dynamic.
I thought I could use the county name from the parameter instead of the data, but that's in an array and I can't figure out how to index it.
I tried:
if {rpt_xtab_waitlist.CountyName} = "statewide" then
t = t + {?County}( RecordNumber)
else
t = t + "for " + {?County}( RecordNumber) + " County"
end if
but it doesn't print the county name corresponding to the selected county in the group tree.
How should I index a parameter array in a formula?
Thanks for any help,
-Beth
Sample county names:
Anoka
Hennepin
Yellow Medicine
Output I get now:
report with page header function suppressed when they select Yellow Medicine county as their parameter from the list of counties
Output I want to get:
report with page header function returning "DD Waiver Waitlist for Yellow Medicine County"
when Yellow Medicine county selection criteria applied returns 0 rows.
I don't think there is a useful index, and for our purposes, they can only select one county as a parameter, so I ended up using the (1) index of the parameter array.
If anyone knows of a way to derive a meaningful index, please post.