Power BI is turning 10! Tune in for a special live episode on July 24 with behind-the-scenes stories, product evolution highlights, and a sneak peek at what’s in store for the future.
Save the dateEnhance your career with this limited time 50% discount on Fabric and Power BI exams. Ends August 31st. Request your voucher.
Hi, I'm trying to solve a fairly simple problem, but I've not been able to find the right combination of commands in the forum so far.
I have many columns in the format {"A.1", "B.1", "C.1", ...}, some of which are filled with null - I'd like to replace these values from a corresponding column, let's call them {"A.2", "B.2", "C.2", ...}. I can replace them one by one, like in the toy example here:
let
Source = Table.FromRecords({
[A.1 = 1, B.1 = null, C.1 = 3, A.2 = 1, B.2 = 2, C.2 = 3],
[A.1 = null, B.1 = 2, C.1 = 3, A.2 = 4, B.2 = 5, C.2 = 6],
[A.1 = 1, B.1 = null, C.1 = null, A.2 = 7, B.2 = 8, C.2 = 9]
}),
#"Replaced nulls in A.1" = Table.ReplaceValue(Source, each [A.1], each if [A.1] = null then [A.2] else [A.1], Replacer.ReplaceValue, {"A.1"}),
#"Replaced nulls in B.1" = Table.ReplaceValue(#"Replaced nulls in A.1", each [B.1], each if [B.1] = null then [B.2] else [A.1], Replacer.ReplaceValue, {"B.1"}),
#"Replaced nulls in C.1" = Table.ReplaceValue(#"Replaced nulls in B.1", each [C.1], each if [C.1] = null then [C.2] else [C.1], Replacer.ReplaceValue, {"C.1"})
in
#"Replaced nulls in C.1"
i.e., I'd like to replace nulls in column A.1 with the corresponding row in column A.2, etc.
But as I have many tens of columns and thousands of rows, I'd like to do the above steps in in a more efficient manner, if possible. Is there a way to fill in the nulls from the paired columns in one step? I was thinking there must be a way to iterate through a paried mapping of columns or similar (such as in a zipped list), but I couldn't get the formula set up correctly. Please can you give me some advice?
Solved! Go to Solution.
Hi @BlueSkies3, try this:
Edit these 3 steps. You can probably delete ReplacedBlankToNull step.
Before
After
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WUtJRcjYCEcZAIsQQRIC4IcZKsTrRSs6GIBGwNEQeogCiAq7EEGwIWBSiCKoKqgyoLhYA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Cat1 [r]" = _t, #"Cat2 [r]" = _t, #"Cat3 [r]" = _t, TargetCat_No1 = _t, TargetCat_No2 = _t, TargetCat_No3 = _t]),
nullReplacementColumns = {"Cat1 [r]", "Cat2 [r]", "Cat3 [r]"},
valReplacementColumns = {"TargetCat_No1", "TargetCat_No2", "TargetCat_No3"},
StepBack = Source,
ReplacedBlankToNull = Table.ReplaceValue(StepBack,"",null,Replacer.ReplaceValue,{"Cat1 [r]", "Cat2 [r]", "Cat3 [r]"}),
ReplaceValuesFromTarget = List.Accumulate(
List.Zip({ nullReplacementColumns, valReplacementColumns }),
ReplacedBlankToNull,
(s,c)=> Table.ReplaceValue(s, null, each Record.Field(_, c{1}) , (x,y,z)=> x??z, {c{0}}) )
in
ReplaceValuesFromTarget
using Table.TransformRows
let
s = your_table,
nullReplacementColumns = {"Cat1 [r]", "Cat2 [r]", "Cat3 [r]"},
valReplacementColumns = {"TargetCat_No1", "TargetCat_No2", "TargetCat_No3"},
f = (r) => Record.TransformFields(
r, List.Transform(
List.Zip({nullReplacementColumns, valReplacementColumns}),
(x) => {x{0}, (w) => w ?? Record.Field(r, x{1})}
)
),
z = Table.FromRecords(Table.TransformRows(s, f))
in
z
Thank you both for your suggestions. The column names were actually just examples. Please could you show me how I might be able to map from and to arbitrary columns, where a simple replacement of ".1" --> ".2" won't work? Thank you very much!
Thank you very much! As an example, could I map from "nullReplacementColumns" to "valReplacementColumns"? I guess there is a way to zip the columns together or similar?
nullReplacementColumns = {"Cat1 [r]", "Cat2 [r]", "Cat3 [r]"}
valReplacementColumns ={"TargetCat_No1", "TargetCat_No2", "TargetCat_No3"}
Hi @BlueSkies3, try this:
Edit these 3 steps. You can probably delete ReplacedBlankToNull step.
Before
After
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WUtJRcjYCEcZAIsQQRIC4IcZKsTrRSs6GIBGwNEQeogCiAq7EEGwIWBSiCKoKqgyoLhYA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Cat1 [r]" = _t, #"Cat2 [r]" = _t, #"Cat3 [r]" = _t, TargetCat_No1 = _t, TargetCat_No2 = _t, TargetCat_No3 = _t]),
nullReplacementColumns = {"Cat1 [r]", "Cat2 [r]", "Cat3 [r]"},
valReplacementColumns = {"TargetCat_No1", "TargetCat_No2", "TargetCat_No3"},
StepBack = Source,
ReplacedBlankToNull = Table.ReplaceValue(StepBack,"",null,Replacer.ReplaceValue,{"Cat1 [r]", "Cat2 [r]", "Cat3 [r]"}),
ReplaceValuesFromTarget = List.Accumulate(
List.Zip({ nullReplacementColumns, valReplacementColumns }),
ReplacedBlankToNull,
(s,c)=> Table.ReplaceValue(s, null, each Record.Field(_, c{1}) , (x,y,z)=> x??z, {c{0}}) )
in
ReplaceValuesFromTarget
Thank you very much! I will try this out. Can I ask what the reason is for referencing StepBack to Source rather than passing Source directly? Thanks.
Hi @BlueSkies3, i know that slorin solved your task but maybe you will also need this:
If you have more than 2 pairs of columns and you want to fill all null columns with value from pair column with higher number, this should work.
Result
let
Source = Table.FromRecords({
[A.1 = 1, B.1 = null, C.1 = 3, A.2 = 1, B.2 = null, C.2 = 3, A.3 = 6, B.3 = 3, C.3 = 8],
[A.1 = null, B.1 = 2, C.1 = 3, A.2 = 4, B.2 = 5, C.2 = null, A.3 = 7, B.3 = 4, C.3 = 2],
[A.1 = 1, B.1 = 3, C.1 = null, A.2 = 7, B.2 = null, C.2 = 9, A.3 = 6, B.3 = 9, C.3 = 8]
}),
Zip = [ a = Table.ColumnNames(Source),
occurence = List.Skip(List.Reverse(List.Distinct(List.Transform(a, each Text.AfterDelimiter(_, "."))))),
column = List.Distinct(List.Transform(a, each Text.BeforeDelimiter(_, "."))),
result = List.Combine(List.Transform(occurence, each List.Zip({ List.Repeat({_}, List.Count(column)), column })))
][result],
StepBack = Source,
ReplaceNulls = List.Accumulate(Zip, StepBack,
(s,c)=> Table.ReplaceValue(s, null,
each Record.Field(_, c{1} & "." & Text.From(Number.From(c{0})+1)),
(x,y,z)=> x??z, {c{1} & "." & c{0}} ))
in
ReplaceNulls
Hi,
let
Source = Table.FromRecords({
[A.1 = 1, B.1 = null, C.1 = 3, A.2 = 1, B.2 = 2, C.2 = 3],
[A.1 = null, B.1 = 2, C.1 = 3, A.2 = 4, B.2 = 5, C.2 = 6],
[A.1 = 1, B.1 = null, C.1 = null, A.2 = 7, B.2 = 8, C.2 = 9]
}),
Replace_null=List.Accumulate(
List.Select(Table.ColumnNames(Source), each Text.EndsWith(_,".1")),
Source,
(state,current) => Table.ReplaceValue(state, null,
each Record.Field(_, Text.Replace(current, ".1", ".2")), (x, y, z) => x??z, {current}))
in
Replace_null
Stéphane
Check out the July 2025 Power BI update to learn about new features.