Страницы: 1
RSS
Как с помощью Power Query преобразовать таблицу с ячейками, разбитыми на несколько, Имеется таблица, где в нескольких столбцах ячейки в строке могут быть разбиты на 2-3. Необходимо значения в этих ячейках распределить в новые созданные столбцы
 
Добрый день всем. Нужна помощь или хотя бы подсказка где искать.
Я е-ком, работаю с маркетплейсами. Поэтому часто приходится делать выгрузки либо по API, либо преобразовывать "сырые данные" прямо из копипасты данных со страницы, если нет возможности выгрузить по API. Сейчас по заданию руководства реализовал выгрузку списка отзывов с ВБ, но на Озоне пока по API они сами не реализовали, поэтому приходится копипастить со страницы. И всё бы ничего, но на Озоне это сделано красиво, но коряво, в том смысле, что - в строке постоянно в разных столбцах ячейки бывают разбиты на несколько. Вот и сейчас то же самое. Хотелось бы автоматизировать подготовку к анализу копируемых данных, но пока не могу понять как.
По моей задумке, выглядеть должно так:
1. Разделить ячейки в столбце "Дата и время", создать дополнительный столбец и ячейки (или данные из них) с временем перенести в него на один уровень с датой
2. Разделить ячейки в столбце "Товар", создать дополнительный столбец и ячейки  (или данные из них) с артикулом перенести в него на один уровень с датой
3. Тут поинтересней. Разделить ячейки в столбце "Отзыв", создать дополнительные столбцы "Достоинства", "Недостатки" и "Комментарий" и ячейки (или данные из них) соответственно перенести в них на один уровень с датой. Как раскидать - понимаю и почти реализовал. Не понимаю только как распределить или вообще в принципе разделить ячейки. Проблема ещё в том, что часть разделённых данных - по 2, часть - по 3 ячейки. Была мысль для каждого товара довести строки до 3х, а там уже распределять, но, опять же - пока нет опыта как такое реализовать если разбито не одинаково.
Файл с листами "исходный" и "результат" для понимания прикладываю. В результативном жёлтым выделил новые создаваемые столбцы. Копируемых строк, само собой, на порядок больше.
Буду благодарен любой подсказке
Изменено: Константин Соколов - 14.11.2023 13:14:51
 
Цитата
Константин Соколов написал:
Как с помощью Power Query преобразовать таблицу
easy
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
    removed = Table.SelectColumns(Source,{"Дата и время", "Статус", "Товар", "Статус получения", "Отзыв"}),
    positions = List.PositionOf(removed[Статус], true, Occurrence.All, each _ <> null),
    maxx = Table.RowCount(Source),
    columns = List.Buffer(Table.ColumnNames(removed)), 
    functions = 
        [Дата и время = (x) => [a = List.RemoveNulls(x), b = [Дата = Date.From(x{0}), Время = Time.From(x{1})]][b],
        Статус = (x) => [Статус = List.RemoveNulls(x){0}],
        Статус получения = (x) => [Статус получения = List.RemoveNulls(x){0}],
        Товар = (x) => [a = List.RemoveNulls(x), b = [Товар = x{0}, Артикул = x{1}]][b],
        Отзыв = (x) =>
            [a = List.RemoveNulls(x), 
            b = Record.FromTable(Table.FromRows(List.Transform(a, (w) => Text.Split(w, ":")), {"Name", "Value"}))][b]],
    f = (x) => List.Transform(columns, (w) => [c = Table.Column(x, w), r = Record.FieldOrDefault(functions, w)(c)][r]),
    g = 
        List.Generate(
            () => [i = 0, offset = positions{0}, count = (positions{1}? ?? maxx) - offset, t = Table.Range(removed, offset, count)],
            (x) => positions{x[i]}? <> null, 
            (x) => [i = x[i] + 1, offset = positions{i}, count = (positions{i + 1}? ?? maxx) - offset, t = Table.Range(removed, offset, count )],
            (x) => Record.Combine(f(x[t]))
        ),
    z = Table.FromRecords(g, List.Distinct(List.Combine(List.Transform(g, Record.FieldNames))), MissingField.UseNull)
