First I think this is a complicated question to follow. Please see the Steps of my M code which I think will make it clearer.
So I am trying to achieve the following:
The idea is any text in the input box can be limited to relevant sections using the parameters table If the Text in the parameters box is Contained in the Text being searched. For me, at least the question is more complicated than it first appears. If required /interested Please see my explanation below:
Desired Output
Fundamentally I want a way of filtering the Input text, using the parameters box such that each line returned is contained only within the relevant sections of start1-End1, Start2-End2.
Ideally, you can use any part of the text to set the limits. So I could say Everything between SECTION1-2, and between lines 2 and 5. will returns lines 2-5.
Or you could say Everything between SECTION 1-3, lines 4-8. Will return lines 4-8. Note you could even say SECTION1-3, Lines 4 -SECTION 4 which would return lines 4 up to 14.
Finally you could even overlap sections and These should still be captured separately and the lines where overlap occurs should repeat in the output.
M Code:
Parameters:
let
Source = Excel.CurrentWorkbook(){[Name="Parameters"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Start1", type text}, {"End1", type text}, {"Start2", type text}, {"End2", type text}}),
#"Filled Down" = Table.FillDown(#"Changed Type",{"Start1", "End1"}),
#"Duplicated Column1" = Table.DuplicateColumn(#"Filled Down", "Start1", "Start1 - Copy"),
#"Duplicated Column2" = Table.DuplicateColumn(#"Duplicated Column1", "End1", "End1 - Copy"),
#"Duplicated Column3" = Table.DuplicateColumn(#"Duplicated Column2", "Start2", "Start2 - Copy"),
#"Duplicated Column4" = Table.DuplicateColumn(#"Duplicated Column3", "End2", "End2 - Copy"),
#"Added Custom" = Table.AddColumn(#"Duplicated Column4", "Custom", each "X"),
#"Merged Columns" = Table.CombineColumns(#"Added Custom",{"Start1", "Custom"},Combiner.CombineTextByDelimiter("+++", QuoteStyle.None),"Start1"),
#"Duplicated Column" = Table.DuplicateColumn(#"Merged Columns", "End1", "End1 - Copy.1"),
#"Merged Columns3" = Table.CombineColumns(#"Duplicated Column",{"Start1", "End1"},Combiner.CombineTextByDelimiter(",", QuoteStyle.None),"Search1"),
#"Added Custom1" = Table.AddColumn(#"Merged Columns3", "Custom", each "X"),
#"Added Custom3" = Table.AddColumn(#"Added Custom1", "Custom.1", each "X"),
#"Merged Columns1" = Table.CombineColumns(#"Added Custom3",{"Start2", "Custom"},Combiner.CombineTextByDelimiter("+++", QuoteStyle.None),"Start2"),
#"Merged Columns4" = Table.CombineColumns(#"Merged Columns1",{"End2", "Custom.1"},Combiner.CombineTextByDelimiter("+++", QuoteStyle.None),"End2"),
#"Merged Columns2" = Table.CombineColumns(#"Merged Columns4",{"Start2", "End2", "End1 - Copy.1"},Combiner.CombineTextByDelimiter(",", QuoteStyle.None),"Search2"),
#"Added Custom2" = Table.AddColumn(#"Merged Columns2", "Custom", each Table.FromColumns({Text.Split([Search1], ","), Text.Split([Search2], ",")})),
#"Removed Other Columns" = Table.SelectColumns(#"Added Custom2",{"Start1 - Copy", "End1 - Copy","Start2 - Copy","End2 - Copy","Custom"}),
#"Expanded Custom" = Table.ExpandTableColumn(#"Removed Other Columns", "Custom", {"Column1", "Column2"}, {"Search1", "Search2"}),
#"Split Column by Delimiter" = Table.SplitColumn(#"Expanded Custom", "Search1", Splitter.SplitTextByEachDelimiter({"+++"}, QuoteStyle.None, true), {"Search1", "Filter1"}),
#"Split Column by Delimiter1" = Table.SplitColumn(#"Split Column by Delimiter", "Search2", Splitter.SplitTextByEachDelimiter({"+++"}, QuoteStyle.None, true), {"Search2", "Filter2"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter1",{{"Search1", type text}, {"Filter1", type text}, {"Search2", type text}, {"Filter2", type text}}),
#"Filled Down1" = Table.FillDown(#"Changed Type1",{"Search1"}),
#"Sorted Rows" = Table.Sort(#"Filled Down1",{{"Filter1", Order.Ascending}}),
#"Replaced Value" = Table.ReplaceValue(#"Sorted Rows",null,"",Replacer.ReplaceValue,{"Filter1", "Search2", "Filter2"})
in
#"Replaced Value"
Text:
let
Source = Excel.CurrentWorkbook(){[Name="TextToSearch"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Text", type text}}),
Search1 = Table.AddColumn(#"Changed Type", "Search1", (x) => Table.SelectRows(Parameters, each Text.Contains(x[Text],[Search1], Comparer.OrdinalIgnoreCase))),
#"Expanded Search1" = Table.ExpandTableColumn(Search1, "Search1", {"Search1", "Filter1"}, {"Search1", "Filter1"}),
#"Filled Down" = Table.FillDown(#"Expanded Search1",{"Search1", "Filter1"}),
#"Filtered Rows" = Table.SelectRows(#"Filled Down", each ([Filter1] = "X")),
#"Removed Other Columns" = Table.SelectColumns(#"Filtered Rows",{"Text", "Search1"}),
Search2 = Table.AddColumn(#"Removed Other Columns", "Search2", (x) => Table.SelectRows(Parameters, each Text.Contains(x[Search1],[Search1], Comparer.OrdinalIgnoreCase) and Text.Contains(x[Text],[Search2], Comparer.OrdinalIgnoreCase))),
#"Removed Other Columns1" = Table.SelectColumns(Search2,{"Text", "Search2"}),
#"Expanded Search2" = Table.ExpandTableColumn(#"Removed Other Columns1", "Search2", {"Start1 - Copy", "End1 - Copy", "Start2 - Copy", "End2 - Copy", "Search2", "Filter2"}, {"Start1 - Copy", "End1 - Copy", "Start2 - Copy", "End2 - Copy", "Search2.1", "Filter2"}),
#"Filled Down1" = Table.FillDown(#"Expanded Search2",{"Search2.1", "Filter2"}),
#"Filtered Rows1" = Table.SelectRows(#"Filled Down1", each ([Filter2] = "X")),
#"Removed Other Columns2" = Table.SelectColumns(#"Filtered Rows1",{"Start1 - Copy", "End1 - Copy", "Start2 - Copy", "End2 - Copy", "Text"}),
#"Filled Down2" = Table.FillDown(#"Removed Other Columns2",{"Start1 - Copy", "End1 - Copy", "Start2 - Copy", "End2 - Copy", "Text"}),
#"Renamed Columns" = Table.RenameColumns(#"Filled Down2",{{"Start1 - Copy", "Start1"}, {"End1 - Copy", "End1"}, {"Start2 - Copy", "Start2"}, {"End2 - Copy", "End2"}})
in
#"Renamed Columns"
Real Example:
https://1drv.ms/x/s!AsrLaUgt0KCLvUgQQctfMtFe057l?e=AkbeP3
Here you go.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCnZ1DvH091MwVNKBs42A7JzMvFSwIJhhohSrE60E5MEE4EpMwTLIOmFsY7gpBnCWIYpqUyTVpnCT4aqNjJRiYwE=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Start1 = _t, End1 = _t, Start2 = _t, End2 = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Start1", type text}, {"End1", type text}, {"Start2", type text}, {"End2", type text}}),
#"Replaced Value" = Table.ReplaceValue(#"Changed Type","",null,Replacer.ReplaceValue,{"Start1", "End1"}),
#"Filled Down" = Table.FillDown(#"Replaced Value",{"Start1", "End1"}),
#"Added Custom" = Table.AddColumn(#"Filled Down", "Custom", each let
input = Input[Text],
s1 = List.PositionOf(input, [Start1]),
e1 = List.PositionOf(input, [End1]),
r1 = if s1=e1 then List.Range(input,s1) else List.Range(input,s1,e1-s1+1),
s2 = List.PositionOf(r1, [Start2]),
e2 = List.PositionOf(r1, [End2]),
r2 = List.Range(r1,s2,e2-s2+1)
in r2),
#"Expanded Custom" = Table.ExpandListColumn(#"Added Custom", "Custom")
in
#"Expanded Custom"
Here it is with partial matches.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8kjNUdJRCnZ1DvH091MwArJzMvNSFQxhDBOlWJ1oJSAPJgBXYgqWQdYJYxvDTTGAswxRVJsiqTaFmwxXbWSkFBsLAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Start1 = _t, End1 = _t, Start2 = _t, End2 = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Start1", type text}, {"End1", type text}, {"Start2", type text}, {"End2", type text}}),
#"Replaced Value" = Table.ReplaceValue(#"Changed Type","",null,Replacer.ReplaceValue,{"Start1", "End1"}),
#"Filled Down" = Table.FillDown(#"Replaced Value",{"Start1", "End1"}),
#"Added Custom" = Table.AddColumn(#"Filled Down", "Custom", each let
input = Input[Text],
s1 = List.PositionOf(input, List.FindText(input,[Start1]){0}),
e1 = List.PositionOf(input, List.FindText(input,[End1]){0}),
r1 = if s1=e1 then List.Range(input,s1) else List.Range(input,s1,e1-s1+1),
s2 = List.PositionOf(r1, List.FindText(input,[Start2]){0}),
e2 = List.PositionOf(r1, List.FindText(input,[End2]){0}),
r2 = List.Range(r1,s2,e2-s2+1)
in r2),
#"Expanded Custom" = Table.ExpandListColumn(#"Added Custom", "Custom")
in
#"Expanded Custom"
Related
EMI Calculation:
Number.Round((rate/12*pv)/(1-Number.Power(1+rate/12,-nper)),0)
where PV is initial loan amount
Rate is the initial rate of interest at the beginning
and nper is 180 = Tenure in months
here the EMI = 107485
Keeping EMI Fixed, now i need to compute monthly interest and principal
The interest calculated formula will be
Previous balance * Rate of interest/12 * no. of days / no of days in the previous month
So if there is no rate change the interest will be prev bal * rate of interest /12 else it will be for the no of days new interest rate applicable.
Principal = EMI-Interest paid
New Balance = Previous Balance - Principal
Amount
What i am not able to achieve is :
Every time Interest is calculated, i want to refer to the previous balance which is not available.
I have tried creating Recursive functions to compute Interest, principal and balance columns:
Below function computes EMI value at the beginning
PMT
(pv,rate,nper)=>
let
payment = Number.Round((rate/12*pv)/(1-Number.Power(1+rate/12,-nper)),0)
in
payment
Below function computes Interest amount (Index Value is the row number / payment no)
Get_InterestValue
(indexValue,table,rate,no_of_days,no_of_days_in_Month)=>
let
prev_idx=indexValue-1,
previousbal = get_previous_balance(indexValue,table),
interest=previousbal*rate/12/no_of_days_in_Month*no_of_days
in
interest
Below function computes Principal amount paid
GetPrincipalPaid
(indexvalue,table,EMI_amount,Interest_amount)=>
let
principal_amount= EMI_amount-Interest_amount
in
principal_amount
Below function computes Previous balance
get_previous_balance
(index_value,table)=>
let
prev_idx=index_value-1,
prev_bal=if prev_idx=0 then fParameter("ParameterTable","Initial_Loan_Amount") else Table.SelectRows(table, each ([Index] = prev_idx)){0}[Bal]
in
prev_bal
fParameter function reads the intial values table
The columns gives errors
I have found a solution as in following code:
Now I am facing performance issue. Below solution works good with 10 Months or smaller. once u go for a higher Tenure, the calculations are very slow and doesnt generate any output for long time or probably crashes before calculations are completed,
is there any way i can speed up the query processing?
PMT Function:
(pv,rate,nper)=>
let
payment = Number.Round((rate/12*pv)/(1-Number.Power(1+rate/12,-nper)),0)
in
payment
fParameter Function:
let Parameter=(TableName,ParameterLabel) =>
let
Source=Excel.CurrentWorkbook(){[Name=TableName]}[Content],
value=Source{[Parameter=ParameterLabel]}[Value]
in
value
in Parameter
Payment Schedule Query:
let
Custom1 = List.Generate(()=>Date.Month(fParameter("ParameterTable","StartDate")),each _<=fParameter("ParameterTable","Tenure_in_Months")*1.5+Date.Month(fParameter("ParameterTable","StartDate"))-1,each _+1),
#"Converted to Table" = Table.FromList(Custom1, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Added Custom" = Table.AddColumn(#"Converted to Table", "Month", each if Number.Mod([Column1],12)=0 then 12 else Number.Mod([Column1],12)),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "Year1", each Date.Year(fParameter("ParameterTable","StartDate"))+Number.RoundDown([Column1]/12)),
#"Added Custom2" = Table.AddColumn(#"Added Custom1", "Year", each if [Month]=12 then [Year1]-1 else [Year1]),
#"Renamed Columns1" = Table.RenameColumns(#"Added Custom2",{{"Column1", "PaymentMonth"}}),
#"Added Custom3" = Table.AddColumn(#"Renamed Columns1", "Payment Date", each #date([Year],[Month],Date.Day(fParameter("ParameterTable","StartDate")))),
#"Removed Other Columns" = Table.SelectColumns(#"Added Custom3",{"Payment Date"}),
#"Changed Type" = Table.TransformColumnTypes(#"Removed Other Columns",{{"Payment Date", type date}}),
#"Added Custom4" = Table.AddColumn(#"Changed Type", "EMI", each EMIValue),
#"Merged Queries" = Table.NestedJoin(#"Added Custom4",{"Payment Date"},Loan_Rates,{"Date"},"Loan_Rates",JoinKind.FullOuter),
#"Expanded Loan_Rates" = Table.ExpandTableColumn(#"Merged Queries", "Loan_Rates", {"Date", "Loan Rate"}, {"Date", "Loan Rate"}),
#"Added Custom5" = Table.AddColumn(#"Expanded Loan_Rates", "New_Date", each if [Date] = null then [Payment Date] else [Date]),
#"Sorted Rows" = Table.Sort(#"Added Custom5",{{"New_Date", Order.Ascending}}),
#"Filled Down" = Table.FillDown(#"Sorted Rows",{"Loan Rate"}),
#"Removed Columns" = Table.RemoveColumns(#"Filled Down",{"Payment Date", "Date"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"New_Date", "Payment Date"}}),
#"Reordered Columns" = Table.ReorderColumns(#"Renamed Columns",{"Payment Date", "EMI", "Loan Rate"}),
#"Added Index" = Table.AddIndexColumn(#"Reordered Columns", "Index", 0, 1),
#"Added Index1" = Table.AddIndexColumn(#"Added Index", "Index.1", 1, 1),
#"Merged Queries1" = Table.NestedJoin(#"Added Index1",{"Index"},#"Added Index1",{"Index.1"},"Added Index1",JoinKind.LeftOuter),
#"Expanded Added Index1" = Table.ExpandTableColumn(#"Merged Queries1", "Added Index1", {"Payment Date"}, {"Payment Date.1"}),
#"Added Custom7" = Table.AddColumn(#"Expanded Added Index1", "Payment.Date.2", each if [Index.1]=1 then fParameter("ParameterTable","Disbursement Date") else [Payment Date.1]),
#"Changed Type1" = Table.TransformColumnTypes(#"Added Custom7",{{"Payment.Date.2", type date}}),
#"Removed Columns2" = Table.RemoveColumns(#"Changed Type1",{"Payment Date.1"}),
#"Renamed Columns2" = Table.RenameColumns(#"Removed Columns2",{{"Payment.Date.2", "Payment Date.1"}}),
#"Added Custom6" = Table.AddColumn(#"Renamed Columns2", "Days", each [Payment Date]-[Payment Date.1]),
#"Extracted Days" = Table.TransformColumns(#"Added Custom6",{{"Days", Duration.Days, Int64.Type}}),
#"Added Custom8" = Table.AddColumn(#"Extracted Days", "No Of Days in Month", each Date.EndOfMonth([Payment Date.1])-Date.StartOfMonth([Payment Date.1])+#duration(1,0,0,0)),
#"Removed Columns1" = Table.RemoveColumns(#"Added Custom8",{"Index", "Payment Date.1"}),
#"Extracted Days1" = Table.TransformColumns(#"Removed Columns1",{{"No Of Days in Month", Duration.Days, Int64.Type}}),
#"Reordered Columns1" = Table.ReorderColumns(#"Extracted Days1",{"Payment Date", "Days", "EMI", "Loan Rate"}),
#"Renamed Columns3" = Table.RenameColumns(#"Reordered Columns1",{{"Index.1", "Index"}}),
#"Reordered Columns2" = Table.ReorderColumns(#"Renamed Columns3",{"Index", "Payment Date", "EMI", "No Of Days in Month", "Days", "Loan Rate"}),
#"Replaced Value" = Table.ReplaceValue(#"Reordered Columns2",null,0,Replacer.ReplaceValue,{"EMI"}),
#"Invoked Custom Function" = Table.AddColumn(#"Replaced Value", "Interest", each Get_InterestValue([Index], Table.Buffer(#"Replaced Value"))),
#"Added Custom9" = Table.AddColumn(#"Invoked Custom Function", "Principal", each [EMI]-[Interest]),
#"Added Custom11" = Table.AddColumn(#"Added Custom9", "Balance", each fParameter("ParameterTable","Initial_Loan_Amount")-List.Sum(List.FirstN(#"Added Custom9"[Principal],[Index]))),
#"Filtered Rows" = Table.SelectRows(#"Added Custom11", each [Interest] > 0)
in
#"Filtered Rows"
Loan_Rates table Query == This reads change of loan rates over a period:
let
Source = Excel.CurrentWorkbook(){[Name="Loan_Rates"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Date", type date}, {"Loan Rate", Percentage.Type}})
in
#"Changed Type"
Get_InterestValue Function
(indexValue,table)=>
let
prev_idx=indexValue-1,
rate=Table.SelectRows(table, each ([Index] = indexValue)){0}[Loan Rate],
no_of_days_in_Month=Table.SelectRows(table, each ([Index] = indexValue)){0}[No Of Days in Month],
no_of_days=Table.SelectRows(table, each ([Index] = indexValue)){0}[Days],
previousbal = get_previous_balance(indexValue,table),
interest=previousbal*rate/12/no_of_days_in_Month*no_of_days
in
interest
GetPrincipalPaid Function:
(indexValue,table)=>
let
EMI_Amount=Table.SelectRows(table, each ([Index] = indexValue)){0}[EMI],
principal_amount= EMI_Amount-Get_InterestValue(indexValue,table)
in
principal_amount
GetBalance Function:
(indexValue,table)=>
let
bal = get_previous_balance(indexValue,table)-GetPrincipalPaid(indexValue,table)
in
bal
get_previous_balance function:
(indexValue,table)=>
let
prev_idx=indexValue-1,
prev_bal=if prev_idx=0 then fParameter("ParameterTable","Initial_Loan_Amount") else GetBalance(prev_idx,table)
in
prev_bal
EMIValue Function:
let
Source = PMT(fParameter("ParameterTable","Initial_Loan_Amount"), fParameter("ParameterTable","Rate_int_PA"), fParameter("ParameterTable","Tenure_in_Months")),
#"Converted to Table" = #table(1, {{Source}}),
#"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "EMI"}}){0}[EMI]
in
#"Renamed Columns"
I am attempting to extract section heading numbers from a column in excel using power query.
I have already achieved this by matching with an existing list. However, I wonder if there is a better way to achieve this in fewer steps.
M Code:
let
Source = Excel.CurrentWorkbook(){[Name="Table7"]}[Content],
#"Trimmed Text1" = Table.TransformColumns(Source,{{"Column1", PowerTrim, type text}}),
SectionNumbers = Table.AddColumn(#"Trimmed Text1", "SectionNumber", (x) => Text.Combine(Table.SelectRows(SectionNumbers, each Text.Contains(x[Column1],[SectionNumbers], Comparer.OrdinalIgnoreCase))[SectionNumbers],", ")),
#"Split Column by Delimiter2" = Table.SplitColumn(SectionNumbers, "SectionNumber", Splitter.SplitTextByEachDelimiter({","}, QuoteStyle.None, true), {"SectionNumber.1", "SectionNumber.2"}),
#"Added Custom1" = Table.AddColumn(#"Split Column by Delimiter2", "Custom", each if [SectionNumber.2] = null then [SectionNumber.1] else [SectionNumber.2]),
#"Removed Other Columns" = Table.SelectColumns(#"Added Custom1",{"Column1", "Custom"})
in
#"Removed Other Columns"
The Section numbers being matched to can be generated using:
SectionNumbers
let
Source = {1..16},
#"Converted to Table" = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Added Custom" = Table.AddColumn(#"Converted to Table", "Custom", each {1..9}),
#"Expanded Custom" = Table.ExpandListColumn(#"Added Custom", "Custom"),
#"Added Custom1" = Table.AddColumn(#"Expanded Custom", "Custom.1", each "."),
#"Merged Columns" = Table.CombineColumns(Table.TransformColumnTypes(#"Added Custom1", {{"Custom", type text}}, "en-GB"),{"Custom", "Custom.1"},Combiner.CombineTextByDelimiter("", QuoteStyle.None),"Merged"),
#"Merged Columns1" = Table.CombineColumns(Table.TransformColumnTypes(#"Merged Columns", {{"Column1", type text}}, "en-GB"),{"Column1", "Merged"},Combiner.CombineTextByDelimiter(".", QuoteStyle.None),"SectionNumbers")
in
#"Merged Columns1"
Essentially I would like a way of extracting any decimal at the start of a cell, either 15.0. or 15.0, or even 15.0.1 etc.
I have considered using regex i.e. \d+\.\d+[.] which should work however I have many rows and find that regex sometimes is computationally intensive in this case, so it takes much longer to load than the Above M Code.
Another power query method
Since you know your section numbers you could:
Generate a (buffered) list of all the section numbers
see if the first space-separated part of the string in column 1 exists in the Section Number list.
let
Source = Excel.CurrentWorkbook(){[Name="Table3"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", type text}}),
//create list of all serial numbers
SerialNumbers = List.Buffer(
let
Part1 = List.Transform({1..16}, each Text.From(_) & "."),
Part2 =List.Transform({1..10}, each Text.From(_) & "."),
sn = List.Accumulate(Part1,{}, (state, current)=> state &
List.Generate(
()=>[s=current & Part2{0}, idx=0],
each [idx] < List.Count(Part2),
each [s=current & Part2{[idx]+1}, idx=[idx]+1],
each [s]))
in
sn),
#"Added Custom" = Table.AddColumn(#"Changed Type", "Custom", each
let
x = Text.Split([Column1]," "){0}
in
if List.Contains(SerialNumbers,x) then x else null, type text)
in
#"Added Custom"
How about
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Added Custom" = Table.AddColumn(Source, "Custom", each if Text.PositionOfAny([Column1], {"0".."9"})>=0 then Text.BeforeDelimiter(Text.From([Column1])," ") else null)
in #"Added Custom"
I wish to generate the Most common, Highest and Lowest values from the following data:
I have also added an additional column to handle text comments.
M Code so far:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", type any}, {"Column2", type any}, {"Column3", type any}, {"Column4", type any}, {"Column5", type any}, {"Column6", type any}}),
#"Added Index" = Table.AddIndexColumn(#"Changed Type", "Index", 0, 1, Int64.Type),
#"Added Custom" = Table.AddColumn(#"Added Index", "Most Common", each List.Mode(
Record.ToList(
Table.SelectColumns(#"Added Index",
List.RemoveFirstN(
Table.ColumnNames(#"Changed Type"))){[Index]}))),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "Highest", each List.Max(
Record.ToList(
Table.SelectColumns(#"Added Index",
List.RemoveFirstN(
Table.ColumnNames(#"Changed Type"))){[Index]}))),
#"Added Custom2" = Table.AddColumn(#"Added Custom1", "Min", each List.Min(
Record.ToList(
Table.SelectColumns(#"Added Index",
List.RemoveFirstN(
Table.ColumnNames(#"Changed Type"))){[Index]}))),
#"Removed Other Columns" = Table.SelectColumns(#"Added Custom2",{"Most Common", "Highest", "Min"})
in
#"Removed Other Columns"
As shown in the image this isn't quite right for the following errors:
When there is an equal split the most common returns null (expected)
Text pulls through as the highest value (not expected)
Will be working on this but any suggestions are appreciated.
Assuming:
You made a mistake on row 7 and 'Not Limited' should be amongst the most frequent values;
You also want to know that 33 is the lowest value in row 12, not just the highest;
You can possibly have multiple unique text values you'd like to concatenate.
let
Source = Excel.CurrentWorkbook(){[Name="Tabel1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", type text}, {"Column2", type text}, {"Column3", type text}, {"Column4", type text}, {"Column5", type text}, {"Column6", type text}}),
#"Added Custom1" = Table.AddColumn(#"Changed Type", "Lists", each Text.Split(Text.Combine({[Column1],[Column2],[Column3],[Column4],[Column5],[Column6]},"|"),"|")),
#"Added Custom" = Table.AddColumn(#"Added Custom1", "Most Common", each Text.Combine(List.Modes([Lists]),",")),
#"Added Custom2" = Table.AddColumn(#"Added Custom", "Highest", each List.Max(List.Transform([Lists], each try Number.FromText(_) otherwise null))),
#"Added Custom3" = Table.AddColumn(#"Added Custom2", "Lowest", each List.Min(List.Transform([Lists], each try Number.FromText(_) otherwise null))),
#"Added Custom4" = Table.AddColumn(#"Added Custom3", "Text Comments", each Text.Combine(List.Distinct(List.RemoveMatchingItems(List.Transform([Lists], each try if Number.FromText(_) <>"" then "" else "" otherwise (_)),{""})),",")),
#"Replaced Errors" = Table.ReplaceErrorValues(#"Added Custom4", {{"Highest", null}, {"Lowest", null}}),
#"Removed Columns" = Table.RemoveColumns(#"Replaced Errors",{"Column1", "Column2", "Column3", "Column4", "Column5", "Column6", "Lists"})
in
#"Removed Columns"
Steps:
All columns to "Type Text";
Created an helper column with lists of values after Text.Combine & Text.Split combo;
Used List.Modes to return most common values inside a Text.Combine to return 'Most Common';
Used List.Max and List.Min in combination with List.Transform to return 'Highest' and 'Lowest' value;
Used a combination of Text.Combine, List.Distinct, List.RemoveMatchingItems and List.Transform to return only unique actual text values;
Removed columns1-6 and helper and replaced errors with 'null'.
I'm working on a simplification of some of my reports by using Power Query.
I have a table with this structure:
In the first column we can see the Sales Order Number.
In the second column we can see the Message type. If it is a XR or PR Message.
And in the last column we can find the Key for the status:
A = Active
B = Active
C = Closed
With this logic I would like to get this result table:
This way I can see as a cross table the type and the state per sales order.
How is this possible by using Power Query?
Are you sure about your results for Sales Order 103?
Try the following M code, amending where necessary (Source step, for example):
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
XRCol = Table.AddColumn(
Source,
"XR",
each Text.BeforeDelimiter([Message], "-") = "XR",
type logical
),
PRCol = Table.AddColumn(
XRCol,
"PR",
each Text.BeforeDelimiter([Message], "-") = "PR",
type logical
),
XRActCol = Table.AddColumn(PRCol, "XR Active", each [XR] and [Key] <> "C", type logical),
PRActCol = Table.AddColumn(XRActCol, "PR Active", each [PR] and [Key] <> "C", type logical),
RemoveCols = Table.RemoveColumns(PRActCol, {"Message", "Key"}),
Group = Table.Group(
RemoveCols,
{"Sales Order"},
{
{"XR", each List.Max([XR]), type logical},
{"PR", each List.Max([PR]), type logical},
{"XR Active", each List.Max([XR Active]), type logical},
{"PR Active", each List.Max([PR Active]), type logical}
}
)
in
Group
If I see it correctly your output PR and XR is mixed up in Sales order 103.
Try if this works for you:
let
Source = Excel.Workbook(File.Contents("C:\Users\maitting\Documents\Mappe1.xlsx"), null, true),
Tabelle1_Sheet = Source{[Item="Tabelle1",Kind="Sheet"]}[Data],
#"Promoted Headers" = Table.PromoteHeaders(Tabelle1_Sheet, [PromoteAllScalars=true]),
#"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers",{{"Sales Order", Int64.Type}, {"Message", type text}, {"Key", type text}}),
#"Split Column by Delimiter" = Table.SplitColumn(#"Changed Type", "Message", Splitter.SplitTextByDelimiter("-", QuoteStyle.Csv), {"Message"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Message", type text}}),
#"Replaced Value" = Table.ReplaceValue(#"Changed Type1","A","Active",Replacer.ReplaceText,{"Key"}),
#"Replaced Value1" = Table.ReplaceValue(#"Replaced Value","B","Active",Replacer.ReplaceText,{"Key"}),
#"Replaced Value2" = Table.ReplaceValue(#"Replaced Value1","C","Closed",Replacer.ReplaceText,{"Key"}),
#"Merged Columns" = Table.CombineColumns(#"Replaced Value2",{"Message", "Key"},Combiner.CombineTextByDelimiter(" - ", QuoteStyle.None),"Merged"),
#"Unpivoted Columns" = Table.UnpivotOtherColumns(#"Merged Columns", {"Sales Order"}, "Attribute", "Value"),
#"Pivoted Column" = Table.Pivot(#"Unpivoted Columns", List.Distinct(#"Unpivoted Columns"[Value]), "Value", "Attribute", List.Count),
#"Added Conditional Column" = Table.AddColumn(#"Pivoted Column", "XR",
each if [#"XR - Active"] = 1 then 1
else if [#"XR - Closed"] = 1 then 1
else 0),
#"Added Conditional Column1" = Table.AddColumn(#"Added Conditional Column", "PR",
each if [#"PR - Active"] = 1 then 1
else if [#"PR - Closed"] = 1 then 1
else 0),
#"Removed Columns" = Table.RemoveColumns(#"Added Conditional Column1",{"XR - Closed", "PR - Closed"}),
#"Reordered Columns" = Table.ReorderColumns(#"Removed Columns",{"Sales Order", "XR", "PR", "XR - Active", "PR - Active"}),
#"Changed Type2" = Table.TransformColumnTypes(#"Reordered Columns",{{"XR", type logical}, {"PR", type logical}, {"XR - Active", type logical}, {"PR - Active", type logical}})
in
#"Changed Type2"
Output:
I've just added Sales order 104 with PR Closed to handle all possible cases.
My version
let Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
RemoveEndingColumn = Table.TransformColumns(Source,{{"Message", each Text.BeforeDelimiter(_, "-"), type text}}),
#"Create MessageKey" = Table.AddColumn(RemoveEndingColumn, "MessageKey", each [Message]&" "&[Key]),
StackColumns = Table.RenameColumns(Table.SelectColumns(#"Create MessageKey",{"Sales Order", "Message"}),{{"Message", "Column"}})& Table.RenameColumns(Table.SelectColumns(#"Create MessageKey",{"Sales Order", "MessageKey"}),{{"MessageKey", "Column"}}),
#"Added Custom1" = Table.AddColumn(StackColumns, "TrueFalse", each true, type logical),
#"Pivoted Column" = Table.Pivot(#"Added Custom1", List.Distinct(#"Added Custom1"[Column]), "Column", "TrueFalse")
in #"Pivoted Column"
I am currently shaping my data. I have one column called "Centro". However, there are so many duplicate texts in just one cell. How Can I remove the duplicate texts and only show distinct texts? Anyone can help on this?Thanks!!
This is my code:
let
Source = Etapa_2_Caricam,
#"Grouped Rows" = Table.Group(Source, {"Material"}, {{"mynewtable", each _, type table [Material=number, Num Form=text, Created on=date, FechaCreac=date, Initiator=text, Texto tarea=text]}}),
#"Added Custom" = Table.AddColumn(#"Grouped Rows", "NoForm", each Table.Column([mynewtable],"Num Form")),
#"Extracted Values" = Table.TransformColumns(#"Added Custom", {"NoForm", each Text.Combine(List.Transform(_, Text.From), ", "), type text}),
#"Added Custom1" = Table.AddColumn(#"Extracted Values", "Iniciador", each Table.Column([mynewtable],"Initiator")),
#"Extracted Values1" = Table.TransformColumns(#"Added Custom1", {"Iniciador", each Text.Combine(List.Transform(_, Text.From), ", "), type text}),
#"Extracted Text Before Delimiter" = Table.TransformColumns(#"Extracted Values1", {{"Iniciador", each Text.BeforeDelimiter(_, ", "), type text}}),
#"Added Custom2" = Table.AddColumn(#"Extracted Text Before Delimiter", "FechaInicio", each Table.Column([mynewtable],"Created on")),
#"Extracted Values2" = Table.TransformColumns(#"Added Custom2", {"FechaInicio", each Text.Combine(List.Transform(_, Text.From), ", "), type text}),
#"Extracted Text Before Delimiter1" = Table.TransformColumns(#"Extracted Values2", {{"FechaInicio", each Text.BeforeDelimiter(_, ", "), type text}}),
#"Added Custom3" = Table.AddColumn(#"Extracted Text Before Delimiter1", "FechaFinalTarea", each let dates = Table.Column([mynewtable],"FechaCreac") in [min = List.Min(dates), max = List.Max(dates)]),
expanded = Table.ExpandRecordColumn(#"Added Custom3", "FechaFinalTarea", {"min", "max"}),
#"Changed Type" = Table.TransformColumnTypes(expanded,{{"min", type date}, {"max", type date}, {"FechaInicio", type date}}),
#"Added Custom4" = Table.AddColumn(#"Changed Type", "TextoTarea", each Table.Column([mynewtable],"Texto tarea")),
#"Extracted Values3" = Table.TransformColumns(#"Added Custom4", {"TextoTarea", each Text.Combine(List.Transform(_, Text.From), ", "), type text}),
#"Changed Type1" = Table.TransformColumnTypes(#"Extracted Values3",{{"Material", type text}}),
#"Split Column by Delimiter" = Table.SplitColumn(Table.TransformColumnTypes(#"Changed Type1", {{"FechaInicio", type text}}, "en-US"), "FechaInicio", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"FechaInicio.1", "FechaInicio.2", "FechaInicio.3"}),
#"Changed Type2" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"FechaInicio.1", Int64.Type}, {"FechaInicio.2", Int64.Type}, {"FechaInicio.3", Int64.Type}}),
#"Renamed Columns" = Table.RenameColumns(#"Changed Type2",{{"FechaInicio.2", "FID"}, {"FechaInicio.1", "FIM"}, {"FechaInicio.3", "FIA"}}),
#"Changed Type3" = Table.TransformColumnTypes(#"Renamed Columns",{{"FIM", type text}, {"FID", type text}, {"FIA", type text}}),
#"Added Custom5" = Table.AddColumn(#"Changed Type3", "FechaInicio", each [FID]&"/"&[FIM]&"/"&[FIA]),
#"Changed Type4" = Table.TransformColumnTypes(#"Added Custom5",{{"FechaInicio", type date}}),
#"Removed Columns1" = Table.RemoveColumns(#"Changed Type4",{"FIM", "FID", "FIA"}),
#"Reordered Columns" = Table.ReorderColumns(#"Removed Columns1",{"Material", "mynewtable", "NoForm", "Iniciador", "FechaInicio", "min", "max", "TextoTarea"}),
#"Split Column by Delimiter1" = Table.SplitColumn(Table.TransformColumnTypes(#"Reordered Columns", {{"max", type text}}, "en-US"), "max", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"max.1", "max.2", "max.3"}),
#"Changed Type5" = Table.TransformColumnTypes(#"Split Column by Delimiter1",{{"max.1", type text}, {"max.2", type text}, {"max.3", type text}}),
#"Added Custom6" = Table.AddColumn(#"Changed Type5", "FechaFinal", each [max.2]&"/"&[max.1]&"/"&[max.3]),
#"Reordered Columns1" = Table.ReorderColumns(#"Added Custom6",{"Material", "mynewtable", "NoForm", "Iniciador", "FechaInicio", "FechaFinal", "min", "max.1", "max.2", "max.3", "TextoTarea"}),
#"Changed Type6" = Table.TransformColumnTypes(#"Reordered Columns1",{{"FechaFinal", type date}}),
#"Removed Columns2" = Table.RemoveColumns(#"Changed Type6",{"max.1", "max.2", "max.3"}),
#"Changed Type7" = Table.TransformColumnTypes(#"Removed Columns2",{{"FechaFinal", type text}, {"FechaInicio", type text}}),
#"Added Custom7" = Table.AddColumn(#"Changed Type7", "Table", each Table.Column([mynewtable],"NoMatAnt")),
#"Extracted Values4" = Table.TransformColumns(#"Added Custom7", {"Table", each Text.Combine(List.Transform(_, Text.From), ", "), type text}),
#"Inserted Text Before Delimiter" = Table.AddColumn(#"Extracted Values4", "Text Before Delimiter", each Text.BeforeDelimiter([Table], ", "), type text),
#"Removed Columns3" = Table.RemoveColumns(#"Inserted Text Before Delimiter",{"Text Before Delimiter"}),
#"Extracted Text Before Delimiter2" = Table.TransformColumns(#"Removed Columns3", {{"Table", each Text.BeforeDelimiter(_, ", "), type text}}),
#"Duplicated Column" = Table.DuplicateColumn(#"Extracted Text Before Delimiter2", "Table", "Table - Copy"),
#"Replaced Value" = Table.ReplaceValue(#"Duplicated Column","CR","",Replacer.ReplaceText,{"Table - Copy"}),
#"Replaced Value1" = Table.ReplaceValue(#"Replaced Value","DO","",Replacer.ReplaceText,{"Table - Copy"}),
#"Replaced Value2" = Table.ReplaceValue(#"Replaced Value1","GT","",Replacer.ReplaceText,{"Table - Copy"}),
#"Replaced Value3" = Table.ReplaceValue(#"Replaced Value2","PR","",Replacer.ReplaceText,{"Table - Copy"}),
#"Renamed Columns1" = Table.RenameColumns(#"Replaced Value3",{{"Table - Copy", "No.FormAnt"}, {"Table", "No.MatAnt"}}),
#"Trimmed Text" = Table.TransformColumns(#"Renamed Columns1",{{"TextoTarea", Text.Trim, type text}}),
#"Added Custom8" = Table.AddColumn(#"Trimmed Text", "Centro", each Table.Column([mynewtable],"Ce")),
#"Extracted Values5" = Table.TransformColumns(#"Added Custom8", {"Centro", each Text.Combine(List.Transform(_, Text.From), ", "), type text})
in
#"Extracted Values5"
The easiest way to do this would be to split the comma separated values (Centro field), into different rows and then remove duplicates. Then you can group them up again to get the comma separated values. For the purpose of demonstrating, I created a table with two fields: PrimaryKey and Centro. Then I used the following steps to get to the desired output:
Source Information:
= Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMlTSUUrUSdJJUorViVYyAvKSdVJ0knWSlWJjAQ==", BinaryEncoding.Base64), Compression.Deflate)),
let _t = ((type text) meta [Serialized.Text = true]) in type table [PrimaryKey = _t, Centro = _t])
Split Column By delimiter (You can do this by selecting the "Split Column - By Delimiter" option in the Transform tab, you have to choose the Centro field before selecting this option):
= Table.ExpandListColumn(Table.TransformColumns(Source, {{"Centro", Splitter.SplitTextByDelimiter(",")}}), "Centro")
Remove Duplicates (You can do this by choosing "Remove Rows - Remove Duplicates" from the Home tab, make sure you choose all the columns before selecting this option):
= Table.Distinct(#"Split Column by Delimiter")
Grouped Rows (You can do this by choosing the "Group By" option in the transform tab, but you would have to edit the query a little to use the delimiter aggregation):
= Table.Group(#"Removed Duplicates", {"PrimaryKey"}, {{"Centro_New", each Text.Combine([Centro],","), type text}})
This should give you the desired output. Hope this helps.
Edit: You can combine all these into a single step and use the following formula:
= Table.Group(Table.Distinct(Table.ExpandListColumn(Table.TransformColumns(Source, {{"Centro", Splitter.SplitTextByDelimiter(",")}}), "Centro")),{"PrimaryKey"}, {{"Centro_New", each Text.Combine([Centro],","), type text}})