Identify first occurence of event based on multiple criterias - excel

I have a dataset in PowerPivot and need to find a way to flag ONLY the first occurrence of a customer sub event
Context: Each event (COLUMN A) can have X number of sub events (COLUMN B),
I already have a flag that identifies a customer event based on multiple criteria's (COLUMN D)... What I need is a way to flag only the first occurrence of a customer sub event within each event, I've added a fake COLUMN E to illustrate how the flagging should work.
UPDATE
Additional situation - Having duplicated customer sub_events but only need to flag the first sub_event... should look like this:

Create a calculated column in your model using the following expression:
=
IF (
[Customer_Event] = 1
&& [Sub_Event]
= CALCULATE (
FIRSTNONBLANK ( 'Table'[Sub_Event], 0 ),
FILTER (
'Table',
'Table'[Event] = EARLIER ( 'Table'[Event] )
&& [Customer_Event] = 1
)
),
1,
0
)
If Sub_Event column is a number replace FIRSTNONBLANK ( 'Table'[Sub_Event], 0 ) by MIN('Table'[Sub_Event])
Also if your machine regional settings use ; (semicolon) as list separator replace every , (comma) in my expression by a semicolon in order to match your settings.
UPDATE: Repeated values in Sub_Event column.
I think we can use CaseRow# column to get the first occurence of Sub_Event value:
=
IF (
[Customer_Event] = 1
&& [Sub_Event]
= CALCULATE (
FIRSTNONBLANK ( 'Table'[Sub_Event], 0 ),
FILTER (
'Table',
'Table'[Event] = EARLIER ( 'Table'[Event] )
&& [Customer_Event] = 1
)
)
&& [CaseRow#]
= CALCULATE (
MIN ( 'Table'[CaseRow#] ),
FILTER (
'Table',
'Table'[Event] = EARLIER ( 'Table'[Event] )
&& [Customer_Event] = 1
)
),
1,
0
)
It is not tested but should work.
Let me know if this helps.

Related

Dax Measure with multiple filters and all

I have a table that has the following structure:
Order
State
Order Date
Order Finished
Department
Area
Value
This table is linked to the calendar table through the column [Order Finished].
Now I would like to get every order - regardless the Order Finished Date with this filters:
State = > 16 && <> 20 <= 99
Department = Drilling
Area = FT1
Bow how?
This approach is not working:
CALCULATE ( SUM ( tbl[Value]),
ALL ( Calendar),
tbl[Department] = "Drilling",
tbl[Area] = "FT1",
tbl[Status] > 16 && <> 20 && <=99 )
Here is a screenshot of the tabel:
You can try this below code-
total_value =
CALCULATE (
SUM (tbl[Value]),
ALL (Calendar),
ALLEXCEPT(tbl,Department),
tbl[Department] = "Drilling",
tbl[Area] = "FT1",
tbl[Status] > 16,
tbl[Status] <> 20,
tbl[Status] <=99
)
If you need department wise different results, you should not have that department filter in the code as shown below-
total_value =
CALCULATE (
SUM (tbl[Value]),
ALL (Calendar),
FILTER(
ALLEXCEPT(tbl,Department),
&& tbl[Area] = "FT1",
&& tbl[Status] > 16,
&& tbl[Status] <> 20,
&& tbl[Status] <=99
)
)

SQL Server 2017 - Dynamically generate a string based on the number of columns in another string

I have the following table & data:
CREATE TABLE dbo.TableMapping
(
[GenericMappingKey] [nvarchar](256) NULL,
[GenericMappingValue] [nvarchar](256) NULL,
[TargetMappingKey] [nvarchar](256) NULL,
[TargetMappingValue] [nvarchar](256) NULL
)
INSERT INTO dbo.TableMapping
(
[GenericMappingKey]
,[GenericMappingValue]
,[TargetMappingKey]
,[TargetMappingValue]
)
VALUES
(
'Generic'
,'Col1Source|Col1Target;Col2Source|Col2Target;Col3Source|Col3Target;Col4Source|Col4Target;Col5Source|Col5Target;Col6Source|Col6Target'
,'Target'
,'Fruit|Apple;Car|Red;House|Bungalo;Gender|Female;Material|Brick;Solution|IT'
)
I would need to be able to automatically generate my GenericMappingValue string dynamically based on the number of column pairs in the TargetMappingValue column.
Currently, there are 6 column mapping pairs. However, if I only had two mapping column pairs in my TargetMapping such as the following...
'Fruit|Apple;Car|Red'
then I would like for the GenericMappingValue to be automatically generated (updated) such as the following since, as a consequence, I would only have 2 column pairs in my string...
'Col1Source|Col1Target;Col2Source|Col2Target'
I've started building the following query logic:
DECLARE #Mapping nvarchar(256)
SELECT #Mapping = [TargetMappingValue] from TableMapping
print #Mapping
SELECT count(*) ColumnPairCount
FROM String_split(#Mapping, ';')
The above query gives me a correct count of 6 for my column pairs.
How would I be able to continue my logic to achieve my automatically generated mapping string?
I think I understand what you are after. This should get you moving in the right direction.
Since you've tagged 2017 you can use STRING_AGG()
You'll want to split your TargetMappingValue using STRING_SPLIT() with ROW_NUMER() in a sub-query. (NOTE: We aren't guaranteed order using string_split() with ROW_NUMBER here, but will work for this situation. Example below using OPENJSON if we need to insure accurate order.)
Then you can then use that ROW_NUMBER() as the column indicator/number in a CONCAT().
Then bring it all back together using STRING_AGG()
Have a look at this working example:
DECLARE #TableMapping TABLE
(
[GenericMappingKey] [NVARCHAR](256) NULL
, [GenericMappingValue] [NVARCHAR](256) NULL
, [TargetMappingKey] [NVARCHAR](256) NULL
, [TargetMappingValue] [NVARCHAR](256) NULL
);
INSERT INTO #TableMapping (
[GenericMappingKey]
, [GenericMappingValue]
, [TargetMappingKey]
, [TargetMappingValue]
)
VALUES ( 'Generic'
, 'Col1Source|Col1Target;Col2Source|Col2Target;Col3Source|Col3Target;Col4Source|Col4Target;Col5Source|Col5Target;Col6Source|Col6Target'
, 'Target'
, 'Fruit|Apple;Car|Red;House|Bungalo;Gender|Female;Material|Brick;Solution|IT' );
SELECT [col].[GenericMappingKey]
, STRING_AGG(CONCAT('Col', [col].[ColNumber], 'Source|Col', [col].[ColNumber], 'Target'), ';') AS [GeneratedGenericMappingValue]
, [col].[TargetMappingKey]
, [col].[TargetMappingValue]
FROM (
SELECT *
, ROW_NUMBER() OVER ( ORDER BY (
SELECT 1
)
) AS [ColNumber]
FROM #TableMapping
CROSS APPLY STRING_SPLIT([TargetMappingValue], ';')
) AS [col]
GROUP BY [col].[GenericMappingKey]
, [col].[TargetMappingKey]
, [col].[TargetMappingValue];
Here's an example of what an update would look like assuming your primary key is the GenericMappingKey column:
--This what an update would look like
--Assuming your primary key is the [GenericMappingKey] column
UPDATE [upd]
SET [upd].[GenericMappingValue] = [g].[GeneratedGenericMappingValue]
FROM (
SELECT [col].[GenericMappingKey]
, STRING_AGG(CONCAT('Col', [col].[ColNumber], 'Source|Col', [col].[ColNumber], 'Target'), ';') AS [GeneratedGenericMappingValue]
, [col].[TargetMappingKey]
, [col].[TargetMappingValue]
FROM (
SELECT *
, ROW_NUMBER() OVER ( ORDER BY (
SELECT 1
)
) AS [ColNumber]
FROM #TableMapping
CROSS APPLY [STRING_SPLIT]([TargetMappingValue], ';')
) AS [col]
GROUP BY [col].[GenericMappingKey]
, [col].[TargetMappingKey]
, [col].[TargetMappingValue]
) AS [g]
INNER JOIN #TableMapping [upd]
ON [upd].[GenericMappingKey] = [g].[GenericMappingKey];
Shnugo brings up a great point in the comments in that we are not guarantee sort order with string_split() and using row number. In this particular situation it wouldn't matter as the output mappings in generic. But what if you needed to used elements from your "TargetMappingValue" column in the final "GenericMappingValue", then you would need to make sure sort order was accurate.
Here's an example showing how to use OPENJSON() and it's "key" which would guarantee that order using Shnugo example:
SELECT [col].[GenericMappingKey]
, STRING_AGG(CONCAT('Col', [col].[colNumber], 'Source|Col', [col].[colNumber], 'Target'), ';') AS [GeneratedGenericMappingValue]
, [col].[TargetMappingKey]
, [col].[TargetMappingValue]
FROM (
SELECT [tm].*
, [oj].[Key] + 1 AS [colNumber] --Use the key as our order/column number, adding 1 as it is zero based.
, [oj].[Value] -- and if needed we can bring the split value out.
FROM #TableMapping [tm]
CROSS APPLY OPENJSON('["' + REPLACE([tm].[TargetMappingValue], ';', '","') + '"]') [oj] --Basically turn the column value into JSON string.
) AS [col]
GROUP BY [col].[GenericMappingKey]
, [col].[TargetMappingKey]
, [col].[TargetMappingValue];
if the data is already in the table and you want to break it out into columns, this should work
select
v.value
,left(v.value, charindex('|',v.value) -1) col1
,reverse(left(reverse(v.value), charindex('|',reverse(v.value)) -1)) col2
from String_split(#mapping,';') v

DAX : Find process time & last operation from date/time difference

Need your help to find "Process Time" in hours and where it in last operation based on Max Operation number
DATEDIFF(
CALCULATE(
SUM(tableX[date/time]),
ALLEXCEPT(tableX,tableX[Operation],tableX[ID]),
tableX[date/time] <= EARLIER(tableX[date/time])
),
tableX[date/time],HOUR
)
I think you are looking for the following calculated column:
Process Time (Hours) = DATEDIFF(
CALCULATE(
MAX('tableX'[Date/Time]),
ALLEXCEPT(tableX,'tableX'[ID]),
'tableX'[date/time] < EARLIER('tableX'[date/time])
),
'tableX'[Date/Time],HOUR
)
This expression calculates the elapsed time sinds the previous step in the operation. If you want to calculate the elapsed time sinds the start of the operation, then simply change MAX('tableX'[Date/Time]) to MIN('tableX'[Date/Time]). Like this:
To create the last column, you can use this:
Last Operation =
IF (
'tableX'[Date/Time]
= CALCULATE ( MAX ( 'tableX'[Date/Time] ), ALLEXCEPT ( 'tableX', tableX[ID] ) ),
"Y",
"N"
)

MDX return caption as value

I got a following MDX query:
SELECT
NON EMPTY
[Measures].[Closed Events] ON COLUMNS
,NON EMPTY
Filter
(
{
[Date].[Year].&[2017]*
([Date].[Week Number].&[36] : [Date].[Week Number].&[52])*
[Visited Contact].[Contact SF Id].Children*
[Assignee].[Role Name].&[PL - Sales Rep HCP]
}
,
[Measures].[Closed Events] > 0
) ON ROWS
FROM [Visit Analysis];
How could I influence set within the filter so that I have both year and week number represented as numbers in excel (data table) and not strings?
What about measures?
With
Member [Measures].[Year] as
Cint([Date].[Year].CurrentMember.Name)
Member [Measures].[Weak] as
Cint([Date].[Week Number].CurrentMember.Name)
SELECT
NON EMPTY
{[Measures].[Closed Events],[Measure].[Year],[Measure].[Weak]} ON COLUMNS
,NON EMPTY
Filter
(
{
[Date].[Year].&[2017]*
([Date].[Week Number].&[36] : [Date].[Week Number].&[52])*
[Visited Contact].[Contact SF Id].Children*
[Assignee].[Role Name].&[PL - Sales Rep HCP]
}
,
[Measures].[Closed Events] > 0
) ON ROWS
FROM [Visit Analysis];

PowerPivot Filter Function

In PowerPivot Excel 2016 I write a formula to summarize year to date sales using filter function as below:
SalesYTD:=CALCULATE (
[Net Sales],
FILTER (
ALL ( Sales),
'sales'[Year] = MAX ( 'Sales'[Year] )
&& 'Sales'[Date] <= MAX ( 'Sales'[Date] )
)
)
And it's work perfectly, now in my data I have a field called "Channel" which I want to filter it in my pivot table but it won't works!
Does anybody knows how should I fix this formula?!
Thanks in advance...
Try:
SalesYTD:=CALCULATE (
[Net Sales],
FILTER (
ALLEXCEPT ( 'Sales', 'Sales'[Channel] ),
'sales'[Year] = MAX ( 'Sales'[Year] )
&& 'Sales'[Date] <= MAX ( 'Sales'[Date] )
)
)
ALLEXCEPT removes all context filters in the table except filters that have been applied to the specified columns, in this case [Channel] column.
Let me know if this helps.

Resources