in
    z
Пришелец-прораб.
 
AlienSx, ох, ничёсе. Спасибо, двойное "Ку", пойду пробовать
 
gheser, в последней строке (Table.FromRecords) значение аргумента с названиями колонок можно руками прописать в виде списка. Зря время потратил на их вычисление. Но это так...
Пришелец-прораб.
 
AlienSx, код работает в последней версии PQ? У меня в офисе Excel 2013, дома - 2021, и дома не пробовал. В офисе выдаёт ошибку при редактировании в расширенном просмотре. Возможно, из-за несоответствия версий PQ
 
gheser, да, у меня новая версия (хотя, давно не обновлялся). Обновите свой офисный пакет. Если не поможет, то ищите где произошел сбой. Возможно, что старые версии не поддерживают какие-то параметры в определенных функциях.
Пришелец-прораб.
 
AlienSx, ага, спасибо что подтвердили догадку. Скорее всего на домашнем компе сработает
 
AlienSx, один раз прошло на ура, а потом затык, причём, на мой взгляд, на ровном месте. Если принимать один отзыв (может состоять из 2-3 строк в файле) за группу записей - 7 групп записей-отзывов переварил, 8-ю группу почему-то не принимает, хотя она по структуре мало чем оттичается от предыдущей, за исключением кол-ва строк (в 7-й - 3 строки, в 8-й - 2). Но ниже встречается аналогичные структуры, и там проблем нет

Ошибка:



При удалении 2х строк проблемного отзыва запрос отработал корректно. Проблемную группу нашёл при просмотре шагов запроса

Файл с выделенной группой, вызывающей ошибку, приложил
 
Цитата
gheser написал:
8-ю группу почему-то не принимает
дело не в группе, а в наличии :( в строке с комментарием. Поправьте разделитель на ": " (с пробелом). Это временно решит проблему - до тех пор, пока не встретится коммент с именно такой подстрокой. Выход - искать самую первую позицию ":" в тексте, чтобы разделить текст по этой позиции. Используйте Text.PositionOf с опцией Occurrence.First и далее Splitter.SplitTextByPositions
Пришелец-прораб.
 
AlienSx, спасибо, сначала бы в вообще разобраться с Вашим кодом :) Что читать / смотреть, чтобы вот так сходу писать запросы на М, без пошагового редактора?
 
Цитата
gheser написал:
Что читать / смотреть
вот это, например
Пришелец-прораб.
 
gheser, AlienSx,
Коллеги, посмотрите насколько подойдет такой код?
Код
let
    fr = Excel.Workbook(File.Contents(C:\ Путь к файлу с именем \2023-11-14 пример.xlsx)),
    a = fr{[Kind = "Sheet" , Item = "исходн"]}[Data],
    a1 = Table.PromoteHeaders(Table.SelectColumns(a, List.Skip(Table.ColumnNames(a)))),
    nm = Table.ColumnNames(a1),
    nmn = {"Дата","Время"}&List.InsertRange(List.Skip(List.RemoveRange(nm,4)), 2, {"Артикул"}),
    nmn1 = nmn&{"Достоинства","Недостатки","Комментарий"},
    f = (x)=>[  z0 = List.Transform(Table.ToColumns(x), (y)=>List.RemoveNulls(y)),
                z1 = List.Combine(List.Transform({0,1,2,3,5,6,7,8},(y)=>z0{y})),
                z2 = List.Zip(List.Transform(z0{4}, (x)=>Text.Split(x,": "))),
                z3 = Record.FromList(z1,nmn)& Record.FromList(z2{1},z2{0}) ] [z3],
                 
    a2 = Table.Group(a1, nm{5}, {"new", (x)=>f(x)}, GroupKind.Local, (s,c)=> Number.From(c<>null)),
    a3 = Table.FromRecords(a2[new], nmn1, MissingField.UseNull),
    a4 = Table.TransformColumns(a3, {"Время", (x)=> DateTime.Time(x)})
