(tbl as table) =>
let
Source = tbl,
// Функция для очистки имен столбцов
CleanColumnName = (name) =>
let
// Заменяем проблемные символы на подчеркивания
Cleaned = Text.Replace(name, ":", "_"),
Cleaned2 = Text.Replace(Cleaned, "/", "_"),
Cleaned3 = Text.Replace(Cleaned2, ".", "_"),
Cleaned4 = Text.Replace(Cleaned3, "-", "_"),
Cleaned5 = Text.Replace(Cleaned4, " ", "_")
in
Cleaned5,
// Функция для проверки наличия табличных столбцов
HasTableColumns = (inputTable) =>
let
ColumnNames = Table.ColumnNames(inputTable),
HasTables = List.AnyTrue(List.Transform(ColumnNames, each
let
firstValueRaw = try Table.FirstValue(Table.SelectColumns(inputTable, _)) otherwise null,
// Заменяем пустые строки на null
firstValue = if firstValueRaw = "" then null else firstValueRaw
in
firstValue <> null and Value.Is(firstValue, type table)))
in
HasTables,
// Функция для преобразования пустых строк в null в табличных столбцах
ReplaceEmptyStrings = (inputTable) =>
let
ColumnNames = Table.ColumnNames(inputTable),
// Находим столбцы, которые могут содержать таблицы
PotentialTableColumns = List.Select(ColumnNames, each
let
firstValueRaw = try Table.FirstValue(Table.SelectColumns(inputTable, _)) otherwise null,
firstValue = if firstValueRaw = "" then null else firstValueRaw
in
firstValue <> null and Value.Is(firstValue, type table)),
// Заменяем пустые строки на null в этих столбцах
ResultTable = List.Accumulate(
PotentialTableColumns,
inputTable,
(state, column) =>
Table.TransformColumns(state, {{
column,
each if _ = "" then null else _,
type any
}})
)
in
ResultTable,
// Функция для раскрытия всех табличных столбцов за один проход
ExpandAllTables = (inputTable) =>
let
// Сначала заменяем пустые строки на null
CleanedTable = ReplaceEmptyStrings(inputTable),
// Находим все табличные столбцы
ColumnNames = Table.ColumnNames(CleanedTable),
TableColumns = List.Select(ColumnNames, each
let
firstValueRaw = try Table.FirstValue(Table.SelectColumns(CleanedTable, _)) otherwise null,
// Заменяем пустые строки на null
firstValue = if firstValueRaw = "" then null else firstValueRaw
in
firstValue <> null and Value.Is(firstValue, type table)),
// Раскрываем все табличные столбцы за один проход
ExpandedTable = List.Accumulate(
TableColumns,
CleanedTable,
(state, column) =>
let
SampleValueRaw = try Table.FirstValue(Table.SelectColumns(state, column)) otherwise null,
// Заменяем пустые строки на null
SampleValue = if SampleValueRaw = "" then null else SampleValueRaw,
IsTableValue = SampleValue <> null and Value.Is(SampleValue, type table),
ResultTable = if not IsTableValue then
state
else
let
NestedColumns = Table.ColumnNames(SampleValue),
CleanedNestedColumns = List.Transform(NestedColumns, each CleanColumnName(_)),
PrefixedColumns = List.Transform(CleanedNestedColumns, each CleanColumnName(column) & "_" & _),
Expanded = Table.ExpandTableColumn(state, column, NestedColumns, PrefixedColumns)
in
Expanded
in
ResultTable
)
in
ExpandedTable,
// Итеративный процесс раскрытия таблиц с проверкой завершения
IterativeExpand = (inputTable, iteration, maxIterations) =>
let
// Проверяем, есть ли еще табличные столбцы
HasTables = HasTableColumns(inputTable),
// Проверяем, не достигли ли мы максимального количества итераций
ShouldContinue = HasTables and iteration < maxIterations,
Result = if not ShouldContinue then
inputTable
else
let
Expanded = ExpandAllTables(inputTable),
NextIteration = @IterativeExpand(Expanded, iteration + 1, maxIterations)
in
NextIteration
in
Result,
// Запускаем процесс с максимальным количеством итераций = 10
FinalResult = IterativeExpand(Source, 1, 12)
in
FinalResult |