Power Query: transform a column by multiplying by another column - excel

I want to do something similar to Power Query Transform a Column based on Another Column, but I'm getting stuck on how to modify the syntax for my particular goal.
Similar to the linked question, assume that I have the following table:
Table 1:
Column A | Column B | Column C
------------------------------
1 | 4 | 7
2 | 5 | 8
3 | 6 | 9
Instead of changing the value of the Column A conditional on Column B, I want to multiply the values in multiple columns (Column B and Column C) by those in Column A and replace the values in the initial columns so that I can get the following:
Table 1:
Column A | Column B | Column C
------------------------------
1 | 4 | 7
2 | 10 | 16
3 | 18 | 27
Is this possible to do without using multiple sequences of Table.AddColumn followed by Table.RemoveColumns?
I have also tried Table.TransformColumns based on this, but not been able to get the syntax right to achieve this.

Table.TransformColumns won't give you Column A unless you can index back into the table, which will only be possible if your columns only have unique data.
Table.TransformRows will let you build new rows with whatever logic you want:
let
Source = Csv.Document("Column A,Column B,Column C
1,4,7
2,5,8
3,6,9"),
PromotedHeaders = Table.PromoteHeaders(Source),
ChangedType = Table.TransformColumnTypes(PromotedHeaders,{{"Column A", type number}, {"Column B", type number}, {"Column C", type number}}),
MultipliedRows = Table.FromRecords(Table.TransformRows(ChangedType,
each [
Column A = [Column A],
Column B = [Column A] * [Column B],
Column C = [Column A] * [Column C]
]))
in
MultipliedRows
This works well for columns B and C, but if you need B through Z you might want fancier logic to avoid repeating yourself.
EDIT: A more general solution for many columns is to use Record.TransformFields on a list of transforms for all column names except "Column A".
let
Source = Csv.Document("Column A,Column B,Column C,D,E,F
1,4,7,1,2,3
2,5,8,4,5,6
3,6,9,7,8,9"),
PromotedHeaders = Table.PromoteHeaders(Source),
ChangedType = Table.TransformColumnTypes(PromotedHeaders,{{"Column A", type number}, {"Column B", type number}, {"Column C", type number}, {"D", type number}, {"E", type number}, {"F", type number}}),
MultipliedRows = Table.FromRecords(Table.TransformRows(ChangedType, (row) =>
let
ColumnA = row[Column A],
OtherColumns = List.RemoveItems(Record.FieldNames(row), {"Column A"}),
Transforms = List.Transform(OtherColumns, (name) => { name, (cell) => cell * ColumnA })
in
Record.TransformFields(row, Transforms)))
in
MultipliedRows

I think the Table.AddColumn followed by Table.RemoveColumns is the usual and clearest way for this transformation. I'm also not happy with the fact that this results in so many steps in PowerQuery.
But due to internal backfolding methods of PowerQuery this will usualy not result in better performance. (PowerQuery trys to give the main Work back to the queried Database if avaiable)

Assuming this doesn't need to be VBA and/or programmatic, you can just copy values in the first column, then highlight the values in the second column, and "Paste Special..." > Multiply.
That will produce the results in the same place you paste the multiplier.

Related

Add Custom and Dynamic columns

I have two tables and am trying to figure out how to create custom code to add dynamic columns with custom names that are based off of row values in another table. I then need to use the values of rows in Table 2 to not only create the column names but also fill the new dynamic Columns with a value from another column in Table 2. Hopefully my pictures below help
Table 1 has varying amount of rows depending on what the user input.
Table 2 has varying amount of rows depending on how many values the user inputs.
Table 1 Before
Col1
Col2
Col 3
stuff 1
stuff 2
stuff 3
stuff 4
stuff 5
stuff 6
.
.
.
.
.
.
Table 2
Name
Values
Name1
100
Name2
500
.
.
NameX
Y
Table 1 After
Col1
Col2
Col 3
"Column" & Name1
"Column"& Name2
...
"Column"& NameX
stuff 1
stuff 2
stuff 3
100
500
...
Y
stuff 4
stuff 5
stuff 6
100
500
...
Y
.
.
.
100
500
...
Y
.
.
.
100
500
...
Y
The "Column" & Name1 meaning I want to concatenate Column with the values in the Name column in Table 2.
You can make this dynamic by not referring to the absolute column names, but rather using the Table.ColumnNames function to return those names.
I did assume that the column names in Table 2 are fixed. If not, that code can be changed.
Read the code comments and examine the Applied Steps window to better understand the methods used. There are examples of setting the data type, and also re-naming columns without referring to a hard-coded column name.
M Code
let
//read in the two tables and set the data types
Source1 = Excel.CurrentWorkbook(){[Name="Table_2"]}[Content],
Table2 =Table.TransformColumnTypes(Source1,
{{"Name", type text},{"Values", type any}}),
Source = Excel.CurrentWorkbook(){[Name="Table_1_Before"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,
List.Transform(Table.ColumnNames(Source), each {_, type text})),
//create the extra columns by
//Transpose Table2
// Use first row as headers
xpose = Table.Transpose(Table2),
#"Promoted Headers" = Table.PromoteHeaders(xpose, [PromoteAllScalars=true]),
#"Changed Type1" = Table.TransformColumnTypes(#"Promoted Headers",
List.Transform(Table.ColumnNames(#"Promoted Headers"), each {_, type any})),
//rename the columns
renameNameCols = Table.RenameColumns(#"Changed Type1",
List.Zip(
{Table.ColumnNames(#"Changed Type1"),
List.Transform(Table.ColumnNames(#"Changed Type1"), each "Column " & _)})),
//Combine the tables
combine = Table.Combine({#"Changed Type",renameNameCols}),
//fill up the original table 2 columns and remove the blank Table 1 rows
#"Filled Up" = Table.FillUp(combine,Table.ColumnNames(renameNameCols)),
#"Filtered Rows" = Table.SelectRows(#"Filled Up", each ([Col1] <> null))
in
#"Filtered Rows"
Original Tables
Results
Note that I did NOT add logic to avoid prepending the ... with the word column, as shown in your desired output, but that is easily added if really needed
My version
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
custom = Table.FromColumns(Table.ToColumns(Source) &Table.ToColumns(Table2), List.Combine({Table.ColumnNames(Source),Table.ColumnNames(Table2)}) ),
#"Filled Down" = Table.FillDown(custom,Table.ColumnNames(Table2))
in #"Filled Down"

How can I sum numbers in the same line in power query?

Good Morning,
I have some doubt in PowerQuery, i have a column with some numbers in the same line that I need to sum, how can I do it?
Example input
field 1 | field 2 | field 3
Planeacion 2,3,1 2,2,2
field 1 | field 2 | field 3
Planeacion 6 6
output
Thanks in advance
In powerquery you can do this
Click-select the columns with the commas
Right click, Replace values, and replace the comma with a plus ( , to +)
Click-select the same columns
Right click, Transform ... lowercase...
edit the resulting formula so that each time you see
Text.Lower, type text
you replace it with
each Expression.Evaluate(_), type number
Sample version for the two columns
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Replaced Value" = Table.ReplaceValue(Source,",","+",Replacer.ReplaceText,{"field 2", "field 3"}),
#"Transform1" = Table.TransformColumns(#"Replaced Value",{{"field 2", each Expression.Evaluate(_), type number}, {"field 3", each Expression.Evaluate(_), type number}})
in #"Transform1"
If you create a function like this:
CREATE FUNCTION [dbo].[csv2list]
(
#p1 varchar(max)
)
RETURNS TABLE
AS
RETURN
(
WITH List as (
SELECT CAST (value AS varchar(max)) value
FROM STRING_SPLIT(SUBSTRING(#p1, 1, LEN(#p1)), ',')
)
SELECT value
FROM List
)
GO
Then you can do:
SELECT * FROM csv2list('2,3,1');
which will produce:
2
3
1
or to sum them, use:
select sum(cast(value as integer)) from csv2list('2,3,1');

How to copy a data row from column A to column B, between each data row

Troubles with the update formula Troubles with formula, asking for a missing matrix Steps, I have tried to retrieve data from column B to column D
Know is telling that I insert insufficient argumentsGood afternoon,
I have column B, with descriptions in Portuguese, row by row and column D with the translations in English:
I'm trying to insert in column D the corresponding translation in Portuguese under each data row in English.
But I can't find any formula to do that, also I didn't find any question like this in the forum.
The only nearest question about, is to insert a blank row between data rows with this formula =MOD(ROW(D2),2)=0 or with a filter adding series. And retrieving data with vlookup, as in the attached image.
You can use power query to tackle this task.
I have used the following data for demonstration. Please note I am using Excel 365 English version.
| Portuguese | English |
|------------|---------|
| um | one |
| dois | two |
| trĂªs | three |
| quatro | four |
| cinco | five |
| seis | six |
| Sete | seven |
| oito | eight |
| nove | nine |
| dez | ten |
Steps are:
Load/Add the data set to Power Query Editor;
Make a duplicated column of Portuguese, then add an Index column with index starting from 1, then you should have something like below:
Use Merge Columns function under Transform tab to merge the English column with the Portuguese - Copy column with a custom delimiter such as hashtag # (as long as this delimiter is not part of your original texts), then you should have:
Use Split Columns function under Transform tab to split the merged column by the same delimiter #, and make sure in the Advanced Settings to choose to put the results into Rows as shown below:
The output will look like the following:
You can choose to remove the Portuguese column if you do not want to show it in the final output, then Close & Load the table to a new worksheet (by default).
Here are the power query M Codes behind the scene. All functions used are within GUI so should be easy to follow and execute.
let
Source = Excel.CurrentWorkbook(){[Name="Table2"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Portuguese", type text}, {"English", type text}}),
#"Duplicated Column" = Table.DuplicateColumn(#"Changed Type", "Portuguese", "Portuguese - Copy"),
#"Added Index" = Table.AddIndexColumn(#"Duplicated Column", "Index", 1, 1),
#"Merged Columns" = Table.CombineColumns(#"Added Index",{"English", "Portuguese - Copy"},Combiner.CombineTextByDelimiter("#", QuoteStyle.None),"Merged"),
#"Split Column by Delimiter" = Table.ExpandListColumn(Table.TransformColumns(#"Merged Columns", {{"Merged", Splitter.SplitTextByDelimiter("#", QuoteStyle.Csv), let itemType = (type nullable text) meta [Serialized.Text = true] in type {itemType}}}), "Merged"),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Merged", type text}})
in
#"Changed Type1"
Let me know if you have any questions. Cheers :)
Put this formula in the Result Column and adjust $A$1 to your first portuguese term and $B$1 to you first translated term:
'=OFFSET($A$1;((ROW()-ROW($B$1))/2)-ROW($A$1)+1;0)
You should get a Column, where every Portuguese term is repeated. Now you can overwrite the formulas in the upper cells with the english translations.
The formula calculates the difference between current (translated row) cell and the first translated row and cuts it in half: that is the row of the portuguese term to associate with this cell. Then it uses that row number as offset to the first row of portuguese terms.
Now, if you want to have the forst row empty, you can of course fill the whole formula in the true part of an if formula:
=IF(MOD(ROW()-ROW($B$1),2)=0;"";OFFSET($A$1;((ROW()-ROW($B$1))/2)-ROW($A$1)+1;0))
That is something you will often do in excel and I assume you know that trick. It makes the core formula a little harder to read, but it basically says: if the current row inside this block is divisible by two, then set the row empty, else set the row equal to the formula I presented above.

How to update values in more than one column based on another column with M in PowerQuery [duplicate]

I want to do something similar to Power Query Transform a Column based on Another Column, but I'm getting stuck on how to modify the syntax for my particular goal.
Similar to the linked question, assume that I have the following table:
Table 1:
Column A | Column B | Column C
------------------------------
1 | 4 | 7
2 | 5 | 8
3 | 6 | 9
Instead of changing the value of the Column A conditional on Column B, I want to multiply the values in multiple columns (Column B and Column C) by those in Column A and replace the values in the initial columns so that I can get the following:
Table 1:
Column A | Column B | Column C
------------------------------
1 | 4 | 7
2 | 10 | 16
3 | 18 | 27
Is this possible to do without using multiple sequences of Table.AddColumn followed by Table.RemoveColumns?
I have also tried Table.TransformColumns based on this, but not been able to get the syntax right to achieve this.
Table.TransformColumns won't give you Column A unless you can index back into the table, which will only be possible if your columns only have unique data.
Table.TransformRows will let you build new rows with whatever logic you want:
let
Source = Csv.Document("Column A,Column B,Column C
1,4,7
2,5,8
3,6,9"),
PromotedHeaders = Table.PromoteHeaders(Source),
ChangedType = Table.TransformColumnTypes(PromotedHeaders,{{"Column A", type number}, {"Column B", type number}, {"Column C", type number}}),
MultipliedRows = Table.FromRecords(Table.TransformRows(ChangedType,
each [
Column A = [Column A],
Column B = [Column A] * [Column B],
Column C = [Column A] * [Column C]
]))
in
MultipliedRows
This works well for columns B and C, but if you need B through Z you might want fancier logic to avoid repeating yourself.
EDIT: A more general solution for many columns is to use Record.TransformFields on a list of transforms for all column names except "Column A".
let
Source = Csv.Document("Column A,Column B,Column C,D,E,F
1,4,7,1,2,3
2,5,8,4,5,6
3,6,9,7,8,9"),
PromotedHeaders = Table.PromoteHeaders(Source),
ChangedType = Table.TransformColumnTypes(PromotedHeaders,{{"Column A", type number}, {"Column B", type number}, {"Column C", type number}, {"D", type number}, {"E", type number}, {"F", type number}}),
MultipliedRows = Table.FromRecords(Table.TransformRows(ChangedType, (row) =>
let
ColumnA = row[Column A],
OtherColumns = List.RemoveItems(Record.FieldNames(row), {"Column A"}),
Transforms = List.Transform(OtherColumns, (name) => { name, (cell) => cell * ColumnA })
in
Record.TransformFields(row, Transforms)))
in
MultipliedRows
I think the Table.AddColumn followed by Table.RemoveColumns is the usual and clearest way for this transformation. I'm also not happy with the fact that this results in so many steps in PowerQuery.
But due to internal backfolding methods of PowerQuery this will usualy not result in better performance. (PowerQuery trys to give the main Work back to the queried Database if avaiable)
Assuming this doesn't need to be VBA and/or programmatic, you can just copy values in the first column, then highlight the values in the second column, and "Paste Special..." > Multiply.
That will produce the results in the same place you paste the multiplier.

Generate all Possible Unique Combinations of two Excel Columns

I have the following simplified data set which I need to create a unique list from and transpose the data from column B at the same time. I think I need to use INDEX, but I am unsure on the correct syntax for this scenario.
The data in column B is delimited by a space.
This is what my data looks like:
|---------------------|------------------|
| Column A | Column B |
|---------------------|------------------|
| 1 | AA BB |
|---------------------|------------------|
| 2 | BB CC |
|---------------------|------------------|
| 3 | DD EE |
|---------------------|------------------|
Required result
|---------------------|------------------|
| Column A | Column B |
|---------------------|------------------|
| 1 | AA |
|---------------------|------------------|
| 1 | BB |
|---------------------|------------------|
| 2 | BB |
|---------------------|------------------|
| 2 | CC |
|---------------------|------------------|
| 3 | DD |
|---------------------|------------------|
| 3 | EE |
|---------------------|------------------|
To get your output table given your input table, you can use Power Query, from the UI, in just a few steps:
Split Column B by the space delimiter.
Select Column A and then select to unpivot other columns
Delete the extra column Attribute that appears when you unpivot.
This is the M code for that operation
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", Int64.Type}, {"Column2", type text}}),
#"Split Column by Delimiter" = Table.SplitColumn(#"Changed Type", "Column2", Splitter.SplitTextByDelimiter(" ", QuoteStyle.Csv), {"Column2.1", "Column2.2"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Column2.1", type text}, {"Column2.2", type text}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type1", {"Column1"}, "Attribute", "Value"),
#"Removed Columns" = Table.RemoveColumns(#"Unpivoted Other Columns",{"Attribute"})
in
#"Removed Columns"
And the results:
Ron Rosenfeld's answer unpivots the data as the OP indicated by the required result.
If you need to create all combinations of data from two columns (rather than unpivoting), normalize the data by placing each set of values in its own column. In this example, Column B has two data entries per cell, which can be split using Data > Text to Columns. To work with unique entries, either use the standard Excel tool Data > Remove Duplicates, or in Excel Power Query Editor, right click the data column header and click Remove Duplicates.
Create separate queries for each column to be included in the combinations. By adding a custom column with a formula referring to the first data query, Power Query will perform a Full Outer Join across the two columns resulting in all combinations.
Final Table Result
Step 1: Data > Text to Columns
(a) Select Column B. In the ribbon, go to Data > Text to Columns.
(b) Split the data on the appropriate delimiter (Space, Tab, etc.).
Step 2: Combine data and remove duplicates
(a) Cut data from Column C and paste into Column B
(b) Paste Column C data into Column B.
(c) Select Column B and then click Data > Remove Duplicates
(d) If warning pops up about data found next to selection, click "Continue with the current selection"
(e) Select checkbox for Column B and click OK.
Step 3: Create data query for Column A
(a) Select Column A and click Data > From Table/Range
(b) Query Settings > PROPERTIES > Name and enter name "ColumnA"
(c) Home > Close & Load > Close & Load To...
(d) Select: Only Create Connection
Step 4: Create data query for Column B
(a) Select Column B
(b) Data > From Table/Range
(c) Query Settings > PROPERTIES > Name and enter name "ColumnB"
(d) Add Column > Custom Column
(e) New column name: Combinations
(f) Custom column formula: =ColumnA
(g) Expand the new "Combinations" column (icon with left/right arrows)
(h) Drag the "Combinations" column to the left side
(i) Home > Close & Load
Step 5: Sort the output data table

Resources