in
    a4
Изменено: Garrys - 23.11.2023 12:21:32 (забыл убрать ",")
 
Garrys, спасибо, дома потестю. Корректно будет поменять File.Contents на Folder.Files? Просто чтобы кидать файл в папку и дальше запросом изменить структуру данных как у Вас в коде. Чтобы не было жёсткой привязки к имени файла.
Я пока не настолько хорош в кодинге на М напрямую, просто смотрел как выглядит код в расширенном редакторе после применения шагов в PQ и сам правил до нужного результата, а вот так чтобы сразу кодить - ещё не дорос, поэтому могу ошибаться
Изменено: gheser - 23.11.2023 11:09:31
 
Garrys, задачу решает? Решает. Почему бы и нет? Повеселила "игра в наперстки" с названиями колонок и в функции  :D  Я б так не смог, у меня так голова не работает. Сразу грустно становится, если такой вариант маячит на горизонте :)  Только запятую в конце  последней строки (a4) уберите.

gheser, нет, это не совсем так делается. Folder.Files("путь_к_папке") даст вам список файлов. В папке могут быть другие файлы, включая временные. Поэтому, расчет на то, что ваш файл будет стоять в первой строке, может оказаться ошибочным. Но если он вдруг гарантировано оказался на 1м месте, то можно, как вариант, fr = Excel.Workbook(Table.FirstValue(Folder.Files("путь_к_папке")))
Пришелец-прораб.
 
AlienSx, похвала от мастера - бальзам на душу) но я сначала пошел от Table.Group, имена колонок появлялись по мере написания..
 
gheser,  обратите внимание, в вашем примере таблица идет не с первого столбца, поэтому в шаге a1 есть List.Skip, который убирает этот пустой столбец
 
Цитата
Garrys написал:
я сначала пошел от Table.Group
все правильно, так и надо. Меня же зачем-то "понесло" через List.PositionOf таблицы нарезать. Но главное здесь - как эту таблицу обработать. Собственно, наши вариации - именно про это.
Пришелец-прораб.
 
AlienSx, в папке гарантированно будет только один файл. Я себе так автоматизировал создание отчётов по ежедневным продажам: тупо скачиваю с маркетплейса отчёт за нужный день, перекидываю его в определённую папку с заменой файла, и в файле с отчётом жму "обновить всё". Остальное делает запрос. Обрабатываемый файл в экселе не открываю, поэтому там временного файла не будет. Нужен ли будет при этом Table.FirstValue из Вашего последнего примера кода?
AlienSx, Garrys, спасибо за помощь и подсказки!
 
Цитата
gheser написал:
Нужен ли будет при этом Table.FirstValue из Вашего последнего примера кода?
Во-первых, чтобы не было разночтений - это переделка первой строки кода Garrys. Во-вторых, да - нужен, конечно. Вы не бойтесь - сами пробуйте что-то в расширенном редакторе.
Пришелец-прораб.
 
Проверил, всё отлично работает.. Допилил под себя, убрал строки с ошибками, ну и прочие косметические мелочи. Спасибо!
 
AlienSx, Garrys, вопрос не по теме. Сам вопрос поднимался ранее в отдельной теме, внятного решения тогда не было, но с момента последнего сообщения в ней прошло 3 года. Возможно, решение уже появилось, а у вас опыта всяко больше моего - может, сможете подсказать решение.

Есть ли возможность выгрузки результата (-ов) запроса (-ов) в обычную таблицу, не умную? Без VBA, а прямо из PQ
 
Цитата
gheser написал:
в обычную таблицу, не умную
мне о такой возможности неизвестно. Вы можете превратить вашу умную таблицу в глупый диапазон одной командой
Пришелец-прораб.
 
И потом после обновления данных через запрос проделывать это каждый раз? :)
 
gheser, нет. После этого действия связь с запросом разрывается, запрос переходит в статус Connection only и его надо опять выгружать на лист.
Пришелец-прораб.
Страницы: 1
Наверх