Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
Naesevol
Frequent Visitor

Parse Dynamic JSON from SQL Column

I've posted this earlier to Desktop, but apparently that post didn't take, so forgive me if this shows up twice!

 

My goal is to parse a JSON string column that is being served up to power bi via a SQL source column. I can successfully parse this column by clicking through and expanding, but it only parses the first object found in my JSON array. It does not parse the second object.

 

I have a SQL View as my source with roughly 30 columns in it. The columns for each row are a Unique ID, 28 other attributes, and a JSON string which is Dynamic in that I won't know the contents, and it could be nested.

 

The SQL layout looks like:

 

LID | ~28 Attributes | EvalResults

 

EvalResults is the JSON in question, which looks like:

 

{
	"values": [{
		"lid": "someguid1",
		"jid": "someguid2",
		"freq_gpsK0": 1.9261547623478617,
		"freq_gpsK0_result": false,
		"freq_accK0": 206.7747298420615,
		"freq_accK0_result": false,
		"freq_gyrK0": 206.73750946018041,
		"freq_gyrK0_result": false,
		"freq_camF0": 61.332985943102443,
		"freq_camR0": 61.367104626493465,
		"freq_camL0": 61.162392526147322,
		"freq_camB0": 61.367104626493465,
		"camFPS_result": false,
		"longtrip": 644.808,
		"longtrip_result": true,
		"build": 26,
		"build_result": true,
		"max_gpsK0_v": 34.427,
		"max_gpsK0_v_result": true,
		"no_pii": true,
		"numcams": 4,
		"numcams_result": true,
		"count_camF0_unordered": 0,
		"count_camR0_unordered": 0,
		"count_camL0_unordered": 0,
		"count_camB0_unordered": 0,
		"camsOrdered_result": true,
		"freq_cbs0": 1583.5442488306596,
		"freq_cbs1": 563.9663279611915,
		"freq_cbs2": 1376.9215022146127,
		"freq_cbs3": null,
		"freq_cbs4": null,
		"freq_cbs5": null,
		"freq_cbs6": null,
		"freq_cbs7": null,
		"freq_cbs8": null,
		"freq_cbs9": null,
		"epoch": 99
	}, {
		"datetime": "2019-08-07T00:00:00",
		"lid": "ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e",
		"jid": "63021e67-bf31-43f9-8f73-7e9c3e8522c4",
		"datetime_result": true,
		"length": 644801,
		"length_result": true,
		"inertial": 100.0,
		"camera": 99.3,
		"inertial_result": true,
		"camera_result": true,
		"accf0_inbounds": 100.0,
		"accb0_inbounds": 100.0,
		"accl0_inbounds": 100.0,
		"accr0_inbounds": 100.0,
		"acck0_inbounds": 100.0,
		"gyrf0_inbounds": 100.0,
		"gyrb0_inbounds": 100.0,
		"gyrl0_inbounds": 100.0,
		"gyrr0_inbounds": 100.0,
		"gyrk0_inbounds": 100.0,
		"camf0_inbounds": 100.0,
		"camb0_inbounds": 100.0,
		"caml0_inbounds": 100.0,
		"camr0_inbounds": 100.0,
		"camf0_inbounds_1sec": 100.0,
		"camb0_inbounds_1sec": 99.9,
		"caml0_inbounds_1sec": 99.9,
		"camr0_inbounds_1sec": 100.0,
		"camf0_inbounds_lateframes": 100.0,
		"camb0_inbounds_lateframes": 100.0,
		"caml0_inbounds_lateframes": 99.5,
		"camr0_inbounds_lateframes": 100.0
	}]
}

I will always have the "values" array, but anything after that is up in the air from nothing in the Array to 15 object in the array. As you can see, I also won't know the names of the keys in the JSON object.

 

When I successfully parse out the first object in this array, the Power Query M looks like this:

 

let
    Source = Sql.Database("mysqlserver", "mydbname", [Query="SELECT * FROM myViewName#(lf)"]),
    #"Parsed JSON" = Table.TransformColumns(Source,{{"EvalResults", Json.Document}}),
    #"Expanded EvalResults" = Table.ExpandRecordColumn(#"Parsed JSON", "EvalResults", {"values"}, {"EvalResults.values"}),
    #"Expanded EvalResults.values" = Table.ExpandListColumn(#"Expanded EvalResults", "EvalResults.values"),
    #"Expanded EvalResults.values1" = Table.ExpandRecordColumn(#"Expanded EvalResults.values", "EvalResults.values", {"lid", "jid", "freq_gpsK0", "freq_gpsK0_result", "freq_accK0", "freq_accK0_result", "freq_gyrK0", "freq_gyrK0_result", "freq_camF0", "freq_camR0", "freq_camL0", "freq_camB0", "camFPS_result", "longtrip", "longtrip_result", "build", "build_result", "max_gpsK0_v", "max_gpsK0_v_result", "no_pii", "numcams", "numcams_result", "count_camF0_unordered", "count_camR0_unordered", "count_camL0_unordered", "count_camB0_unordered", "camsOrdered_result", "epoch"}, {"EvalResults.values.lid", "EvalResults.values.jid", "EvalResults.values.freq_gpsK0", "EvalResults.values.freq_gpsK0_result", "EvalResults.values.freq_accK0", "EvalResults.values.freq_accK0_result", "EvalResults.values.freq_gyrK0", "EvalResults.values.freq_gyrK0_result", "EvalResults.values.freq_camF0", "EvalResults.values.freq_camR0", "EvalResults.values.freq_camL0", "EvalResults.values.freq_camB0", "EvalResults.values.camFPS_result", "EvalResults.values.longtrip", "EvalResults.values.longtrip_result", "EvalResults.values.build", "EvalResults.values.build_result", "EvalResults.values.max_gpsK0_v", "EvalResults.values.max_gpsK0_v_result", "EvalResults.values.no_pii", "EvalResults.values.numcams", "EvalResults.values.numcams_result", "EvalResults.values.count_camF0_unordered", "EvalResults.values.count_camR0_unordered", "EvalResults.values.count_camL0_unordered", "EvalResults.values.count_camB0_unordered", "EvalResults.values.camsOrdered_result", "EvalResults.values.epoch"})
in
    #"Expanded EvalResults.values1"

 

This would be OK if I only ever needed to grab one object from the array, but it fails at getting down to the second object.

 

