Case sensitivity is one of the more confusing aspects of Power BI: while the Power Query engine is case sensitive, the main Power BI engine (that means datasets, relationships, DAX etc) is case insensitive. Imke Feldmann shows how to make Power Query case insensitive through custom M here; in this blog post I’m going to concentrate on what case insensitivity means in datasets and DAX and show a way to (kind of) work around it.
Starting with a simple example, let’s say you have a data source that contains data that looks like this:
This is what the data looks like in the Power Query Editor which is, as I said, case sensitive – which means that it sees “A” and “a” as different characters, so you see six distinct characters in each row of the table. This could be data from any data source; to make things easy I’ve used the following M query to generate this table:
let Source = #table( type table [MyTextColumn = text], { {"A"}, {"a"}, {"B"}, {"b"}, {"C"}, {"c"} }) in Source
When this data gets loaded into a Power BI dataset, however, you’ll see the following in the Data pane of the main Power BI window:
Because the main Power BI engine is case insensitive – so for example “a” and “A” are considered as the same character – when this data is loaded in, it only sees three distinct characters and you can’t be sure whether you’ll get the lower case or upper case character stored twice. This is just the way it works; while an instance of Analysis Services Tabular, which is basically the same engine that is found in Power BI, can be either case sensitive or case insensitive, this option isn’t available in Power BI. There is an idea to support case sensitivity as an option in Power BI here and while there are some valid scenarios where you need this, in my experience case sensitivity causes a lot of problems so I can see why it wasn’t a priority.
What’s more you’ll find that DAX calculations are case insensitive too. If you try the following DAX expression to create a calculated table:
Demo Table = DATATABLE( "MyTextColumn", STRING, { {"A"}, {"a"} } )
You’ll get this:
DAX measures behave in a similar way. Given the following table:
If you use the following measure in a table visual:
Demo Measure = IF( SELECTEDVALUE('Demo Table 2'[MyIntColumn])=1, "A", "a" )
…you’ll see:
The only way you can work around this case insensitivity is to make text values that would otherwise look the same to the Power BI engine somehow different. One way of doing this would be to add some extra characters to your text. You might think adding some extra spaces would be the way to go; revisiting the first M query shown above, you could add a space to every lower case character in the table like so:
let Source = #table( type table [MyTextColumn = text], { {"A"}, {"a "}, {"B"}, {"b "}, {"c "}, {"C"} }) in Source
But this doesn’t work because another little-known behaviour of the Power BI engine is that all leading and trailing spaces are trimmed when text is loaded. Anyway, spaces may not be visible but they still take up… well space. A better option – and one that actually works – is to use the Unicode Zero-Width Space character and the M Character.FromNumber function instead like so:
let Source = #table( type table [MyTextColumn = text], { {"A"}, {"a" & Character.FromNumber(8203)}, {"B"}, {"b" & Character.FromNumber(8203)}, {"c" & Character.FromNumber(8203)}, {"C"} }) in Source
The great thing about this character is that although it’s there, it’s invisible and takes no space. When you load this last M query into Power BI you see the following table:
Let’s finish off with a more advanced example of how to use this rather excellent character. Say you have the following source data returned by an M query called SourceData:
Of course, when this table is loaded into Power BI, you see the following:
BUT, the following M query takes this table and for each row goes through the text in the OriginalText column and adds a zero-width space after each lower case character:
let Source = SourceData, ToList = Table.AddColumn( Source, "Chars", each Text.ToList([OriginalText]) ), LowerCaseChars = {"a".."z"}, AddInvisibleChars = Table.AddColumn( ToList, "AddInvisibleChars", each List.Transform( [Chars], each if List.Contains(LowerCaseChars, _) then _ & Character.FromNumber(8203) else _ ) ), RecombineList = Table.AddColumn( AddInvisibleChars, "OutputText", each Text.Combine([AddInvisibleChars]), type text ), RemovedOtherColumns = Table.SelectColumns( RecombineList, {"OutputText"} ) in RemovedOtherColumns
When you load the output of this query into Power BI, because the zero-width spaces after each lower case character make Power BI see each piece of text as being different, it looks like case has been preserved even when it hasn’t:
You can download the Power BI file for this last example here.
[Thanks to Greg Galloway, Akshai Mirchandani and Jeffrey Wang for their help with this post]