Table.TransformColumnTypes 1 – определяем типы данных в столбцах пачкой без привязки к именам

#АнатомияФункций - Table.TransformColumnTypes



Всем привет!

Очередной раз всплыл вопрос про типизацию столбцов. Кто не в курсе напомню суть проблемы – можно выставить в настройках, чтобы типы определялись при загрузке таблицы автоматически, можно уже после загрузки таблицы в интерфейсе нажать кнопку «Определить тип данных» - и всё будет замечательно… НО! На самом деле в ходе данной операции PQ создаёт шаг, использующий функцию Table.TransformColumnTypes и во втором аргументе оказывается фиксированный список столбцов с типами. Соответственно, если в дальнейшем в таблицу будут добавляться столбцы – они просто не будут типизироваться, а если какой-то столбец будет переименован или удалён, то вообще вылезет ошибка.



Посему задача – уйти от фиксированного списка и соорудить всё кодом. Поехали:

let

from = #table({"a".."e"},{{123,"мама",12.34,#date(2023,1,1),#time(1,2,3)},{234,"мыла",23.45,#date(2023,2,2),#time(2,3,4)},{345,"раму",34.56,#date(2023,3,3),#time(3,4,5)}}),

lst = List.Transform(Record.FieldValues(from{0}),Value.Type),

tr = List.Zip({Table.ColumnNames(from),lst}),

to = Table.TransformColumnTypes(from,tr)

in

to


from - в простейшем варианте у нас красивая табличка без пропусков

lst – поэтому берем первую стоку, преобразуем её в список значений, определяем их типы

tr – соединяем названия столбцов с полученными типами через List.Zip

to
– преобразуем столбцы



Правда, если б всё было так просто, не было бы поста… В данных могут быть пропуски:





let

from = #table({"a".."e"},{{123,null,12.34,#date(2023,1,1),null},{null,"мыла",null,#date(2023,2,2),#time(2,3,4)},{345,"раму",34.56,null,#time(3,4,5)}}),

lst=List.Transform(Table.ToColumns(Table.Range(from,0,10)),f),

f=(x)=>List.Mode(List.Transform(List.RemoveNulls(x),Value.Type)),



tr = List.Zip({Table.ColumnNames(from),lst}),

to = Table.TransformColumnTypes(from,tr)

in

to





from – уже менее красивая табличка

lst – поэтому мы не можем опираться на первую строку, а берем несколько, в данном случае 10 (стандартно интерфейс работает с первой 1000), разбиваем таблицу на списки по столбцам и к каждому полученному списку применяем функцию f

f
– функция удаляет null-ы, определяет тип оставшихся значений и берёт наиболее часто встречающийся (List.Mode)

tr и to – аналогично первому случаю – собрали список преобразований и применили.



Вуаля, задача решена!



Правда если бы она была решена полностью в названии поста не было бы номера 1…

Потому что на самом деле у нас ещё остаются – определение целые или дробные числа у нас в столбце, датавремя или дата, даты/время/датавремя в виде текста (привет 1С) и т.п. И этим мы займемся в следующем посте )))



Надеюсь, было полезно.

Всех благ!

@buchlotnik