I have tried a lot of finessing with Power Query M, but I am new to it. 

Is this possible to achieve? I would be open to either one big table with all of the columns in it, or sub tables under each row (as long as the performance wasn't an issue). Whatever allows me to get at the data!

 

Thank you in advance!

1 ACCEPTED SOLUTION

Hi @Naesevol 

this gets us back to my original solution where I assumed that there must probably more than one JSON object involved. Im just borrowing the last lines of code and combine them with your scenario:

 

let
    Source = Sql.Database("mysqlserver", "mysqldb", [Query="SELECT * FROM mySQLView#(lf)"]),
    #"Filtered Rows" = Table.SelectRows(Source, each ([EvalResults] <> null)),
    #"Sorted Rows1" = Table.Sort(#"Filtered Rows",{{"AcquireTime", Order.Descending}}),
    #"Parsed JSON" = Table.TransformColumns(#"Sorted Rows1",{{"EvalResults", Json.Document}}),
    #"Expanded EvalResults" = Table.ExpandRecordColumn(#"Parsed JSON", "EvalResults", {"values"}, {"EvalResults.values"}),
    ListOfRecordsToTable = Table.AddColumn(#"Expanded EvalResults", "Custom", each Record.ToTable(Record.Combine([EvalResults.values]))),
    #"Expanded Custom" = Table.ExpandTableColumn(ListOfRecordsToTable, "Custom", {"Name", "Value"}, {"Name", "Value"}),
    #"Removed Columns" = Table.RemoveColumns(#"Expanded Custom",{"values"}),
    #"Pivoted Column" = Table.Pivot(#"Removed Columns", List.Distinct(#"Removed Columns"[Name]), "Name", "Value")
in
    #"Pivoted Column"

Of course here could be typos or name mismatches, as I couldn't test your code.

But the important thing is NOT to expand the list column (as this will cause the dups), but instead add the column "Custom" instead.

 

 

Imke Feldmann (The BIccountant)

If you liked my solution, please give it a thumbs up. And if I did answer your question, please mark this post as a solution. Thanks!

How to integrate M-code into your solution -- How to get your questions answered quickly -- How to provide sample data -- Check out more PBI- learning resources here -- Performance Tipps for M-queries

View solution in original post

10 REPLIES 10
ImkeF
Super User
Super User

Hi @Naesevol 

not sure if my understanding is correct, but please check what this code does. No hardcoded Field/Column-names in there:

 

let
    Source = "[{#(cr)#(lf)#(tab)""values"": [{#(cr)#(lf)#(tab)#(tab)""lid"": ""someguid1"",#(cr)#(lf)#(tab)#(tab)""jid"": ""someguid2"",#(cr)#(lf)#(tab)#(tab)""freq_gpsK0"": 1.9261547623478617,#(cr)#(lf)#(tab)#(tab)""freq_gpsK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_accK0"": 206.7747298420615,#(cr)#(lf)#(tab)#(tab)""freq_accK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_gyrK0"": 206.73750946018041,#(cr)#(lf)#(tab)#(tab)""freq_gyrK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_camF0"": 61.332985943102443,#(cr)#(lf)#(tab)#(tab)""freq_camR0"": 61.367104626493465,#(cr)#(lf)#(tab)#(tab)""freq_camL0"": 61.162392526147322,#(cr)#(lf)#(tab)#(tab)""freq_camB0"": 61.367104626493465,#(cr)#(lf)#(tab)#(tab)""camFPS_result"": false,#(cr)#(lf)#(tab)#(tab)""longtrip"": 644.808,#(cr)#(lf)#(tab)#(tab)""longtrip_result"": true,#(cr)#(lf)#(tab)#(tab)""build"": 26,#(cr)#(lf)#(tab)#(tab)""build_result"": true,#(cr)#(lf)#(tab)#(tab)""max_gpsK0_v"": 34.427,#(cr)#(lf)#(tab)#(tab)""max_gpsK0_v_result"": true,#(cr)#(lf)#(tab)#(tab)""no_pii"": true,#(cr)#(lf)#(tab)#(tab)""numcams"": 4,#(cr)#(lf)#(tab)#(tab)""numcams_result"": true,#(cr)#(lf)#(tab)#(tab)""count_camF0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camR0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camL0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camB0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""camsOrdered_result"": true,#(cr)#(lf)#(tab)#(tab)""freq_cbs0"": 1583.5442488306596,#(cr)#(lf)#(tab)#(tab)""freq_cbs1"": 563.9663279611915,#(cr)#(lf)#(tab)#(tab)""freq_cbs2"": 1376.9215022146127,#(cr)#(lf)#(tab)#(tab)""freq_cbs3"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs4"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs5"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs6"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs7"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs8"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs9"": null,#(cr)#(lf)#(tab)#(tab)""epoch"": 99#(cr)#(lf)#(tab)}, {#(cr)#(lf)#(tab)#(tab)""datetime"": ""2019-08-07T00:00:00"",#(cr)#(lf)#(tab)#(tab)""lid"": ""ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e"",#(cr)#(lf)#(tab)#(tab)""jid"": ""63021e67-bf31-43f9-8f73-7e9c3e8522c4"",#(cr)#(lf)#(tab)#(tab)""datetime_result"": true,#(cr)#(lf)#(tab)#(tab)""length"": 644801,#(cr)#(lf)#(tab)#(tab)""length_result"": true,#(cr)#(lf)#(tab)#(tab)""inertial"": 100.0,#(cr)#(lf)#(tab)#(tab)""camera"": 99.3,#(cr)#(lf)#(tab)#(tab)""inertial_result"": true,#(cr)#(lf)#(tab)#(tab)""camera_result"": true,#(cr)#(lf)#(tab)#(tab)""accf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accl0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""acck0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrl0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrk0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds_1sec"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds_1sec"": 99.9,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds_1sec"": 99.9,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds_1sec"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds_lateframes"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds_lateframes"": 100.0,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds_lateframes"": 99.5,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds_lateframes"": 100.0#(cr)#(lf)#(tab)}]#(cr)#(lf)}, #(cr)#(lf){#(cr)#(lf)#(tab)""values"": [{#(cr)#(lf)#(tab)#(tab)""lid"": ""someguid1"",#(cr)#(lf)#(tab)#(tab)""jid"": ""someguid2"",#(cr)#(lf)#(tab)#(tab)""freq_gpsK0"": 1.9261547623478617,#(cr)#(lf)#(tab)#(tab)""freq_gpsK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_accK0"": 206.7747298420615,#(cr)#(lf)#(tab)#(tab)""freq_accK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_gyrK0"": 206.73750946018041,#(cr)#(lf)#(tab)#(tab)""freq_gyrK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_camF0"": 61.332985943102443,#(cr)#(lf)#(tab)#(tab)""freq_camR0"": 61.367104626493465,#(cr)#(lf)#(tab)#(tab)""freq_camL0"": 61.162392526147322,#(cr)#(lf)#(tab)#(tab)""freq_camB0"": 61.367104626493465,#(cr)#(lf)#(tab)#(tab)""camFPS_result"": false,#(cr)#(lf)#(tab)#(tab)""longtrip"": 644.808,#(cr)#(lf)#(tab)#(tab)""longtrip_result"": true,#(cr)#(lf)#(tab)#(tab)""build"": 26,#(cr)#(lf)#(tab)#(tab)""build_result"": true,#(cr)#(lf)#(tab)#(tab)""max_gpsK0_v"": 34.427,#(cr)#(lf)#(tab)#(tab)""max_gpsK0_v_result"": true,#(cr)#(lf)#(tab)#(tab)""no_pii"": true,#(cr)#(lf)#(tab)#(tab)""numcams"": 4,#(cr)#(lf)#(tab)#(tab)""numcams_result"": true,#(cr)#(lf)#(tab)#(tab)""count_camF0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camR0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camL0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camB0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""camsOrdered_result"": true,#(cr)#(lf)#(tab)#(tab)""freq_cbs0"": 1583.5442488306596,#(cr)#(lf)#(tab)#(tab)""freq_cbs1"": 563.9663279611915,#(cr)#(lf)#(tab)#(tab)""freq_cbs2"": 1376.9215022146127,#(cr)#(lf)#(tab)#(tab)""freq_cbs3"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs4"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs5"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs6"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs7"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs8"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs9"": null,#(cr)#(lf)#(tab)#(tab)""epoch"": 99#(cr)#(lf)#(tab)}, {#(cr)#(lf)#(tab)#(tab)""datetime"": ""2019-08-07T00:00:00"",#(cr)#(lf)#(tab)#(tab)""lid"": ""ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e"",#(cr)#(lf)#(tab)#(tab)""jid"": ""63021e67-bf31-43f9-8f73-7e9c3e8522c4"",#(cr)#(lf)#(tab)#(tab)""datetime_result"": true,#(cr)#(lf)#(tab)#(tab)""length"": 644801,#(cr)#(lf)#(tab)#(tab)""length_result"": true,#(cr)#(lf)#(tab)#(tab)""inertial"": 100.0,#(cr)#(lf)#(tab)#(tab)""camera"": 99.3,#(cr)#(lf)#(tab)#(tab)""inertial_result"": true,#(cr)#(lf)#(tab)#(tab)""camera_result"": true,#(cr)#(lf)#(tab)#(tab)""accf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accl0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""acck0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrl0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrk0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds_1sec"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds_1sec"": 99.9,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds_1sec"": 99.9,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds_1sec"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds_lateframes"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds_lateframes"": 100.0,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds_lateframes"": 99.5,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds_lateframes"": 100.0#(cr)#(lf)#(tab)}]#(cr)#(lf)}#(cr)#(lf)]",
    #"Parsed JSON" = Json.Document(Source),
    #"Converted to Table" = Table.FromList(#"Parsed JSON", Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"values"}, {"values"}),
    #"Added Index" = Table.AddIndexColumn(#"Expanded Column1", "Index", 1, 1),
    ListOfRecordsToTable = Table.AddColumn(#"Added Index", "Custom", each Record.ToTable(Record.Combine([values]))),
    #"Expanded Custom" = Table.ExpandTableColumn(ListOfRecordsToTable, "Custom", {"Name", "Value"}, {"Name", "Value"}),
    #"Removed Columns" = Table.RemoveColumns(#"Expanded Custom",{"values"}),
    #"Pivoted Column" = Table.Pivot(#"Removed Columns", List.Distinct(#"Removed Columns"[Name]), "Name", "Value")
in
    #"Pivoted Column"

 

Imke Feldmann (The BIccountant)

If you liked my solution, please give it a thumbs up. And if I did answer your question, please mark this post as a solution. Thanks!

How to integrate M-code into your solution -- How to get your questions answered quickly -- How to provide sample data -- Check out more PBI- learning resources here -- Performance Tipps for M-queries

Hi @ImkeF  - this definitely parses both objects in the values array!

 

It looks like adding an index was probably the thing I was missing. Taking it to a table, expanding, and pivoting back is clever.

 

That said, it looks like you've changed the JSON structure a little, and you've made the top level an array as opposed to an object, like:

 

[{
	"values": [{
		"lid": "someguid1",
		"jid": "someguid2",
		"freq_gpsK0": 1.9261547623478617,
		"freq_gpsK0_result": false,
		"freq_accK0": 206.7747298420615,
		"freq_accK0_result": false,
		"freq_gyrK0": 206.73750946018041,
		"freq_gyrK0_result": false,
		"freq_camF0": 61.332985943102443,
		"freq_camR0": 61.367104626493465,
		"freq_camL0": 61.162392526147322,
		"freq_camB0": 61.367104626493465,
		"camFPS_result": false,
		"longtrip": 644.808,
		"longtrip_result": true,
		"build": 26,
		"build_result": true,
		"max_gpsK0_v": 34.427,
		"max_gpsK0_v_result": true,
		"no_pii": true,
		"numcams": 4,
		"numcams_result": true,
		"count_camF0_unordered": 0,
		"count_camR0_unordered": 0,
		"count_camL0_unordered": 0,
		"count_camB0_unordered": 0,
		"camsOrdered_result": true,
		"freq_cbs0": 1583.5442488306596,
		"freq_cbs1": 563.9663279611915,
		"freq_cbs2": 1376.9215022146127,
		"freq_cbs3": null,
		"freq_cbs4": null,
		"freq_cbs5": null,
		"freq_cbs6": null,
		"freq_cbs7": null,
		"freq_cbs8": null,
		"freq_cbs9": null,
		"epoch": 99
	}, {
		"datetime": "2019-08-07T00:00:00",
		"lid": "ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e",
		"jid": "63021e67-bf31-43f9-8f73-7e9c3e8522c4",
		"datetime_result": true,
		"length": 644801,
		"length_result": true,
		"inertial": 100.0,
		"camera": 99.3,
		"inertial_result": true,
		"camera_result": true,
		"accf0_inbounds": 100.0,
		"accb0_inbounds": 100.0,
		"accl0_inbounds": 100.0,
		"accr0_inbounds": 100.0,
		"acck0_inbounds": 100.0,
		"gyrf0_inbounds": 100.0,
		"gyrb0_inbounds": 100.0,
		"gyrl0_inbounds": 100.0,
		"gyrr0_inbounds": 100.0,
		"gyrk0_inbounds": 100.0,
		"camf0_inbounds": 100.0,
		"camb0_inbounds": 100.0,
		"caml0_inbounds": 100.0,
		"camr0_inbounds": 100.0,
		"camf0_inbounds_1sec": 100.0,
		"camb0_inbounds_1sec": 99.9,
		"caml0_inbounds_1sec": 99.9,
		"camr0_inbounds_1sec": 100.0,
		"camf0_inbounds_lateframes": 100.0,
		"camb0_inbounds_lateframes": 100.0,
		"caml0_inbounds_lateframes": 99.5,
		"camr0_inbounds_lateframes": 100.0
	}]
}, 
{
	"values": [{
		"lid": "someguid1",
		"jid": "someguid2",
		"freq_gpsK0": 1.9261547623478617,
		"freq_gpsK0_result": false,
		"freq_accK0": 206.7747298420615,
		"freq_accK0_result": false,
		"freq_gyrK0": 206.73750946018041,
		"freq_gyrK0_result": false,
		"freq_camF0": 61.332985943102443,
		"freq_camR0": 61.367104626493465,
		"freq_camL0": 61.162392526147322,
		"freq_camB0": 61.367104626493465,
		"camFPS_result": false,
		"longtrip": 644.808,
		"longtrip_result": true,
		"build": 26,
		"build_result": true,
		"max_gpsK0_v": 34.427,
		"max_gpsK0_v_result": true,
		"no_pii": true,
		"numcams": 4,
		"numcams_result": true,
		"count_camF0_unordered": 0,
		"count_camR0_unordered": 0,
		"count_camL0_unordered": 0,
		"count_camB0_unordered": 0,
		"camsOrdered_result": true,
		"freq_cbs0": 1583.5442488306596,
		"freq_cbs1": 563.9663279611915,
		"freq_cbs2": 1376.9215022146127,
		"freq_cbs3": null,
		"freq_cbs4": null,
		"freq_cbs5": null,
		"freq_cbs6": null,
		"freq_cbs7": null,
		"freq_cbs8": null,
		"freq_cbs9": null,
		"epoch": 99
	}, {
		"datetime": "2019-08-07T00:00:00",
		"lid": "ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e",
		"jid": "63021e67-bf31-43f9-8f73-7e9c3e8522c4",
		"datetime_result": true,
		"length": 644801,
		"length_result": true,
		"inertial": 100.0,
		"camera": 99.3,
		"inertial_result": true,
		"camera_result": true,
		"accf0_inbounds": 100.0,
		"accb0_inbounds": 100.0,
		"accl0_inbounds": 100.0,
		"accr0_inbounds": 100.0,
		"acck0_inbounds": 100.0,
		"gyrf0_inbounds": 100.0,
		"gyrb0_inbounds": 100.0,
		"gyrl0_inbounds": 100.0,
		"gyrr0_inbounds": 100.0,
		"gyrk0_inbounds": 100.0,
		"camf0_inbounds": 100.0,
		"camb0_inbounds": 100.0,
		"caml0_inbounds": 100.0,
		"camr0_inbounds": 100.0,
		"camf0_inbounds_1sec": 100.0,
		"camb0_inbounds_1sec": 99.9,
		"caml0_inbounds_1sec": 99.9,
		"camr0_inbounds_1sec": 100.0,
		"camf0_inbounds_lateframes": 100.0,
		"camb0_inbounds_lateframes": 100.0,
		"caml0_inbounds_lateframes": 99.5,
		"camr0_inbounds_lateframes": 100.0
	}]
}
]

Is this necessary? If so, I think I can alter my structure to always have an array at the top level.

I will try to apply this to my actual SQL Source JSON Column and report back with the findings.

 

Thanks!

Hi @Naesevol 

no, there's no need to adjust to that structure. I just assumed that there must be more than one element there.

The latest JSON you've posted looks exactly like mine. So if you actually have a different structure for multiple objects, please post and I'll adjust the code.

 

 

Imke Feldmann (The BIccountant)

If you liked my solution, please give it a thumbs up. And if I did answer your question, please mark this post as a solution. Thanks!

How to integrate M-code into your solution -- How to get your questions answered quickly -- How to provide sample data -- Check out more PBI- learning resources here -- Performance Tipps for M-queries

Hi @ImkeF ,


Sorry for the confusion, I posted yours in my reply. My original JSON is in my original post.

 

Original JSON:

{
	"values": [{
		"lid": "someguid1",
		"jid": "someguid2",
		"freq_gpsK0": 1.9261547623478617,
		"freq_gpsK0_result": false,
		"freq_accK0": 206.7747298420615,
		"freq_accK0_result": false,
		"freq_gyrK0": 206.73750946018041,
		"freq_gyrK0_result": false,
		"freq_camF0": 61.332985943102443,
		"freq_camR0": 61.367104626493465,
		"freq_camL0": 61.162392526147322,
		"freq_camB0": 61.367104626493465,
		"camFPS_result": false,
		"longtrip": 644.808,
		"longtrip_result": true,
		"build": 26,
		"build_result": true,
		"max_gpsK0_v": 34.427,
		"max_gpsK0_v_result": true,
		"no_pii": true,
		"numcams": 4,
		"numcams_result": true,
		"count_camF0_unordered": 0,
		"count_camR0_unordered": 0,
		"count_camL0_unordered": 0,
		"count_camB0_unordered": 0,
		"camsOrdered_result": true,
		"freq_cbs0": 1583.5442488306596,
		"freq_cbs1": 563.9663279611915,
		"freq_cbs2": 1376.9215022146127,
		"freq_cbs3": null,
		"freq_cbs4": null,
		"freq_cbs5": null,
		"freq_cbs6": null,
		"freq_cbs7": null,
		"freq_cbs8": null,
		"freq_cbs9": null,
		"epoch": 99
	}, {
		"datetime": "2019-08-07T00:00:00",
		"lid": "ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e",
		"jid": "63021e67-bf31-43f9-8f73-7e9c3e8522c4",
		"datetime_result": true,
		"length": 644801,
		"length_result": true,
		"inertial": 100.0,
		"camera": 99.3,
		"inertial_result": true,
		"camera_result": true,
		"accf0_inbounds": 100.0,
		"accb0_inbounds": 100.0,
		"accl0_inbounds": 100.0,
		"accr0_inbounds": 100.0,
		"acck0_inbounds": 100.0,
		"gyrf0_inbounds": 100.0,
		"gyrb0_inbounds": 100.0,
		"gyrl0_inbounds": 100.0,
		"gyrr0_inbounds": 100.0,
		"gyrk0_inbounds": 100.0,
		"camf0_inbounds": 100.0,
		"camb0_inbounds": 100.0,
		"caml0_inbounds": 100.0,
		"camr0_inbounds": 100.0,
		"camf0_inbounds_1sec": 100.0,
		"camb0_inbounds_1sec": 99.9,
		"caml0_inbounds_1sec": 99.9,
		"camr0_inbounds_1sec": 100.0,
		"camf0_inbounds_lateframes": 100.0,
		"camb0_inbounds_lateframes": 100.0,
		"caml0_inbounds_lateframes": 99.5,
		"camr0_inbounds_lateframes": 100.0
	}]
}

 

Your JSON:

[{
	"values": [{
		"lid": "someguid1",
		"jid": "someguid2",
		"freq_gpsK0": 1.9261547623478617,
		"freq_gpsK0_result": false,
		"freq_accK0": 206.7747298420615,
		"freq_accK0_result": false,
		"freq_gyrK0": 206.73750946018041,
		"freq_gyrK0_result": false,
		"freq_camF0": 61.332985943102443,
		"freq_camR0": 61.367104626493465,
		"freq_camL0": 61.162392526147322,
		"freq_camB0": 61.367104626493465,
		"camFPS_result": false,
		"longtrip": 644.808,
		"longtrip_result": true,
		"build": 26,
		"build_result": true,
		"max_gpsK0_v": 34.427,
		"max_gpsK0_v_result": true,
		"no_pii": true,
		"numcams": 4,
		"numcams_result": true,
		"count_camF0_unordered": 0,
		"count_camR0_unordered": 0,
		"count_camL0_unordered": 0,
		"count_camB0_unordered": 0,
		"camsOrdered_result": true,
		"freq_cbs0": 1583.5442488306596,
		"freq_cbs1": 563.9663279611915,
		"freq_cbs2": 1376.9215022146127,
		"freq_cbs3": null,
		"freq_cbs4": null,
		"freq_cbs5": null,
		"freq_cbs6": null,
		"freq_cbs7": null,
		"freq_cbs8": null,
		"freq_cbs9": null,
		"epoch": 99
	}, {
		"datetime": "2019-08-07T00:00:00",
		"lid": "ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e",
		"jid": "63021e67-bf31-43f9-8f73-7e9c3e8522c4",
		"datetime_result": true,
		"length": 644801,
		"length_result": true,
		"inertial": 100.0,
		"camera": 99.3,
		"inertial_result": true,
		"camera_result": true,
		"accf0_inbounds": 100.0,
		"accb0_inbounds": 100.0,
		"accl0_inbounds": 100.0,
		"accr0_inbounds": 100.0,
		"acck0_inbounds": 100.0,
		"gyrf0_inbounds": 100.0,
		"gyrb0_inbounds": 100.0,
		"gyrl0_inbounds": 100.0,
		"gyrr0_inbounds": 100.0,
		"gyrk0_inbounds": 100.0,
		"camf0_inbounds": 100.0,
		"camb0_inbounds": 100.0,
		"caml0_inbounds": 100.0,
		"camr0_inbounds": 100.0,
		"camf0_inbounds_1sec": 100.0,
		"camb0_inbounds_1sec": 99.9,
		"caml0_inbounds_1sec": 99.9,
		"camr0_inbounds_1sec": 100.0,
		"camf0_inbounds_lateframes": 100.0,
		"camb0_inbounds_lateframes": 100.0,
		"caml0_inbounds_lateframes": 99.5,
		"camr0_inbounds_lateframes": 100.0
	}]
}, 
{
	"values": [{
		"lid": "someguid1",
		"jid": "someguid2",
		"freq_gpsK0": 1.9261547623478617,
		"freq_gpsK0_result": false,
		"freq_accK0": 206.7747298420615,
		"freq_accK0_result": false,
		"freq_gyrK0": 206.73750946018041,
		"freq_gyrK0_result": false,
		"freq_camF0": 61.332985943102443,
		"freq_camR0": 61.367104626493465,
		"freq_camL0": 61.162392526147322,
		"freq_camB0": 61.367104626493465,
		"camFPS_result": false,
		"longtrip": 644.808,
		"longtrip_result": true,
		"build": 26,
		"build_result": true,
		"max_gpsK0_v": 34.427,
		"max_gpsK0_v_result": true,
		"no_pii": true,
		"numcams": 4,
		"numcams_result": true,
		"count_camF0_unordered": 0,
		"count_camR0_unordered": 0,
		"count_camL0_unordered": 0,
		"count_camB0_unordered": 0,
		"camsOrdered_result": true,
		"freq_cbs0": 1583.5442488306596,
		"freq_cbs1": 563.9663279611915,
		"freq_cbs2": 1376.9215022146127,
		"freq_cbs3": null,
		"freq_cbs4": null,
		"freq_cbs5": null,
		"freq_cbs6": null,
		"freq_cbs7": null,
		"freq_cbs8": null,
		"freq_cbs9": null,
		"epoch": 99
	}, {
		"datetime": "2019-08-07T00:00:00",
		"lid": "ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e",
		"jid": "63021e67-bf31-43f9-8f73-7e9c3e8522c4",
		"datetime_result": true,
		"length": 644801,
		"length_result": true,
		"inertial": 100.0,
		"camera": 99.3,
		"inertial_result": true,
		"camera_result": true,
		"accf0_inbounds": 100.0,
		"accb0_inbounds": 100.0,
		"accl0_inbounds": 100.0,
		"accr0_inbounds": 100.0,
		"acck0_inbounds": 100.0,
		"gyrf0_inbounds": 100.0,
		"gyrb0_inbounds": 100.0,
		"gyrl0_inbounds": 100.0,
		"gyrr0_inbounds": 100.0,
		"gyrk0_inbounds": 100.0,
		"camf0_inbounds": 100.0,
		"camb0_inbounds": 100.0,
		"caml0_inbounds": 100.0,
		"camr0_inbounds": 100.0,
		"camf0_inbounds_1sec": 100.0,
		"camb0_inbounds_1sec": 99.9,
		"caml0_inbounds_1sec": 99.9,
		"camr0_inbounds_1sec": 100.0,
		"camf0_inbounds_lateframes": 100.0,
		"camb0_inbounds_lateframes": 100.0,
		"caml0_inbounds_lateframes": 99.5,
		"camr0_inbounds_lateframes": 100.0
	}]
}
]

No prob!

If it's just one object, the code is even simpler:

 

let
    Query2 = "{#(cr)#(lf)#(tab)""values"": [{#(cr)#(lf)#(tab)#(tab)""lid"": ""someguid1"",#(cr)#(lf)#(tab)#(tab)""jid"": ""someguid2"",#(cr)#(lf)#(tab)#(tab)""freq_gpsK0"": 1.9261547623478617,#(cr)#(lf)#(tab)#(tab)""freq_gpsK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_accK0"": 206.7747298420615,#(cr)#(lf)#(tab)#(tab)""freq_accK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_gyrK0"": 206.73750946018041,#(cr)#(lf)#(tab)#(tab)""freq_gyrK0_result"": false,#(cr)#(lf)#(tab)#(tab)""freq_camF0"": 61.332985943102443,#(cr)#(lf)#(tab)#(tab)""freq_camR0"": 61.367104626493465,#(cr)#(lf)#(tab)#(tab)""freq_camL0"": 61.162392526147322,#(cr)#(lf)#(tab)#(tab)""freq_camB0"": 61.367104626493465,#(cr)#(lf)#(tab)#(tab)""camFPS_result"": false,#(cr)#(lf)#(tab)#(tab)""longtrip"": 644.808,#(cr)#(lf)#(tab)#(tab)""longtrip_result"": true,#(cr)#(lf)#(tab)#(tab)""build"": 26,#(cr)#(lf)#(tab)#(tab)""build_result"": true,#(cr)#(lf)#(tab)#(tab)""max_gpsK0_v"": 34.427,#(cr)#(lf)#(tab)#(tab)""max_gpsK0_v_result"": true,#(cr)#(lf)#(tab)#(tab)""no_pii"": true,#(cr)#(lf)#(tab)#(tab)""numcams"": 4,#(cr)#(lf)#(tab)#(tab)""numcams_result"": true,#(cr)#(lf)#(tab)#(tab)""count_camF0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camR0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camL0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""count_camB0_unordered"": 0,#(cr)#(lf)#(tab)#(tab)""camsOrdered_result"": true,#(cr)#(lf)#(tab)#(tab)""freq_cbs0"": 1583.5442488306596,#(cr)#(lf)#(tab)#(tab)""freq_cbs1"": 563.9663279611915,#(cr)#(lf)#(tab)#(tab)""freq_cbs2"": 1376.9215022146127,#(cr)#(lf)#(tab)#(tab)""freq_cbs3"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs4"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs5"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs6"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs7"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs8"": null,#(cr)#(lf)#(tab)#(tab)""freq_cbs9"": null,#(cr)#(lf)#(tab)#(tab)""epoch"": 99#(cr)#(lf)#(tab)}, {#(cr)#(lf)#(tab)#(tab)""datetime"": ""2019-08-07T00:00:00"",#(cr)#(lf)#(tab)#(tab)""lid"": ""ad803d67-e9a4-4a67-87a5-a79c8a5b8f3e"",#(cr)#(lf)#(tab)#(tab)""jid"": ""63021e67-bf31-43f9-8f73-7e9c3e8522c4"",#(cr)#(lf)#(tab)#(tab)""datetime_result"": true,#(cr)#(lf)#(tab)#(tab)""length"": 644801,#(cr)#(lf)#(tab)#(tab)""length_result"": true,#(cr)#(lf)#(tab)#(tab)""inertial"": 100.0,#(cr)#(lf)#(tab)#(tab)""camera"": 99.3,#(cr)#(lf)#(tab)#(tab)""inertial_result"": true,#(cr)#(lf)#(tab)#(tab)""camera_result"": true,#(cr)#(lf)#(tab)#(tab)""accf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accl0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""accr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""acck0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrl0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""gyrk0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds_1sec"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds_1sec"": 99.9,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds_1sec"": 99.9,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds_1sec"": 100.0,#(cr)#(lf)#(tab)#(tab)""camf0_inbounds_lateframes"": 100.0,#(cr)#(lf)#(tab)#(tab)""camb0_inbounds_lateframes"": 100.0,#(cr)#(lf)#(tab)#(tab)""caml0_inbounds_lateframes"": 99.5,#(cr)#(lf)#(tab)#(tab)""camr0_inbounds_lateframes"": 100.0#(cr)#(lf)#(tab)}]#(cr)#(lf)}",
    #"Parsed JSON" = Json.Document(Query2),
    values = #"Parsed JSON"[values],
    Custom1 = Record.Combine(values),
    Custom2 = Table.FromRecords({Custom1})
in
    Custom2

 

Imke Feldmann (The BIccountant)

If you liked my solution, please give it a thumbs up. And if I did answer your question, please mark this post as a solution. Thanks!

How to integrate M-code into your solution -- How to get your questions answered quickly -- How to provide sample data -- Check out more PBI- learning resources here -- Performance Tipps for M-queries

Hm - there appears to be a bug whenever I edit a reply to a form post, my post disappears, so I am resubmitting my reply.

 

Your most recent reply gets me parsed down properly, but it results in a new table which drops all of my previous columns, and only keeps the JSON column as the new table.

 

I think maybe I was not clear enough on the ask originally, my apologies:

 

I need to be able to loop through each SQL Row, parse the JSON column, and store the resulting Keys from the JSON as new columns on the SQL Source Table (or store the JSON key/values as a new table that relates to each row).

 

A simple example below.

 

Take my source:

 

lid | sqlcol1 | sqlcol 2| EvalResults |

   1      yyy        iii              json1
   2      xxx        bbb          json2

 

Where json1 is:

 

 

{
	"values": [{
		"aaa": 1.92,
		"bbb": false
	}]
}

 

Where json2 is:

 

 

{
	"values": [{
		"aaa": 2.00,
		"bbb": true
	}, {
		"xxx": "2.2",
		"yyy": true
	}]
}

 

 

      I would want my resulting table to look like:

 

lid | sqlcol1 | sqlcol 2| EvalResults.aaa |EvalResults.bbb|EvalResults.xxx|EvalResults.yyy

   1      yyy        iii              1.92                 false                     null                  null    
   2      xxx        bbb          2.00                  true                     2.2                    true

 

Is this possible? I imagine I will need to loop through each row, but am not familiar enough with Power Query M to be certain that is correct, or even doable.

 

Thank you so much for the help so far!

 

 

Updating for any future seekers of knowledge:

 

My first SQL row had a JSON column that only contained an array which held a single object.

When I sorted my SQL rows by most recently added, I had a JSON column that contained an array which held more than one object.

 

Power BI then recgonized that there were multiple objects to Parse. Here is my resulting Power Query M when it appropriately recognized the JSON column:

 

let
    Source = Sql.Database("mysqlserver", "mysqldb", [Query="SELECT * FROM mySQLView#(lf)"]),
    #"Filtered Rows" = Table.SelectRows(Source, each ([EvalResults] <> null)),
    #"Sorted Rows1" = Table.Sort(#"Filtered Rows",{{"AcquireTime", Order.Descending}}),
    #"Parsed JSON" = Table.TransformColumns(#"Sorted Rows1",{{"EvalResults", Json.Document}}),
    #"Expanded EvalResults" = Table.ExpandRecordColumn(#"Parsed JSON", "EvalResults", {"values"}, {"EvalResults.values"}),
    #"Expanded EvalResults.values" = Table.ExpandListColumn(#"Expanded EvalResults", "EvalResults.values"),
    #"Expanded EvalResults.values1" = Table.ExpandRecordColumn(#"Expanded EvalResults.values", "EvalResults.values", {"lid", "jid", "freq_gpsK0", "freq_gpsK0_result", "freq_accK0", "freq_accK0_result", "freq_gyrK0", "freq_gyrK0_result", "freq_camF0", "freq_camR0", "freq_camL0", "freq_camB0", "camFPS_result", "longtrip", "longtrip_result", "build", "build_result", "max_gpsK0_v", "max_gpsK0_v_result", "no_pii", "numcams", "numcams_result", "count_camF0_unordered", "count_camR0_unordered", "count_camL0_unordered", "count_camB0_unordered", "camsOrdered_result", "freq_cbs0", "freq_cbs1", "freq_cbs2", "freq_cbs3", "freq_cbs4", "freq_cbs5", "freq_cbs6", "freq_cbs7", "freq_cbs8", "freq_cbs9", "epoch", "datetime", "datetime_result", "length", "length_result", "inertial", "camera", "inertial_result", "camera_result", "accf0_inbounds", "accb0_inbounds", "accl0_inbounds", "accr0_inbounds", "acck0_inbounds", "gyrf0_inbounds", "gyrb0_inbounds", "gyrl0_inbounds", "gyrr0_inbounds", "gyrk0_inbounds", "camf0_inbounds", "camb0_inbounds", "caml0_inbounds", "camr0_inbounds", "camf0_inbounds_1sec", "camb0_inbounds_1sec", "caml0_inbounds_1sec", "camr0_inbounds_1sec", "camf0_inbounds_lateframes", "camb0_inbounds_lateframes", "caml0_inbounds_lateframes", "camr0_inbounds_lateframes", "ReasonForRecording", "FingerPrint"}, {"EvalResults.values.lid", "EvalResults.values.jid", "EvalResults.values.freq_gpsK0", "EvalResults.values.freq_gpsK0_result", "EvalResults.values.freq_accK0", "EvalResults.values.freq_accK0_result", "EvalResults.values.freq_gyrK0", "EvalResults.values.freq_gyrK0_result", "EvalResults.values.freq_camF0", "EvalResults.values.freq_camR0", "EvalResults.values.freq_camL0", "EvalResults.values.freq_camB0", "EvalResults.values.camFPS_result", "EvalResults.values.longtrip", "EvalResults.values.longtrip_result", "EvalResults.values.build", "EvalResults.values.build_result", "EvalResults.values.max_gpsK0_v", "EvalResults.values.max_gpsK0_v_result", "EvalResults.values.no_pii", "EvalResults.values.numcams", "EvalResults.values.numcams_result", "EvalResults.values.count_camF0_unordered", "EvalResults.values.count_camR0_unordered", "EvalResults.values.count_camL0_unordered", "EvalResults.values.count_camB0_unordered", "EvalResults.values.camsOrdered_result", "EvalResults.values.freq_cbs0", "EvalResults.values.freq_cbs1", "EvalResults.values.freq_cbs2", "EvalResults.values.freq_cbs3", "EvalResults.values.freq_cbs4", "EvalResults.values.freq_cbs5", "EvalResults.values.freq_cbs6", "EvalResults.values.freq_cbs7", "EvalResults.values.freq_cbs8", "EvalResults.values.freq_cbs9", "EvalResults.values.epoch", "EvalResults.values.datetime", "EvalResults.values.datetime_result", "EvalResults.values.length", "EvalResults.values.length_result", "EvalResults.values.inertial", "EvalResults.values.camera", "EvalResults.values.inertial_result", "EvalResults.values.camera_result", "EvalResults.values.accf0_inbounds", "EvalResults.values.accb0_inbounds", "EvalResults.values.accl0_inbounds", "EvalResults.values.accr0_inbounds", "EvalResults.values.acck0_inbounds", "EvalResults.values.gyrf0_inbounds", "EvalResults.values.gyrb0_inbounds", "EvalResults.values.gyrl0_inbounds", "EvalResults.values.gyrr0_inbounds", "EvalResults.values.gyrk0_inbounds", "EvalResults.values.camf0_inbounds", "EvalResults.values.camb0_inbounds", "EvalResults.values.caml0_inbounds", "EvalResults.values.camr0_inbounds", "EvalResults.values.camf0_inbounds_1sec", "EvalResults.values.camb0_inbounds_1sec", "EvalResults.values.caml0_inbounds_1sec", "EvalResults.values.camr0_inbounds_1sec", "EvalResults.values.camf0_inbounds_lateframes", "EvalResults.values.camb0_inbounds_lateframes", "EvalResults.values.caml0_inbounds_lateframes", "EvalResults.values.camr0_inbounds_lateframes", "EvalResults.values.ReasonForRecording", "EvalResults.values.FingerPrint"})

  in
    #"Expanded EvalResults.values1"

I fear this is not very scalable, since the JSON can, and will shift in the future.. but maybe it will help someone looking for a solve for a smaller data set.

 

Now I am fighting with a new issue. Each row is being duplicated. I'll need to figure out a way to join the rows on LID, so that I don't have twice the number of records (or thrice if I happened to ever have three objects to parse).

 

Will report back when I figure out a path forward without dupes.

 

Hi @Naesevol 

this gets us back to my original solution where I assumed that there must probably more than one JSON object involved. Im just borrowing the last lines of code and combine them with your scenario:

 

let
    Source = Sql.Database("mysqlserver", "mysqldb", [Query="SELECT * FROM mySQLView#(lf)"]),
    #"Filtered Rows" = Table.SelectRows(Source, each ([EvalResults] <> null)),
    #"Sorted Rows1" = Table.Sort(#"Filtered Rows",{{"AcquireTime", Order.Descending}}),
    #"Parsed JSON" = Table.TransformColumns(#"Sorted Rows1",{{"EvalResults", Json.Document}}),
    #"Expanded EvalResults" = Table.ExpandRecordColumn(#"Parsed JSON", "EvalResults", {"values"}, {"EvalResults.values"}),
    ListOfRecordsToTable = Table.AddColumn(#"Expanded EvalResults", "Custom", each Record.ToTable(Record.Combine([EvalResults.values]))),
    #"Expanded Custom" = Table.ExpandTableColumn(ListOfRecordsToTable, "Custom", {"Name", "Value"}, {"Name", "Value"}),
    #"Removed Columns" = Table.RemoveColumns(#"Expanded Custom",{"values"}),
    #"Pivoted Column" = Table.Pivot(#"Removed Columns", List.Distinct(#"Removed Columns"[Name]), "Name", "Value")
in
    #"Pivoted Column"

Of course here could be typos or name mismatches, as I couldn't test your code.

But the important thing is NOT to expand the list column (as this will cause the dups), but instead add the column "Custom" instead.

 

 

Imke Feldmann (The BIccountant)

If you liked my solution, please give it a thumbs up. And if I did answer your question, please mark this post as a solution. Thanks!

How to integrate M-code into your solution -- How to get your questions answered quickly -- How to provide sample data -- Check out more PBI- learning resources here -- Performance Tipps for M-queries

@IMK you're a hero! Just a slight tweak for my specific names:

 

let
    Source = Sql.Database("mysqldb, "mysqlserver", [Query="SELECT * FROM MySqlView#(lf)"]),
    #"Filtered Rows" = Table.SelectRows(Source, each ([EvalResults] <> null)),
    #"Sorted Rows1" = Table.Sort(#"Filtered Rows",{{"AcquireTime", Order.Descending}}),
    #"Parsed JSON" = Table.TransformColumns(#"Sorted Rows1",{{"EvalResults", Json.Document}}),
    #"Expanded EvalResults" = Table.ExpandRecordColumn(#"Parsed JSON", "EvalResults", {"values"}, {"EvalResults.values"}),
    ListOfRecordsToTable = Table.AddColumn(#"Expanded EvalResults", "Custom", each Record.ToTable(Record.Combine([EvalResults.values]))),
    #"Expanded Custom" = Table.ExpandTableColumn(ListOfRecordsToTable, "Custom", {"Name", "Value"}, {"Name", "Value"}),
    #"Removed Columns" = Table.RemoveColumns(#"Expanded Custom",{"EvalResults.values"}),
    #"Pivoted Column" = Table.Pivot(#"Removed Columns", List.Distinct(#"Removed Columns"[Name]), "Name", "Value"),
    #"Sorted Rows" = Table.Sort(#"Pivoted Column",{{"AcquireTime", Order.Descending}})
in
    #"Sorted Rows"

 

The key was indeed:

 

But the important thing is NOT to expand the list column (as this will cause the dups), but instead add the column "Custom" instead.

 

And then of course the removal of the EvalResults.values (original expanded column) and the pivot back.


Really appreciate it!

Thanks @ImkeF  - this gets me close. This parses the json column down to a brand new table, but I lose all the rest of my previous sql data.

 

I guess I may not have been fully clear from the get-go though: I need to do this for each row (thousands of rows) returned from my SQL View, and append the results of the JSON column to the original source table (or have child tables that can be accessed from within the report).

 

Each unique JSON key found should show up as a column on my original table.

 

Is there a way to loop through and do this parsing for each object (which holds an array of objects), and get a result that renders all of the JSON values as new columns, appended to my original source table?

 

For example let's say my source SQL looks like this with only two rows (for simplicity):

 

| LID |   SqlColumn1   |   SqlColumn2    | EvalResults      |

  1       somedata             somedata2      evalresultJson1

  2       somedata1           somedata22    evalresultJson2

 

 

Let's say that evalresultJson1 value was:

 

 

{
	"values": [{
		"abc": 0.98,
		"xyz": true
	}]
}

and evalresultJson2 is:

 

 

{
	"values": [{
		"abc": 1.92,
		"xyz": false
	}, {
		"zzz": true,
		"vvv": 644801
	}]
}

 

 

My desired result would be something like:

 

| LID |  SqlColumn1 SqlColumn2  | EvalResults.abc  | EvalResults.xyz| EvalResults.zzz | EvalResults.vvv |

  1       somedata        somedata2      0.98                        true                    null                        null

  2       somedata1     somedata22    1.92                        false                   true                        644801

 

I imagine the solution must be to loop through, and do the parsing you have shown, and append back to the original table somehow? Or to create child tables?

 

Is this kind of thing possible? 

 

Thank you very much for the help so far!

 

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.

Top Solution Authors
Top Kudoed Authors