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

Get Fabric Certified for FREE during Fabric Data Days. Don't miss your chance! Learn more

Reply
alexdi
Helper II
Helper II

Expand a self-referencing table from tabular lists of rows and columns?

I have these tables:

Groups:

GroupIDName
1Group1
2Group2

 

Users:

UserIDUser
1Bob
2Shelly

 

I'm trying to create this:

RecursiveMerge:

UserIDUserGroup1Group2
1Bob  
2ShellyY 

 

With these requirements:

  • User will manually populate User/Group relationships (the "Y" above) after matrix is generated
  • Add, remove, or change the names of Users and Groups, and have the changes automatically update the table, without removing the relationships, provided the IDs of the relevant Users and Groups continue to exist

So far, I can create the table, but if I rename a Group, the relationships disappear. I assume this is because of the way the query is matching columns to add and remove them as the query is refreshed.  

 

This is the code I have:

 

 

 

let
    Source = Excel.CurrentWorkbook(){[Name="RecursiveMerge"]}[Content],
    Source2 = Excel.CurrentWorkbook(){[Name="Users"]}[Content],  
    #"Merged Queries" = Table.NestedJoin(Source2,{"ID", "User"},Source,{"ID", "User"},"Removed Columns",JoinKind.LeftOuter),
    #"Expanded Removed Columns" = Table.ExpandTableColumn(#"Merged Queries", "Removed Columns", List.Skip(Table.ColumnNames(Source),2)),
    #"Removed Other Columns" = Table.SelectColumns(#"Expanded Removed Columns",{"ID", "User"}&Groups[Name], MissingField.UseNull)
in
    #"Removed Other Columns"

 

 

 

How can I modify this to preseve relationships when I change Group or User names? Thank you. 

1 ACCEPTED SOLUTION
Jimmy801
Community Champion
Community Champion

Hello @alexdi 

 

now this requires some advanced coding. It includes to include the Group-id in your column names, foresee a renmaing process as well as deleting and adding process. I've tried this and found a solution. You have to change 2 queries. Here the code for it

 

//Groups
let
    Source = Excel.CurrentWorkbook(){[Name="Groups"]}[Content],
    AddKey = Table.AddColumn(Source, "Key", each Text.From([ID])&"-"&Text.From([Name]))
in
    AddKey

 

//RecursiveMerge

let
	Source = Excel.CurrentWorkbook
	(
		)
{[Name="RecursiveMerge"]}[Content
],
Source2 = Excel.CurrentWorkbook
(
	)
{[Name="Users"]}[Content
],
#"Merged Queries" = Table.NestedJoin
(
	Source2,
	{"ID"},
	Source,
	{"ID"},
	"Removed Columns",
	JoinKind.LeftOuter
),
#"Expanded Removed Columns" = Table.ExpandTableColumn
(
	#"Merged Queries",
	"Removed Columns",
	List.Skip
	(
		Table.ColumnNames
		(
			Source
		),
		2
	)
),
SelectGroups = Table.FromRecords
(
	Table.TransformRows
	(
		Table.AddColumn
		(
			Table.AddColumn
			(
				Table.ExpandTableColumn
				(
					Table.NestedJoin
					(
						Table.TransformColumnTypes
						(
							Table.SplitColumn
							(
								Table.FromList
								(
									List.Select
									(
										Table.ColumnNames
										(
											#"Expanded Removed Columns"
										),
										each Text.Contains
										(
											_,
											"-"
										)
									),
									Splitter.SplitByNothing
									(
										)
								),
								"Column1",
								Splitter.SplitTextByDelimiter
								(
									"-"
								)
							),
							{{"Column1.1", type number}}
						),
						"Column1.1",
						Groups,
						"ID",
						"Groups"
					),
					"Groups",
					{"Name"},
					{"Name"}
				),
				"OldName",
				each Text.From
				(
					[Column1.1]
				)
			&"-"&[Column1.2]
		),
		"NewName",
		each Text.From
		(
			[Column1.1]
		)
	&"-"&[Name]
),
(
	row
)
=> if row[NewName]=null then Record.TransformFields
(
	row,
	{"NewName", each row[OldName]&" / to be deleted"}
)
else row
)
),
RenameColumns = Table.RenameColumns
(
	#"Expanded Removed Columns",
	List.Zip
	(
		{SelectGroups[OldName],SelectGroups[NewName]}
	)
),
ColumnsToAdd = List.Difference
(
	Groups[Key
],
Table.ColumnNames
(
	RenameColumns
)
),
AddColumns = Table.SelectColumns
(
	RenameColumns,
	Table.ColumnNames
	(
		RenameColumns
	)
&ColumnsToAdd,
MissingField.UseNull
)
 in 
	AddColumns

 

Try it out

I'm looking forward to your feedback

If this post helps or solves your problem, please mark it as solution (to help other users find useful content and to acknowledge the work of users that helped you)
Kudoes are nice too

Have fun

Jimmy

View solution in original post

16 REPLIES 16
dax
Community Support
Community Support

Hi @alexdi , 

You could try to refer to my sample for details.

Best Regards,
Zoe Zhi

If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.

 

Thank you for that attempt. I apologize, I wasn't clear about what I was asking.

 

The Y values will be arbitrary entered and changed after the matrix is generated. They must be retained even when the matrix changes, provided the ID for the relevant Group and User continue to exist in those tables. (The Groups table should have an ID; I've updated the original post to reflect this.)

Jimmy801
Community Champion
Community Champion

Hello @alexdi 

 

where do you maintain this values? Are you using Excel?

 

Jimmy

Yes, Excel. I've been translating the queries provided to account for that data source. 

Jimmy801
Community Champion
Community Champion

Hello @alexdi 

 

I've tried to build up your scenario, but was not able to. 

could you please share the Excel-file

 

Thanks

 

Jimmy

https://gofile.io/?c=E2wOVi

 

Sure, here's the file.

Jimmy801
Community Champion
Community Champion

Hello @alexdi 

 

why is there a connection needed between the Groups-table and your recursive-query? I don't see any benefits of having this connection. Whats the goal of having this?

 

BR

 

Jimmy

Apologies for the delay-- the groups table is the source for the column names in the recursive query. It's using them to determine what column layout should be after the query is refreshed. 

Jimmy801
Community Champion
Community Champion

Hello @alexdi 

 

now this requires some advanced coding. It includes to include the Group-id in your column names, foresee a renmaing process as well as deleting and adding process. I've tried this and found a solution. You have to change 2 queries. Here the code for it

 

//Groups
let
    Source = Excel.CurrentWorkbook(){[Name="Groups"]}[Content],
    AddKey = Table.AddColumn(Source, "Key", each Text.From([ID])&"-"&Text.From([Name]))
in
    AddKey

 

//RecursiveMerge

let
	Source = Excel.CurrentWorkbook
	(
		)
{[Name="RecursiveMerge"]}[Content
],
Source2 = Excel.CurrentWorkbook
(
	)
{[Name="Users"]}[Content
],
#"Merged Queries" = Table.NestedJoin
(
	Source2,
	{"ID"},
	Source,
	{"ID"},
	"Removed Columns",
	JoinKind.LeftOuter
),
#"Expanded Removed Columns" = Table.ExpandTableColumn
(
	#"Merged Queries",
	"Removed Columns",
	List.Skip
	(
		Table.ColumnNames
		(
			Source
		),
		2
	)
),
SelectGroups = Table.FromRecords
(
	Table.TransformRows
	(
		Table.AddColumn
		(
			Table.AddColumn
			(
				Table.ExpandTableColumn
				(
					Table.NestedJoin
					(
						Table.TransformColumnTypes
						(
							Table.SplitColumn
							(
								Table.FromList
								(
									List.Select
									(
										Table.ColumnNames
										(
											#"Expanded Removed Columns"
										),
										each Text.Contains
										(
											_,
											"-"
										)
									),
									Splitter.SplitByNothing
									(
										)
								),
								"Column1",
								Splitter.SplitTextByDelimiter
								(
									"-"
								)
							),
							{{"Column1.1", type number}}
						),
						"Column1.1",
						Groups,
						"ID",
						"Groups"
					),
					"Groups",
					{"Name"},
					{"Name"}
				),
				"OldName",
				each Text.From
				(
					[Column1.1]
				)
			&"-"&[Column1.2]
		),
		"NewName",
		each Text.From
		(
			[Column1.1]
		)
	&"-"&[Name]
),
(
	row
)
=> if row[NewName]=null then Record.TransformFields
(
	row,
	{"NewName", each row[OldName]&" / to be deleted"}
)
else row
)
),
RenameColumns = Table.RenameColumns
(
	#"Expanded Removed Columns",
	List.Zip
	(
		{SelectGroups[OldName],SelectGroups[NewName]}
	)
),
ColumnsToAdd = List.Difference
(
	Groups[Key
],
Table.ColumnNames
(
	RenameColumns
)
),
AddColumns = Table.SelectColumns
(
	RenameColumns,
	Table.ColumnNames
	(
		RenameColumns
	)
&ColumnsToAdd,
MissingField.UseNull
)
 in 
	AddColumns

 

Try it out

I'm looking forward to your feedback

If this post helps or solves your problem, please mark it as solution (to help other users find useful content and to acknowledge the work of users that helped you)
Kudoes are nice too

Have fun

Jimmy

Thanks @Jimmy801! I can see what you're trying to do it, it's very clever. Unfortunately I'm hitting an error on the SelectGroups step: "Expression.Error: The field 'Column1' of the record wasn't found." To test the solution, I downloaded my sample sheet, updated the Group connection, and then attempted to update the RecursiveMerge query. 

 

Can you link to a copy of a sheet where this worked for you? 

Jimmy801
Community Champion
Community Champion

Hello @alexdi 

 

sorry, i forgot to mention that you have to rename your column header  according to the specification.. .meaning combining ID and Group with "-" like this

image.png

another specificaiton is also that no other column can contain a "-" because this identifies your groupings

 

Hope its working out now

 

Jimmy

@Jimmy801, renaming the columns in the recursive table as described allowed me to add new columns and change column names in the Group table. However, removing entries in that table does not remove from the the recursive table, though the column names do have "to be deleted" appended (sometimes multiple times) to them. Is the intent to delete them manually? 

Jimmy801
Community Champion
Community Champion

Hello @alexdi 

 

exactly, this is the idea behind. So you can relly steer your process well. You think it's a godd idea too?

 

Jimmy

I think there are benefits to that approach, but for this audience, I'm telling them not to change anything at all on the matrix sheets except the associations. Ideally the matrix layout would be solely dictated by the data sheets with no manual column culling. Definitely a good thought though.

Jimmy801
Community Champion
Community Champion

Hello @alexdi 

 

this tasks in Excel are easy as you block ranges etc. So setup the process as you need it and my programm will do the rest 🙂

 

All the best

 

Jimmy

Anonymous
Not applicable

Hi all,

 

an alternative can use the column position as an index, instead of adding it to the name (which to an extent goes against the idea of free-text renaming). This obviously means that columns can not be deleted or re-arranged, only renamed or added to the right.

 

Kind regards,

JB

Helpful resources

Announcements
Fabric Data Days Carousel

Fabric Data Days

Advance your Data & AI career with 50 days of live learning, contests, hands-on challenges, study groups & certifications and more!

October Power BI Update Carousel

Power BI Monthly Update - October 2025

Check out the October 2025 Power BI update to learn about new features.

FabCon Atlanta 2026 carousel

FabCon Atlanta 2026

Join us at FabCon Atlanta, March 16-20, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.

Top Kudoed Authors