Uploaded by alibbook

Приручи данные с помощью Power

advertisement
Кен Пульс и Мигель Эскобар
Приручи данные с помощью
Power Query в Excel и Power BI
by
Ken Puls &
Miguel Escobar
Holy Macro! Books
PO Box 541731
Merritt Island, FL 32953
ПРИРУЧИ ДАННЫЕ
с помощью Power Query
в Excel и Power BI
Использование Power Query для получения и преобразования
исходных данных
Прежнее название «M Is for (Data) Monkey»
Кен Пульс
и Мигель Эскобар
Москва, 2022
УДК 004.424
ББК 32.372
П88
П88
Кен Пульс, Мигель Эскобар
Приручи данные с помощью Power Query в Excel и Power BI / пер. с англ.
А. Ю. Гинько. – М.: ДМК Пресс, 2022. – 572 с.: ил.
ISBN 978-5-93700-105-4
Иногда нас называют мартышками, работающими с данными, но на самом деле
мы чаще походим на волшебников. Наши данные редко появляются на свет в готовом к работе виде, и у нас могут уходить долгие часы на их очистку, фильтрацию
и преобразование. Power Query помогает сократить этот процесс при первичной
обработке данных, а все последующие обновления позволяет свести к простому
нажатию на кнопку. Когда дело касается импорта, очистки и преобразования исходных данных для дальнейшего анализа, освоить Power Query бывает гораздо
легче, чем выучить формулы Excel или язык программирования VBA.
Нет сомнений, что Power Query навсегда изменит подход специалистов Excel к
работе с данными. Если у вас есть Excel, значит, у вас уже есть Power Query – этот
инструмент встроен в Excel 2016 и выше. Эта книга поможет вам извлечь максимум пользы из Power Query.
УДК 004.424
ББК 32.372
Master Your Data with Power Query in Excel and Power BI, published by Holy Macro! Books.
Copyright © 2021, Russian-language edition copyright.
Все права защищены. Любая часть этой книги не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения
владельцев авторских прав.
ISBN 978-1-61547-058-7 (англ.)
ISBN 978-5-93700-105-4 (рус.)
© Tickling Keys, Inc., 2021
© Перевод, оформление, издание,
ДМК Пресс, 2022
Оглавление
Предисловие от издательства ......................................................................15
Предисловие ..........................................................................................................17
Как Power Query изменил НАШИ жизни ........................................................17
История Кена: «Кофе и Power Query» .........................................................17
История Мигеля: новый старт .....................................................................18
Благодарности от авторов ................................................................................19
Благодарности от Кена .................................................................................20
Благодарности от Мигеля .............................................................................21
Наши преданные читатели ..........................................................................22
И наконец… ....................................................................................................22
Глава 0. Революция данных ...........................................................................23
Общий сценарий для аналитиков данных ....................................................23
Преимущества и опасности черной магии....................................................24
Будущее изменилось .........................................................................................26
Почему Power Query – это магия? ...................................................................28
Извлечение .....................................................................................................29
Преобразование.............................................................................................29
Загрузка ..........................................................................................................30
Возможности Power Query и интеграция с другими продуктами ..............31
Компоненты Power Query.............................................................................32
Цикл обновлений Power Query ........................................................................34
Power Query Online ........................................................................................34
Microsoft 365 ...................................................................................................35
Excel 2016/2019/2021 .....................................................................................35
Excel 2010 & 2013 ...........................................................................................35
Power BI Desktop ............................................................................................35
Как использовать эту книгу .............................................................................36
Где найти Power Query? ................................................................................36
Excel 365 ..........................................................................................................36
Power BI Desktop ............................................................................................37
Предыдущие версии Excel............................................................................37
Подключение к данным ...............................................................................37
Особые пометки ............................................................................................38
Сопроводительные файлы ...........................................................................38
Глава 1. Основы Power Query ........................................................................39
Перед началом ...................................................................................................39
Изменение настроек Power Query по умолчанию в Excel .......................40
Изменение настроек Power Query по умолчанию в Power BI .................40
Извлечение .........................................................................................................41
6  Оглавление
Настройки подключения (выбор данных) .................................................41
Аутентификация............................................................................................42
Предварительный просмотр .......................................................................42
Выбор назначения запроса ..........................................................................43
Преобразование .................................................................................................44
Редактор Power Query ...................................................................................45
Преобразования по умолчанию ..................................................................46
Источник (Source) ..........................................................................................46
Повышенные заголовки (Promoted Headers).............................................47
Измененный тип (Changed Type) ................................................................47
Создание и изменение преобразований ...................................................48
Загрузка...............................................................................................................50
Установка типов данных ..............................................................................50
Переименование запроса ............................................................................52
Загрузка запроса в Excel ...............................................................................52
Загрузка запроса в Power BI .........................................................................53
Обновление запросов .......................................................................................54
Редактирование запросов ................................................................................55
Запуск редактора Power Query в Power BI ..................................................56
Запуск редактора Power Query в Excel ........................................................56
Просмотр шагов.............................................................................................57
Настройка шагов ...........................................................................................57
Влияние Power Query ........................................................................................60
Глава 2. Управление запросами ...................................................................61
Использование архитектуры со множеством запросов...............................61
Разделение запросов на E, T и L ..................................................................61
Преимущества совмещения запросов .......................................................62
Преимущества разделения запросов .........................................................63
Влияние разделения запросов на производительность..........................63
Ссылки на запросы ............................................................................................65
Создание базового запроса..........................................................................65
Ссылочные запросы ......................................................................................66
Визуализация дерева зависимостей запросов .........................................69
Просмотр зависимостей при помощи Monkey Tools ...............................70
Выбор места загрузки запроса ........................................................................71
Выбор места загрузки запроса в Power BI .................................................72
Выбор места загрузки запроса в Excel .......................................................72
Изменение места назначения .....................................................................76
Организация запросов ......................................................................................78
Создание папок в Power Query ....................................................................78
Перенос запросов в группы .........................................................................79
Изменение порядка следования запросов и групп ..................................80
Создание подпапок запросов ......................................................................81
Разделение существующих запросов .............................................................81
Заключительные мысли об архитектуре запросов .......................................82
Оглавление  7
Глава 3. Типы данных и ошибки...................................................................85
Типы и форматы данных..................................................................................85
Форматы .........................................................................................................85
Типы данных ..................................................................................................86
Как устанавливать формат данных в Power Query? .................................90
Порядок шагов имеет значение ..................................................................90
Важность определения типов данных .......................................................92
Распространенные ошибки в Power Query ....................................................93
Ошибки на уровне шага ...................................................................................94
Ошибки источников данных .......................................................................95
Ошибки вида «столбец X не найден» .........................................................97
Ошибки значений..............................................................................................99
Обнаружение ошибок ...................................................................................99
Ошибки из-за неправильного приведения типов .................................101
Ошибки по причине несовместимости типов данных..........................103
Проверка запросов на ошибки ......................................................................105
Обнаружение источника ошибок .............................................................105
Исправление исходного запроса ..............................................................106
Удаление запроса с ошибками ..................................................................108
Заключительные мысли о типах данных и ошибках .................................108
Глава 4. Перенос запросов между Excel и Power BI.........................109
Перенос запросов между решениями ..........................................................109
Перенос запросов Excel в новую рабочую книгу ....................................110
Перенос запросов из Excel в Power BI.......................................................113
Перенос запросов из Power BI в Excel.......................................................114
Перенос запросов из Power BI в новый проект Power BI .......................115
Импорт запросов из Excel в Power BI ............................................................115
Только внешние источники данных.........................................................116
Импорт модели данных Excel в Power BI .................................................118
Импорт данных на основе таблиц Excel – копирование .......................119
Таблицы Excel – сохранение подключения .............................................126
Заключительные мысли о переносе запросов между решениями ..........128
Глава 5. Импортирование из плоских файлов....................................131
Понимание процесса импорта данных ........................................................131
Определение системных настроек ...........................................................132
Как программа интерпретирует плоские данные..................................133
Импортирование файлов с разделителями.................................................135
Источник данных ........................................................................................136
Извлечение данных ....................................................................................136
Задача............................................................................................................137
Использование локали для установки корректных типов данных .....138
Импортирование файлов без разделителей ...............................................141
Подключение к файлу.................................................................................142
Очистка файлов без разделителей ...........................................................143
8  Оглавление
Разделение столбцов по позиции .............................................................145
Прелесть ошибок в Power Query ................................................................146
Удаление лишних столбцов .......................................................................148
Объединение столбцов ...............................................................................149
Разделение столбцов по разделителю .....................................................150
Исключение дублирующихся пробелов ...................................................151
Минута славы Power Query ........................................................................152
Глава 6. Импортирование из файлов Excel ..........................................155
Данные в активной рабочей книге ...............................................................155
Подключение к таблицам Excel .................................................................156
Подключение к табличным диапазонам .................................................158
Подключение к именованным диапазонам ............................................161
Динамические именованные диапазоны................................................163
Подключение к рабочим листам Excel из той же книги ........................165
Данные из других рабочих книг ....................................................................165
Подключение к файлу Excel .......................................................................166
Подключение к таблицам ..........................................................................168
Подключение к именованным диапазонам ............................................169
Подключение к рабочим листам ...............................................................170
Заключительные мысли о подключении к данным Excel .........................174
Глава 7. Простые техники преобразования данных ........................177
Снимаем проклятие сводных данных ..........................................................177
Подготовка данных .....................................................................................178
Отмена свертывания других столбцов ....................................................179
Повторное сведение данных при помощи сводной таблицы ..............181
Есть ли жизнь после обновления данных? ..............................................182
Разница между различными типами отмены свертывания ................183
Сведение столбца ............................................................................................184
Разделение столбцов.......................................................................................186
Разделение столбца на несколько столбцов............................................187
Разделение столбца на строки ..................................................................188
Разделение на столбцы с отменой свертывания против
разделения на строки ..............................................................................190
Фильтрация и сортировка ..............................................................................191
Фильтрация значений ................................................................................192
Применение контекстных фильтров........................................................195
Сортировка данных.....................................................................................197
Группирование данных ..................................................................................198
Глава 8. Добавление данных .......................................................................203
Базовые операции по добавлению данных .................................................203
Добавление двух таблиц.............................................................................205
Добавление дополнительных таблиц .......................................................208
Объединение запросов с разными заголовками ........................................211
Оглавление  9
Добавление таблиц и диапазонов в текущем файле ..................................213
Консолидация таблиц .................................................................................214
Консолидация диапазонов и рабочих листов .........................................218
Используйте =Excel.CurrentWorkbook() с осторожностью .....................221
Заключительные мысли о добавлении запросов........................................221
Глава 9. Объединение файлов ....................................................................223
Практический пример ....................................................................................223
Описание процесса .........................................................................................225
Методология объединения файлов ..........................................................225
Архитектура запросов при объединении файлов ..................................225
Шаг 0: подключение к папке ..........................................................................227
Подключение к локальной/сетевой папке ..............................................228
Подключение к папке SharePoint..............................................................229
Подключение к OneDrive для бизнеса......................................................231
Подключение к другим файловым системам .........................................231
Шаг 1: фильтрация и страховка на будущее ................................................232
Методология шага 1 ....................................................................................232
Применение шага 1 к нашему примеру...................................................233
Шаг 2: объединение файлов ...........................................................................235
Методология шага 2 ....................................................................................236
Применение шага 2 к нашему примеру...................................................236
Шаг 3: преобразование данных в запросе примера ...................................239
Почему нужно использовать запрос «Преобразовать пример
файла»? ......................................................................................................239
Использование запроса «Преобразовать пример файла».....................240
Шаг 4: преобразование данных в мастер-запросе .....................................243
Исправление ошибки на уровне шага в мастер-запросе ......................243
Сохранение свойств файлов ......................................................................244
Добавление дополнительных шагов ........................................................246
Обновление ......................................................................................................248
Использование данных ..............................................................................248
Добавление новых файлов .............................................................................249
Повышение эффективности с помощью сохранения верхних строк ......250
Глава 10. Объединение данных .................................................................253
Основы объединения данных ........................................................................253
Создание подготовительных запросов ....................................................254
Выполнение объединения запросов ........................................................254
Типы соединений ............................................................................................257
Внешнее соединение слева ........................................................................260
Внешнее соединение справа .....................................................................262
Полное внешнее соединение.....................................................................264
Внутреннее соединение .............................................................................265
Антисоединение слева ...............................................................................265
Антисоединение справа .............................................................................266
10  Оглавление
Полное антисоединение.............................................................................267
Декартовы произведения ...............................................................................268
Методология ................................................................................................268
Пример ..........................................................................................................268
Случайные декартовы произведения ......................................................271
Объединения с приблизительными совпадениями ...................................272
Методология ................................................................................................273
Пример ..........................................................................................................273
Поиск нечетких соответствий .......................................................................277
Основы нечеткого поиска ..........................................................................278
Таблицы преобразования ..........................................................................279
Управление порогом подобия ...................................................................281
Стратегии поддержки решений с нечетким поиском ...........................283
Глава 11. Источники данных в интернете ............................................285
Подключение к файлам данных в интернете .............................................285
Подключение к веб-страницам .....................................................................287
Подключение к данным на веб-странице ...............................................287
Естественные и предлагаемые таблицы ..................................................288
Добавление таблиц с использованием примеров ..................................289
Подключение к страницам без таблиц .........................................................291
Предостережения при работе с данными из интернета ...........................296
Сбор данных .................................................................................................296
Целостность данных ...................................................................................296
Надежность решения ..................................................................................297
Глава 12. Реляционные источники данных .........................................298
Подключение к базам данных .......................................................................298
Соединение с БД ..........................................................................................298
Управление учетными данными ..............................................................301
Не можете подключиться к нашей базе данных?...................................302
Использование навигатора........................................................................303
Исследование данных .................................................................................304
Свертывание запросов....................................................................................307
Что такое свертывание запросов? ............................................................308
Какие технологии поддерживает механизм свертывания запросов? ...310
Распространенные мифы относительно свертывания запросов.........311
Уровни конфиденциальности .......................................................................313
Объявление уровней конфиденциальности данных .............................315
Управление уровнями конфиденциальности данных ..........................315
Конфиденциальность и производительность.........................................316
Отключение движка конфиденциальности ............................................317
Оптимизация ...................................................................................................320
Глава 13. Преобразование табличных данных ..................................323
Сложные шаблоны сведения данных ...........................................................323
Оглавление  11
Сведение сгруппированных данных ........................................................323
Сведение вертикально сгруппированных данных ................................330
Сведение горизонтально сгруппированных данных ............................332
Сложные шаблоны отмены свертывания данных ......................................337
Отмена свертывания данных с подкатегориями ...................................337
Эффективная отмена свертывания данных с подкатегориями ...........345
Изменение запроса отмены свертывания данных
с подкатегориями ....................................................................................346
Сохранение значений null при отмене свертывания данных ..............349
Продвинутые техники группирования данных ..........................................352
Процент от целого .......................................................................................352
Ранжирование данных ...............................................................................355
Нумерация сгруппированных строк (номера строк по секциям)........359
Глава 14. Условная логика в Power Query .............................................364
Основы условной логики ................................................................................364
Описание набора данных...........................................................................364
Подключение к данным .............................................................................365
Создание условной логики при помощи интерфейса пользователя .....366
Условная проверка в ручном режиме ...........................................................369
Воспроизведение функции Excel ЕСЛИОШИБКА (IFERROR) ....................372
Работа с несколькими условиями .................................................................376
Сравнение со следующей/предыдущей строкой ........................................379
Столбцы из примеров .....................................................................................383
Глава 15. Значения в Power Query ............................................................389
Типы значений в Power Query .......................................................................389
Таблицы ............................................................................................................391
Списки ...............................................................................................................392
Синтаксис .....................................................................................................392
Создание списков ............................................................................................392
Преобразование списка в таблицу ...........................................................394
Создание списка из столбца таблицы ......................................................395
Создание списка списков ...........................................................................397
Записи ...............................................................................................................400
Синтаксис .....................................................................................................400
Создание записи..........................................................................................401
Преобразование записи в таблицу ...........................................................402
Создание нескольких записей...................................................................402
Преобразование нескольких записей в таблицу ....................................403
Доступ к записям таблиц по позиции (индексирование строк) ..........405
Доступ к записям таблиц по критерию....................................................407
Создание записей из каждой строки таблицы........................................410
Значения ...........................................................................................................412
Двоичные данные............................................................................................413
Ошибки .............................................................................................................413
12  Оглавление
Ошибки на уровне строки..........................................................................413
Ошибки на уровне шага .............................................................................414
Функции ............................................................................................................415
Ключевые слова в Power Query ......................................................................418
#binary ...........................................................................................................419
#date, #datetime и #datetimezone ..............................................................420
#time ..............................................................................................................421
#duration .......................................................................................................422
type ................................................................................................................423
#table .............................................................................................................426
Глава 16. Изучаем язык M .............................................................................429
Структура запроса на языке M ......................................................................429
Структура запроса .......................................................................................430
Область определения запроса и идентификаторы ................................432
Обобщенные идентификаторы .................................................................434
Комментарии к коду ...................................................................................435
Собираем все воедино ................................................................................437
Понимание процесса выполнения запроса .................................................438
Что такое ленивое вычисление? ...............................................................439
План выполнения запроса .........................................................................440
Итераторы (построчное выполнение) ..........................................................443
Ремарка по поводу рекурсивных функций в Power Query ....................443
Ключевые слова each и _.............................................................................444
Другие техники ................................................................................................449
Получение первого значения из столбца таблицы ................................449
Замена на null при ошибке навигации ....................................................451
Создание динамического списка заголовков типизированных
столбцов ....................................................................................................452
Создание динамического списка заголовков нетипизированных
столбцов ....................................................................................................456
Глава 17. Параметры и пользовательские функции ........................461
Воссоздание метода объединения файлов ..................................................461
Создание примера файла (Sample File) ....................................................462
Создание параметра Sample File Parameter ............................................463
Создание преобразования файла (Transform Sample) ...........................465
Создание функции Transform Function ....................................................466
Вызов функции Transform Function..........................................................467
Обновление функции Transform Function ...............................................467
Ключевые выводы .......................................................................................468
Создание настраиваемых функций с помощью параметров ...................469
Создание параметра FilePath ....................................................................470
Создание запроса Timesheet Transform ...................................................471
Создание функции Timesheet Function....................................................473
Обновление запроса Timesheet.................................................................473
Оглавление  13
Создание настраиваемых функций вручную ..............................................477
Построение сценария разового применения .........................................477
Преобразование запроса в функцию .......................................................478
Вызов функции ............................................................................................481
Отладка настраиваемых функций ............................................................482
Восстановление функциональности ........................................................484
Таблицы динамических параметров ............................................................485
Проблема с динамическими путями к файлам ......................................485
Реализация таблицы динамических параметров ..................................487
Создание таблицы параметров .................................................................487
Реализация функции fnGetParameter.......................................................489
Вызов функции ............................................................................................490
Применение таблиц параметров ..................................................................492
Глава 18. Техники работы с датой и временем..................................494
Определение границ календаря ....................................................................494
Динамическое создание границ календаря ............................................495
Корректировка начальной и конечной дат для нестандартных
финансовых периодов.............................................................................497
Корректировка начальной и конечной дат для 364-дневного
календаря ..................................................................................................499
Календари с последовательными датами....................................................501
Создание календаря....................................................................................501
Обогащение календаря за счет дополнительных столбцов..................503
Столбцы для финансовых периодов в 12-месячном календаре ..........503
Столбцы-идентификаторы периодов для 364-дневного календаря ...504
Столбцы финансовых периодов для календарей 4-4-5
(и их разновидностей).............................................................................506
Что находится в файле с примерами?......................................................509
Заполнение особых диапазонов даты и времени.......................................510
Заполнение определенного количества дат ...........................................510
Заполнение определенного количества часов по каждой дате ...........512
Заполнение определенного количества дат с заданными
интервалами .............................................................................................513
Разнесение данных на основе таблиц с датами..........................................515
Разнесение данных по дням ......................................................................515
Разнесение данных по целым месяцам ...................................................518
Разнесение данных по заданному количеству месяцев
от начальной даты ...................................................................................522
Заключительные штрихи к разнесению данных....................................525
Глава 19. Оптимизация запросов ..............................................................527
Оптимизация настроек Power Query ............................................................527
Глобальные параметры загрузки данных................................................527
Глобальные параметры редактора Power Query .....................................528
Глобальные параметры безопасности .....................................................528
14  Оглавление
Глобальные параметры конфиденциальности .......................................529
Настройки текущей книги (файла) – фоновые данные .........................529
Настройки текущей книги (файла) – другие ...........................................531
Использование функций буферизации........................................................531
Форсирование вычисления значения ......................................................532
Буферизация вычисления значения ........................................................534
Снижение временных лагов во время разработки.....................................537
Стратегия уменьшения временных лагов ...............................................538
Пример борьбы с временными лагами при разработке .......................539
Адаптация решения для снижения временных лагов ...........................541
Изменение данных в предпросмотре ......................................................544
Ошибка Formula Firewall ................................................................................544
Ошибка Formula.Firewall №1: несовместимость уровней
конфиденциальности ..............................................................................545
Ошибка Formula.Firewall № 2: доступ к источнику данных .................545
Вызов ошибки перестроения сочетания данных ...................................546
Перестроение сочетания данных против создания цепочек
запросов.....................................................................................................548
Перестроение сочетания данных против выравнивания запросов ....551
Перестроение сочетания данных при передаче значений в SQL ........553
Заключительные мысли об ошибках Formula.Firewall ..........................555
Глава 20. Автоматизация обновлений ....................................................557
Варианты автоматического обновления в Excel.........................................557
Обновления в Excel без VBA...........................................................................557
Фоновое обновление ..................................................................................558
Обновление каждые X минут ....................................................................558
Обновление при открытии рабочей книги .............................................559
Быстрая загрузка данных ...........................................................................559
Автоматизация обновлений запросов в Excel с помощью VBA ...............560
Обновление одного подключения ............................................................560
Обновление в определенном порядке .....................................................563
Обновление всех запросов .........................................................................565
Проблемы с синхронным обновлением ..................................................565
Расписание обновлений в Power BI ..............................................................566
Предметный указатель ...................................................................................568
Предисловие от издательства
Отзывы и пожелания
Мы всегда рады отзывам наших читателей. Расскажите
нам, что вы думаете об этой книге, – что понравилось
или, может быть, не понравилось. Отзывы важны для нас,
чтобы выпускать книги, которые будут для вас максимально полезны.
Вы можете написать отзыв или оставить комментарий на странице книги https://dmkpress.com/catalog/computer/
data/978-5-93700-105-4/ в разделе «Отзывы и рецензии».
Также можно послать письмо главному редактору по
адресу dmkpress@gmail.com; при этом укажите название
книги в теме письма.
Если вы являетесь экспертом в какой-либо области
и заинтересованы в написании новой книги, заполните форму на нашем сайте по адресу http://dmkpress.com/
authors/publish_book/ или напишите в издательство по адресу dmkpress@gmail.com.
Список опечаток
Просканируйте код
камерой смартфона
и пройдите по ссылке
Хотя мы приняли все возможные меры для того, чтобы обеспечить высокое качество наших текстов, ошибки все равно случаются. Если вы найдете
ошибку в одной из наших книг – возможно, ошибку в основном тексте или
программном коде, – мы будем очень благодарны, если вы сообщите нам о
ней. Сделав это, вы избавите других читателей от недопонимания и поможете нам улучшить последующие издания этой книги.
Если вы найдете какие-либо ошибки в коде, пожалуйста, сообщите о них
главному редактору по адресу dmkpress@gmail.com, и мы исправим это в следующих тиражах.
Нарушение авторских прав
Пиратство в интернете по-прежнему остается насущной проблемой. Издательства «ДМК Пресс» и Tickling Keys очень серьезно относятся к вопросам
защиты авторских прав и лицензирования. Если вы столкнетесь в интернете
с незаконной публикацией какой-либо из наших книг, пожалуйста, пришлите
нам ссылку на интернет-ресурс, чтобы мы могли применить санкции.
Ссылку на подозрительные материалы можно прислать по адресу электронной почты dmkpress@gmail.com.
Мы высоко ценим любую помощь по защите наших авторов, благодаря
которой мы можем предоставлять вам качественные материалы.
Предисловие
Как Power Query изменил НАШИ жизни
История Кена: «Кофе и Power Query»
Именно такое название было указано в моем календаре Outlook для ноябрьской встречи в далеком уже 2013 году. Это было во время одного из
слетов Microsoft MVP. Незадолго до этого инструмент сменил свое прежнее
имя Data Explorer, и у меня была запланирована встреча за кофе с Мигелем
Льописом (Miguel Llopis) и Фейсалом Мохамудом (Faisal Mohamood) из команды Power Query, где мы собирались обсудить преимущества и недостатки
данного инструмента с позиции пользователя Excel.
В той беседе я высказал свое мнение о том, что Power Query прелестен, но
в то же время по своей сути является не более чем неуклюжей заменой SQL
Server Management Studio. Я по сей день отчетливо помню ту часть дискуссии.
Тогда я много работал с SSMS и Power Query и был раздосадован тем, что новый продукт фактически выполняет ограниченный круг задач Management
Studio. В то же время у меня не получалось заставить его работать так же.
То, что произошло дальше, перевернуло все мои жалобы и стенания с ног
на голову. Я восстанавливаю события по памяти, но ответ был примерно
следующий:
«Кен, Power Query – это вовсе не замена SSMS. Мы создали этот инструмент
для пользователей Excel… Чтобы им никогда не пришлось изучать и использовать язык SQL».
Тем, кто меня знает, прекрасно известно, что я редко лезу за словом в
карман, но в тот момент я ничего не смог сказать. Этот ответ буквально
перевернул мой мир.
Вы должны понимать, что я не совсем обычный пользователь Excel. Я прекрасно знаю SQL – до опасного прекрасно. К тому же у меня есть большой
опыт работы с языками VBA, VB.NET, C#, XML и другими. И хотя я люблю
неизведанные технологии и новые вызовы, все эти языки я изучал по необходимости. Как правило, мои требования бывают довольно сложными,
и я бросаюсь в новые для себя области по принципу «утону или выплыву».
Встреча, о которой я поведал, изменила мое отношение к Power Query навсегда. Я сделал шаг назад и взглянул на этот инструмент под другим углом.
После этого я начал использовать его по его прямому назначению – посредством интерфейса и без написания запросов SQL везде, где это возможно.
И вы знаете, Power Query расцвел для меня новыми красками – он позволил
мне добраться до самой сути данных и решать задачи, ранее мне неподвластные.
Я обожаю Power Query. И не только за то, что он позволяет мне делать, но
и за то, как просто он позволяет это делать – без необходимости писать код
18  Предисловие
вообще. Да, в этом инструменте есть свой язык программирования, к услугам которого вы можете прибегать по мере роста сложности ваших задач,
но это совсем не обязательно. И именно это делает Power Query таким привлекательным – он обладает одним из лучших интерфейсов, какие я только
видел, и, по сути, пишет код за вас, пока вы нажимаете на кнопки. Также мне
нравится это средство за то, как быстро наши ученики способны освоить его
и начать реализовывать свои первые решения с его помощью, приносящие
реальную пользу. Этот продукт целиком и полностью нацелен на применение
в бизнесе.
Что касается меня лично, то Power Query позволил мне уйти из офиса и
организовать собственное дело. Мы проводим очное и заочное обучение, а
также распространяем платное дополнение к Excel – Monkey Tools, способное
значительно облегчить выполнение задач при работе с Power Query и Power
Pivot в Excel. В конце концов, я не знаю большего счастья, чем видеть благодарного и просветленного ученика, понявшего, как можно улучшить свою
работу и при этом еще и сэкономить время.
История Мигеля: новый старт
Перед тем как начать собственный бизнес в качестве фрилансера в
2013 году, я прочно застолбил за собой репутацию продвинутого пользователя, так что решил сохранить это прозвище после ухода из офиса и назвать
так свой канал на YouTube и новый сайт – The Power User.
Я никогда не был айтишником, но всегда был тем парнем, который старается выжать максимум возможного из имеющихся под рукой технологических средств, и по большей части таким средством был обычный Excel,
и далеко не всегда последней версии. В какой-то момент Excel и сводные
таблицы стали моим вторым именем.
В 2013 году я познакомился с Power Query. Я даже не могу вспомнить, как
именно это было, но помню, что в моей повседневной рутинной работе тогда
приходилось довольно часто фильтровать данные, удалять столбцы, повышать заголовки, разворачивать столбцы и т. д. Я не знал VBA (и до сих пор
не знаю), так что Power Query буквально открыл для меня новый мир с новыми возможностями, которых раньше у меня не было. Мне больше не было
нужды думать о том, чтобы становиться экспертом в VBA или SQL – все, что
мне нужно было, – это освоить Power Query, с которым все мои проблемы с
манипуляцией данными остались бы в прошлом.
Интерфейс пользователя Power Query полностью меня захватил. Он показался мне настолько интуитивно понятным, словно можно было усесться
в него, пристегнуться ремнями и рассекать между моими данными так, как
мне нравится. В то время это был совершенно новый инструмент, и в интернете не было абсолютно никакой информации о том, как выжать из него максимум. Так что я решил заполнить это зияющую пустоту и начать создавать
полезный обучающий контент о Power Query самостоятельно.
В процессе ведения блога и записи видео я познакомился с массой людей,
среди которых были Роб Колли (Rob Collie) и Билл Джелен (Bill Jelen), и через
них я узнал о Кене, в то время активно увлекающемся Power Query. Ни разу не
Предисловие  19
встречаясь лично, мы с ним решили объединить усилия, поскольку чувствовали, что наши знания в области Power Query дополняют друг друга, к тому
же мы оба страстно хотели донести до людей полезную информацию о таком богатом инструменте. Мы запустили проект под названием PowerQuery.
Training, и информация, накопленная за время его работы, легла в основу
первого издания нашей книги. Во время ее написания и даже до этого мы
прекрасно осознавали всю мощь Power Query и его способность максимально облегчить жизнь пользователям Excel. Для нас этот инструмент был
тогда и остается сейчас самым большим прорывом в области средств
обслуживания данных.
С момента выхода первого издания книги прошло много времени, на протяжении которого читатели, друзья и коллеги то и дело напоминали нам о
том, что некоторые картинки и приемы в ней постепенно устаревают, одновременно признавая пользу книги в деле освоения Power Query и раскрытия
его потенциала. Признаться, это и было нашей изначальной целью – мы
хотели изменить жизнь людей так же, как когда-то Power Query изменил
нашу жизнь, сделав процесс преобразования данных простым и интуитивно
понятным.
С 2015 по 2021 год мы с Кеном получили огромное множество подтверждений того, что Power Query действительно изменил не одну жизнь – косвенно или напрямую. И такие подтверждения всякий раз вызывают улыбку на
наших лицах. Это в том числе повлияло на наше желание написать второе
издание книги и сделать его таким, каким оно в итоге получилось. Мы хотели все сделать правильно, и ради этого нам пришлось ждать идеального
момента для выхода книги.
Благодарности от авторов
Издание книги – долгий и кропотливый процесс, и немало людей принимают
в нем прямое или косвенное участие. А без помощи перечисленных ниже
людей книга, которую вы держите в руках, никогда бы не увидела свет.
Билл Джелен (Bill Jelen). Более доброжелательного и дружелюбного человека нам даже трудно представить. Написание любой книги отнимает очень
много сил и времени, и совмещать этот процесс с повседневными рабочими
обязанности очень и очень трудно, особенно когда речь идет о столь динамично развивающейся технологии, как Power Query. И представьте себе, что
в последний момент вам сдают книгу, которая оказывается вдвое толще,
чем было запланировано изначально! Билл же со смирением и пониманием
принимал все наши задержки и правки, и только благодаря ему мы смогли
управиться в срок.
Мигель Льопис (Miguel Llopis). С той самой встречи за чашкой кофе Мигель стал для нас своим парнем в Microsoft. Он как-то даже пошутил, что его
основная работа – отвечать на письма от Кена. Мигель на протяжении всего
времени нашего знакомства оказывал нам неоценимую поддержку и очень
быстро реагировал на просьбы внести какие-то изменения или исправить
ошибки.
20  Предисловие
Курт Хагенлохер (Curt Hagenlocher), Эрен фон Лех (Ehren Von Lehe), Мэтт
Массон (Matt Masson) и все парни из команды Power Query / Power BI. Нам
даже трудно выразить, с какой готовностью и рвением эти ребята отвечали
на наши письма. Их помощь и разъяснения очень помогли нам в написании
данной книги.
Вин Хопкинс (Wyn Hopkins), Кристиан Ангьял (Cristian Angyal) и Мэтт Эллингтон (Matt Allington). Эти ребята оказали нам большую поддержку с материалами, которые мы могли истолковать неправильно.
Бесчисленное количество людей, оставивших полезные комментарии в наших блогах и видео, посетивших наши обучающие тренинги и поделившихся
собственными решениями со всем миром. Каждый из вас помог нам в освоении новых методов и приемов, которые мы использовали при написании
этой книги, да и было просто весело.
Благодарности от Кена
Наша первая книга фактически началась 6 марта 2014 года с письма, в котором меня представили Мигелю Эскобару. У него была мечта написать книгу, посвященную Power Query. Несмотря на то что мы ни разу до этого не
виделись, да и после знакомства не встречались еще несколько лет, идеи
и энергия Мигеля меня очень вдохновили. Итогом нашего сотрудничества
стало первое издание этой книги под названием «M is for Data Monkey»,
обучающий сайт Power Query Workshop, наш проект Power Query Academy и,
наконец, второе издание книги, которое вы держите в руках. Без вовлеченности Мигеля во все эти начинания у нас бы точно ничего не получилось. Его
страсть зарядила меня на покорение новых высот в освоении Power Query,
особенно это касается языка M. Хотя я до сих пор не могу понять, как он
может работать 24 часа в сутки!
Также эта книга никогда бы не была закончена без поддержки моей семьи.
И это был больше, чем просто оплот и очаг. Моя супруга Диана (Deanna)
несколько раз прочитала книгу от корки до корки, исправив в ней мои опечатки и характерные для меня ошибки, когда мой мозг и пальцы находятся в разных абзацах. Кроме того, хотелось бы отдельно поблагодарить мою
дочь Аннику (Annika) за ликбез относительно употребления так называемой
оксфордской запятой (запятая, которая ставится перед союзом «и» в конце
списка. – Прим. перев.), включая тот факт, что Тейлор Свифт ее не использует.
Но было бы неплохо, если бы она сказала мне это раньше, чем за 72 часа до
сдачи книги в печать!
Хотелось бы отметить команду нашего сообщества Excelguru,оборонявшую
крепость, пока я дописывал книгу. Ребека Сакс (Rebekah Sax) успешно справлялась со всей грудой дел, которую мы на нее свалили, Абдулла Альхарби
(Abdullah Alharbi) реализовывал все наши идеи в коде инструмента Monkey
Tools, а мой друг, ментор и бывший менеджер Джим Олсен (Jim Olsen) приглядывал за нашей бухгалтерией. Без вашей поддержки мы бы никогда не
добились успеха и не завершили то, что начали.
Все, кто работает в команде Excel, могут подтвердить вам, какие страстные
письма я порой пишу в службу поддержки. Я абсолютно уверен, что чаще
Предисловие  21
остальных с большим отрывом мои письма читает Ги Ханкин (Guy Hunkin),
работающий на стыке технологий Power Query и Excel и отвечающий за интеграцию этих инструментов. Бесконечное терпение этого человека меня
просто поражает, и я даже не знаю, как поблагодарить его за то, что он всегда
воспринимает критику профессионально и никогда – персонально. Я также
очень рад, что, помимо ответов на мои письма и звонки, Ги лично посетил
пару моих обучающих семинаров, что в конечном счете помогло ему улучшить выпускаемый продукт.
Наконец, я хотел бы поблагодарить нашего партнера по бизнесу Мэтта
Эллингтона (Matt Allington). Мэтт присоединился к нам с Мигелем в начале
пандемии COVID, чтобы помочь нам расширить проект Power Query Academy.
С тех пор мы провели ребрендинг, переименовавшись в https://skillwave.training,
и предлагаем ученикам курсы с тренерами или в режиме самообразования
по Power Query, Power Pivot, Power BI и другим дисциплинам. Мы с Мэттом
дружим очень давно, и его советы в отношении составления плана и расстановки приоритетов очень помогли в издании этой книги.
Благодарности от Мигеля
Я бы в первую очередь хотел поблагодарить ВАС за то, что читаете эту
книгу. Да… ВАС! Именно вы являлись главной движущей силой нашей работы и наших намерений снабдить читателя всеми необходимыми ресурсами
для превращения в [М]астера данных, [М]ага данных и в конечном счете в
[М]артышку данных. Я заранее хотел бы сказать вам спасибо за стремление
сделать этот мир лучше – по крайней мере в области принятия бизнес-решений в мире данных.
Также я хотел бы сказать спасибо всем практикующим профессионалам
в Excel и бизнес-аналитике, сподвигнувшим нас на написание этой книги и
реализацию других проектов, связанных с Power Query. Быть частью такого
сообщества – настоящая честь, и вы можете присоединиться к нему, просто
начав использовать эти инструменты для работы с данными.
Не забываю я и о помощи моих друзей и семьи. Но я боюсь кого-то из
них не упомянуть, поэтому даже не буду пытаться это сделать, так безопаснее! :)
Особая благодарность Кену за его всестороннюю поддержку и невероятные усилия по преодолению языкового барьера при общении со мной. Мой
испанский английский зачастую берет верх, но Кен меня всегда понимает и
помогает выразить мысли более понятно.
Также хотелось бы отметить парней из команды Power Query: Курта
Хагенлохера (Curt Hagenlocher), Эрена фон Леха (Ehren Von Lehe), Мэтта
Массона (Matt Masson) и Мигеля Льописа (Miguel Llopis), которых я спамил начиная с 2013 года. Сегодня уже 4 июля 2021-го, но они ни разу не
проигнорировали ни одно мое письмо и даже не попросили меня остановиться. Если бы мне понадобились курсы по сохранению терпения и
обслуживанию клиентов, я бы обратился именно к ним. Они в этом деле
настоящие MVP!
22  Предисловие
Наши преданные читатели
Многие из наших читателей сделали предзаказ этой книги сразу же, как
только она появилась на Amazon, другие подписались на наши курсы Power
Query Academy по адресу https://skillwave.training (или https://powerquery.training).
Всем этим людям была обещана бесплатная копия новой книги, и, к сожалению, они вынуждены были очень долго ждать ее. Спасибо за терпение
и понимание. Мы очень надеемся, что потраченное время будет с лихвой
компенсировано пользой от книги.
И наконец…
Огромная благодарность членам Power Query Academy на сайте Skillwave.
Training, которые выразили готовность проверить на ошибки нашу книгу в
очень сжатые сроки. Отдельно мы хотим выразить признательность Сету
Барону (Seth Barron), Рэндаллу Макгенри (Randall McHenry), Стэнтону Берлински (Stanton Berlinsky), Джну Хэквуду (John Hackwood), Митчеллу Аллану
(Mitchell Allan), Нику Осдейл-Попа (Nick Osdale-Popa), Майку Кардашу (Mike
Kardash) и Лиллиан (Lillian) – каждый из них прислал нам более десяти неточностей, обнаруженных в издании на этапе корректуры.
Также мы еще раз хотим сказать спасибо ВАМ за то, что купили книгу,
поверили в наши методы обучения и стали частью движения Power Query.
Эта книга была написана для вас – чтобы помочь вам управлять данными.
Мы очень надеемся, что вы освоите этот навык и посчитаете это учебное
пособие своим лучшим приобретением.
Глава
0
Революция данных
Общий сценарий для аналитиков данных
Производим ли мы базовый ввод информации, строим ли простые отчеты
или разрабатываем полноценные бизнес-решения с использованием VBA,
SQL и/или других языков, мы так или иначе работаем с данными. Наши наборы навыков и умений могут сильно варьироваться, но в основном работа
с информацией включает в себя:





извлечение данных из источника;
преобразование данных под свои нужды;
добавление наборов данных;
объединение разных данных вместе;
обогащение данных для расширенного анализа.
Мы работаем с данными, и как бы мы ни именовали наши должности
официально, наша задача – получить данные, очистить их и превратить в
информацию. Какого-то лоска и великой славы в нашей работе нет, но она
невероятно важна, поскольку без нее аналитическая информация будет оставаться разрозненной и ненадежной.
Преобразование
Трудяга в Excel
Таблица, пригодная
для работы в Excel
Рис. 0.1. За кулисами все мы работяги от Excel и информационные трудяги,
пытающиеся достичь своих целей в работе с данными
Долгие годы нашим основным рабочим инструментом был Microsoft Excel.
И хотя Excel обладает достаточной функциональностью для построения пол-
24  Глава 0. Революция данных
ноценных систем бизнес-аналитики на основе данных, в вопросе превращения сырых данных в пригодную для анализа информацию этот инструмент
сам по себе не так силен. Иногда большую часть своего рабочего времени мы
тратим как раз на то, чтобы получить данные из источника, подготовить их
для анализа, преобразовав в привычные нам таблицы, и передать системе
анализа или формирования отчетности.
Но те, кто знают нашу работу поближе, понимают, что мы не просто трудяги, а настоящие Волшебники данных! Наши исходные данные редко появляются на свет в виде, пригодном для анализа, – гораздо чаще нам приходится тратить долгие часы на их очистку, фильтрацию и преобразование
в приемлемый вид.
После завершения процесса преобразования данных мы можем с легкостью использовать весь доступный арсенал инструментов для аналитики.
Условное форматирование, фильтрация, сводные таблицы, диаграммы, срезы и многое другое – все эти средства можно применять для свершения настоящей магии и удивления аудитории.
Но мы вступаем в игру на гораздо более ранней стадии процесса. Нам
поступают грязные и сырые данные, обычно хранящиеся в текстовых файлах или в Excel (а если ОЧЕНЬ повезет, в базе данных), и мы используем все
имеющиеся у нас средства для их очистки и подготовки к использованию.
В конечном счете наша цель проста: максимально быстро привести исходные
данные к табличной форме, сохранив при этом их точность и масштабируемость. Для каждой задачи данные могут поступать разрозненно из самых
разных источников, и наша задача – собрать их все воедино. Без магии здесь
точно не обойтись…
Сырые данные в разном
виде и форме
(из одного или нескольких
источников)
Здесь творится
магия
(с помощью формул Excel,
VBA и иных средств)
Результат усердной работы
таблица, готовая к загрузке или
анализу
Рис. 0.2. Черная магия: что происходит за сценой при консолидации данных
Преимущества и опасности черной магии
Настоящие волшебники Excel используют в своем деле различные колдовские техники – иногда отдельно, иногда в сочетании с другими инструментами. Вот лишь некоторые из них:
 формулы Excel (Excel formulas). Зачастую к этой технике разработчики
прибегают в первую очередь, используя полное многообразие фор-
Преимущества и опасности черной магии  25
мул, включая ВПР (VLOOKUP), ИНДЕКС (INDEX), ПОИСКПОЗ (MATCH),
СМЕЩ (OFFSET), ЛЕВСИМВ (LEFT), ДЛСТР (LEN), СЖПРОБЕЛЫ (TRIM),
ПЕЧСИМВ (CLEAN) и др. Хотя формулами в Excel пользуются практически все, их сложность и реализуемые с их помощью задачи зависят
в большей степени от опыта пользователя или разработчика;
 VBA (Visual Basic for Applications). Мощный язык программирования,
способный обеспечить полноценное и динамическое преобразование
данных. В то же время эта техника обычно доступна только продвинутым пользователям Excel, обладающим определенным опытом в
программировании и ощущающим в себе силы разобраться во всех
нюансах языка;
 выражения SQL (SQL Statements). Эта техника подразумевает использование еще одного языка – на этот раз языка запросов SQL – для манипулирования данными. Это очень мощный язык, с помощью которого
можно выбирать, сортировать, фильтровать, группировать данные и
производить с ними множество других действий. В реальности же этой
техникой также пользуются только профессионалы, тогда как обычный
пользователь Excel даже не знает, как подступиться к этой теме. Язык
SQL – это главный инструмент разработчиков баз данных по всему
миру, но и пользователям Excel, честно говоря, было бы неплохо познакомиться с его основами.
Объединяет все эти инструменты то, что в прежние времена при преобразовании данных в полезную информацию мы были ограничены только ими.
Однако, несмотря на все преимущества этих средств работы с данными,
им присущи два серьезных недостатка: время, требуемое на реализацию
решения, и время, необходимое для освоения инструмента.
И хотя самым могущественным волшебникам по силам строить полноценные решения по загрузке и преобразованию исходных данных при помощи
только одних этих средств, на освоение этой древней магии у них уходит
не один год, а затем они вынуждены тратить много времени на разработку,
тестирование и поддержку своих решений. Кроме того, таким решениям
зачастую катастрофически не хватает гибкости: при небольшом изменении
формата исходных данных разработчику может потребоваться немало времени на корректировку процедуры импорта, как и при добавлении нового
источника.
Это ведет к третьей опасности наличия в компании таких волшебников:
все они строят потрясающие решения, которые перестают работать сразу
после их ухода. И тогда в компании понимают, что ничего не понимают в
созданном алгоритме и что никто разобраться в нем не в силах.
А иногда задачу сбора и подготовки данных поручают тем, кто просто не
в состоянии освоить все эти магические премудрости. И хотя в этом случае
компания не будет так сильно страдать во время отказа настроенной волшебником системы, хорошего здесь тоже мало, поскольку такой человек будет
бесконечно растрачивать временные и финансовые ресурсы компании, на
ежедневной основе совершая одни и те же никому не нужные операции импорта и трансформации данных.
26  Глава 0. Революция данных
Остановитесь на секунду и подумайте, сколько времени в вашей организации тратится каждый день на повторяющиеся операции по очистке входных
данных в Excel. Умножьте это время на среднюю зарплату в вашей компании, а
теперь на количество подобных компаний в вашей отрасли. Нам продолжать?
Стоимость неэффективной производительности будет очень и очень высока.
Нет, нам нужно что-то другое. Какой-то продукт, который можно будет
достаточно быстро освоить и который позволит автоматизировать процесс
загрузки и очистки данных, чтобы мы могли сконцентрироваться на превращении данных в информацию и тем самым сэкономить деньги компании.
И такой продукт уже есть! Встречайте Power Query!
Будущее изменилось
Power Query – решение всех проблем в работе с данными, поскольку этот инструмент практически лишен недостатков, присущих всем перечисленным
выше техникам. Освоить Power Query можно достаточно быстро, ведь он обладает одним из наиболее интуитивно понятных интерфейсов, с которыми
нам доводилось работать. Кроме того, все производимые действия фиксируются в последовательности шагов, которые впоследствии можно просмотреть или изменить при необходимости. И все, что было сделано при помощи
Power Query, можно воспроизвести посредством пары щелчков мыши.
Для нас – людей, которые долгие годы реализовывали решения в Excel с
помощью перечисленных выше техник, – Power Query явился глотком свежего воздуха, и сразу по нескольким причинам.
Первая из них состоит в простоте этого инструмента, работе в котором
очень легко обучиться. В процессе выполнения импорта и преобразования данных освоить Power Query можно даже быстрее, чем формулы Excel,
а сложные решения с его помощью можно реализовывать легче, чем в VBA.
Преимущества инструмента
–>
Время на освоение инструмента
VBA
Формулы Excel
Минуты
Время на освоение –>
Рис. 0.3. Power Query задумывался как простое в использовании
средство преобразования данных
Годы
Будущее изменилось  27
Именно простотой использования Power Query мы объясняем повсеместное исчезновение с арены прежних волшебников, ловко манипулирующих
данными при помощи старых средств. Даже если один из таких волшебников
наворотит какое-нибудь сложное решение в Power Query, то после его ухода
можно будет с гораздо меньшими усилиями найти того, кто с минимальными расходами на обучение сможет поддерживать и расширять прежний
функционал. Затраты в этом случае будут исчисляться не неделями, а часами.
Каким бы странным это ни казалось профессиональным разработчикам
Excel, но рядовым сотрудникам компании не доставляет удовольствия разбираться в сложных формулах этого программного пакета. Они хотят просто открыть инструмент, подключиться с его помощью к источнику данных,
нажать пару кнопок, чтобы очистить набор данных, загрузить результат в
программу и построить необходимый им отчет. По этой причине Power Query
пользуется большой популярностью не только у разработчиков, хорошо владеющих формулами в Excel. С такими богатыми возможностями интерфейса
пользователю в большинстве случаев не придется запоминать никаких формул и функций для получения необходимого результата.
ИСПОЛЬЗОВАНИЕ СРЕДСТВ ПРЕОБРАЗОВАНИЯ
Все пользователи
Excel
Формулы
VBA
SQL
Влияние Power
Query
Рис. 0.4. Простота использования Power Query привлекает не только сторонников
классических методов работы
У нас нет ни малейших сомнений в том, что Power Query полностью изменит подход в работе с данными всех пользователей Excel, включая продвинутых разработчиков. Мы хотим особо отметить, что ни в коем случае
не принижаем значимости формул Excel, а также языков VBA и SQL. В конце
концов, без этих инструментов не было бы и нас таких, какими мы являемся.
Формулы до сих пор абсолютно незаменимы во многих аспектах работы с
Excel, не касающихся преобразования данных, – Power Query вам здесь никак
28  Глава 0. Революция данных
не поможет. Знание VBA позволит пользователю реализовывать более сложные алгоритмы, включая подключение к другим приложениям и создание
макросов для импорта и экспорта данных. Ну а запрос на языке SQL, написанный настоящим профессионалом, всегда будет давать фору по скорости
выполнения запросу Power Query.
Однако что касается задачи подключения к источнику, импорта исходных данных, их очистки и преобразования, а также загрузки в Excel – тут у
Power Query конкурентов нет, ведь только этот инструмент позволит полностью автоматизировать весь процесс с минимальными затратами времени.
А с учетом регулярных обновлений, выпускаемых командой Power Query,
разрывы в эффективности между запросами SQL и Power Query постоянно и
стремительно уменьшаются.
Также стоит помнить, что Power Query относится не только к Excel. В прошлом, если бы вы построили систему преобразования и загрузки данных в
Excel, она навсегда осталась бы в этой среде, а для ее переноса на другую
платформу потребовалось бы полностью ее переписывать. В то же время
в основе Power Query изначально заложены возможности переноса и масштабируемости ваших решений. Таким образом, одно и то же технологическое решение, реализованное посредством Power Query, будет работать как
в Excel, так и в Power BI Desktop, Power Automate и Power BI Dataflows. Это
означает, что процесс преобразования данных, выполненный при помощи
Power Query и проверенный в Excel, может быть с легкостью перенесен в
Power BI Desktop или Power BI Dataflows без потери функционала.
Помимо создания масштабируемых и универсальных решений, Power
Query, по сути, дает вам возможность освоить расширяемую технологию, и
вы сможете применить полученные знания на любых платформах. А самое
главное, что команда Power Query в ближайшее время вряд ли остановится
на пути расширяемости своего продукта.
Также стоит отметить, что подобные принципы интеграции позволяют
разработчикам эффективно использовать несколько платформ одновременно. К примеру, вы можете при необходимости направлять запросы SQL непосредственно в Power Query, настраивать обновления посредством VBA в Excel
или планировать их в Power BI, напрямую загружать запросы Power Query в
модель данных или сущности и многое другое.
Почему Power Query – это магия?
Первоочередная задача, с которой сталкивается любой специалист по работе
с данными при реализации надежных и устойчивых решений, – это доступ,
очистка и преобразование исходных данных. Всем нам нужен был инструмент с загадочной аббревиатурой, о которой далеко не все слышали, – ETL.
И в виде такого инструмента ETL предстал Power Query. В его задачи как
раз входит извлечение (Extract) данных почти из любых источников, преобразование (Transform) их в любой желаемый вид и загрузка (Load). Но что
означают эти самые действия?
Почему Power Query – это магия  29
1
Извлечение
2
Преобразование
3
Загрузка
Рис. 0.5. Извлечение, преобразование и загрузка данных
Извлечение
Извлечение (extraction) данных, как мы сказали выше, может производиться практически из любых источников, включая текстовые файлы, файлы
CSV, базы данных и веб-страницы. В дополнение команда Power Query разработала массу коннекторов, позволяющих получать данные из источников, из которых иначе извлечь информацию было бы очень проблематично.
Это, например, такие источники данных, как Microsoft Exchange, Salesforce и
разное программное обеспечение как услуга (Software As A Service – SAAS).
Также существуют коннекторы ODBC и OLEDB, с помощью которых можно
подключаться к базам данных, еще не охваченным разработчиками. Сегодня
практически не важно, где находятся ваши исходные данные, – почти к любым из них вы сможете подключиться при помощи инструмента Power Query.
Преобразование
Говоря о преобразовании (transformation) данных, мы подразумеваем следующие операции:
 очистка данных (data cleansing) – может состоять в исключении информации о ненужных отделах, удалении пустых значений или строк.
Также на этапе очистки может быть выполнено преобразование строк
из верхнего регистра в нижний, разделение данных на колонки и конвертация дат в формат вашего региона. В общем, на стадии очистки
происходит первоначальная подготовка данных для их использования;
 интеграция данных (data integration) – если вы используете в Excel функции ВПР (VLOOKUP), ИНДЕКС (INDEX), ПОИСКПОЗ (MATCH) или новую
ПРОСМОТРX (XLOOKUP), значит, вы знакомы с интеграцией нескольких наборов данных. Power Query умеет объединять данные как вертикально, так и горизонтально, позволяя вам добавлять (append) одну
таблицу к другой, создавая длинную таблицу, или объединять (merge)
таблицы по горизонтали без необходимости пользоваться функцией
ВПР (VLOOKUP). Также на этом этапе вы можете выполнять и другие
операции, включая группировку данных;
 обогащение данных (data enrichment) – на этой стадии преобразования
данных вы можете добавлять новые столбцы и выполнять вычисления
30  Глава 0. Революция данных
с вашим набором данных. К примеру, вам может потребоваться вычислить общие суммы продаж, добавив столбец Gross Sales, в котором
значения из колонки Sales Quantity будут умножены на значения из
колонки Sales Price. Или вы захотите ввести новые форматы даты в
соответствии с исходной колонкой в таблице транзакций. Все это можно сделать на этапе обогащения данных в Power Query. Фактически с
помощью Power Query вы можете создавать новые динамические таблицы на базе значений на листах Excel, наборов данных SQL и даже
содержимого веб-страниц. Нужна динамическая таблица с календарем
за предыдущие пять лет? Power Query справится с этим легко и просто.
Что действительно впечатляет в Power Query, так это то, как много преобразований в нем можно выполнить, пользуясь одними лишь кнопками и
меню в интерфейсе, – без необходимости писать код. Этот инструмент был
разработан для конечных пользователей, и с помощью него действительно
можно несколькими щелчками мыши выполнить преобразования, которые
сложно было бы произвести даже посредством языков SQL или VBA. Это
просто здорово!
Если же вы принадлежите к тем пользователям, которые любят докапываться до самой сути, крутить формулы и писать код, с Power Query вы также
не соскучитесь. Хотя для того, чтобы комфортно работать с этим инструментом, нет необходимости изучать особый язык, этот язык все же есть, и с
помощью него Power Query фиксирует все выполненные вами действия. Язык
этот называется M, и мы любим шутить, что, видимо, буквы от A до L просто
были заняты. Язык M позволит вам писать еще более эффективные запросы
в Power Query и делать просто удивительные вещи.
Использовать язык M или нет – решать только вам. Вне зависимости от
того, какой путь вы выберете, вы будете поражены тем, сколько всего в этом
инструменте можно сделать, не используя навыки программирования.
Загрузка
Поскольку все программные пакеты, имеющие поддержку Power Query,
обладают своим назначением, по расположению загружаемых данных они
также будут различаться.
1. Excel: загрузка в таблицы Excel, модель данных Power Pivot или просто
в виде подключения.
2. Power BI: загрузка в модель данных или в виде подключения.
3. Power Automate (ранее Microsoft Flow): загрузка в рабочие книги Excel
(надеемся, в будущем появятся и другие варианты загрузки).
4. Потоки данных (dataflows): загрузка в хранилище Azure Data Lake
Storage, Dataverse или в виде подключения.
Фраза в виде подключения может кого-то сбивать с толку, но это означает
лишь то, что мы можем создавать запросы, которые можно использовать в
других запросах. Это позволяет реализовывать достаточно интересные подходы, о которых мы поговорим подробно далее в этой книге.
Возможности Power Query и интеграция с другими продуктами  31
Хотя кому-то может быть интересно узнать, куда конкретно загружаются данные в том или ином случае, в целом это не самый важный момент в
процессе работы инструмента ETL. Важнее то, как осуществляется загрузка,
точнее даже то, как выполнить эту загрузку снова.
По своей сути Power Query можно назвать средством записи макросов,
поскольку он тщательно фиксирует все действия, которые вы выполняете в
процессе работы с данными. Таким образом, вы лишь раз определяете свой
запрос и указываете, куда хотите его загрузить. После этого все, что вам
нужно, – это просто обновлять свой запрос.
Определяй
однажды
Используй
постоянно
Рис. 0.6. Процесс объявления преобразований происходит один раз,
дальше вы пользуетесь тем, что сделали
Вы только задумайтесь. Вы импортируете свой текстовый файл – тот самый, на загрузку и очистку данных в котором у вас уходит минут по 20 каждый месяц. Power Query позволит вам вдвое сократить это время в первый
раз, а в дальнейшем новые файлы будут загружаться уже без вашего участия.
До сих пор вы тратили эти 20 минут, поражая Excel своими навыками
работы в нем, и ежемесячно выполняли одни и те же заученные действия с
файлами… Подождите, а вы уверены, что вам это нужно?
Мы же предлагаем вам просто перезаписывать старый текстовый файл и
нажимать на кнопку обновления данных в Excel или Power BI. И все. Да нет,
серьезно! А если вы публикуете свои данные в Power BI или настраиваете поток данных, вы можете создать автоматическое расписание, чтобы не делать
даже этого!
В этом и заключается истинная мощь Power Query. Мало того, что его легко
использовать, его очень легко использовать повторно! С его помощью вы
можете превратить свой тяжелый труд в инвестицию в будущее и высвободить время для чего-то стоящего.
Возможности Power Query и интеграция
с другими продуктами
Power Query – это технология, произведшая настоящую революцию в мире
бизнес-аналитики. Официально она появилась в Excel в 2013 году в виде
надстройки, а сегодня она полноценно входит в состав восьми различных
32  Глава 0. Революция данных
продуктов, включая Excel, Power BI Desktop, SQL Server Integration Services
и Azure Data Factory. А когда вы будете читать эту книгу, возможно, интеграцией с этим инструментом смогут похвастаться и другие программные
продукты для работы с данными от Microsoft.
Влияние Power Query просто феноменально – всего за несколько лет этот
инструмент сумел буквально перевернуть жизни многих специалистов по работе с данными из самых разных областей. Недостатком такой высочайшей
интеграции в разные продукты является то, что она никогда не проходит бесследно. И разработчикам Power Query приходится очень нелегко, балансируя
между многочисленными функциями и возможностями своего инструмента
с учетом связи со всеми этими продуктами, имеющими свои требования.
В результате они вынуждены идти на многочисленные компромиссы в отношении функционала в зависимости от продукта интеграции.
Компоненты Power Query
Power Query можно сравнить с луковицей – у этого инструмента, как и
у лука, есть чешуйки, представляющие собой ключевые компоненты Power
Query.
Глядя на Power Query, мы почти буквально видим эти чешуйки. В процессе
чтения данной книги вы будете понимать, как много всего происходит «под
капотом» Power Query во время работы с этим инструментом. В частности,
все это время за вас трудится язык M, видимый для пользователя, и внутренний движок Power Query, скрытый от наших глаз. На рис. 0.7 представлен
Power Query в разрезе.
Интерфейс
пользователя
Power Query
Запросы M
Движок M
Рис. 0.7. Слои Power Query
Всего Power Query насчитывает три слоя, но в некоторых интеграциях могут
участвовать только первые два. Эти слои:
 движок M (M Engine) – внутренний движок выполнения запросов,
обрабатывающий инструкции, написанные на внутреннем языке Power
Query – M;
 запросы M (M Query) – набор команд, доступных языку M;
Возможности Power Query и интеграция с другими продуктами  33
 интерфейс пользователя Power Query (Power Query User Interface) –
также известен как редактор Power Query (Power Query Editor). Графический интерфейс, помогающий пользователю выполнять различные
действия, в том числе:
• создавать и модифицировать запросы на языке M путем простого
взаимодействия с интерфейсом;
• визуализировать запросы и их результаты;
• управлять запросами путем создания групп запросов, добавления
метаданных и т. д.
Как минимум любая интеграция Power Query с тем или иным продуктом включает в себя два из перечисленных слоев: движок M и запросы M.
В табл. 0.1 приведены все присутствующие компоненты в различных интеграциях.
Таблица 0.1. Не все интеграции Power Query включают в себя все слои Power Query
Движок M
Запросы M
Интерфейс пользователя
Power Query
Excel
Да
Да
Да
Power BI Desktop
Да
Да
Да
Потоки данных Power BI
Да
Да
Да
SQL Server Integration
Services
Да
Да
Нет
Компоненты
Если сравнивать возможности Power Query в Excel и возможности Power
Query при работе с потоками данных Power BI в 2021 году, можно заметить
некоторые различия. Потоки данных Power BI используют пользовательский
интерфейс Power Query Online, тогда как в Excel и Power BI возможности базируются на интерфейсе Power Query Desktop. И хотя эти два интерфейса отличаются, процессы, лежащие в их основе, по большей мере схожи.
Если же вы проведете это сравнение в 2024 году, мы уверены, разница
окажется не столь существенной. Причина этого в том, что команда разработчиков Power Query стремится к полной универсализации и унификации
интерфейса инструмента во всех продуктах интеграции.
Конечно, в будущем у разных продуктов также могут сохраняться свои
особенности при работе с Power Query. К примеру, импорт данных в таблицу
непосредственно из активной рабочей книги может остаться прерогативой использования этого инструмента исключительно в Excel, но в целом
интерфейсы заметно сближаются. Некоторые из существующих различий
охватывают все три описанных выше слоя Power Query, тогда как другие касаются только интерфейса пользователя (как, например, различия в иконках
в разных продуктах).
В последние годы компания Microsoft вкладывает огромные средства в
развитие инструментария интерфейса Power Query Online. По окончании
тестирования внедренного решения оно переносится в предварительную
34  Глава 0. Революция данных
версию выпуска Power Query Desktop, а затем следует официальное обновление этого интерфейса. Это означает, что если вы хотите воспользоваться
всеми новейшими средствами и возможностями Power Query, вам следует
обратиться к продукту, взаимодействующему с Power Query с помощью интерфейса Online, – например, к потокам данных Power BI.
Ни для кого не секрет, как быстро и стремительно развивается Power
Query – как в плане возможностей, так и в отношении пользовательского
интерфейса. В связи с этим мы отдаем себе отчет в том, что писать книгу по
Power Query и надеяться, что скриншоты в ней не устареют, было бы очень
странно. К примеру, выход этой книги был отложен на целых два года в ожидании того, когда одна важная возможность появится в интерфейсе Power
Query, доступном в Excel.
И хотя в книге мы будем постоянно приводить пошаговые описания тех
или иных действий, мы обязаны предостеречь вас на предмет того, если в
вашем случае внешне та или иная процедура будет выглядеть несколько иначе по причине вышедших обновлений. Неизменно будет одно – рецепты и
подходы, лежащие в основе примеров. Это основы, которым мы и собираемся
вас научить, – как обращаться с данными вне зависимости от имеющегося
интерфейса пользователя. И в этом отношении мы надеемся, что наша книга
будет полезна пользователям и разработчикам еще не один год.
Цикл обновлений Power Query
Перед тем как начать говорить о том, как добраться до Power Query, давайте
пару слов скажем об обновлениях этого инструмента. Вам может показаться,
что мы бежим впереди паровоза, но на то есть свои причины.
Команда Power Query выпускает обновления ежемесячно. Мы говорим не
об исправлениях ошибок (хотя они тоже, конечно, присутствуют), а о новых возможностях и расширениях. Некоторые обновления незначительные,
другие довольно весомые. В начале 2015 года, помнится, разработчики выпустили обновление, сократившее время загрузки запросов на 30 %. В июле
того же года они пофиксили серьезные проблемы с обновлением данных в
Power Pivot. В последующие годы были добавлены типы объединения таблиц,
условные столбцы и многое другое. Что касается последних трех лет, то здесь
можно вспомнить обновления, в которых появились добавление столбца из
примеров (Columns from Example), нечеткие соответствия (Fuzzy Matching)
и другие возможности.
Так как же получать эти обновления? Здесь все зависит от того, в каком
именно продукте вы работаете с Power Query.
Power Query Online
Интерфейс Power Query Online используется при обращении к Power Query
онлайн в таких продуктах, как Power Automate, и при работе с потоками данных Power BI. Это все веб-службы, и обновлять в них вам ничего не требуется.
Все новые возможности в этом случае устанавливаются автоматически, а вам
просто нужно следить за новинками.
Цикл обновлений Power Query  35
Microsoft 365
Мы предпочитаем пользоваться Excel и другими продуктами семейства
Office по подписке Microsoft 365. Если у вас есть подписка, все программное
обеспечение будет обновляться автоматически в соответствии с выбранным
каналом обновления (Channel) для вашей версии продукта.
🍌 Подробнее о каналах обновления можно почитать по адресу https://docs.
microsoft.com/ru-ru/deployoffice/overview-update-channels.
Excel 2016/2019/2021
Как мы уже отметили, Power Query не стоит на месте, а постоянно развивается. Если вспомнить Excel 2016, официально вышедший в сентябре
2015 года, то в нем Power Query впервые был интегрирован на уровне базовой
установки. Однако изначально в нем присутствовали ошибки при работе с
именованными диапазонами, а также использовался устаревший алгоритм
объединения файлов. Кроме того, в этой версии не были представлены типы
объединения, условные столбцы и столбцы из примеров.
Хорошие новости состоят в том, что хоть Excel 2016 и 2019 не входят в
подписку Microsoft, без обновлений Power Query не остается. И мы настоятельно рекомендуем вам установить последнюю доступную версию продукта
перед продолжением чтения этой книги.
Секрет получения этих обновлений кроется в том, чтобы Windows при загрузке очередных новинок обновляла все, что нам нужно. Добиться этого в
Windows 10 можно следующим образом:
 нажмите на кнопку Windows и введите Windows;
 выберите пункт Параметры центра обновления Windows (Windows
Update Settings);
 перейдите в раздел Дополнительные параметры (Advanced Options);
 убедитесь, что установлен флажок При обновлении Windows получать обновления для других продуктов Майкрософт (Give me
updates for other Microsoft products when I update Windows).
Excel 2010 & 2013
Для версий Excel ниже 2016 Power Query необходимо скачать и установить
вручную с адреса https://go.microsoft.com/fwlink/?LinkId=317450. Последнее обновление для Excel 2010 и 2013 было выпущено в марте 2019 года.
Power BI Desktop
В Power BI Desktop предусмотрено два механизма поставки. Если вы установили этот пакет посредством Microsoft Store, он будет обновляться автоматически. Если же Power BI Desktop был установлен по ссылке Дополнительные параметры скачивания (Advanced download options) по адресу https://
36  Глава 0. Революция данных
powerbi.microsoft.com/ru-ru/downloads, вам необходимо будет вручную скачивать и
устанавливать обновления.
🍌 Примечание. Пользователям Power BI повезло больше остальных – они пер-
выми получают новинки Power Query. Информация об обновлениях скрывается в окне Параметры (Options) на вкладке Предварительные версии
возможностей (Preview Features). Если вы хотите узнать, какие обновления
пойдут в Excel, вам сюда. Новые возможности обычно сначала появляются
в Power BI Desktop, а затем, по приобретении статуса общего доступа через
два-три месяца, отправляются в Excel.
Как использовать эту книгу
В первую очередь мы бы хотели, чтобы эта книга могла стать вашим главным
практическим помощником в отношении Power Query в целом и языка M в
частности – вне зависимости от того, являетесь вы новичком или профессионалом в области ETL. Наша цель – помочь читателю справиться с распространенными задачами, возникающими на практике ежедневно, и показать,
как для их решения можно применять Power Query. Также мы рассмотрим
множество продвинутых сценариев с использованием языка M, чтобы вы
научились не только строить решения при помощи Power Query, но и знали,
как сделать их надежными и устойчивыми.
Большая часть примеров и иллюстраций, используемых в этой книге, будут
показаны применительно к версии Excel Microsoft 365. И если не указано
обратное, все сценарии должны одинаково корректно работать и в Excel, и
в Power BI.
Где найти Power Query?
Чтобы использовать в работе Power Query, нужно знать, где он находится.
Рис. 0.8. Расположение Power Query в Excel
Excel 365
В версии Excel, выпущенной в рамках продукта Microsoft 365 (далее мы будем называть его просто Excel 365), доступ к командам Power Query можно по-
Революция данных  37
лучить в группе меню Получить и преобразовать данные (Get & Transform)
на вкладке Данные (Data). Тогда как для распространенных источников данных предусмотрены отдельные кнопки, к полному списку источников можно
получить доступ, нажав на кнопку Получить данные (Get Data).
Power BI Desktop
Работая с Power BI Desktop, для доступа к Power Query вам даже не придется
покидать вкладку Главная (Home) – большая кнопка Получить данные (Get
Data) будет прямо у вас перед глазами, не промахнетесь.
Рис. 0.9. Расположение Power Query в Power BI Desktop
Предыдущие версии Excel
Несмотря на то что в этой книге мы будем ориентироваться на Excel 365,
большинство описываемых нами сценариев будут прекрасно работать и в более ранних версиях. Разве что доступ к командам Power Query везде будет
осуществляться по-разному:
 Excel 2019: по большей части интерфейс Excel 2019 совпадает с
Excel 365. Единственным заметным отличием на момент написания
книги является то, что кнопка Из листа (From Sheet), которая будет
появляться на наших скриншотах регулярно, в Excel 2019 называется
Из таблицы/диапазона (From Table/Range);
 Excel 2016: как и в продуктах Office 2019/365, входной точкой в Power
Query является вкладка Данные (Data), но сама кнопка называется
Создать запрос (New Query) и расположена посередине вкладки Данные;
 Excel 2010/2013: в этих версиях Excel инструмент Power Query после
загрузки и установки будет располагаться на отдельной вкладке. Когда
вы увидите в этой книге, что вам необходимо нажать на кнопку Получить данные (Get Data) на вкладке Данные (Data), то переходите на
вкладку Power Query и ищите соответствующую команду там.
Подключение к данным
С помощью Power Query вы можете подключаться к самым разным источникам данных, варианты которых можно найти, нажав на кнопку Получить
данные (Get Data) на вкладке Данные (Data) в Excel или на вкладке Глав-
38  Глава 0. Революция данных
ная (Home) в Power BI Desktop. Тогда как в Excel источники данных разбиты
на подкатегории прямо в пунктах меню, в Power BI Desktop для просмотра
иерархии необходимо нажать на кнопку Другие (More).
С целью соблюдения единообразия мы будем использовать следующую
последовательность команд для открытия файла CSV:
 создайте новый запрос  Из файла  Из файла Text/CSV.
В Excel это действие будет осуществляться следующим образом:
 открыть вкладку Данные (Data)  нажать на кнопку Получить данные (Get Data)  Из файла (From File)  Из текстового/CSV-файла
(From Text/CSV).
В Power BI Desktop действия будут такими:
 открыть вкладку Главная (Home)  нажать на кнопку Получить данные (Get Data)  Другие (More)  Файл (File)  Текстовый или CSVфайл (Text/CSV).
Если вы по-прежнему используете Excel 2016 или более ранней версии,
последовательность будет следующая:
 Excel 2016: открыть вкладку Данные (Data)  нажать на кнопку Создать запрос (New Query)  Из файла (From File)  Из текстового/
CSV-файла (From Text/CSV);
 Excel 2010/2013: открыть вкладку Power Query  Из файла (From
File)  Из текстового/CSV-файла (From Text/CSV).
Особые пометки
🍌 Примечание. Примечания в книге будут выделяться абзацами с соответству-
ющей иконкой. В них я буду рассказывать о каких-то полезных возможностях
и трюках, которые помогут вам более эффективно использовать Power Query.
🙈 Предупреждение. Предупреждения также будут выделяться абзацами, и в
них я буду подмечать моменты, которые в будущем могут приводить к проблемам. Пропускать предупреждения вы можете только на свой страх и риск.
Сопроводительные файлы
Перед тем как двигаться дальше, я настоятельно рекомендую вам скачать
все рабочие книги по указанному ниже адресу, чтобы следить за происходящим и параллельно пробовать все самим: https://www.skillwave.training/
book-master-your-data-examples.
Ну что ж, пришло время познакомиться с этим потрясающим инструментом поближе! Приступим!
Глава
1
Основы Power Query
Главная задача Power Query – собирать и преобразовывать исходные данные
в желаемый формат, после чего загружать их в таблицы для нужд бизнес-аналитики. В простейшем виде процесс, который Power Query будет стараться
выполнить без вашего вмешательства, можно представить так, как показано
на рис. 1.1.
Извлечение
Преобразование
Загрузка
• Подключение
к данным
• Обработка
• Очистка
• Форматирование
• Определение
типов данных
• Загрузка в место
назначения
Рис. 1.1. Общие принципы работы Power Query
Разумеется, мы можем вмешиваться в этот процесс на любой его стадии.
И именно это мы будем делать на протяжении всей книги. Но для начала полезно будет пройтись по всем пунктам и понять, что на той или иной стадии
делает Power Query.
Перед началом
Прежде чем отправляться в путешествие по Power Query, мы советуем вам
кое-что изменить в интерфейсе. Для чего? Дело в том, что компания Microsoft
по умолчанию отключила некоторые полезные опции, чтобы не перегружать
ваше сознание, но, к сожалению, некоторые из них критически важны для
полноценной работы с этим инструментом. А раз вы держите в руках данную
книгу, значит, вы хотите научиться правильно обращаться с Power Query.
Powered by TCPDF (www.tcpdf.org)
40  Глава 1. Основы Power Query
Изменение настроек Power Query
по умолчанию в Excel
Добраться до настроек инструмента Power Query в Excel можно следующим
образом:
 перейдите на вкладку Данные (Data), раскройте выпадающую кнопку
Получить данные (Get Data) и выберите пункт Параметры запроса
(Query Options);
 в разделе Глобальные ( Global) откройте секцию Загрузка данных
(Data Load) и убедитесь, что флажок Быстрая загрузка данных (Fast
Data Load) установлен. Эта настройка приведет к блокированию пользовательского интерфейса Excel во время обновления данных, но позволит обеспечить актуальность информации при работе;
 в разделе Глобальные (Global) откройте секцию Редактор Power Query
(Power Query Editor) и убедитесь, что все флажки установлены. Самым
важным здесь является флажок Отобразить строку формул (Formula
Bar is showing), но остальные опции также имеют большое значение,
и в данной книге мы будем предполагать, что они у вас установлены;
 нажмите на кнопку OK.
В этом диалоговом окне есть и другие интересные настройки, но для начала хватит и этих.
Изменение настроек Power Query
по умолчанию в Power BI
Чтобы изменить настройки по умолчанию в Power BI Desktop, сделайте
следующее:
 на вкладке Файл (File) откройте раздел Параметры и настройки
(Options & settings) и выберите пункт Параметры (Options);
 в разделе Глобальные ( Global) откройте секцию Редактор Power
Query (Power Query Editor) и убедитесь, что все флажки установлены. В особенности нас интересует пункт Отобразить строку формул
(Formula Bar is showing), но остальные опции также имеют значение;
 нажмите на кнопку OK.
🍌 Примечание. Находясь в окне настроек в Power BI Desktop, вы можете также
открыть секцию Предварительные версии возможностей (Preview Features)
в разделе Глобальные (Global) и посмотреть список новых опций. Поскольку
все новинки сначала появляются именно в Power BI Desktop, здесь можно
увидеть, какими возможностями в ближайшем будущем может пополниться
Power Query в Excel.
Извлечение  41
Извлечение
В данной главе мы будем импортировать простые файлы CSV посредством
Power Query в Excel и Power BI для демонстрации возможностей Power Query,
его интерфейса и различий между двумя платформами.
Процесс ETL всегда начинается с этапа извлечения данных, который, в
свою очередь, делится на четыре стадии, показанные на рис. 1.2.
Настройка
Аутентификация
Предварительный просмотр
Назначение
запроса
Рис. 1.2. Четыре составляющие процесса извлечения данных
Настройки подключения (выбор данных)
На первом шаге необходимо выбрать и настроить подключение к данным,
с которыми мы собираемся работать. Давайте создадим запрос, использующий простейший коннектор к файлу CSV в Excel:
 нажмите на выпадающую кнопку Получить данные (Get Data) и в
меню Из файла (From File) выберите пункт Из текстового/CSV-файла
(From Text/CSV).
В Power BI Desktop аналогичные действия выполняются следующим образом:
 нажмите на кнопку Получить данные (Get Data), выберите пункт Другие (More) и в разделе Файл (File) укажите вариант Текстовый или
CSV-файл (From Text/CSV).
Стоит заметить, что импортировать текстовые или CSV-файлы можно и гораздо проще. Поскольку к таким файлам аналитики обращаются достаточно
часто, разработчики предусмотрели более быстрый способ для их загрузки.
В Excel вы увидите соответствующую кнопку непосредственно справа от
кнопки Получить данные (Get Data) на вкладке Данные (Data). А в Power
BI нужный вам коннектор располагается на первом уровне вложенности в
выпадающей кнопке Получить данные (Get Data), так что вам нет необходимости добираться до него через пункт Другие (More). Но мы упоминаем
полный путь к подключению, поскольку далее в этой книге будем работать
с самыми разными источниками данных.
42  Глава 1. Основы Power Query
Рис. 1.3. Подключение к текстовому/CSV-файлу в Excel (слева)
и Power BI Desktop (справа)
🍌 Примечание. В Power BI Desktop предусмотрена возможность подключения
к большему количеству источников данных по сравнению с Excel. По установившейся традиции разработчики стремятся добавлять тестовые коннекторы сначала в Power BI, а после прохождения полной проверки переносят их
в Excel.
Теперь, когда мы нашли нужный тип подключения, пришло время выбрать источник данных в виде файла. В нашем случае откроем следующий
файл: Ch01 Examples\Basic Import.csv.
Аутентификация
Многие источники данных требуют дополнительной аутентификации
(authentication) перед подключением. Если ваш источник данных относится к подобному случаю, на этом этапе вы получите запрос на ввод личных
данных. К счастью, мы имеем дело с файлом, расположенным локально на
вашем компьютере, к которому у вас есть полный доступ.
Предварительный просмотр
После выбора файла откроется окно, похожее на то, что показано на рис. 1.4.
Извлечение  43
Рис. 1.4. Окно предварительного просмотра в Power Query
Целью является показать вам, как Power Query видит исходные данные,
чтобы вы могли внести необходимые коррективы перед началом процесса преобразования. Обычно на этом этапе мало что требуется менять, поскольку Power Query в абсолютном большинстве случаев делает правильные
предположения о характере данных. Несмотря на это, в верхней части окна
расположены следующие выпадающие списки для настройки данных:
 источник файла (File Origin). Здесь вы можете выбрать кодировку
исходного файла. Вам редко нужно будет пользоваться этой опцией;
 разделитель (Delimiter). В этом списке вам также очень редко понадобится менять настройки, поскольку в большинстве случаев Power Query
прекрасно справляется с определением разделителя. При необходимости вы можете выбрать разделитель из списка, установить пользовательский разделитель и даже задать фиксированную длину столбцов;
 обнаружение типов данных (Data Type Detection). Здесь вы можете
задать способ определения типов исходных данных на основе первых
200 строк или всего набора данных. Также есть вариант вовсе не определять типы данных.
Очень важно обратить внимание на информационное сообщение о том,
что данные в предварительном просмотре были усечены из-за ограничения
размера.
Выбор назначения запроса
Чаще всего вам не придется вносить какие-то изменения в окне предварительного просмотра. Главная цель этого окна – дать вам понять, в каком
виде представлены данные, и ответить на три следующих вопроса.
44  Глава 1. Основы Power Query
1. Это неправильный набор данных? В этом случае вы всегда можете нажать кнопку Отмена (Cancel).
2. С данными все в порядке? Тогда нажимайте кнопку Загрузить (Load).
3. Данные нуждаются в трансформации или обогащении? Тогда ваш выбор – кнопка Преобразовать данные (Transform Data).
🍌 Примечание. По нашим предположениям, около 80–90 % данных нуждают-
ся в преобразовании перед их использованием. Сложность преобразований
может варьироваться от самых элементарных (вроде изменения названий
столбцов) до действительно серьезных. Вне зависимости от того, что вам
требуется, вашим выбором по умолчанию всегда должна быть кнопка Преобразовать данные, а не Загрузить.
Теперь, когда вы увидели предварительный снимок данных и решили,
что это именно та информация, которая вам требуется, нажмите на кнопку
Преобразовать данные, чтобы перейти в Power Query. Редактор откроется
в новом окне, как показано на рис. 1.5.
Рис. 1.5. Редактор Power Query в Excel
Преобразование
Следующим этапом процесса ETL является преобразование данных. В отличие от классических методов импорта данных в Excel, Power Query позволяет
вам видеть и модифицировать преобразования, выполненные системой по
умолчанию. Эти изменения можно делать в окне редактора Power Query, которое открывается после нажатия на кнопку Преобразовать данные.
Преобразование  45
Редактор Power Query
В редакторе Power Query присутствуют семь главных областей, к которым
мы будем обращаться на протяжении всей книги. На рис. 1.6 они помечены
цифрами.
Рис. 1.6. Семь областей редактора Power Query
Предназначение областей в редакторе Power Query следующее.
1. Лента (Ribbon). Располагается в верхней части окна. Лента Power Query
делится на четыре пункта меню: Главная (Home), Преобразование
(Transform), Добавление столбца (Add Column) и Просмотр (View).
2. Панель навигатора запросов (Query Navigator Pane). В версиях Excel
до 365 эта панель по умолчанию была свернута. Вы всегда можете
нажать на кнопку со стрелкой выше слова Запросы (Queries), чтобы
раскрыть или скрыть эту панель. Обратите внимание, что в Excel 365
и Power BI панель навигатора по умолчанию раскрыта, и вы можете
скрыть ее, нажав на ту же кнопку со стрелкой.
3. Строка формул (Formula Bar). Если вы не видите эту область, значит,
не выполнили наши рекомендации по настройке Power Query. Строка
формул очень важна при работе с данными, так что мы настоятельно
рекомендуем вам установить соотвующий флажок на вкладке Просмотр (View).
4. Окно текущего представления (Current View Window). Это ваше главное рабочее окно для преобразования данных и просмотра результатов. Также здесь могут отображаться схема данных и диаграмма.
5. Строка состояния (Status Bar). Располагается в нижней части окна
и содержит краткую сводку о количестве строк и столбцов в запросе,
46  Глава 1. Основы Power Query
а также о числе строк, на основании которых выполняется профилирование столбцов. В правой части строки состояния имеется информация
о времени последнего обновления предварительного просмотра.
6. Окно свойств (Properties Window). В этой области содержится информация об имени запроса, которое наследуется из источника данных.
7. Панель примененных шагов (Applied Steps Window). В вашем путешествии по Power Query эта область станет одной из важнейших, поскольку в ней отображаются все шаги преобразований, примененные
к предварительному просмотру, которые после импорта будут распространены на весь набор данных в целом.
Преобразования по умолчанию
После первоначального извлечения данных из файла бывает полезно узнать, какие действия Power Query выполнил по умолчанию. Для этого обратите
внимание на панель Примененные шаги в правой части окна. Вы увидите,
что три действия уже выполнены.
1. Источник (Source).
2. Повышенные заголовки (Promoted Headers).
3. Измененный тип (Changed Type).
Важно знать, что каждый шаг на этой панели можно выделить и посмотреть подробно. Давайте сделаем это.
Источник (Source)
По умолчанию первый шаг каждого загруженного запроса будет называться Источник (Source) – вне зависимости от источника данных. Выбор этого
шага на панели Примененные шаги приведет к преобразованию окна предварительного просмотра, чтобы вы видели исходные данные в том виде, как
видит их Power Query. Этот вид показан на рис. 1.7.
Рис. 1.7. Визуальное представление шага Источник (Source)
На этом этапе процесса ETL Power Query идентифицировал разделители-запятые в исходных данных, но больше никаких преобразований не выполнял.
При этом внутренние алгоритмы Power Query уже определили некоторые
несоответствия в данных – к примеру, данные в первой строке сильно отличаются от дальнейших значений. Это очень напоминает… заголовки!
Преобразование  47
Повышенные заголовки (Promoted Headers)
Если выделить шаг Повышенные заголовки (Promoted Headers) на панели
примененных шагов, вы увидите результат предположения, о котором мы
сказали выше. Power Query взял значения из первой строки и заменил ими
Column1, Column2 и т. д. в первоначальных заголовках, что видно по рис. 1.8.
Рис. 1.8. Результат выполнения шага повышения заголовков
Измененный тип (Changed Type)
Заключительный шаг, который выполнил Power Query по умолчанию, называется Измененный тип (Changed Type), и результат его выполнения показан на рис. 1.9.
Рис. 1.9. В заголовках столбцов виден результат преобразования типов данных
Как действовал Power Query? Он просканировал первые 200 строк в каждом столбце и сделал определенные предположения о том, данные каких
типов в них содержатся. После этого он закрепил определенные типы данных за столбцами, чтобы в таком виде информацию загрузить в место назначения. Наиболее популярные типы данных, которые вы будете встречать
в Power Query:
 Дата и время (DateTime): отображается при помощи иконки с календарем и часами;
 Целое число (Whole number): этому типу соответствует иконка «123»;
 Десятичное число (Decimal number): обозначается иконкой «1.2»;
 Текст (Text): для этого типа используется иконка «ABC».
🍌 Примечание. В Power Query есть и другие типы данных, но мы будем говорить о них подробнее в следующих главах.
48  Глава 1. Основы Power Query
Создание и изменение преобразований
До сих пор мы видели, что Power Query помог нам выполнить первоначальное преобразование данных и ни разу не ошибся. А что, если мы захотим
внести изменения в извлеченные данные?
Давайте начнем с удаления столбца, который нам не нужен, – POS Hour.
Мы не собираемся анализировать представленные данные на этом уровне
детализации. Для этого вы можете пойти одним из следующих путей.
1. Выделите столбец POS Hour, щелкните правой кнопкой мыши по его
заголовку и выберите пункт Удалить (Remove).
2. Выделите столбец POS Hour и нажмите на клавишу Delete на клавиатуре.
Какой бы способ вы ни выбрали, столбец исчезнет из таблицы, а на панели Примененные шаги появится новый шаг с именем Удаленные столбцы
(Removed Columns), как показано на рис. 1.10.
Рис. 1.10. Шаг Удаленные столбцы исключил из запроса колонку POS Hour
Но постойте! А если мы передумаем и захотим вернуть удаленный столбец? Не проблема, достаточно просто удалить примененный шаг. Сейчас мы
не будем этого делать, но если хотите попробовать, выделите последний шаг
на панели Примененные шаги и нажмите на крестик слева от названия
шага. Шаг тут же исчезнет, а колонка восстановит свое место в запросе. Вы
можете воспринимать эту возможность как улучшенную отмену действия
(Undo) в других приложениях. В отличие от отмены действия, которую невозможно выполнить после закрытия приложения, удалить шаг из панели
примененных шагов вы можете всегда.
Но вернемся к модификации наших данных. Как насчет того, чтобы упростить названия колонок, начиная со столбца Item Name?
 Щелкните правой кнопкой мыши на заголовке столбца Item Name, выберите пункт Переименовать (Rename) и введите новое имя Item.
На панели примененных шагов появится новый шаг с именем Переименованные столбцы (Renamed Columns). Вы уже понемногу начинаете привыкать
к основному принципу работы Power Query: любое выполненное действие
приводит к добавлению нового шага.
Преобразование  49
🍌 Примечание. Возможность отменить предыдущее действие очень важна, но
у показанной здесь особенности есть и другое, не менее важное предназначение, состоящее в том, что вы можете щелкать на любые шаги, чтобы
посмотреть, какие преобразования они выполняют. Power Query всегда работает с копией ваших данных, так что исходные данные вы никак не нарушите.
Это дает вам возможность нажимать на все кнопки, чтобы посмотреть, что
будет. Если не понравится результат, просто удалите шаг. Мы рекомендуем
вам самостоятельно проделать это со всеми командами, которые вам незнакомы. При этом вы не только освоите новый функционал, но и научитесь
сопоставлять описания шагов на панели Примененные шаги с действиями,
которые они выполняют.
Такое поведение Power Query очень важно понимать. В отличие от традиционного Excel, в котором выполненные действия нигде не сохраняются, в
Power Query ведется полный учет примененных трансформаций. По умолчанию каждое действие, которое вы выполните при помощи интерфейса
пользователя, будет отражено на панели примененных шагов. И даже если
вы не знаете, какой именно шаг привел к тому или иному изменению данных, вы по крайней мере можете видеть, какой тип действия выполняется на
определенном шаге. А если выбрать предыдущий шаг, можно посмотреть, в
каком состоянии находились данные перед тем, как действие было выполнено. После этого можно выделить интересующий вас шаг, чтобы посмотреть
результат выполненного преобразования.
А что произойдет, если мы захотим переименовать еще один столбец?
Снова добавится шаг? Давайте проверим. Как и в Excel, в Power Query можно
практически любое действие выполнить несколькими способами. На этот раз
давайте переименуем столбец следующим образом:
 дважды щелкните мышью по заголовку столбца Units Sold;
 измените текст заголовка на Units.
Обратите внимание, что столбец переименовался, но шаг на панели примененных шагов не добавился! У нас по-прежнему лишь один шаг с именем
Переименованные столбцы (Renamed Columns), что видно по рис. 1.11.
Рис. 1.11. Два действия по переименованию столбцов объединились в один шаг
50  Глава 1. Основы Power Query
Заметьте, что любой способ переименования столбцов приведет к одному
и тому же результату. При этом, если выполнить два схожих действия подряд,
Power Query попытается объединить их в один шаг. Причина этого проста:
это позволит не раздувать без необходимости список примененных шагов
и сделает его более легким для чтения. Многие файлы требуют выполнения
похожих действий, так что это весьма полезная особенность поведения инструмента.
🍌 Примечание. Конечно, при желании у этой особенности можно найти и не-
гативное последствие. Скажем, что делать, если вы переименовали шесть
столбцов подряд, а затем поняли, что один из них переименовывать не нужно было? Если удалить шаг, будут потеряны все произведенные изменения.
В качестве альтернативы вы можете добавить шаг с восстановлением имени
столбца, переименованного по ошибке. А можете и вручную подправить код
на языке M. Как это сделать – мы будем изучать в данной книге позже.
Загрузка
На данном этапе у нас есть запрос, в котором выполнены следующие действия:




осуществлено подключение к файлу CSV;
повышены заголовки из первой строки и установлены типы данных;
удалены ненужные столбцы;
переименованы два столбца, чтобы их имена были более понятными.
Для этого набора данных произведенных действий вполне достаточно.
Наши данные приведены в понятный табличный формат, очищены и готовы
к обработке аналитиком. Пришло время завершить процесс с помощью загрузки данных.
Установка типов данных
Перед загрузкой данных всегда бывает полезно переопределить типы данных для всех столбцов в наборе. О причинах этого мы расскажем чуть позже,
но хотим, чтобы у вас с самого начала вырабатывались правильные привычки при работе с Power Query. Фактически так делает сама Microsoft, и
именно поэтому по умолчанию последним шагом в запросах Power Query
присутствует действие по изменению типов данных.
И хотя вы можете щелкать отдельно по иконке с типом данных в заголовке каждого столбца в вашем наборе данных и менять его, скорее всего, это
займет достаточно много времени. Лучше позволить Power Query самому
попытаться определить все типы данных в запросе, а затем скорректировать
его действия. Для этого выполните следующее:
Загрузка  51
 выделите любой столбец;
 нажмите сочетание клавиш CTRL+A для выделения всех колонок;
 перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Определить тип данных (Detect Data Type).
В результате на панели примененных шагов появится новый шаг с именем
Измененный тип1 (Changed Type1), как показано на рис. 1.12.
Рис. 1.12. Результат переопределения типов данных столбцов
Почему же Измененный тип1? Дело в том, что еще один шаг с изменением
типов данных уже присутствует в списке примененных шагов. Этот шаг Power
Query автоматически применил после повышения заголовков. Кстати, это
помогает понять еще несколько важных принципов, по которым работает
Power Query.
1. Каждый шаг в списке примененных шагов должен иметь уникальное
имя.
2. При добавлении шага движок Power Query будет добавлять единицу
или увеличивать на единицу имя последнего шага аналогичного типа.
3. Схожие шаги, выполненные подряд, будут объединяться в один шаг, а
если между ними есть другие шаги, то не будут.
Обязаны ли вы оставлять то имя шага, которое было выбрано Power Query
по умолчанию? Вовсе нет. Хотя в основном мы советуем оставлять имена
шагов по умолчанию и наблюдать за тем, какие команды интерфейса какие
шаги создают, вы вправе менять названия шагов по своему усмотрению. Для
этого сделайте следующее:
 щелкните правой кнопкой мыши по шагу, имя которого хотите изменить, и в контекстном меню выберите пункт Переименовать (Rename);
 введите новое имя шага – Lock in Data Types.
52  Глава 1. Основы Power Query
🍌 Примечание. Единственный шаг, который вам не удастся переименовать
таким способом, – это Источник (Source). Для этого необходимо вручную
редактировать код запроса на языке M.
Переименование запроса
По умолчанию Power Query устанавливает имя источника данных в качестве имени запроса. Но поскольку Basic Import – отнюдь не лучшее имя для запроса, вы всегда можете переименовать его. Для этого выполните следующие
действия:
 перейдите на панель Примененные шаги (Query Settings Pane) и
в разделе Свойства (Properties) выделите содержимое поля Имя
(Name);
 введите новое имя запроса – Transactions.
Итоговый запрос должен выглядеть так, как показано на рис. 1.13.
Рис. 1.13. Результат переименования запроса
Загрузка запроса в Excel
Теперь нам осталось загрузить подготовленный запрос в Excel. Для этого
выполните следующие действия:
 перейдите на вкладку Главная (Home) в Power Query;
 нажмите на кнопку Закрыть и загрузить (Close & Load).
В этот момент Power Query применит наши шаги не только к данным в
окне предварительного просмотра, но и ко всему набору данных в источнике
в целом. В зависимости от объема исходных данных и сложности преобразований это может занять некоторое время. По окончании загрузки вы увидите
обработанные данные в таблице на новом рабочем листе, как показано на
рис. 1.14.
Загрузка  53
Рис. 1.14. Запрос Transactions, загруженный в Excel
На рис. 1.14 мы также пометили цифрами три важные области в интерфейсе Excel.
1. Панель Запросы и подключения (Queries & Connections). Запросы,
перечисленные здесь, будут в точности соответствовать по именам
запросам, подготовленным в Power Query.
2. Секция Имя таблицы (Table Name). Здесь также обычно будет содержаться имя запроса, но все недопустимые символы в нем будут заменены на символ подчеркивания (_). Кроме того, в случае конфликтов
с именами других листов в рабочей книге к имени запроса будет добавлено уникальное числовое окончание.
3. Имя рабочего листа. Здесь также обычно будет находиться имя запроса
с символами подчеркивания, имя может быть усечено при необходимости, а в случае конфликтов с именами других листов к имени запроса
будет добавлено уникальное числовое окончание в круглых скобках.
🍌 Примечание. Каждый из перечисленных элементов может быть переимено-
ван, и называться они могут в итоге совершенно по-разному, это не повлияет
на работоспособность книги.
Загрузка запроса в Power BI
Единственным существенным отличием процесса загрузки запроса в Power
BI по сравнению с Excel является название кнопки. Итак, для загрузки данных в Power BI сделайте следующее:
54  Глава 1. Основы Power Query
 перейдите на вкладку Главная (Home) в Power Query;
 нажмите на кнопку Закрыть и применить (Close & Apply).
Как и в случае с Excel, в этот момент Power Query применит шаги ко всему
набору данных в источнике. Также при работе с Power BI данные будут загружены не на рабочий лист, а в модель данных. После загрузки вы увидите
свою таблицу в следующих секциях:
 на панели Поля (Fields), расположенной в правой части окна;
 на левой вкладке Данные (Data), как показано на рис. 1.15;
 на вкладке Модель (Model).
Рис. 1.15. Таблица Transactions, загруженная в Power BI Desktop
Тогда как Excel показывает суммарное количество загруженных строк на
панели Запросы и подключения, Power BI этого не делает. Эту информацию
вы можете получить в Power BI, переключившись на вкладку Данные путем
выбора таблицы из правой панели Поля. После этого в нижней левой части
экрана появится информация о загруженных строках.
🍌 Примечание. В отличие от Excel, Power BI сортирует данные после их загрузки по первому столбцу. Чтобы скопировать такое поведение в Excel, вам придется явным образом добавить шаг с сортировкой перед загрузкой данных.
Обновление запросов
Со временем, узнавая Power Query все лучше и лучше, вы обнаружите, что
при помощи этого инструмента можно обрабатывать и очищать исходные
данные гораздо более эффективно по сравнению с классическими методами
при работе в Excel. Но истинная магия Power Query проявляется тогда, когда
вы понимаете, что можете обновлять созданные ранее запросы при изменении
данных, поступающих на вход. Это позволит прогнать обновленные данные
через все шаги преобразования и загрузить новые данные в место назначения. И что еще лучше – сделать это можно очень легко:
Редактирование запросов  55
 в Excel: перейдите на вкладку Данные (Data) и нажмите на кнопку
Обновить все (Refresh All);
 в Power BI: перейдите на вкладку Главная (Home) и нажмите на кнопку
Обновить (Refresh).
После этого вам останется подождать, пока Power Query считает обновленные данные из файла, обработает их и загрузит в таблицу Excel или модель
данных.
И если Power BI информирует пользователя о происходящем при помощи
специального диалогового окна, то в Excel бывает трудно понять, что в текущий момент происходит. В строке состояния, находящейся в нижней части
окна Excel, будет выведена соответствующая информация, но это не самый
очевидный способ оповещения. Лучше всего ориентироваться на панель Запросы и подключения, на которой появится индикатор выполнения загрузки данных. На рис. 1.16 показано, как внешне выглядит процесс обновления
информации из источника в Excel и Power BI соответственно.
Рис. 1.16. Процесс загрузки данных в Excel (слева) и Power BI Desktop (справа)
После окончания загрузки Excel покажет в этом заголовке количество обработанных строк, а в Power BI, как мы уже сказали, эту информацию можно
получить на вкладке Данные.
Этот метод прекрасно работает с файлами данных, которые обновляются на регулярной основе. Вне зависимости от того, является ли источник
файлом Excel, обновляемым сразу несколькими людьми, или файлом CSV,
который вы загружаете в конце месяца и кладете поверх старого, вы можете
сделать полное обновление данных всего в один клик.
Редактирование запросов
Хотя обновлять данные одним нажатием мышки – это здорово, иногда требуется, например, перед обновлением изменить источник данных. Допустим, наш запрос был нацелен на обработку и загрузку данных из файла с
названием Jan.CSV, в котором хранятся данные за январь. Но в следующем
месяце вы получаете новый файл с именем Feb.CSV. Очевидно, что в этом
случае одного щелчка мыши вам явно не хватит, поскольку это приведет
к обновлению лишь январских данных и не затронет новую информацию,
56  Глава 1. Основы Power Query
содержащуюся в файле Feb.CSV. Что нам нужно сделать, так это изменить
путь к файлу с исходными данными перед выполнением обновления. А это
значит, что нам необходимо отредактировать имеющийся у нас запрос. Для
этого нужно вернуться в редактор Power Query. А как это сделать – зависит
от используемого вами инструмента.
Запуск редактора Power Query в Power BI
В Power BI открыть редактор Power Query проще простого. Все, что вам
нужно, – это перейти на вкладку Главная (Home) и нажать на кнопку Преобразование данных (Transform Data), как показано на рис. 1.17. Это приведет
к открытию окна редактора Power Query, в котором вы можете изменить
существующие запросы и даже создать новые.
Рис. 1.17. Кнопка преобразования данных в Power BI
Запуск редактора Power Query в Excel
В Excel запустить редактор Power Query можно тремя способами, два из которых полагаются на активную панель Запросы и подключения. К сожалению, при запуске нового экземпляра Excel эту панель необходимо открывать
вручную, и это может сбивать пользователей с толку. Поскольку в наше время
львиная доля решений в Excel так или иначе связана с Power Query, первым
делом после открытия Excel вы делаете активной эту панель. А сделать это
можно четырьмя способами:
 перейти на вкладку Данные (Data) и нажать на кнопку Запросы и
подключения (Queries & Connections);
 перейти на вкладку Данные (Data), нажать на кнопку Получить данные (Get Data) и выбрать пункт Запустить редактор Power Query
(Launch Power Query Editor);
 открыть панель Запросы и подключения (Queries & Connections),
щелкнуть правой кнопкой мыши по запросу и выбрать пункт Изменить (Edit);
 открыть панель Запросы и подключения (Queries & Connections) и
дважды щелкнуть мышью по запросу.
Редактирование запросов  57
🍌 Примечание. Поскольку мы в большинстве случаев предпочитаем оставлять
панель Запросы и подключения открытой, чаще всего мы пользуемся последними двумя способами. Мы также любим шутить по этому поводу, говоря о том, что выбор способа зависит от того, хотите ли вы, чтобы на вашей
мышке больше изнашивалась левая кнопка, или стремитесь к равномерному
износу кнопок.
Просмотр шагов
Вернувшись в редактор Power Query, вы можете просмотреть любой из созданных шагов на панели Примененные шаги (Applied Steps). Выделяя шаг,
вы будете видеть в области предварительного просмотра состояние данных
на момент окончания действия выделенного шага.
🍌 Примечание. В окне предварительного просмотра используется технология
кеширования данных. Если вы заметили, что данные в таблице утратили
актуальность, или хотите убедиться, что в нее загружены последние сведения, вам необходимо вручную обновить информацию. Для этого можно нажать на кнопку Обновить предварительный просмотр (Refresh Preview) на
вкладке Главная (Home) в редакторе Power Query, как показано на рис. 1.18.
Рис. 1.18. Кнопка обновления предварительного просмотра
в редакторе Power Query
Настройка шагов
После возвращения в редактор Power Query вы можете добавлять новые
шаги, удалять существующие и даже редактировать шаги из состава запроса.
Сейчас мы покажем, что нужно сделать, чтобы направить запрос на новый
источник данных.
🙈 Предупреждение. Если вы откроете окончательные версии файлов для Excel
или Power BI из этой главы (с пометкой Complete), то увидите, что обновление
в них работать не будет. Причина в том, что шаг Источник (Source) в этих
файлах указывает на исходный файл, находящийся на нашем компьютере.
Следуя шагам из этого раздела, вы сможете выбрать в качестве источника
собственные файлы.
58  Глава 1. Основы Power Query
Взгляните на шаги, представленные на рис. 1.19.
Рис. 1.19. Примененные шаги в запросе Transactions
На этом рисунке можно заметить кое-что очень важное, а именно кнопки
с шестеренками справа от двух шагов, дающие возможность изменить шаги
при помощи пользовательского интерфейса.
🍌 Примечание. Как правило, если выполняемое действие в Power Query со-
провождается показом диалогового окна, впоследствии созданный шаг
будет отмечен шестеренкой, позволяющей настроить его параметры. Если
действие не подразумевает ввода данных в диалоговом окне, шестеренка,
скорее всего, не появится. Но из этого правила есть и исключения, и примером такого исключения является шаг с повышением заголовков.
Мы понимаем, что обращение к файлу с данными должно производиться
где-то в начале списка шагов. К счастью, у первого шага Источник (Source)
как раз есть шестеренка:
 выделите шаг Источник (Source);
 нажмите на кнопку с шестеренкой.
Откроется диалоговое окно, показанное на рис. 1.20, в котором вы можете
настроить ключевые составляющие этого шага.
Нам необходимо изменить значение в первом поле диалогового окна –
Путь к файлу (File Path). Давайте это сделаем:
 нажмите на кнопку Обзор (Browse);
 выберите файл Ch01 Examples\New Data.csv;
 нажмите на кнопку OK, чтобы закрыть диалоговое окно.
🍌 Примечание. Power Query прекрасно справился с задачей первоначальной
настройки всех параметров этого шага, так что ничего другого нам менять не
нужно. А что было бы, если бы он выбрал неправильный разделитель? Ничего страшного. В этом же окне настроек есть поле для указания разделителя,
и вы можете изменить его при необходимости.
Редактирование запросов  59
Рис. 1.20. Настройка шага Источник
Если данные в новом файле будут значительно отличаться, вы сразу заметите это в окне предварительного просмотра. Но в наших файлах данные
похожи. Как в этом случае убедиться, что изменения вступили в силу? Дело
усложняется еще и тем, что в наших файлах содержится более 999 строк, которые представлены в окне предварительного просмотра. Так что же делать?
Загрузим данные!
🍌 Примечание. Конечно, вы можете выделять каждый шаг в примененных
шагах, чтобы убедиться, что все работает, но делать это нет необходимости.
Поскольку наши данные обладают одинаковой структурой, все шаги будут
применены без проблем, и не нужно проходить по ним всем.
 на вкладке Главная (Home) нажмите на кнопку Закрыть и загрузить
(Close & Load) для Excel или Закрыть и применить (Close & Apply)
для Power BI.
Данные будут загружены, и вы сможете проверить это в Excel на панели Запросы и подключения, как показано на рис. 1.21, или в Power BI на вкладке
Данные.
Рис. 1.21. Количество загруженных строк изменилось с 4575 на 4921
60  Глава 1. Основы Power Query
Влияние Power Query
Освоившись с Power Query, вы в какой-то момент поймете, что этот инструмент постепенно оказывает все большее влияние на ваш рабочий процесс.
Давайте перечислим ключевые возможности этой технологии, известные
нам на данный момент:
 с помощью Power Query можно подключаться к огромному количеству
разнообразных источников данных;
 Power Query фиксирует все произведенные вами действия, создавая
некое подобие скрипта;
 Power Query никогда не затрагивает исходные данные, что позволяет
применять различные шаги и удалять их, если результат вас не устраивает;
 шаги в Power Query можно менять в будущем, когда исходные данные
изменятся.
Как видите, возможности Power Query просто огромны. Представьте, что
вы создали решение на основе скрипта Power Query по массовой очистке
исходных данных и загрузке их на рабочий лист Excel. Данные в Excel в дальнейшем используются в качестве основы для отчетов и диаграмм. В прошлом при получении нового файла с информацией вам пришлось бы заново
вручную производить очистку исходных данных, после чего копировать и
вставлять их в таблицу.
С приходом Power Query вся эта лишняя работа становится не нужна. Вы
просто нажимаете на кнопку Обновить все (Refresh All), и от вас больше
ничего не требуется. Все действительно очень просто. И дело не только в
быстроте, но и в постоянстве производимых операций и практически полном
исключении человеческого фактора, который зачастую становится источником ошибок.
Даже если вы не собираетесь пользоваться богатыми возможностями
Power Query в отношении обновления данных, вы сможете применять широкий спектр инструментов, входящих в его состав, для очистки и обработки
данных. Как вы узнаете, читая эту книгу, действительно сложные задачи по
приведению исходных данных к надлежащему виду выполняются при помощи Power Query с поразительной легкостью и быстротой, что позволяет все
силы сосредоточить на том, за что вам платят, а именно на анализе данных.
Также хочется отметить, что с Power Query вам не придется изучать отдельные инструменты ETL для Excel, Power BI и других программных продуктов. Power Query присутствует в Excel, Power BI Desktop, потоках данных
Power BI, Power Automate и многих других пакетах и службах от Microsoft. При
этом в компании четко дали понять, что возлагают большие надежды на эту
технологию и планируют в будущем внедрять ее во все большем количестве
продуктов. Изучать новый программный пакет всегда нелегко, но радует
хотя бы то, что впоследствии вы сможете применять его на самых разных
платформах.
Глава
2
Управление запросами
Перед тем как погрузиться в захватывающий мир преобразований Power
Query, необходимо убедиться в том, что вы примерно представляете, какие
сложности и задачи могут ждать вас в будущем. Большинство решений в области бизнес-аналитики начинаются с небольшого проекта, но постепенно
разрастаются до немыслимых размеров. В данной главе мы поговорим о методах, которые позволят вам все держать под контролем вне зависимости от
масштаба реализуемого проекта.
Использование архитектуры со множеством
запросов
Как вы узнали из первой главы, инструмент Power Query предоставляет вам
полноценный функционал в области ETL-решений. Вы увидели, как Power
Query последовательно создает и обрабатывает запрос. Неудобства возникают тогда, когда масштаб проекта значительно увеличивается. В таких условиях всегда хочется добавить к решению дополнительные слои, чтобы как-то
его структурировать.
Разделение запросов на E, T и L
Вместо того чтобы выполнять все необходимые шаги в едином запросе,
всегда можно разбить процесс на несколько запросов. Давайте рассмотрим
следующую структуру запросов:
 сырые данные (Raw Data). Этот запрос можно использовать для извлечения данных из источника. На этом этапе мы делаем лишь минимальные преобразования данных. Максимум, что можно себе позволить
здесь, – это исключить лишние столбцы и строки. Наша конечная цель
на этом шаге – очищенная таблица с исходным наполнением, вне зависимости от необходимости использовать все без исключения данные.
Это то место, где вы можете просматривать и изменять источник данных, а также видеть, какие записи вам доступны;
 подготовка (Staging). Наша цель на этом этапе – выполнить большую часть преобразований, входящих в процесс ETL. Здесь мы будем
62  Глава 2. Управление запросами
фильтровать данные, сокращая их объем, и выполнять полный процесс
очистки и преобразований, подготавливая наши данные для анализа.
Хотя этот этап может состоять и из одного запроса, вы можете разбить
его на несколько запросов, если это необходимо;
 модель данных (Data Model). Эти запросы можно рассматривать как завершающую фазу подготовки данных перед их загрузкой, и они предполагают наличие имени создаваемой таблицы в Excel или модели данных. Обычно на этом шаге происходит добавление или объединение
запросов, подготовленных на предыдущем этапе, если это необходимо,
а также установка типов данных для столбцов в таблице.
На первый взгляд кажется, что здесь все как-то слишком усложнено. Нужны ли вам три разных запроса для сбора данных, манипулирования ими
и загрузки в Excel? Оказывается, у Кена и Мигеля разные мнения на этот
счет…
Преимущества совмещения запросов
Мигель предпочитает реализовывать все шаги в рамках одного или минимально возможного количества запросов. Такой подход отвечает современным тенденциям по минимизации всего и вся в большинстве языков программирования, что приводит к исключению составляющих, в которых нет
особой необходимости, и приведению проекта к лаконичному виду. Давайте
приведем некоторые плюсы концепции совмещения запросов:
 если в вашем списке всего несколько запросов, найти нужный не составит труда. Поскольку в навигаторе Power Query не предусмотрен поиск,
это преимущество можно назвать весьма значительным;
 чем больше у вас запросов, тем труднее бывает отследить их происхождение, так как Power Query обладает не самым богатым инструментарием в этой области;
 случаются ситуации, когда разделение запросов приводит к появлению
ошибки Formula Firewall. Это может расстраивать, но иногда приходится объявлять все источники данных в одном запросе, чтобы избежать
таких неприятностей;
 некоторые программы, использующие в своей работе Power Query, –
такие как SSIS и Azure Data Factory – поддерживают только единичные запросы. Если вы планируете переносить свое решение на одну
из таких платформ, лучше реализовывать его с применением одного
запроса;
 с одним запросом бывает легче просматривать все в едином окне представления и вносить необходимые изменения. Это бывает особенно
удобно, если вы используете инструменты диагностики запросов, выполняете проверку на свертывание запросов (query folding) или исследуете планы их выполнения.
Использование архитектуры со множеством запросов  63
Преимущества разделения запросов
Кен придерживается концепции разделения запросов и приводит в защиту
своего мнения несколько аргументов, в числе которых следующие:
 с использованием такой структуры можно легко выбрать запрос с сырыми данными, посмотреть, какие данные доступны вам в источнике,
и обновить запрос, если источник изменился;
 появляется возможность повторного использования запросов (от сырых данных до подготовки), что позволяет минимизировать дублирование работы;
 при изменении пути к исходным данным вам необходимо будет поменять его лишь в одном месте, независимо от того, сколько раз источник
используется в вашем проекте;
 переход на новый тип источника данных также облегчается – достаточно будет создать новое подключение параллельно со старым источником, убедившись, что все столбцы имеют одинаковые имена, а затем
просто выполнить замену;
 как мы уже сказали, бывают случаи, когда необходимо использовать единый запрос, чтобы избежать возникновения ошибки Formula
Firewall. Но встречаются и ситуации, когда, наоборот, нужно для этого
разделить запросы.
Кен также считает, что в пользу этой техники можно привести еще массу
доводов. А когда вы начнете использовать Power Query в качестве инструмента подготовки данных для многомерных моделей в Power Pivot или Power BI,
вы удивитесь, как легко и удобно такая структура позволяет строить таблицы
фактов (Fact) и измерения (Dimension). По этой причине курс по многомерному моделированию на https://skillwave.training начинается именно с этой
темы.
🍌 Примечание. Одним из основных преимуществ использования инструментов Power Query и Power Pivot является возможность быстрого создания прототипов масштабных решений из области бизнес-аналитики даже без привлечения разработчиков. Даже если вы начнете свой проект с подключения
к Excel в качестве источника данных, ничто не мешает вам настроить его
таким образом, чтобы в дальнейшем можно было перевести его на использование базы данных SQL.
Влияние разделения запросов на производительность
Вас может беспокоить вопрос о том, как повлияет процесс разделения запросов на общую производительность сценария. Приведет ли такая схема к
замедлению процесса обновления данных?
64  Глава 2. Управление запросами
При использовании Power BI и Excel 2019 и выше (включая Microsoft 365)
ответ на поставленный выше вопрос будет отрицательным. В версиях Power
Query этих продуктов применяется продвинутая технология, названная кешированием узлов (node caching), призванная сохранять результаты обновления запросов для повторного использования в рамках одной сессии обновления.
Представьте, что у вас есть структура запросов по извлечению данных из
файла CSV, показанная на рис. 2.1.
Сырые
данные
Подготовка
Продажи
(Sales)
Клиенты
(Clients)
Рис. 2.1. Цепь запросов с повторным использованием результатов,
полученных на шаге подготовки данных
Предположим, что на шаге с сырыми данными выполняется совсем немного действий, тогда как на этапе подготовки производится сложный многоуровневый процесс очистки данных. Запросы по продажам и клиентам –
очень простые и короткие. Фактически здесь производится обращение к
результатам шага с подготовкой данных и удаляются колонки и строки, не
нужные для этого разреза.
В момент обновления запрос с подготовкой данных будет выполнен, а его
результаты будут кешированы. Далее запрос Sales будет ссылаться на этот
кеш, выполнять дополнительные преобразования и загружать данные в место назначения. После этого запрос Clients сделает то же самое – обратится к
кешированным данным и выполнит с ними свои преобразования. Как видите, запрос с подготовкой данных выполняется лишь раз, после чего результаты многократно используются в качестве входа для других запросов.
Сравните этот пример со сценарием, приведенным на рис. 2.2.
Сырые
данные
Подготовка
Продажи
(Sales)
Сырые
данные
Подготовка
Клиенты
(Clients)
Рис. 2.2. Раздельные цепи запросов на основе одного источника данных
Ссылки на запросы  65
В данном случае запрос Sales перед загрузкой данных обратится к источнику – файлу CSV, после чего будет выполнен запрос по подготовке данных
и действия из запроса по продажам.
Поскольку цепь запроса Clients является обособленной, при его выполнении потребуется повторить все перечисленные выше действия, за исключением того, что вместо запроса по продажам будет выполнен запрос по
клиентам.
Как видите, использование ссылок на запросы позволяет оптимизировать
процесс и избавиться от дублирования операций.
🙈 Предупреждение. Внимание! В приведенных выше сценариях запросы с
сырыми данными и подготовкой должны быть настроены именно как подготовительные запросы (staging query). Если эти запросы будут загружены
в таблицу или модель данных, будут созданы связанные сущности (linked
entities), которые потребуют более длительного времени на обработку.
Ссылки на запросы
Как же настроить запросы, чтобы они следовали этому шаблону? Давайте
воссоздадим на практике описанный выше пример.
Создание базового запроса
Начните с открытия новой рабочей книги Excel или файла Power BI. После
этого выполните следующие действия:
 создайте новый запрос с помощью коннектора Из текстового/CSVфайла (From Text/CSV);
 укажите путь к файлу \Ch01 Examples\Basic Import.csv;
 нажмите на кнопку Преобразовать данные (Transform Data), чтобы
открылся редактор Power Query;
 переименуйте запрос в Raw Data на панели Параметры запроса (Query Settings).
В данный момент ваш запрос должен выглядеть так, как показано на
рис. 2.3.
Рис. 2.3. Первое впечатление Power Query от файла Basic Import.csv
66  Глава 2. Управление запросами
У вас бывало такое, что вы создали отчет, а начальник через пару месяцев попросил вас его расширить? И вам надо как-то узнать, содержатся ли
в исходном наборе данных сведения, которые вас просят вывести. Как раз
это одна из главных целей данного запроса: посмотреть доступную вам информацию.
По сути, такой запрос мы получили автоматически, подключившись к нашему источнику данных. Перед нами исходная таблица со всеми столбцами
из набора данных и строками, попавшими в диапазон предварительного
просмотра.
🍌 Примечание. Помните, что каждый источник данных при создании запроса
Raw Data должен рассматриваться отдельно. В каких-то источниках достаточно будет оставить запрос, созданный Power Query по умолчанию. В других
понадобится удалить шаг с изменениями типов данных, отфильтровать данные или даже дополнить столбцы. Вы увидите такие ситуации, читая данную
книгу.
Ссылочные запросы
После создания базового запроса Raw Data пришло время сослаться на
него при создании первого подготовительного запроса. Для этого необходимо, чтобы панель навигатора запросов была открыта. В Power BI она открыта
по умолчанию, а в Excel придется открыть ее вручную, щелкнув по кнопке со
стрелкой на панели Запросы (Queries), как показано на рис. 2.4.
Рис. 2.4. Открытие панели навигатора запросов в Excel
На этой панели вы можете видеть все запросы и выполнять с ними необходимые действия. Щелкните правой кнопкой мыши по запросу Raw Data и
выберите пункт Ссылка (Reference).
Это приведет к созданию нового запроса с именем Raw Data (2). Нам необходимо переименовать его в Staging, и это можно сделать следующими
способами.
1. Щелкнуть правой кнопкой мыши по запросу на панели навигатора и
выбрать пункт Переименовать (Rename).
Ссылки на запросы  67
2. Дважды щелкнуть мышью по запросу на панели навигатора и изменить
имя.
3. Изменить содержимое поля Имя (Name) в разделе Свойства (Properties)
на панели Параметры запроса (Query Settings).
Каждый из этих способов приведет к переименованию запроса, так что не
важно, какой из них вы выберете.
Теперь давайте сразу создадим запрос для загрузки данных в место назначения:
 щелкните правой кнопкой мыши по запросу Staging на панели навигатора и выберите пункт Ссылка (Reference);
 переименуйте запрос Staging (2) в Sales.
Теперь давайте посмотрим, что мы сделали на данный момент (следите
по рис. 2.5).
1. На панели навигатора у нас есть три запроса, и в данный момент выделен запрос Sales.
2. В отличие от исходного запроса Raw Data, в котором присутствует три
шага, запрос Sales состоит из единственного шага с именем Источник
(Source).
3. В строке формул отображается содержимое шага Источник, дающее
понять, что этот шаг принимает вывод запроса Staging.
Рис. 2.5. Текущее состояние запросов
Очень важно понять, что означает это выражение в строке формул. А означает оно то, что, что бы ни происходило в запросе Staging, результат поступит
на вход запроса Sales. Давайте это проверим:
 выделите запрос Staging;
 выделите столбец POS Hour и нажмите на клавишу Delete (или выберите пункт Удалить (Remove) в контекстном меню);
 дважды щелкните мышью по заголовку столбца Item Name и переименуйте его в Item;
 дважды щелкните мышью по заголовку столбца Units Sold и переименуйте его в Units.
68  Глава 2. Управление запросами
В данный момент запрос Staging должен выглядеть так, как показано на
рис. 2.6.
Рис. 2.6. Запрос Staging после очистки данных
Теперь вернитесь на панели навигатора к запросу Sales. Он выглядит так,
как на рис. 2.7.
Рис. 2.7. Что-нибудь изменилось в запросе Sales?
Если вы внимательно посмотрите на структуру запроса Sales, то увидите,
что она не изменилась: он по-прежнему состоит из одного примененного
шага, а в строке формул так же, как и до изменения запроса Staging, написано = Staging.
Но в предварительном просмотре изменения очевидны, не правда ли?
Сейчас здесь выведены данные в соответствии с произведенными изменениями в запросе Staging. Столбец POS Hour, изначально присутствовавший в
запросе Sales, пропал, а еще два столбца оказались переименованы.
Несмотря на то что мы не вносили никаких изменений в запрос Sales,
данные в предварительном просмотре поменялись. Но если задуматься, эти
изменения вполне логичны, поскольку мы внесли корректировки в запрос,
на который ссылается наш запрос Sales. Таким образом, любые изменения,
которые будут происходить в запросе Staging, должны автоматически распространяться на запрос Sales, поскольку его источником является запрос
Staging.
Давайте добавим в запрос Sales новый шаг, чтобы зафиксировать типы
данных перед финализацией этой цепи запросов:
 выделите столбец Item и нажмите сочетание клавиш CTRL+A, чтобы
выделить все колонки;
Ссылки на запросы  69
 перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Определить тип данных (Detect Data Type).
Итак, что мы сделали? Мы разбили процесс ETL на три запроса, которые
работают по схеме, показанной на рис. 2.8.
Подготовка
Сырые данные
• Источник: CSV-файл
• Повышенные
заголовки
• Измененный тип
• Источник: Raw Data
• Удаленные столбцы
• Переименованные
столбцы
Продажи
• Источник: Staging
• Фиксация типов
данных
Рис. 2.8. Процесс ETL, состоящий из трех запросов
И хотя вам может показаться, что мы выполнили как-то слишком много
действий для простого запроса, на самом деле создание таких цепочек запросов с определенными шагами для каждой фазы поможет вам с легкостью
масштабировать свои решения в будущем.
🍌 Примечание. Вопрос, который вы всегда будете себе задавать, звучит так: какие преобразования в какие запросы нужно добавлять? Ответ на этот вопрос
весьма субъективен, и со временем вы выработаете собственные правила на
этот счет.
Визуализация дерева зависимостей запросов
Также вы должны знать, что в Power Query есть встроенный инструмент
просмотра дерева зависимостей запросов, облегчающий понимание существующих цепочек и связей между запросами. Чтобы открыть этот инструмент,
необходимо перейти на вкладку Просмотр (View) и нажать на кнопку Зависимости запроса (Query Dependencies).
🙈 Предупреждение. Хотя внешне просмотр зависимостей запросов выглядит
привлекательно, на момент выхода книги актуальная версия Power Query
не включала в себя некоторые важные возможности инструмента. Для небольших моделей данных это не так критично, но по мере роста сложности
модели эффективно использовать этот инструмент становится очень затруднительно. В компании Microsoft начали работать над этим вопросом в рамках Power Query Online, предоставив намного более детализированный и
интерактивный инструмент под названием Представление схемы (Diagram
View).
70  Глава 2. Управление запросами
Для нашего примера дерево зависимостей будет выглядеть так, как показано на рис. 2.9.
Рис. 2.9. Просмотр зависимостей запроса
Для максимального комфорта советуем нажать на кнопку с четырьмя
стрелками в нижней правой части окна. Это позволит масштабировать
диаграмму таким образом, чтобы она помещалась в окне. Также вы можете приближать и отдалять просмотр при помощи ползунка слева от этой
кнопки.
Просмотр зависимостей при помощи Monkey Tools
Если у вас возникли проблемы со сложной структурой запросов, с которой
вам непросто разобраться в Power Query, вы можете попробовать использовать надстройку Excel от Кена под названием Monkey Tools, представляющую
собой улучшенную версию инструмента просмотра зависимостей запросов.
Хотя в этой надстройке содержится очень много полезных возможностей
по созданию и проверке запросов, ее ключевым инструментом является
Query Sleuth, позволяющий выполнять трассировку запросов, как показано
на рис. 2.10.
Выбор места загрузки запроса  71
Рис. 2.10. Monkey Tools Query Sleuth отображает дерево зависимостей
и код M для запроса Calendar
Узнать больше об этой надстройке и скачать бесплатную пробную версию
вы можете на сайте Кена по адресу https://xlguru.ca/monkeytools.
Выбор места загрузки запроса
Теперь, когда все запросы созданы, пришло время их загрузить. По правде
говоря, нам необходимо загрузить в рабочую книгу Excel или модель данных
Power BI лишь один запрос – Sales. Raw Data и Staging, по сути, являются вспомогательными запросами, позволяющими выйти на нужный нам результат
в запросе Sales, и хранить их данные не имеет никакого смысла.
Хорошая новость состоит в том, что в Power Query есть для этого все необходимое. В Power BI это достигается путем отмены загрузки запроса, а в
Excel – с помощью загрузки в виде подключения (Connection Only). В результате Power Query никогда не будет выполнять шаги таких запросов, за исключением ситуаций, когда они будут вызваны из других запросов в цепочке.
На протяжении этой книги мы будем называть запросы, созданные в режиме
подключения, подготовительными (staging query), поскольку именно в подготовке данных для других запросов и состоит их главная задача.
72  Глава 2. Управление запросами
Выбор места загрузки запроса в Power BI
По умолчанию все запросы в Power BI будут загружаться в модель данных.
Если вам нужно изменить такое поведение, щелкните правой кнопкой мыши
по запросу на панели навигатора и снимите флажок Включить загрузку
(Enable Load) в контекстном меню.
Как видно по рис. 2.11, запросы, которые не будут загружаться в модель
данных, будут помечены курсивом.
Рис. 2.11. Снятие флажка загрузки запроса переведет
его в категорию подготовительных
Обратите внимание, что термин Включить загрузку не влияет на то, будет
ли запрос обновляться. После нажатия на кнопку Закрыть и применить
(Close & Apply) или последующего требования обновить данные запрос Sales
вызовет запрос Staging, который в свою очередь обратится к запросу Raw
Data. Но в конечном счете в модели данных Power BI появится только запрос
Sales.
Выбор места загрузки запроса в Excel
Тогда как с Power BI все легко и понятно, в Excel далеко не все так однозначно.
Трудности здесь связаны с тем, что, в отличие от Power BI, где можно каждый запрос конфигурировать отдельно, Excel позволяет выбрать лишь одно
место загрузки для всех запросов, созданных в рамках одной сессии Power
Query (пока открыт редактор Power Query). Это не очень приятно, ведь у нас
есть три запроса, а на рабочий лист мы хотим загрузить только один из них,
тогда как остальные желаем оставить в виде подготовительных запросов.
К сожалению, это невозможно, и нам необходимо выбрать одно место назначения для всех трех запросов.
Выбор места загрузки запроса  73
🍌 Примечание. Этого можно избежать, если после создания и загрузки каж-
дого запроса следующий запрос создавать заново. Для этого необходимо
повторно открывать редактор Power Query, что может быть весьма неудобно,
поскольку сбивает с мысли.
С учетом того, что нам предлагают выбрать одно место назначения для
всех запросов, придется хорошенько подумать, какое именно место выбрать.
🙈 Предупреждение. Худшее решение, которое здесь можно принять, – это
перейти в редакторе Power Query на вкладку Главная (Home) и нажать на
кнопку Закрыть и загрузить (Close & Load). Причина этого в том, что в этом
случае Excel загрузит каждый запрос в новую таблицу на новом листе. Иными словами, мы получим по рабочему листу и таблице с полным содержанием для всех наших запросов: Raw Data, Staging и Sales!
Чтобы этого избежать, нам придется изменить поведение Power Query
по умолчанию следующим образом: перейдите на вкладку Главная (Home),
нажмите на текст под кнопкой Закрыть и загрузить (Close & Load), а не на
саму кнопку, и выберите вариант Закрыть и загрузить в… (Close & Load
To…), как показано на рис. 2.12.
Рис. 2.12. Нам нужна эта кнопка!
После этого в Excel откроется диалоговое окно Импорт данных (Import
Data), показанное на рис. 2.13, в котором вы сможете выбрать место назначения.
74  Глава 2. Управление запросами
Рис. 2.13. Выбор места назначения запроса в Excel
Давайте посмотрим, какие у нас есть варианты:
 Таблица (Table): каждый из трех запросов будет загружен в отдельную
таблицу на отдельном рабочем листе;
 Отчет сводной таблицы (PivotTable Report): если у вас один запрос,
данные будут загружены в кеш сводной таблицы (PivotCache), а на листе
будет создана сводная таблица. В нашем случае с тремя запросами все
они будут загружены в модель данных, а затем будет создана сводная
таблица на новом рабочем листе;
 Сводная диаграмма (PivotChart): аналогично предыдущему варианту,
но с созданием сводной диаграммы вместо сводной таблицы;
 Только создать подключение (Only Create Connection): исключает загрузку запроса, пока мы не внесем изменение (или не вызовем запрос
по ссылке из другого запроса).
🍌 Примечание. Четыре варианта, описанных выше, являются взаимоисключа-
ющими, но с каждым из них вы можете выбрать опцию Добавить эти данные
в модель данных (Add this data to the Data Model). Если этот флажок установить совместно с импортом данных в таблицу, данные будут загружены
одновременно и на рабочий лист, и в модель данных, что обычно не рекомендуется, тогда как загрузка в виде подключения позже позволит изменить
поведение запроса и загрузить данные в модель.
Пришло время сделать выбор:
 установите переключатель в положение Только создать подключение (Only Create Connection);
 нажмите на кнопку OK.
Выбор места загрузки запроса  75
Все ваши запросы будут загружены в виде подключений, что видно по
рис. 2.14.
Рис. 2.14. Загруженные в виде подключений запросы
Так зачем нужно выбирать вариант только с подключением при наличии
нескольких запросов? Представьте, что было бы, если бы мы решили загрузить все запросы на рабочий лист или в модель данных. В этом случае создавались бы и сами запросы, и Excel пришлось бы создавать для них отдельные
рабочие листы или таблицы в модели данных. И после этого вам необходимо
было бы ждать, когда все данные загрузятся, причем для всех трех запросов.
Но и это не все. Далее вы бы вернулись, чтобы пометить два запроса, которые
должны были быть загружены в виде подключений, после чего снова вынуждены были бы ждать, пока Excel все обновит, удалив ненужные данные.
Причина того, почему мы выбираем вариант только с подключением,
очень проста – это скорость. Такой тип загрузки выполняется практически
мгновенно, а обновляются только те запросы, которые необходимо загрузить. Это настолько полезная опция, что мы даже установили ее в Excel в качестве действия по умолчанию. Если вы тоже хотите это сделать, выполните
следующие действия:
 нажмите на выпадающую кнопку Получить данные (Get Data) и выберите пункт Параметры запроса (Query Options). В появившемся
диалоговом окне перейдите в раздел Загрузка данных (Data Load);
 установите переключатель в положение Указать пользовательские
параметры загрузки по умолчанию (Specify Custom Default Load
Settings);
76  Глава 2. Управление запросами
 снимите флажок Загрузить в лист (Load To Worksheet). Вы могли бы
подумать, что здесь будет опция загрузки в виде подключения, но
снятие флажков, по сути, и активирует этот вариант, как показано на
рис. 2.15.
Рис. 2.15. Настройка для загрузки запросов
в виде подключения по умолчанию
🙈 Предупреждение. Не забудьте снять флажок Загрузить в лист (Load To Worksheet). В противном случае вы просто повторите вариант загрузки, принятый
по умолчанию.
Изменение места назначения
Теперь наша проблема состоит в том, что таблица Sales загружена только
в виде подключения, а нам необходимо загрузить ее на лист. Как же нам это
сделать?
Первое, что пытается сделать любой пользователь Excel в такой ситуации, – изменить запрос и установить для него другое место назначения в
редакторе Power Query. Каково же бывает его удивление, когда он видит, что
кнопка Закрыть и загрузить в… (Close & Load To…) оказывается недоступной. Получается, что после создания запроса вы уже не можете изменить
место его назначения в редакторе Power Query.
Вместо этого вы должны сделать следующее, чтобы изменить место загрузки запроса Sales или любого другого:
 перейдите в Excel на панель Запросы и подключения (Queries &
Connections);
 щелкните правой кнопкой мыши по запросу, который хотите изменить
(Sales), и выберите пункт Загрузить в… (Load To…), как показано на
рис. 2.16.
В открывшемся диалоговом окне Импорт данных (Import Data) вы можете
выбрать другой вариант загрузки. В нашем случае мы остановимся на уже
опробованном варианте Таблица (Table).
Выбор места загрузки запроса  77
Рис. 2.16. Изменение места назначения
после загрузки запроса в Excel
Итоговый результат, показанный на рис. 2.17, окажется таким же, как и в
предыдущей главе, но с более надежной и масштабируемой структурой запросов.
Рис. 2.17. От данных к рабочему листу через цепочку запросов
🍌 Примечание. Хотя мы показали только вариант изменения варианта загрузки с подключения на таблицу, вы можете использовать этот способ для любых комбинаций.
🍌 Совет от профессионала. По ошибке загрузили запрос в виде таблицы вместо подключения? Вместо того чтобы менять место назначения запроса и
затем удалять рабочий лист, попробуйте сначала удалить лист. После этого
запрос автоматически переключится в состояние загрузки в виде подключения. Это позволит вам сэкономить целый шаг!
78  Глава 2. Управление запросами
Организация запросов
Чем больше вы будете работать с Power Query и осваивать методы, приведенные в этой главе, тем больше запросов вы будете создавать. Спустя какое-то
время вам непременно потребуется их как-то организовывать. Power Query
позволяет создавать папки и подпапки для группирования имеющихся у
вас запросов. Этот функционал реализован на панели навигатора в редакторе Power Query, а также на панели Запросы и подключения (Queries &
Connections) в Excel.
Создание папок в Power Query
Создать новую группу или папку можно двумя способами, вне зависимости
от того, находитесь вы на панели навигатора в редакторе Power Query или на
панели Запросы и подключения (Queries & Connections) в Excel.
Чтобы создать новую группу, сделайте следующее:
 щелкните правой кнопкой мыши по пустому месту на панели и выберите пункт Создать группу… (New Group…).
Для переноса запроса в группу с ее одновременным созданием выполните
такие действия:
 выделите запрос на панели (или несколько запросов с зажатой клавишей CTRL);
 щелкните правой кнопкой мыши по любому из выделенных запросов и выберите в выпадающем подменю перемещения в группу пункт
Создать группу… (New Group…).
Откроется диалоговое окно, в котором вы сможете ввести имя и, при необходимости, описание группы, как показано на рис. 2.18.
Рис. 2.18. Создание новой группы для организации запросов
Организация запросов  79
В нашем случае мы создадим три следующие группы:
 Raw Data Sources;
 Staging Queries;
 Data Model.
В результате панель Запросы и подключения (Queries & Connections) в
Excel должна приобрести вид, показанный на рис. 2.19.
Рис. 2.19. Три папки готовы принимать запросы
🍌 Примечание. В редакторе Power Query описание группы будет показано при
наведении на нее мышью.
Перенос запросов в группы
Разумеется, если вы создаете группу одновременно с переносом в нее запроса, он уже будет находиться в ней. В противном случае наши существующие запросы окажутся в автоматически созданной группе с именем Другие
запросы (Other Queries).
Казалось бы, разносить запросы по группам было бы очень удобно путем
простого перетаскивания их мышью, но, к сожалению, такой функционал
Powered by TCPDF (www.tcpdf.org)
80  Глава 2. Управление запросами
реализован только на панели навигатора в редакторе Power Query, но не на
панели Запросы и подключения (Queries & Connections) в Excel. Здесь вам
придется выполнить следующие несложные действия:
 щелкнуть правой кнопкой мыши на запросе;
 в выпадающем пункте меню Переместить в группу (Move to Group)
выбрать нужную группу.
🍌 Примечание. Работая в Excel, вы можете легко вернуться в редактор Power
Query, дважды щелкнув мышью по любому запросу. После этого сможете
воспользоваться способом перетаскивания запросов в группы при помощи
мыши.
Изменение порядка следования запросов и групп
Группы запросов располагаются в списке изначально в порядке их создания. И хотя в этом есть логика, иногда вам необходимо менять порядок
следования элементов на панели. Как и в случае с перемещением запросов
в группы, менять порядок расположения групп и запросов на панели при помощи мыши можно только в редакторе Power Query. В Excel для этого нужно
сделать следующее:
 щелкните правой кнопкой мыши по запросу или группе и выберите
пункт меню Вверх (Move Up) или Вниз (Move Down);
 повторите это действие столько раз, сколько необходимо, пока группы
и запросы не выстроятся в нужном порядке.
В нашем случае мы бы хотели расположить группы по степени их значимости, а именно: Data Model, Staging Queries и, наконец, Raw Data Sources.
Можно сделать это в Excel при помощи описанной выше процедуры, но гораздо удобнее будет воспользоваться функционалом с переносом элементов
мышью, доступным в редакторе Power Query, как показано на рис. 2.20.
Рис. 2.20. Изменение порядка следования групп запросов
при помощи мыши в редакторе Power Query
Разделение существующих запросов  81
Создание подпапок запросов
Для создания вложенной группы с запросами необходимо щелкнуть правой кнопкой мыши на группе и выбрать пункт Создать группу (New Group).
🍌 Примечание. Тогда как можно создавать группы «на лету» при переносе в
них запросов, подгруппы таким образом создавать нельзя. Получается, необходимо сначала создать подгруппу, а затем переносить в нее запрос, как
показано на рис. 2.21.
Рис. 2.21. Иерархия групп для хранения
запросов в многомерной модели
Разделение существующих запросов
Конечно, далеко не все новички в Power Query следуют при работе с запросами всем принципам, описанным в данной главе. Скорее всего, большинство
из них реализовало бы всю работу в одном запросе. А что делать потом?
Неужели это конец? Придется переписывать все решение с нуля, чтобы все
правильно организовать? Вовсе нет!
Давайте вспомним запрос с именем Transactions, созданный нами ранее.
Панель с примененными шагами из этого запроса показана на рис. 2.22.
Рис. 2.22. Примененные шаги в запросе Transactions
82  Глава 2. Управление запросами
Чтобы сделать этот запрос функционально эквивалентным той структуре,
которую мы выстроили в данной главе, необходимо выполнить следующие
действия по его разделению:
 перейдите в режим редактирования запроса Transactions;
 щелкните правой кнопкой мыши на шаге Lock in Data Types и выберите
пункт Извлечь предыдущий (Extract Previous);
 введите Staging в поле Имя нового запроса (New query name);
 выделите запрос Staging;
 щелкните правой кнопкой мыши на шаге Removed Columns и выберите
пункт Извлечь предыдущий (Extract Previous);
 введите Raw Data в поле Имя нового запроса (New query name).
В результате мы получим цепочку запросов, практически идентичную той,
которую построили в предыдущих разделах главы, что видно по рис. 2.23.
Сырые данные
• Источник: CSV-файл
• Повышенные
заголовки
• Измененный тип
Подготовка
• Источник: Raw Data
• Удаленные столбцы
• Переименованные
столбцы
Transactions
• Источник: Staging
• Фиксация типов
данных
Рис. 2.23. Результат разделения запроса Transactions на три составляющие
Бывает непросто осознать, как именно следует разделить запрос. Здесь
важно понимать, что все шаги, стоящие перед тем, который вы выделили
при разделении, будут перемещены в отдельный запрос.
🍌 Примечание. Реальность такова, что мы не всегда можем четко понять, когда
следует остановиться с наполнением шагами одного запроса и начать новый
путем создания ссылки. Хорошая новость состоит в том, что у нас всегда есть
удобная команда Извлечь предыдущий (Extract Previous), с помощью которой мы можем разделить запросы и после их написания.
Заключительные мысли об архитектуре запросов
Конечно, разделение задачи на несколько запросов требует времени. А стоит
ли игра свеч? Ответ на этот вопрос зависит от целей вашего проекта.
Кен считает, что максимальное разделение запросов позволяет добиться
необходимой гибкости при преобразовании исходной структуры информации для моделей данных. Мигель, напротив, придерживается мнения о том,
Заключительные мысли об архитектуре запросов  83
что чем меньше запросов, тем лучше. Работая с Power Query, вы постепенно
выработаете собственное представление об этом аспекте моделирования.
В конце концов, это лишь вопрос вкуса и стиля. Вам может показаться, что
для конкретного решения лучше подойдет один, два или целых восемь запросов. Кроме того, иногда вы будете отходить от собственного стиля для
лучшей реализации специфической задачи.
В данной книге мы делаем упор на преобразование данных, в связи с чем
в большинстве случаев для простоты будем обходиться одним запросом. Но
в реальных задачах вы можете реализовывать сколь угодно сложную структуру запросов.
Прекрасно то, что мы вольны сами выбирать степень гибкости архитектуры под конкретные задачи.
Глава
3
Типы данных и ошибки
Данная глава будет посвящена двум наиболее распространенным задачам,
с которыми сталкиваются новички при работе с Power Query. Речь пойдет о
типах (не форматах) данных и о том, как работать с ошибками, возникающими в Power Query.
Типы и форматы данных
Один из самых часто задаваемых вопросов на наших курсах, в блогах и на
форумах звучит так: «А как мне отформатировать данные в Power Query или
Power BI?» Короткий ответ – никак, а расшифровка повлечет за собой дискуссию о типах данных в сравнении с форматами.
Форматы
Чтобы проиллюстрировать проблему, давайте взглянем на простые входные данные в Excel из книги Ch03 Examples\Data Types vs Formats.xlsx, показанные на рис. 3.1.
Рис. 3.1. Простые числовые данные в Excel
Здесь вы видите числовые данные, отформатированные в Excel. Хотя
округление чисел в таблице произведено до количества знаков, указанного
в первом столбце, отформатированы все значения для вывода шести знаков
после запятой. Здесь очень важно понимать, что в первой строке в столбце Whole находится значение 9553, обладающее числовым типом данных
(numeric data type), но отформатированное (formatted) для отображения в
виде 9 553,000000 (в английской локали 9,553.000000).
Почему это так важно? Если вы попросите немца отформатировать эти
данные, его вариант формата будет отличаться от вашего – он предпочтет
86  Глава 3. Типы данных и ошибки
написать так: 9.553,000000. Значение числа при этом не изменилось, изменилось лишь его отображение.
🍌 Примечание. Форматирование влияет только на внешний вид данных, а не
на их значение или точность.
Типы данных
Хотя в версии Microsoft 365 в этом отношении наблюдаются какие-то подвижки, исторически Excel не делает больших различий между форматами и
типами данных. Если вы посмотрите на сокращенный список типов данных,
заявленных в Excel, то увидите следующие:





числовой (Numbers);
текстовый (Text);
пустые значения (Blanks);
ошибки (Errors);
логические значения (Boolean, True/False).
При этом даты фактически представлены в виде чисел, соответствующих
количеству дней, прошедших с 1 января 1900 года, но отформатированных в
привычном для нас виде. Время представлено в виде десятичных чисел (как
доля от дня), отформатированных как часы, минуты и секунды.
В Power Query предусмотрено пять основных типов данных:





число (Numeric);
дата и время (Dates & Times);
текст (Text);
истина/ложь (Boolean, True/False);
двоичный (Binary, файлы).
Первые две категории типов данных включают в себя подтипы, показанные на рис. 3.2. Также
важно понимать, что перечисленные типы данных являются явными, и от этого зависит, как
те или иные значения будут преобразованы из
одного типа в другой.
На этом этапе очень важно понимать, что сейчас мы говорим исключительно о типах данных,
а не об их формате. Давайте посмотрим, что произойдет при загрузке этих данных в Power Query:
 отобразите панель Запросы и подключения (Queries & Connections), нажав на
вкладке Данные (Data) одноименную
кнопку;
Рис. 3.2. Типы данных в Power
Query
Типы и форматы данных  87
 дважды щелкните мышью по запросу DataTypes;
 выделите ячейку в третьей строке в столбце Whole.
Сейчас важно сделать несколько замечаний по поводу этого запроса, которые мы пометили цифрами на рис. 3.3.
Рис. 3.3. Как свести бухгалтера с ума? Сделайте так,
чтобы дробная часть чисел не была выровнена!
Индикатор типа данных в левой части заголовка столбца показывает иконку вида «ABC123» – тип данных, не присутствовавший в представленном
выше списке. Официально этот тип данных именуется any (любой) и указывает на то, что либо для этой колонки не был определен тип данных явно,
либо в ней присутствуют данные различных типов.
В выбранной вами ячейке содержится значение 9350,095. Несмотря на то
что другие значения в этой строке включают четыре знака после запятой, в
данном случае для выражения описываемого числа достаточно трех. Поэтому
Power Query отобразил это значение именно так.
При выделении одной ячейки с данными Power Query отображает ее содержимое в нижней левой части окна. Это бывает очень удобно, поскольку здесь
можно вывести текст большей длины, который даже можно выделять, что позволяет определить, например, есть ли в начале или конце строки пробелы.
Как видите, Power Query показывает нам здесь сырые данные, для которых
не определены типы. Давайте определим их сами и начнем с первых двух
столбцов:
 щелкните на иконке «ABC123» в заголовке столбца Precision и выберите
пункт Целое число (Whole Number);
 то же самое проделайте с колонкой Whole;
 выделите ячейку, которую выделяли ранее.
Заметили что-то новое? Правильно, число 9350,095 поменялось на 9350,
причем как в самой ячейке, так и в области предпросмотра данных в нижней
части окна, как видно на рис. 3.4.
Установив столбцам целочисленный тип, вы потеряли дробную часть значений в них. Если это как раз то, что вам нужно, прекрасно. Но если вы хотели сохранить десятичные знаки для правильности дальнейших агрегаций,
а тип приводили только для нужд форматирования, что ж, у вас проблемы,
поскольку часть чисел после запятой была благополучно утеряна.
88  Глава 3. Типы данных и ошибки
Рис. 3.4. Число было округлено до целого
Теперь давайте поработаем с типом столбца Currency:
 щелкните на иконке «ABC123» в заголовке столбца Currency и выберите
пункт Валюта (Currency) (в Power BI этот тип представлен как Fixed
Decimal Number);
 выделите ячейку в последней строке колонки.
Первое, что бросается в глаза, – это изменившийся формат значения в
колонке, хотя у вас он может выглядеть и не в точности так, как показано на
рис. 3.5. В результате изменения типа данных все числа были отформатированы под два знака после запятой.
Рис. 3.5. Валютный тип данных включает в себя особое форматирование
🍌 Примечание. Любопытно, что в более ранних версиях Power Query тип данных Валюта (Currency, Fixed Decimal) не обладал составляющей форматирования. Иными словами, значение 1603 в них было бы показано без десятичных знаков. Но под влиянием сообщества компания Microsoft снабдила
валютный тип данных форматированием в соответствии с настройками в
панели управления Windows.
В отношении этого типа данных стоит отметить интересную особенность –
если вы посмотрите в область предпросмотра в нижней части окна, то увидите, что значение из последней строки показано как 2951,8819, тогда как в
таблице выведено 2 951,88. При этом мы помним, что в источнике это число
выглядело так: 2951,881907. Таким образом, мы понимаем, что само значе-
Типы и форматы данных  89
ние при преобразовании в валютный тип было округлено до четырех знаков
после запятой.
🍌 Примечание. Несмотря на то что отображаются значения типа Валюта
(Currency) с двумя десятичными знаками, внутренне они округляются до четырех знаков. Если такое поведение кажется вам странным, вспомните обменные курсы иностранных валют, которые обычно содержат четыре знака
после запятой.
Последний тип данных, который мы здесь опишем, – это Десятичное число (Decimal). Применим его к последнему столбцу с именем Decimal:
 щелкните на иконке «ABC123» в заголовке столбца Decimal и выберите
пункт Десятичное число (Decimal);
 выделите ячейку в последней строке колонки.
Как видите, значения в колонке сохранили свою исходную точность – без
округлений и дополнительного форматирования. При этом замыкающие
нули в десятичной части чисел будут удалены, а останутся только значимые
числовые окончания. Это можно проверить, сравнив значения в ячейках с
областью предварительного просмотра в нижней части окна – они должны
полностью совпадать, как показано на рис. 3.6.
Рис. 3.6. Тип данных Десятичное число (Decimal) сохраняет все десятичные знаки чисел
Здесь важно еще раз отметить, что типы данных и форматирование – это
не одно и то же:
 форматирование определяет внешний вид значений и не влияет на
точность хранящихся чисел;
 тип данных отвечает за хранение значений и определяет точность чисел в соответствии с заданным типом.
Это главное различие между этими понятиями. Изменение типа данных
зачастую влияет на значения, хранящиеся в памяти, тогда как форматирование – никогда.
90  Глава 3. Типы данных и ошибки
Как устанавливать формат данных в Power Query?
Если говорить коротко, то никак.
В войне между типами и форматами данных редактор Power Query целиком и полностью на стороне первых. Почему? Да потому, что никто не будет
исследовать ваши данные в редакторе Power Query. Этот инструмент создан
для получения правильных данных, а не их представления. В конечном же
счете мы выгружаем преобразованные данные в одно из двух мест:
 Excel: на рабочий лист или в модель данных Power Pivot;
 Power BI: в модель данных.
🍌 Примечание. Не забывайте, что в этой книге мы в основном ориентируемся
на Excel и Power BI. Если вы используете Power Query совместно с другим
продуктом Microsoft, у вас могут быть свои места назначения для преобразованных данных.
Форматирование применяется на этапе представления данных. Оно может
быть реализовано:
 в ячейках рабочих листов Excel. Вне зависимости от того, куда загружены данные – на лист или в сводную таблицу, – если они представлены в
Excel, вы можете применять к ним правила форматирования;
 в определениях мер (measure), если данные загружены в модель: в
Excel это можно контролировать путем задания числовых форматов по умолчанию при создании мер, а в Power BI необходимо выбрать меру и установить для нее формат на вкладке Моделирование
(Modeling);
 на диаграммах и визуальных элементах: в Excel вы можете управлять
правилами форматирования при выводе данных в виде диаграмм, и
то же самое можно делать в Power BI при создании визуальных элементов.
Порядок шагов имеет значение
Поскольку изменение типа данных напрямую влияет на точность хранящихся значений, необходимо понимать важность последовательности применяемых шагов Измененный тип (Changed Type). Для демонстрации этого
выполните следующие действия:
 убедитесь, что на панели примененных шагов у вас выделен шаг Изме­
ненный тип (Changed Type);
 нажмите на иконку «123» в заголовке столбца Whole и выберите тип
данных Десятичное число (Decimal);
 в появившемся диалоговом окне выберите вариант Добавить шаг (Add
new step), а не Заменить текущее (Replace current).
Типы и форматы данных  91
🙈 Предупреждение. Мы хотим, чтобы вы поняли, насколько важен порядок
применения шагов в Power Query, и вы должны всегда внимательно проверять последовательность шагов с изменением типов данных, применяемых
при импорте данных автоматически. Не забывайте, что по умолчанию Power
Query принимает решение о применяемых типах данных на основании лишь
первой тысячи строк в данных, и если первое десятичное значение в столбце
появится только в 1001-й строке, Power Query применит целочисленный тип
данных, округлив до целого все значения в столбце. И даже если в следующих шагах вы попытаетесь восстановить нужный вам тип данных, утраченная дробная часть не вернется!
🍌 Примечание. Вам может стать интересно, почему Power Query не заменяет
предыдущий шаг с изменением типов данных без спроса. Дело в том, что
существуют типы данных, которые необходимо преобразовывать в промежуточный вид, перед тем как приводить к нужному формату. Представьте, что
вы конвертируете данные о датах и времени, представленные в текстовом
виде, в тип, хранящий только даты. Вы не сможете преобразовать значение
вида 2012-12-23 12:05 PM в дату без предварительного приведения к типу
данных, хранящему дату и время.
Рис. 3.7. Что произойдет с дробной частью значений при изменении
типа данных столбца Whole на Десятичное число (Decimal)?
Обычно при применении типов данных к столбцам Power Query молча
выполняет данное вами указание. Однако в случаях, когда у вас выделен шаг
Измененный тип (Changed Type) и вы пытаетесь изменить тип данных колонки, к которой уже применено аналогичное действие, Power Query попросит
вас сделать выбор: изменить настройки текущего шага или добавить новый.
Сделанный вами выбор может напрямую повлиять на результат.
При добавлении нового шага сначала будет выполняться существующий
шаг Измененный тип (Changed Type), после чего к получившимся в результате
значениям столбца будет применен новый тип данных. В нашем примере
мы первоначально применили к столбцу Whole целочисленный тип данных,
фактически избавившись от дробной части значений. После этого мы попытались изменить тип данных этой колонки на десятичное число. Но проб-
92  Глава 3. Типы данных и ошибки
лема в том, что дробных частей у значений уже нет, они были уничтожены
на предыдущем шаге в процессе округления.
Если бы мы выбрали вариант Заменить текущее (Replace current) вместо
Добавить шаг (Add new step), результат был бы совершенно иным. Power
Query не стал бы добавлять новый шаг с изменением типа данных, а изменил
бы существующий, и в итоге дробная часть значений была бы сохранена.
Важность определения типов данных
Поскольку вам все равно придется форматировать данные в Excel или
Power BI, да еще и неправильный выбор типов данных может привести к нарушению точности данных, может, лучше вообще отказаться от установки
типов данных в Power Query?
Ответ однозначный – нет!
Первая причина необходимости устанавливать типы данных в Power Query
состоит в том, что все функции Power Query требуют на вход данные определенного типа, и здесь, в отличие от Excel, не производится неявное приведение типов. Если данные в вашем столбце приведены к числовому типу, а
команда, которую вы хотите применить, требует на вход текстовую информацию, вы получите ошибку.
Вторая причина проистекает из того, что Power Query будет вынужден произвести попытку преобразования данных с неопределенным типом «any»,
который характеризуется иконкой «ABC123», к наиболее подходящему, с
его точки зрения, типу. И хотя иногда это у него будет получаться отлично,
в целом очень опасно производить загрузку данных на рабочий лист или в
модель данных с не определенными явным образом типами данных. Почему? Посмотрите на рис. 3.8, на котором показано, что может происходить с
данными неопределенного типа при загрузке в разные места назначения.
Рис. 3.8. Данные могут быть интерпретированы по-разному
в зависимости от места назначения загрузки
Как видите, в данных, представленных в Power Query, тип не определен,
о чем свидетельствует иконка «ABC123», но при этом значения выглядят
как даты. Они даже выделены курсивом, что может намекать на то, что это
действительно даты.
Что происходит при загрузке данных на рабочий лист Excel? В условиях
полной неопределенности Power Query сделал попытку определить, что же
Распространенные ошибки в Power Query  93
от этих данных нам нужно, и в результате вернул порядковые номера дат в
виде целых чисел.
Здесь и заключается опасность! Место назначения загрузки указывает на
модель данных (изначально или при помощи изменения запроса). Вывод
выглядит прекрасно, не так ли? Проблема лишь в том, что значения в Excel
выровнены по левому краю, – и это указывает на то, что на самом деле это
никакие не даты, а обычный текст! И действительно, если проверить модель
данных, несложно заметить, что данные были загружены в виде текста.
🍌 Примечание. Power BI также не является исключением из правила. Для хранения информации в этом продукте используется модель данных, так что
значения неопределенного типа в нее будут загружены в виде текста, как и
в модель данных Excel.
Оставлять данные неопределенного типа в Power Query очень опасно.
К столбцам, помеченным типом any, будет применяться определенный формат, но это не значит, что для них будет определяться тип данных. Вне зависимости от используемой версии инструмента, это не то, что нам нужно.
И хуже того то, что при изменении места назначения запроса может измениться и вывод.
🍌 Примечание. Позже в этой книге вы познакомитесь с такими действиями, как
объединение и добавление таблиц. Эти операции позволяют комбинировать
информацию из различных наборов данных в одном столбце. И если данные
при этом будут разных типов, Power Query вернется к использованию неопределенного типа any.
🙈 Предупреждение. Но не отчаивайтесь! Просто заведите себе привычку по-
следним шагом в запросе для загрузки данных на рабочий лист или в модель
данных размещать установку типов данных!
Распространенные ошибки в Power Query
В Power Query выделяют два вида ошибок (error), которые проявляются поразному:
 ошибки на уровне шага (Step Level Error): эти ошибки, как ясно из названия, возникают на уровне шага, предотвращая выполнение как самого этого шага, так и всех последующих. Вы узнаете о возникновении
ошибки на уровне шага по тому, что ваш запрос перестанет загружаться;
94  Глава 3. Типы данных и ошибки
 ошибки значений (Value Error): ошибки такого рода возникают на уровне
ячейки. При этом запрос все равно загрузится, но значения с ошибками
будут заменены пустыми значениями в конечном источнике данных.
Чтобы лучше понять, как проявляются разные ошибки и как их исправлять,
откройте файл, располагающийся по адресу Ch03 Examples\Error Types.xlsx в
папке с сопроводительными материалами.
Вы увидите прекрасную табличку на рабочем листе, показанную на рис. 3.9,
и на данный момент никаких проблем вроде нет.
Рис. 3.9. Выходная таблица на основе запроса ErrorData
Пока все в порядке, но сейчас самое время вызвать пару ошибок. Перейдите на вкладку Данные (Data) и нажмите на кнопку Обновить все (Refresh
All).
Появится сообщение об ошибке, показанное на рис. 3.10, говорящее о невозможности обнаружить источник данных.
Рис. 3.10. Извините, но вы не можете обновить этот файл
Поскольку в результате возникновения ошибки файл не может быть загружен, мы понимаем, что имеем дело с ошибкой на уровне шага.
Ошибки на уровне шага
Две наиболее распространенные разновидности ошибок на уровне шага возникают, когда Power Query:
 не может найти источник данных;
 не может найти имя столбца.
Ошибки на уровне шага  95
Чтобы решить возникшую проблему, необходимо отредактировать запрос, найдя шаг, ставший причиной появления ошибки, и определив, с какой
именно проблемой мы имеем дело:
 перейдите на вкладку Данные (Data) и нажмите на кнопку Запросы и
подключения (Queries & Connections), чтобы открыть соответствующую панель;
 перейдите в режим редактирования запроса ErrorData.
🍌 Примечание. При отладке запросов всегда лучше нажимать на кнопку Об-
новить предварительный просмотр (Refresh Preview) на вкладке Главная
(Home) в редакторе Power Query, чтобы убедиться, что работаете не с кешированной версией запроса, в которой искомой ошибки может не быть.
Ошибки источников данных
По умолчанию при редактировании запросов будет выбран последний
шаг. В таких условиях очень хорошо проявляются ошибки на уровне шага –
при их наличии Power Query отобразит большой желтый блок с сообщением,
показанный на рис. 3.11, в области предварительного просмотра, на месте
данных.
Рис. 3.11. Хьюстон, у нас проблема, и она на уровне шага!
Об этом сообщении можно сказать следующее:
 начинается оно с указания конкретного типа ошибки (error type). В данном случае это тип DataSource.Error, указывающий на то, что Power
Query не может обнаружить источник данных;
 ниже находится область Сведения (Details) с указанием элемента, ставшего причиной ошибки. В нашем примере это полный путь к файлу;
 справа находится кнопка Перейти к ошибке (Go To Error), которая
отображается, если текущий шаг НЕ является источником ошибки.
В большинстве ситуаций нажатие на кнопку Перейти к ошибке приведет
к выделению шага, ставшего причиной проблемы. Но в нашем случае будет
открыт шаг Повышенные заголовки (Promoted Headers). А нажатие на кнопку
с шестеренкой в попытке настроить шаг приведет к появлению сообщения о
том, что присутствуют ошибки на более ранних шагах, что видно по рис. 3.12.
96  Глава 3. Типы данных и ошибки
Рис. 3.12. Настройка шага невозможна, если на предшествующих шагах
есть ошибки уровня шага
Вполне вероятно, что данный баг будет исправлен к тому времени, когда вы будете читать эту книгу. Но вам все равно будет полезно узнать, как
справляться с этой проблемой. А тут все просто – следуйте от шага к шагу,
пока не доберетесь до источника проблемы или первого шага в запросе, как
показано на рис. 3.13.
Рис. 3.13. В нашем примере ошибка возникла именно на первом шаге
Это достаточно распространенная ошибка, особенно когда вы делитесь
своими решениями в Power Query с коллегами, поскольку пути к источникам
часто бывают прописаны непосредственно в первом шаге. Пути к личным
папкам вроде Desktop и Downloads часто содержат имя пользователя компьютера, и даже сетевые диски на разных компьютерах в сети могут называться
по-разному. Фактически каждый завершенный (с пометкой Completed) файл
из загруженной вами папки с примерами будет содержать подобную ошибку,
поскольку ваши исходные данные будут храниться совсем не там, где наши.
Существует три способа обновления пути к файлам.
1. Щелкните по кнопке с изображением шестеренки справа от шага Источник (Source), или
Ошибки на уровне шага  97
2. Нажмите на кнопку Изменить параметры (Edit Settings) в сообщении
об ошибке, или
3. На вкладке Главная (Home) нажмите на кнопку Настройки источника
данных (Data Source Settings), выберите отсутствующий источник и
нажмите на кнопку Изменить источник (Change Source).
🍌 Примечание. Диалоговое окно Настройки источника данных (Data Source
Settings) можно открыть, и не заходя в редактор Power Query. В Excel пункт
Параметры источника данных располагается в нижней части списка в выпадающей кнопке Получить данные (Get Data) на вкладке Данные (Data).
В Power BI соответствующая кнопка находится в выпадающей кнопке Преобразование данных (Transform Data) на вкладке Главная (Home).
Вне зависимости от того, какой способ вы выберете, будет открыто окно для
изменения пути к файлу. Укажите правильный путь к файлу Ch03 Examples\
ErrorData.csv.
После этого вы должны увидеть, что окно предварительного просмотра
заполнится значениями.
🙈 Предупреждение. Тогда как первые два способа приведут к изменению пути
к источнику только для текущего запроса, последний позволит откорректировать все экземпляры источника, даже если они используются в нескольких
запросах. Несмотря на это, вам также придется нажать на кнопку Обновить
предварительный просмотр (Refresh Preview), чтобы редактор Power Query
определил, что вы изменили источник данных.
Ошибки вида «столбец X не найден»
Теперь давайте инициируем появление другой ошибки на уровне шага.
Для этого выполните следующие действия:
 выберите шаг Повышенные заголовки (Promoted Headers);
 дважды щелкните мышью по заголовку столбца Item Name и переименуйте его в Item;
 подтвердите, что хотите вставить новый шаг;
 выделите шаг Измененный тип (Changed Type).
После этого в окне предварительного просмотра исчезнут данные и появится сообщение об ошибке, показанное на рис. 3.14. Это ошибка на уровне
шага, из-за которой данные не могут быть загружены. Но на этот раз причина
ошибки будет в другом.
98  Глава 3. Типы данных и ошибки
Рис. 3.14. Ошибка типа Expression.Error, говорящая об отсутствии столбца
Эта ошибка встречается даже чаще, чем неправильное написание пути
к источнику данных. Вне зависимости от того, чем она была вызвана, она
указывает на наличие в формуле имени столбца, отсутствующего на предыдущем шаге запроса. В данном случае Power Query пытается установить тип
данных для столбца с именем Item Name, но не находит его, поскольку ранее
мы его переименовали.
Хотя эта ошибка может встречаться в совершенно разных местах, чаще
всего она появляется именно на шаге Измененный тип (Changed Type). Причина этого в том, что на данном шаге имена переименовываемых столбцов
указываются явно. И если впоследствии тем или иным способом один из
столбцов будет переименован или удален на более ранней стадии запроса, вы
будете получать подобную ошибку на всех последующих шагах, где формула
будет явным образом ссылаться на эту колонку.
Как же исправить эту ошибку? Опять же, существует несколько способов:
 удалите шаг с изменением типов данных и создайте его заново, основываясь на актуальном списке столбцов;
 измените предыдущие шаги запроса таким образом, чтобы требуемый
столбец вновь появился;
 удалите шаг запроса, ставший причиной отсутствия нужной колонки;
 вручную измените формулу шага, откорректировав название столбцов.
К окончанию чтения данной книги вы будете легко и просто править формулы шагов вручную, но пока мы выберем более легкий вариант. Мы намеренно вставили шаг, чтобы сломать наш запрос, так что давайте от него
избавимся:
 щелкните по крестику слева от имени шага Переименованные столбцы
(Renamed Columns), чтобы удалить его;
 вновь выделите шаг Измененный тип (Changed Type), чтобы убедиться,
что данные вернулись в окно предварительного просмотра, как показано на рис. 3.15.
Ошибки значений  99
Рис. 3.15. И снова все в порядке!
🍌 Примечание. В подавляющем большинстве случаев можно безопасно уда-
лить шаг Измененный тип (Changed Type), приводящий к возникновению подобной ошибки. Спросите себя, действительно ли вам нужно наличие шага
по изменению типов данных в середине запроса или достаточно добавить
его в конце списка.
Ошибки значений
Хотя ошибки на уровне шага встречаются в Power Query повсеместно, это
не единственный тип проблем, с которыми вы можете столкнуться. Другим
распространенным видом ошибок являются ошибки значений (Value error),
и они зачастую могут быть более опасными по причине своей меньшей очевидности.
Ошибки значений чаще всего появляются в двух сценариях:
 при неправильном преобразовании типов данных;
 при выполнении операций с несовместимыми типами данных.
Давайте посмотрим, как легко можно инициировать подобные ошибки.
Обнаружение ошибок
Если взглянуть на столбец Units Sold в нашем примере и на рис. 3.16, можно
заметить, что с ним не все в порядке.
В данном случае мы отчетливо видим, что ошибочные значения содержатся в нашей колонке в строках со второй по четвертую, но в реальности
ошибки далеко не всегда будут видны в окне предварительного просмотра.
Так как же нам определить, что в столбце возникли проблемы?
Если вы работаете в Power BI или Microsoft 365, вы это сразу заметите по
красной линии непосредственно под наименованием столбца, за которой
следует линия в полоску. Это явный индикатор того, что со столбцом не все
в порядке.
100  Глава 3. Типы данных и ошибки
Рис. 3.16. Похоже, в столбце Units Sold есть какие-то ошибки
Если вы хотите узнать подробности, можете установить следующие три
флажка на вкладке Просмотр (View):
 качество столбца (Column Quality);
 распределение столбцов (Column Distribution);
 профиль столбца (Column Profile).
Это позволит отобразить под заголовками столбцов базовые статистические показатели по ним, включая графики, как показано на рис. 3.17, и это
облегчит оценку их качества.
Рис. 3.17. Индикаторы качества столбцов
Флажок качество столбца (Column Quality) отвечает за три цветовых индикатора, а распределение столбцов (Column Distribution) – за график распределения, отражающий количество отдельных (distinct) и уникальных (unique)
значений в столбце. Флажок профиль столбца (Column Profile) позволяет отобразить детализированную информацию о столбце в нижней части экрана
при его выделении.
Ошибки значений  101
🍌 Примечание. Если вы посмотрите на строку состояния в нижней части окна
Power Query, то увидите такую фразу: «Профилирование столбца на основе
первых строк (1000)» (Column profiling based on top 1000 rows). Это не так
очевидно, но по этой фразе можно щелкнуть мышью и установить профилирование на основе всего набора данных, а не только первой тысячи строк.
Вы могли заметить, что для столбца Units Sold выводится не вся статистика
и графики. Причина в наличии ошибок в столбце. Как только мы их исправим, статистические сведения примут такой же вид, как и в других колонках.
🍌 Примечание. Поскольку статистика занимает дополнительное место на
экране, мы обычно работаем с отключенными флажками качества и распределения столбцов, но флажок с профилем столбца держим включенным.
Это позволяет легко и быстро посмотреть дополнительную информацию по
столбцу при его выделении, а в остальное время все свободное пространство в окне предварительного просмотра занимают данные.
🙈 Предупреждение. Эти возможности были реализованы в Microsoft 365 уже
после выхода Excel 2019 и не присутствуют в этой и более ранних версиях
продукта. В отсутствие этих визуальных индикаторов вы можете опуститься
в нижнюю часть таблицы, чтобы проверить ее на наличие ошибок.
Ошибки из-за неправильного приведения типов
Теперь, когда мы знаем, что в нашем столбце есть как минимум одна ошибка, что необходимо сделать, чтобы повлиять на причину ее возникновения?
Для начала выделите ячейку с ошибочным значением и ознакомьтесь с
текстом ошибки, который отобразится в окне предварительного просмотра.
При этом необходимо понимать, что место щелчка мышью имеет большое
значение:
 если щелкнуть по самому слову Error в ячейке, Power Query создаст
новый шаг в запросе и перейдет к ошибке. Хотя в этом случае вы будете видеть описание ошибки, это вас вряд ли устроит, поскольку все
остальные данные в окне предварительного просмотра исчезнут;
 если же щелкнуть по свободному месту в ячейке рядом со словом Error,
Power Query отобразит описание ошибки под областью предварительного просмотра. Преимущество такого способа состоит в том, что вы не
утратите контекст всего запроса и не получите дополнительные шаги
после решения проблемы.
102  Глава 3. Типы данных и ошибки
Давайте посмотрим, что стало причиной возникновения ошибки в нашем
случае. Для этого щелкните на пустом пространстве рядом с первым словом
Error в столбце Units Sold, как показано на рис. 3.18.
Рис. 3.18. Щелкните справа от слова Error, чтобы отобразить панель с результатами
🍌 Примечание. Если вы случайно щелкнули по самому слову Error, тем самым
добавив новый шаг в запрос, просто удалите его, чтобы вернуться к окну
предварительного просмотра данных.
Вы увидите, что в нижней части окна предпросмотра появится желтая
панель с указанием типа ошибки: DataFormat.Error. Такая терминология может сбивать с толку, поскольку возникшая ошибка не имеет ничего общего
с форматом данных, а говорит о том, что значения в указанных ячейках несовместимы с выбранным типом данных.
При выполнении шага Измененный тип (Changed Type) Power Query делает
попытку преобразования значений в ячейках колонки к выбранному типу в
соответствии с определением форматов для указанного типа в региональных
настройках Windows (Windows Regional Settings). И если сделать ему это не
удается, появляется ошибка о невозможности преобразования типов. Стоит
отметить, что при приведении данных к текстовому типу (Text) такая ошибка
обычно не возникает, тогда как преобразование из текста в любой другой тип
зачастую ведет к описанной проблеме.
Если вы посмотрите на заголовок столбца, то заметите, что для него установлен тип данных Целое число (Whole Number), что характеризуется иконкой «123», но ошибка возникла из-за того, что в ячейке оказалось неопределенное значение N/A. Значение N/A не может быть представлено в виде
целого числа, и поэтому Power Query генерирует ошибку.
Что ж, теперь мы знаем причину возникновения проблемы. И что делать?
Как и всегда при работе с Power Query, у нас есть несколько вариантов:
 добавить новый шаг перед шагом Измененный тип (Changed Type) с
заменой значений N/A на 0;
 добавить новый шаг перед шагом Измененный тип (Changed Type) с
заменой значений N/A на ключевое слово null;
Ошибки значений  103
 щелкнуть правой кнопкой мыши по заголовку столбца Units Sold, выбрать пункт меню Заменить ошибки (Replace Errors) и указать значение 0;
 выделить столбец Units Sold и на вкладке Главная (Home) в выпадающей кнопке Удалить строки (Remove Rows) выбрать пункт Удалить
ошибки (Remove Errors);
 выделить все столбцы и на вкладке Главная (Home) в выпадающей
кнопке Удалить строки (Remove Rows) выбрать пункт Удалить ошибки (Remove Errors).
🙈 Предупреждение. Перед тем как удалять строки, мы настоятельно рекомен-
дуем пройтись по данным и убедиться в правильности такого метода. Наиболее безобидным из предложенных является вариант с заменой ошибок,
а самым кардинальным – способ с удалением строк с ошибками во всех
столбцах. Какой метод подойдет вам – зависит от конкретной задачи.
В нашем случае все ошибки, похоже, вызваны наличием значения N/A в
поле Units Sold, и это, судя по содержимому других столбцов, внутренние
инструкции для кухни. Вероятно, мы можем просто удалить эти строки. Но
давайте сделаем это наиболее консервативным способом, чтобы не потерять
данные, которые в будущем могут нам понадобиться. Для этого выделите
столбец Units Sold, после чего на вкладке Главная (Home) в выпадающей
кнопке Удалить строки (Remove Rows) выберите пункт Удалить ошибки
(Remove Errors).
В результате мы получим чистенькую таблицу без ошибок, как показано
на рис. 3.19.
Рис. 3.19. Все ошибки были удалены из нашего набора данных
Ошибки по причине несовместимости типов данных
Чтобы продемонстрировать проблему, причиной которой является несовместимость типов данных, давайте создадим новый столбец, в котором
произведем увеличение значений из колонки Units Sold:
104  Глава 3. Типы данных и ошибки
 измените тип данных столбца Units Sold на Текст (Text);
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 введите следующую формулу для столбца: [Units Sold] * 10;
 нажмите на кнопку OK.
В результате мы получим новый столбец со сплошными ошибками, как
показано на рис. 3.20.
Рис. 3.20. Power Query не понравилась эта формула
На панели с результатами выводится сообщение об ошибке типа Expression.
Error, вызванной неправильным применением математических операторов.
В сообщении говорится о том, что нельзя применять подобные операторы к
столбцам текстового и числового типов. И если Excel закрыл бы на это глаза,
неявным образом преобразовав текстовые значения из столбца Units Sold
в числовой вид перед умножением на десять, Power Query показывает себя
более категоричным и отвечает: «Нет, вы не можете этого сделать!»
🍌 Примечание. К сожалению, по содержанию сообщения не совсем понятно,
слева или справа от математического оператора находится текстовое значение. Чтобы понять это, потребуется более внимательно рассмотреть формулу
на шаге Добавлен пользовательский объект (Added Custom) и проверить
типы данных участвующих в вычислении столбцов.
Хотя эту ошибку можно исправить в самой формуле, мы оставим этот
подход для более поздних глав данной книги. А сейчас просто сделайте следующее:
 удалите шаг Добавлен пользовательский объект (Added Custom);
 удалите шаг Измененный тип1 (Changed Type1).
Окно предварительного просмотра должно заполниться чистыми данными без ошибок.
Проверка запросов на ошибки  105
Проверка запросов на ошибки
Мы уже рассмотрели некоторые разновидности ошибок на уровне шага и
ошибок значений. Теперь можно перезагрузить данные. Для этого нажмите
на кнопку Закрыть и загрузить (Close & Load) (в Power BI эта кнопка называется Закрыть и применить (Close & Apply)).
Данные должны загрузиться, но… мы получили уведомление о 4572 загруженных строках и 345 ошибках, что видно по рис. 3.21.
Рис. 3.21. Постойте… А разве мы не исправили все эти ошибки?
Обнаружение источника ошибок
В зависимости от цветовой схемы, которую вы используете в Excel, может
быть не всегда заметно, что информация об ошибках в этом сообщении выделена другим цветом по сравнению с загруженными строками. Причина
этого проста – это ссылка. Щелкните по ней. Это вернет вас в редактор Power
Query, в котором появился новый запрос с именем Ошибки в <ваш запрос>
(Errors in <your query>).
Опуская подробную механику создания этого вспомогательного запроса,
скажем лишь, что он берет ваш исходный запрос, добавляет к нему порядковые номера строк, после чего фильтрует его таким образом, чтобы остались
только строки с ошибками. На рис. 3.22 видно, что ошибки в строках импортированного файла начинаются со строки 3882. И этим объясняется, почему
мы не видели их до загрузки.
Рис. 3.22. Вот он – источник наших проблем!
106  Глава 3. Типы данных и ошибки
В попытке сберечь драгоценные ресурсы вашего компьютера Power Query
ограничивает количество строк в окне предварительного просмотра и позволяет вам строить запросы только на основании имеющихся данных. А уже
во время загрузки данных Power Query применяет созданные шаги ко всем
данным в источнике. Такой подход позволяет избежать чересчур объемных
предварительных загрузок. И это очень важно, ведь с помощью Power Query вы
можете подключаться к огромным объемам данных. А если их все пришлось бы
перед очисткой загружать на локальный компьютер, было бы очень грустно.
Как видите, недостатки этой концепции проявляются при наличии различий в шаблоне данных, входящих и не входящих в область предварительного
просмотра. Если в случае с ошибками в столбце Units Sold мы были сразу об
этом уведомлены, то в колонке POS Hour ошибочные значения начали появляться только начиная с 3882-й строки, и мы не могли их обнаружить вплоть
до момента загрузки.
Внимательно изучив сообщение об ошибке, мы можем понять, что проблема заключается в том, что в какой-то момент времени мы перешли от
целочисленного вида значений в поле POS Hour на значения в формате 21:00.
Power Query справился бы с приведением этих значений к формату времени,
но к целочисленному виду он их привести не сумел из-за наличия двоеточия.
Теперь, когда мы знаем причину проблемы, мы можем исправить ее, несмотря на то что не видим всех данных в области предварительного просмотра.
Исправление исходного запроса
Чтобы исправить исходный запрос, необходимо открыть его и присмотреться к примененным в рамках него шагам. Для этого нужно:
 открыть панель навигатора;
 выделить запрос ErrorData.
После этого вы можете внимательно рассмотреть примененные шаги в
соответствующей панели. Но как же нам обнаружить проблему? Давайте подумаем вместе:
 нам не хочется просто удалять строки. В отличие от строк со служебной
информацией в предыдущем примере, в данном случае речь идет о
строках с продажами, которые нам необходимо сохранить;
 мы знаем, что новые значения могут содержать данные в формате
21:00, тогда как до этого данные представляли собой целые числа от 8
до 20. Но мы не знаем, какие значения стоят за 21:00. Происходит ли
там возврат к 22 или используется формат 22:00?
 ошибка, скорее всего, возникает на шаге Измененный тип (Changed
Type).
Что, если перед применением шага Измененный тип (Changed Type) отсекать строку «:00»? Это должно сработать, давайте попробуем:
Проверка запросов на ошибки  107
 выделите шаг Повышенные заголовки (Promoted Headers);
 щелкните правой кнопкой мыши на заголовке столбца POS Hour и выберите пункт Замена значений… (Replace Values…). В открывшемся
диалоговом окне нажмите на кнопку Вставить (Insert);
 в поле Значение для поиска (Value to Find) введите :00;
 поле Заменить на (Replace With) оставьте пустым;
 нажмите на кнопку OK.
🍌 Примечание. Проблема такого подхода к исправлению запроса заключается
в том, что вы не видите результат в окне предварительного просмотра. Если
вас это беспокоит, вы всегда можете временно удалить верхние строки в запросе, чтобы видеть эффект производимого действия. В нашем случае нам
необходимо было бы удалить 3880 строк, чтобы первая ошибка проявилась
во второй из оставшихся строк. Но не забудьте удалить этот временный шаг
по окончании работы с запросом.
Здесь нам важно убедиться, что наши изменения сработали. Для этого
мы можем просто повторно загрузить данные и убедиться, что ошибка исчезла. На вкладке Главная (Home) нажмите на кнопку Закрыть и загрузить
(Close & Load) для Excel или Закрыть и применить (Close & Apply) для
Power BI.
🍌 Примечание. Вы могли бы вернуться к запросу с ошибками и обновить окно
предварительного просмотра. Но вам придется ждать, когда загрузятся данные, так почему бы не загрузить его одновременно в конечное место назначения?
Рис. 3.23. Ура! Больше никаких ошибок!
По результатам операции, показанной на рис. 3.23, мы можем сделать пару
наблюдений.
108  Глава 3. Типы данных и ошибки
1. Мы успешно исправили ошибки.
2. Запрос с ошибками по умолчанию был создан в виде только подключения (Connection Only).
Со вторым пунктом нам повезло, поскольку нам не хотелось бы загружать
все строки с ошибками на отдельный рабочий лист.
🍌 Примечание. Помните, что каждое действие по очистке данных уникально и
требует хорошего понимания шаблона данных. К примеру, если в какой-то
строке в нашем примере вместо 22:00 появится значение 22:01, наши шаги
по исправлению ошибок не сработают. В этом случае нам придется придумывать новый способ.
Удаление запроса с ошибками
После избавления от проблем нет смысла продолжать хранить запрос с
ошибками. Если возникнут новые неприятности, мы сможем щелкнуть по
количеству ошибок и тем самым создать новый вспомогательный запрос.
Избавиться от запроса с ошибками можно как на панели Запросы и подключения (Queries & Connections) в Excel, так и на панели навигатора непосредственно в редакторе Power Query. Для этого можно выделить запрос и
нажать на клавишу Delete или щелкнуть по запросу правой кнопкой мыши
и выбрать пункт Удалить (Delete).
Заключительные мысли о типах данных
и ошибках
В этой главе мы начали говорить о представленных в Power Query типах
данных, а также о том, как обнаруживать, отслеживать и исправлять возникающие ошибки. Эти концепции очень важны не только в процессе отладки
запросов, но и для приобретения уверенности в применении новых техник,
которые мы будем показывать на протяжении всей книги. Но это лишь базовые знания. Впереди еще очень много нового, начиная от работы с датами и
валютами и заканчивая намеренным вызовом ошибок с целью выполнения
фильтрации…
Глава
4
Перенос запросов
между Excel и Power BI
Не важно, сколько времени вы уделяете планированию, в тот или иной момент вы поймете, что вам необходимо скопировать свои запросы в другое
решение. Вам может понадобиться перенести запросы между двумя рабочими книгами, из Excel в Power BI и даже из Power BI в Excel. В данной главе
мы рассмотрим шаги, необходимые для перемещения запросов из одних
сценариев в другие. И хотя в книге мы в основном говорим об Excel и Power
BI, приведенные здесь шаги будут идентичными практически для любого
решения Power Query в рамках большого разнообразия продуктов Microsoft.
Перенос запросов между решениями
Для демонстрации копирования запросов Power Query между решениями
начнем с цепочки запросов, построенной в Excel с использованием структуры, показанной на рис. 4.1.
Сырые
данные
(Raw Data)
Data.CSV
Подготовка
(Staging)
Продажи
(Sales)
Таблица
рабочего
листа
Рис. 4.1. Последовательность запросов в файле Simple Query Chain.xlsx
Прежде чем погрузиться в это решение, необходимо убедиться в том, что
мы ссылаемся на нужный нам источник данных. Это позволит нам избежать
ошибок на уровне шага, связанных с источником, при рассмотрении различных вариантов переноса запросов между решениями.
Чтобы обновить файл, выполните следующие действия:
 откройте рабочую книгу Ch04 Examples\Simple Query Chain.xlsx в Excel;
 отобразите панель Запросы и подключения (Queries & Connections);
110  Глава 4. Перенос запросов между Excel и Power BI
 перейдите в режим редактирования запроса Raw Data;
 на вкладке Главная (Home) нажмите на кнопку Настройки источника
данных (Data Source Settings);
 выберите путь к файлу Ch01 Example Files\Basic Import.csv;
 закройте диалоговое окно Настройки источника данных;
 на вкладке Главная (Home) нажмите на кнопку Закрыть и загрузить
(Close & Load);
 сохраните рабочую книгу.
🍌 Примечание. Обычно вам не придется выполнять приведенные выше шаги,
поскольку в большинстве случаев вы будете создавать запросы на локальном компьютере с прямым доступом к источнику данных. Однако если вы
откроете чужой сценарий или решение, источник данных для которого изменил свое местоположение, лучше будет сразу указать правильный путь к
актуальному источнику перед копированием запросов в другой проект.
Перенос запросов Excel в новую рабочую книгу
Начнем с самого простого решения – копирования запросов из одной рабочей книги Excel в другую.
Первое, что вам необходимо сделать, – это убедиться в том, что панель
Запросы и подключения (Queries & Connections) активна. Именно здесь
вы увидите список запросов, с которыми вам предстоит работать. Осталось
выбрать запросы, которые вы желаете перенести в другой файл.
Панель Запросы и подключения поддерживает полный функционал
взаимодействия с объектами при помощи мыши. Так что вам доступны все
перечисленные действия:
 выбор одного запроса мышью;
 выбор последовательности запросов путем выделения первого и последнего запросов в диапазоне с зажатой клавишей SHIFT;
 выборочное выделение запросов при помощи клавиши CTRL.
🍌 Примечание. Единственная опция, которая не поддерживается на панели
Запросы и подключения, – это сочетание клавиш CTRL+A для выделения
всех запросов.
Хотя запросы можно выделять выборочно, что произойдет, если перед запросом, который вы отметили, останутся не выделенные вами запросы (по
забывчивости или по причине незнания)? Давайте посмотрим:
 щелкните правой кнопкой мыши по запросу Sales и выберите пункт
Копировать (Copy) или выделите запрос и нажмите сочетание клавиш
CTRL+C;
Перенос запросов между решениями  111
 откройте в Excel вкладку Главная (File), нажмите на кнопку Создать
(New) и выберите вариант Пустая книга (Blank Workbook).
В новой рабочей книге сделайте следующее:
 перейдите на вкладку Данные (Data) и нажмите на кнопку Запросы и
подключения (Queries & Connections);
 щелкните правой кнопкой мыши по пустой области на открывшейся
панели и выберите пункт Вставить (Paste) или перейдите на панель и
нажмите сочетание клавиш CTRL+V.
Обратите внимание, что Power Query вставил на панель не только тот запрос, который вы копировали, но и все предшествующие в цепочке запросы.
Вы также могли заметить, что для созданных запросов было установлено
правильное место назначения, как видно по рис. 4.2.
Рис. 4.2. Копирование запроса Sales в новую рабочую книгу Excel
🍌 Примечание. Это очень полезная особенность механизма переноса запросов, позволяющая вам не забыть скопировать важные составляющие цепочки.
При переносе целой цепочки запросов в новую книгу или в книгу, не содержащую части этой цепочки, все работает отлично. Но что будет, если
фрагменты копируемой цепочки уже содержатся в месте назначения? Например, сейчас у нас в книге есть запросы Raw Data и Staging. Что будет, если
мы вернемся в первую книгу, снова скопируем запрос Sales и вставим его в
нашу книгу? Вероятно, будет создан новый запрос Sales, указывающий на
существующие запросы Raw Data и Staging, не так ли? Проверим:
112  Глава 4. Перенос запросов между Excel и Power BI




вернитесь в первоначальную рабочую книгу;
скопируйте запрос Sales любым из перечисленных выше способов;
перейдите в нашу новую книгу;
вставьте скопированный запрос, щелкнув правой кнопкой мыши по
пустой области на панели Запросы и подключения и выбрав пункт
Вставить (Paste).
Как видите, вместо интеграции с существующими запросами Power Query
создал заново всю цепочку запросов, что показано на рис. 4.3, поскольку
запросы с такими именами уже присутствовали в рабочей книге, к именам
новых запросов была добавлена цифра 2 в скобках.
Рис. 4.3. Power Query заново создал всю цепочку запросов
Это может расстраивать, ведь нам бы хотелось иметь возможность самим
задать опции, которые позволили бы избежать конфликтов между запросами
при копировании и вставке. К сожалению, такого выбора у нас нет.
Если вам необходимо, чтобы новый запрос Sales (2) использовал данные,
полученные в результате запроса Staging, а не Staging (2), вы должны перенаправить его на нужный вам запрос самостоятельно. Для этого сделайте
следующее:
 перейдите в режим редактирования запроса Sales (2);
 выделите шаг Источник (Source);
 измените формулу в строке формул таким образом, чтобы запрос использовал результат выполнения запроса Staging. Формула должна обрести следующий вид: =Staging;
 закройте редактор Power Query и позвольте данным обновиться.
Теперь вы можете удалить запросы Raw Data (2) и Staging (2) (в обратном
порядке), поскольку они нам больше не нужны.
Перенос запросов между решениями  113
🍌 Примечание. Можно было просто скопировать исходный код запроса и
вставить его, как было описано выше. Но для этого придется воспользоваться расширенным редактором, о котором мы будем подробно говорить в
следующих главах книги.
Перенос запросов из Excel в Power BI
Теперь, когда вы знаете, как копировать запросы из одной рабочей книги
Excel в другую, давайте посмотрим, намного ли сложнее осуществлять перенос запросов между Excel и Power BI. Выполните следующие действия:
 удалите рабочую книгу, которую вы создали на предыдущем шаге;
 откройте Power BI;
 вернитесь в первоначальную рабочую книгу Excel.
Как вы увидите, перенос запросов из Excel в Power BI производится не
сложнее, чем из одной книги в другую. Сделайте следующее:
 скопируйте запрос Sales любым из перечисленных выше способов;
 вернитесь в Power BI;
 на вкладке Главная (Home) нажмите на кнопку Преобразование данных (Transform Data);
 щелкните правой кнопкой мыши по навигационной панели и выберите
пункт Вставить (Paste).
В результате, как и в Excel, будет создана цепочка из трех запросов, что
видно по рис. 4.4.
Рис. 4.4. Копирование запросов из Excel (слева) в Power BI (справа)
114  Глава 4. Перенос запросов между Excel и Power BI
Все, что осталось, – это нажать на кнопку Закрыть и применить (Close &
Apply), чтобы данные обновились.
🙈 Предупреждение. Если ваши запросы используют внешние источники данных, копирование таким образом сработает великолепно. Но если в качестве
источника используется таблица Excel, могут возникнуть проблемы, поскольку в Power BI нет рабочих листов. Это приведет к возникновению ошибки на
уровне шага по причине некорректного источника данных. При переносе в
Power BI решений, базирующихся на таблицах Excel, необходимо воспользоваться механизмом импорта запросов, о чем мы будем говорить далее.
Перенос запросов из Power BI в Excel
Вы уже начали привыкать к легкости, с которой решения, реализованные с
помощью Power Query, можно переносить между Excel и Power BI. А что, если
нам понадобится скопировать запросы в обратном направлении? Никаких
проблем! Для этого выполните следующие действия:
откройте проект Power BI;
перейдите к запросам;
скопируйте нужный вам запрос;
переключитесь в Excel и активируйте панель Запросы и подключения
(Queries & Connections);
 вставьте скопированный запрос.




Как видите, копировать запросы из Power BI в Excel не сложнее, чем в обратном направлении, при условии что вы не используете коннекторы, недоступные для Power Query в Excel.
В распоряжении Power BI есть намного больше коннекторов, чем у Excel
(многие из которых находятся на стадии тестирования). Кроме того, в отличие от Excel, Power BI поддерживает пользовательские коннекторы.
Что же будет, если вы попытаетесь скопировать в Excel решение, в котором применяется коннектор, которого нет в Excel? Вы получите ошибку
Expression.Error на уровне шага, подобную той, что показана на рис. 4.5.
Рис. 4.5. Пользовательский коннектор WooCommerce недоступен в Excel
🍌 Примечание. К сожалению, без добавления в Excel нужного коннектора со
стороны команды разработчиков Power Query или возможности использовать пользовательские коннекторы эту проблему не решить. Все решения,
построенные на базе таких коннекторов, будут работать только в Power BI.
Импорт запросов из Excel в Power BI  115
Перенос запросов из Power BI в новый проект Power BI
Копирование запросов из одного проекта Power BI в другой выполняется
очень легко. Для большинства пользователей, у которых в распоряжении
обычно есть только одна версия Power BI Desktop, перенос запросов из одного
проекта в другой будет происходить безболезненно.
🙈 Предупреждение. Если вы являетесь обладателем нескольких версий Power
BI (например, установленных из Windows Store, по прямой ссылке или в виде
сервера отчетов Power BI (Power BI Report server)), у вас могут возникнуть
проблемы при переносе запросов из более новых версий Power BI Desktop в
более старые. Обычно сложности возникают при использовании новых коннекторов или их обновленных версий. В этом случае вы почти наверняка
получите ошибку на уровне шага, говорящую о том, что параметр коннектора
не может быть применен.
Импорт запросов из Excel в Power BI
Хотя копирование и вставка запросов из Excel в Power BI, как мы уже видели,
прекрасно работают, у нас также есть возможность импортировать (import)
их. Когда стоит предпочесть один метод другому?
Давайте для начала сравним их при помощи табл. 4.1, в которой сведены
возможности двух упомянутых способов переноса запросов.
Таблица 4.1. Сравнение методов переноса запросов из Excel в Power BI
Копирование / Вставка
Импорт
Должна быть открыта
Должна быть закрыта
Копирование/импорт
специфических запросов
Да
Нет
Копирование/импорт всех
запросов
Да
Да
Импорт структуры модели данных
Нет
Да
Импорт мер
Нет
Да
Изменение подключения к
источникам в виде таблиц Excel
Нет
Да
Исходная рабочая книга Excel
Если вы не работаете с моделью данных Power Pivot в Excel, для вас самым
большим преимуществом импорта перед копированием будет возможность
автоматически адаптировать источники данных, ссылающиеся на таблицы
в исходной рабочей книге. Как мы уже говорили ранее, попытка перенести
такие запросы из Excel в Power BI при помощи копирования и вставки приведет к появлению ошибки на уровне шага из-за неспособности Power BI
116  Глава 4. Перенос запросов между Excel и Power BI
понять такой источник данных. В случае с импортом Power BI предоставит
вам возможность выбора коннектора для работы с такими таблицами.
Если вы используете модель данных в Excel, то сможете в полной мере
воспользоваться всеми преимуществами импорта перед копированием, такими как загрузка, помимо самих запросов, связей и мер, а также сортировка
иерархий.
В этом разделе мы рассмотрим три возможных сценария, чтобы продемонстрировать, как различные источники данных влияют на процесс
импорта.
Только внешние источники данных
Для начала посмотрим, что происходит, когда вы импортируете в Power BI
файл Excel, полагающийся только на внешний источник данных:
 откройте новый файл в Power BI Desktop;
 на вкладке Файл (File) перейдите в раздел Импортировать (Import) и
выберите пункт Power Query, Power Pivot, Power View;
 найдите и откройте файл Excel, из которого мы в предыдущих примерах копировали запросы: Ch04 Examples\Simple Query Chain.xlsx;
 в открывшемся окне нажмите на кнопку Запуск (Start).
После этого Power BI начнет процесс импорта данных из файла, по окончании которого вы увидите окно, похожее на то, что изображено на рис. 4.6.
Рис. 4.6. Файл Excel успешно загружен
Удивительно, что на этапе, когда кажется, что все уже позади, вам придется
сделать еще пару завершающих действий:
 закройте диалоговое окно кнопкой Закрыть (Close);
 нажмите на кнопку Применить изменения (Apply Changes) для загрузки данных, как показано на рис. 4.7.
Импорт запросов из Excel в Power BI  117
Рис. 4.7. Операция импорта не будет завершена, пока вы не нажмете
на кнопку Применить изменения (Apply Changes)
После этого ваши запросы будут запущены. Данные загрузятся в модель, и
вы сможете приступать к построению отчетов. Но постойте! А ничего этого
не произошло! Никакие таблицы созданы не были, несмотря на то что вы
нажали на кнопку Применить изменения. Что же пошло не так?
Дело в том, что Power BI не видит рабочие книги Excel в качестве допустимых отчетов. Хотя книги Excel могут содержать сводные таблицы и диаграммы, а также другую аналитику, построенную на основе результатов Power
Query, для Power BI это ничего не меняет. Любой запрос Excel, не загруженный в модель данных Power Pivot, будет импортирован в Power BI только в
виде подключения.
Чтобы исправить это, вам необходимо изменить настройку параметра загрузки запроса следующим образом:
 перейдите на вкладку Главная (Home) и нажмите на кнопку Преобразование данных (Transform Data);
 щелкните правой кнопкой мыши по запросу Sales и убедитесь, что
флажок Включить загрузку (Enable load) установлен, как показано на
рис. 4.8;
Рис. 4.8. Запросы, загруженные на рабочий лист,
оказываются с отключенной опцией загрузки
 нажмите на вкладке Главная (Home) на кнопку Закрыть и применить
(Close & Apply).
Теперь таблица со всеми ее данными будет загружена в модель, и вы сможете приступать к построению аналитических отчетов.
118  Глава 4. Перенос запросов между Excel и Power BI
Импорт модели данных Excel в Power BI
На этот раз мы импортируем решение, содержащее модель данных, а в
качестве источника использующее таблицы из текущей рабочей книги Excel.
Схема зависимостей книги Excel показана на рис. 4.9.
Рис. 4.9. Две таблицы Excel и 12 запросов свелись
к четырем таблицам в модели данных Excel
Хотя не имеет большого значения, как именно работают эти запросы, важно понимать, что две таблицы хранятся в «текущей рабочей книге», а это
означает, что данные и решение располагаются в одном и том же файле.
Вы также должны понимать, что структура Power Query в этом файле действует как слой ETL для модели данных Power Pivot, включающей в себя
четыре помеченные таблицы, четыре связи и две меры (Sales и Budget), как
показано на рис. 4.10.
Рис. 4.10. Модель данных, полученная из структуры Power Query
Импорт запросов из Excel в Power BI  119
Наконец, в файле есть рабочий лист с именем Report, содержащий сводную
диаграмму и срез на основе модели данных, как показано на рис. 4.11.
Рис. 4.11. Отчет, содержащийся в файле Simple Model.xlsx
Это довольно простое решение на основе Power Query и Power Pivot, демонстрирующее совместную работу двух этих инструментов. Если вы хотите
рассмотреть это решение более внимательно, то можете найти его в файле
Ch04 Examples\Simple Model.xlsx.
Предположим, вы получили в свое распоряжение такую модель данных и
решили перенести решение в Power BI. Перед вами встанет проблема, заключающаяся в том, что все данные, запросы, модель данных и отчеты находятся
в одном файле, и вы не знаете всей логики их формирования. Но вы можете
выбрать все запросы в файле Excel одновременно и скопировать их в новый
файл Power BI, как описывалось ранее в этой главе. И если запросы таким
образом перенесутся, то связи и меры – нет. В результате вам придется прописывать их вручную, что может быть довольно затруднительно.
Импорт данных на основе таблиц Excel – копирование
С учетом сложности модели данных, обсуждавшейся ранее, мы бы хотели
перенести ее из Excel в Power BI максимально просто.
Функция импортирования в Power BI предназначена как раз для подобных
сценариев, давайте посмотрим, как она работает:
 откройте новый экземпляр Power BI Desktop;
 на вкладке Файл (File) перейдите в раздел Импортировать (Import) и
выберите пункт Power Query, Power Pivot, Power View;
 найдите и откройте следующий файл Excel: Ch04 Examples\Simple Model.
xlsx.
🍌 Примечание. Любопытно, что в названии пункта, служащего для импорта
данных из Excel, даже нет упоминания этого продукта.
Powered by TCPDF (www.tcpdf.org)
120  Глава 4. Перенос запросов между Excel и Power BI
После нажатия на кнопку Запуск (Start) откроется диалоговое окно, показанное на рис. 4.12.
Рис. 4.12. Как бы вы хотели импортировать данные?
Давайте последуем выбору по умолчанию и нажмем на кнопку Копирование данных (Copy Data), после чего начнется импорт запросов и компонентов модели данных, как видно по рис. 4.13.
Рис. 4.13. Power BI успешно загрузил запросы, модель данных и меры
Пока все в порядке. Если перейти на вкладку Модель (Model) в левой части
окна Power BI Desktop, вы увидите, что вся структура модели, включая связи,
меры и даже статусы видимости полей, была импортирована корректно, что
показано на рис. 4.14.
Импорт запросов из Excel в Power BI  121
Рис. 4.14. Модель данных Excel была целиком импортирована в Power BI
Если переключиться на вкладку Отчет (Report), можно даже легко повторить диаграмму из Excel. Для этого:
 откройте вкладку Отчет (Report) в Power BI Desktop;
 на панели Визуализации (Visualizations) нажмите на кнопку Гистограмма с группировкой (Clustered Column Chart);
 на панели Поля (Fields) раскройте таблицу Sales и установите флажок
напротив меры Sales;
 на панели Поля (Fields) раскройте таблицу Budgets и установите флажок напротив меры Budget;
 также на этой панели раскройте таблицу Calendar и установите флажок
для поля Month Short, как показано на рис. 4.15.
Рис. 4.15. По рисунку это плохо заметно, но даты даже отсортированы
в правильном порядке!
122  Глава 4. Перенос запросов между Excel и Power BI
Все выглядит очень прилично! По крайней мере, пока мы не обновим отчет.
Рис. 4.16. Что здесь происходит?
🍌 Примечание. Если у вас таблица обновится без проблем, то вы увидите другое сообщение. Но мы рекомендуем вам дочитать этот раздел.
Для решения возникшей проблемы нам придется отредактировать запросы. Начнем с одного из запросов Raw Data и посмотрим, как Power BI
копирует таблицы Excel:
 перейдите на вкладку Главная (Home) и нажмите на кнопку Преобразование данных (Transform Data);
 выберите запрос Raw Data – Budgets.
Вы сразу заметите, что возникли какие-то проблемы, как показано на
рис. 4.17.
Рис. 4.17. Почему все даты отображаются с ошибкой?
Если вчитаться в сообщение об ошибке, можно понять, что проблема возникает при попытке представления значения 43131 в виде даты. Но откуда
взялось это число?
Импорт запросов из Excel в Power BI  123
Выделите шаг Источник (Source) и нажмите на кнопку с шестеренкой.
Откроется таблица, созданная Power BI в файле в результате копирования
данных из Excel. Любопытно, что в колонке с датами стоят вовсе не даты, а
загадочные числа, что видно по рис. 4.18.
Рис. 4.18. Откуда взялись эти цифры?
На этом этапе вы должны четко понимать три вещи.
1. Эта таблица целиком содержится в Power BI и должна обновляться
здесь, если вам необходимо внести какие-то изменения в источник
данных. Изменения, сделанные в файле Excel, НЕ перенесутся в этот
файл.
2. Все даты копируются в виде порядковых номеров (количества дней,
прошедших с 1 января 1900 года), а не в виде привычных нам дат.
3. Существует ограничение на то, сколько данных Power BI будет показывать вам на этом шаге. Если превысить его, Power BI не позволит
редактировать таблицу, а поскольку она создается с использованием
сжатого формата JSON, вы не сможете просто изменить формулу Power
Query для добавления значений.
Хотя последний пункт очень важен с точки зрения поддержания данных
в актуальном состоянии, это точно не наш случай. Это понятно по тому, что
на шаге Источник нет никаких ошибок в таблице данных.
После закрытия этого окна и возвращения к шагу Измененный тип (Changed
Type) мы видим, что ошибка, связанная с невозможностью представить числа в виде дат, никуда не исчезла. Давайте попробуем переопределить этот
шаг, чтобы можно было работать с датами:
 выделите столбец Date и щелкните по иконке с календарем в его заголовке;
 поменяйте тип данных на Целое число (Whole Number);
 нажмите на кнопку Заменить текущее (Replace) вместо добавления
нового шага.
В результате, как видно на рис. 4.19, ошибки исчезли, и столбец заполнился
целочисленными значениями, представляющими собой порядковые номера
дат.
124  Глава 4. Перенос запросов между Excel и Power BI
Рис. 4.19. Порядковые номера вместо дат
🍌 Примечание. Интересно, что красная полоса под заголовком столбца, гово-
рящая о наличии ошибок, никуда не делась. Вы можете либо проигнорировать ее, либо выбрать другой запрос и вновь вернуться к запросу Raw Data –
Budgets, чтобы полоса исчезла.
Итак, мы добились определенного прогресса, но не достаточного, поскольку нам хотелось бы видеть в столбце даты в привычном для нас виде. Однако
мы не можем просто взять и изменить тип данных – в этом случае ошибки
вернутся. Вместо этого нужно сделать следующее:
 выберите столбец с датами и установите тип данных Целое число
(Whole Number);
 теперь измените тип данных на Дата (Date);
 в открывшемся диалоговом окне нажмите на кнопку Добавить шаг
(Add new step) вместо замены.
В результате мы получим содержимое колонки в виде дат, как показано
на рис. 4.20.
Рис. 4.20. Даты в правильном формате
Помните, в предыдущей главе мы говорили о том, что после изменения
типа данных все последующие шаги базируются на этом выводе? И если
текстовые значения мы не могли напрямую преобразовать в даты, промежуточный перевод их в числа позволил это сделать.
Теперь нам нужно сделать то же самое применительно к запросу Raw
Data – Sales. Выполните следующие действия:
Импорт запросов из Excel в Power BI  125






выберите запрос Raw Data – Sales;
выделите колонку Date и щелкните по кнопке с календарем;
установите тип данных Целое число (Whole Number);
нажмите на кнопку Заменить текущее (Replace);
снова выделите колонку Date и поменяйте тип данных на Дата (Date);
в открывшемся диалоговом окне нажмите на кнопку Добавить шаг
(Add new step) вместо замены.
Теперь, когда мы расправились с нашими ошибками, можно загружать
данные. Для этого перейдите на вкладку Главная (Home) и нажмите на кнопку Закрыть и применить (Close & Apply). Данные будут загружены без проблем.
🙈 Предупреждение. Это известная проблема, свойственная механизму импор-
та данных из Excel в Power BI с конвертацией в формат JSON при наличии
столбцов с датами. Пока разработчики ее не исправят, вам придется при
загрузке данных в Power BI каждый раз проделывать подобные действия с
датами.
Несмотря на указанный баг, в целом этот метод импорта данных из Excel
в Power BI работает очень прилично. Кроме того, подобно Excel, в Power BI
загруженные данные также будут содержаться в едином файле, что облегчает процесс распространения информации друзьям и коллегам, которым не
нужно будет беспокоиться об обновлении путей к источнику данных.
🍌 Примечание. Дело в том, что такие таблицы никогда не предназначались для
использования в качестве баз данных, и они не только не могут превышать
определенного размера, но и для работы с ними отсутствуют эффективные
инструменты. Поэтому мы рекомендуем пользоваться ими с большой осторожностью. В конце концов, рекомендованной практикой является импортирование данных из внешних файлов, будь то рабочая книга Excel, база
данных или любой другой источник, а не хранение их в том же решении.
Однако этот способ импорта таит ряд потенциальных опасностей. Имейте в виду, что по завершении любые обновления, которые вам необходимо
внести в источник данных, потребуют редактирования запроса и обновления
шага Источник. Это может быть очень неудобным, так как вам придется не
только изменять и перемещаться по структуре запроса для редактирования
данных в источнике, но и ждать какое-то время, пока обновится предварительный просмотр. Но даже эти неудобства не столь критичны. По достижении вашей таблицей определенного размера Power BI просто запретит
вам выполнять какие бы то ни было изменения, а в ответ на ваши действия
будет демонстрировать сообщение о превышении ограничения на размер,
показанное на рис. 4.21.
126  Глава 4. Перенос запросов между Excel и Power BI
Рис. 4.21. Сообщение об ошибке
Таблицы Excel – сохранение подключения
В предыдущем разделе мы импортировали модель данных из Excel путем
копирования данных в файл, но это лишь один из двух возможных вариантов
выполнения этого действия. Также вы можете вместо копирования информации из Excel в Power BI создавать подключение к файлу Excel, в котором
хранятся данные.
Хотя этот способ сопряжен с риском того, что вам придется обновлять путь
к внешнему файлу, по крайней мере так вы сможете избежать ошибок, связанных с датами, и не столкнетесь с невозможностью добавлять строки или
редактировать записи в источнике. Данные будут оставаться в файле Excel,
а значит, все производимые изменения в источнике можно будет получать с
помощью обычного обновления.
Давайте повторим наш предыдущий сценарий, но на этот раз выберем
вариант с созданием подключения к файлу Excel вместо копирования. Шаги,
которые вам необходимо выполнить:
 откройте новый файл в Power BI Desktop;
 на вкладке Файл (File) перейдите в раздел Импортировать (Import) и
выберите пункт Power Query, Power Pivot, Power View;
 найдите и откройте файл Excel Ch04 Examples\Simple Model.xlsx;
 в открывшемся окне нажмите на кнопку Запуск (Start);
 нажмите на кнопку Сохранить подключение (Keep Connection).
🍌 Примечание. К сожалению, в диалоговом окне по умолчанию выделена
кнопка Копировать данные (Copy Data) в качестве рекомендованного выбора, но нам кажется, что гораздо лучше пользоваться именно опцией сохранения подключения.
В результате миграции Power BI, как и раньше, создаст модель данных,
связи и меры. И мы снова сможем легко и быстро создать столбчатую диаграмму на основе полученных данных:
 откройте вкладку Отчет (Report) в Power BI Desktop;
 на панели Визуализации (Visualizations) нажмите на кнопку Гистограмма с группировкой (Clustered Column Chart);
 на панели Поля (Fields) раскройте таблицу Sales и установите флажок
напротив меры Sales;
 на панели Поля (Fields) раскройте таблицу Budgets и установите флажок напротив меры Budget;
Импорт запросов из Excel в Power BI  127
 также на этой панели раскройте таблицу Calendar и установите флажок
для поля Month Short, как показано на рис. 4.22.
Рис. 4.22. Диаграмма выглядит очень знакомой!
В результате мы получили такое решение, как в предыдущем разделе, за
исключением того, что сами данные остались в файле Excel, а мы лишь импортируем их оттуда, а не копируем и не храним в файле Power BI. Теперь,
если файл Excel изменит свое местоположение, вам придется обновить источник данных при помощи редактирования запроса или путем нажатия на
кнопку Настройки источника данных (Data Source Settings) в редакторе
Power Query.
Одно существенное отличие в этом решении по сравнению с предыдущим
все же есть. В условиях необходимости обращения к файлу Excel Power BI
создал запрос, который обновляется без внесения изменений.
Рис. 4.23. Именно такого поведения мы ждали от нашей копии!
128  Глава 4. Перенос запросов между Excel и Power BI
Заключительные мысли о переносе запросов
между решениями
В данной главе вы познакомились со всеми самыми простыми способами
переноса запросов между Excel и Power BI. Основных правил здесь, пожалуй,
два:
 если вам нужны просто запросы или группы запросов без компонентов
моделей данных, ваш выбор – копирование и вставка;
 если же вы хотите перенести из Excel в Power BI все решение целиком,
лучше использовать импортирование, при этом желательно данные
оставить физически в файле Excel.
Единственный вариант, который мы не рассмотрели, касается переноса
запросов из Power BI обратно в Excel. К сожалению, по причине того, что
в Power BI используется более новая версия модели данных с поддержкой
возможностей, не реализованных в Excel, в компании Microsoft решили не
давать переносить запросы в Excel. Таким образом, на первый взгляд, единственным способом для переноса решения из Power BI в Excel является копирование и вставка запросов и воссоздание модели данных вручную.
Рис. 4.24. Импорт модели данных из Power BI в Excel при помощи Monkey Tools
Заключительные мысли о переносе запросов между решениями  129
Однако инструмент Кена под названием Monkey Tools все же позволяет
перенести модель данных из Power BI в Excel. Конечно, он не даст перенести
элементы, не поддерживаемые в Excel, но со структурой запросов, связями
типа «один ко многим» и мерами этот инструмент справляется отлично.
Кроме того, Monkey Tools выведет вам понятный список того, что перенести
не удалось. В общем, хотите ли вы перебросить из Power BI в Excel только запросы или модель данных целиком, Monkey Tools вам в этом поможет.
🍌 Примечание. Подробнее почитать об этой надстройке, а также скачать ее
бесплатную версию вы можете на сайте Кена по адресу https://xlguru.ca/
monkeytools.
Глава
5
Импортирование
из плоских файлов
Будучи специалистом по работе с данными, вы будете очень часто в своей
профессиональной деятельности сталкиваться с импортом, обработкой и
преобразованием исходных данных перед их использованием. Признаемся,
не у многих из нас есть доступ к базам данных с идеально структурированной и форматированной информацией. Так что данные нам чаще всего
достаются в виде неотформатированных должным образом текстовых или
CSV-файлов, которые необходимо преобразовать перед загрузкой в Excel
или Power BI. Таким образом, наше исходное сырье обычно представлено в
следующих видах:
 текстовые файлы с разделителями в виде символа;
 CSV-файлы с запятыми в качестве разделителей.
С такими данными во все времена приходилось немало повозиться, чтобы
привести их к виду, пригодному для анализа, но с появлением Power Query
все стало гораздо проще.
Понимание процесса импорта данных
Текстовые и CSV-файлы принято называть плоскими (flat file) из-за недостатка дополнительного слоя с метаданными, описывающими содержимое
файла. Для нас это критически важно, поскольку означает, что нам необходимо как-то интерпретировать исходные данные перед их непосредственной загрузкой в Excel или Power BI. Чтобы научиться мастерски обращаться
с данными при помощи Power Query, нужно четко понимать, как процесс
импорта выглядит изначально и как (и когда) нам необходимо вмешиваться
в ситуацию, чтобы привести данные в порядок.
🍌 Примечание. Хотя перечень плоских файлов не ограничивается текстовыми
и CSV-файлами, они являются наиболее популярными. Фактически любой
файл, представляющий исходные данные в виде одного «листа», можно назвать плоским.
132  Глава 5. Импортирование из плоских файлов
Определение системных настроек
Первое, что вам необходимо понять, – это то, что вывод, который мы получаем в процессе импорта из плоского файла, напрямую зависит от параметров, установленных в панели управления Windows. Чтобы определить
(и изменить) ваши текущие системные настройки, необходимо немного побродить по окнам в Windows:
 нажмите на клавишу Win, введите словосочетание Панель управления
(Control Panel) и откройте появившийся пункт;
 если панель управления открылась в виде категорий, выберите пункт
Изменение форматов даты, времени и чисел (Change date, time or
number formats);
 если же панель управления выглядит как набор значков, выберите вариант Региональные стандарты (Region).
В результате откроется диалоговое окно Регион (Region), показанное на
рис. 5.1, в котором вы можете посмотреть и изменить требуемые системные
настройки.
Рис. 5.1. Региональные настройки в панели управления Windows
Если вам когда-нибудь хотелось изменить настройки отображения дат
или отрицательных чисел по умолчанию в любых приложениях Windows, вы
пришли по адресу!
Главное в этом окне – это ваши установки по умолчанию. По рис. 5.1 видно,
что наша система настроена на представление даты в формате ISO yyyy-MM-
Понимание процесса импорта данных  133
dd, а не в стандартном виде для Канады (dd-MM-yyyy) или США (MM-dd-yyyy).
Также у нас изменено представление отрицательных чисел, а в качестве разделителя целой и дробной частей установлена точка.
🙈 Предупреждение. В отличие от Excel, Power Query регистрозависим. В нем
запись MM относится к месяцам, а mm – к минутам.
Здесь очень важно понимать, что все эти настройки специфичны для вашего конкретного компьютера. Таким образом, при установке типа данных
для столбца в Power Query вы будете видеть его форматирование на основе
этих системных настроек. Если вы поделитесь своим решением с кем-то
еще, этот кто-то будет видеть данные в столбцах в соответствии со своими
установками.
Теперь, когда вы знаете, где живут все эти настройки, пришло время понять, почему все это так важно при работе с Power Query.
Как программа интерпретирует плоские данные
Трудности программной интерпретации данных состоят в необходимости
точно знать три вещи.
1. Какой тип разделения данных используется в файле: по конкретному
символу, по шаблону символов или по ширине.
2. Какой символ или шаблон символов используется для отделения одной
записи от другой.
3. Какой тип данных ассоциируется с каждой точкой данных.
Проблема с плоскими файлами заключается в отсутствии метаданных в
виде схемы с указанием ответов на перечисленные вопросы. Но программе,
выполняющей импорт данных, просто необходимо сделать какие-то предположения на этот счет, чтобы корректно осуществить загрузку. Тогда как
большинство программ достаточно успешно справляются с первыми двумя
вопросами, с определением типов данных почти у всех них возникают проблемы.
Давайте рассмотрим для примера следующую точку данных: 1/8/18.
Логично было бы предположить, что речь здесь идет о дате, но о какой
именно? О 8 января 2018 года? Или о 1 августа 2018 года? А может, о 18 августа 2001-го? Все зависит от того, с помощью какой программы осуществлялась
выгрузка данных и откуда родом был программист, написавший функцию
выгрузки. Если из Америки, скорее всего, речь идет о 8 января 2018 года.
А если из Европы, то о 1 августа 2018 года. В случае же, если программист
решит прочитать предпочтительный формат данных из ваших региональных
настроек Windows, дата может быть любой!
Причина, по которой все это так важно, заключается, как мы уже говорили,
в отсутствии метаданных, которые могли бы сказать нам, в каком формате
представлены данные в файле. Так что программе придется делать опреде-
134  Глава 5. Импортирование из плоских файлов
ленные предположения во время импорта. И первым делом она обратится к
настройкам в панели управления Windows.
🍌 Примечание. У вас случалось, что вы открывали текстовый или CSV-файл в
Excel и в ряде строк даты отображались правильно, а в других были представлены в виде текста? Нет, не случалось. Если вы ответили на этот вопрос
положительно, в действительности перед вами были данные, в которых часть
дат отображалась неправильно, а другая была представлена как текст. В этом
случае правильными могли считаться только 12 дат в году: 1/1, 2/2, 3/3 и т. д.
Давайте рассмотрим конкретный набор данных, в котором сделаны следующие предположения:
 данные экспортировались в текстовый файл с использованием формата дат MM/dd/yy;
 в региональных настройках Windows установлен короткий формат дат
следующего образца: dd/MM/yyyy;
 в панели управления в качестве разделителя десятичных разрядов
установлена точка, а для отделения разрядов используется запятая.
В результате для каждой точки данных программа попытается вывести тип
данных, а формат установит в соответствии с текущими региональными и
иными настройками в панели управления, как показано на рис. 5.2.
Сырые данные
Выведенное значение
Форматирование
Рис. 5.2. Из текстового файла в Excel, попутно испортив все даты
Настоящий алгоритм приведения типов данных будет более сложным по
сравнению с приведенной здесь схемой, но вы должны понимать, что в целом
шаги будут следующими:
 программа попытается преобразовать значение 1/8/18 в дату с использованием формата dd/MM/yyyy, примененного в панели управления
Windows. В результате будет сгенерировано число 43313 (по количеству
дней, прошедших до означенной даты с 1 января 1900 года). Это значение будет затем помещено в ячейку в Excel;
 программа попробует преобразовать в дату с использованием того же
формата и значения 1/13/18, но, не обнаружив в календаре месяца с
порядковым номером 13, сделает предположение о том, что значение
не представляет собой дату. Таким образом, в ячейке значение будет
выведено в виде текста;
Импортирование файлов с разделителями  135
 программа сделает попытку преобразовать встреченный текст 45.67 в
значение. Результирующее число будет помещено в ячейку. Если преобразование выполнить не удастся, значение будет помещено в ячейку
в виде текста;
 процесс будет повторен для каждой точки данных в исходном файле.
После преобразования всех исходных данных в значения программа применит к ним правила форматирования на основании текущих настроек в
панели управления.
Так в чем проблема? Дата 8 января 2018 года, выгруженная программистом
в файл в виде 1/8/18, соответствующем формату MM/dd/yy, была интерпретирована неправильно, а именно как 1 августа 2018 года, как предписано в
наших региональных настройках в панели управления.
Но хуже всего то, что, как только значение было преобразовано в дату и записано в ячейку, изменить его уже нельзя. В этом традиционно заключалась
сложность загрузки текстовых и CSV-файлов в Excel. Получить неправильные
данные в этом случае очень легко, а выявить ошибки бывает не так просто.
И даты вызывают наибольшее количество вопросов. Поскольку многие
популярные системы управления базами данных были написаны американскими программистами для американских компаний, экспорт дат в них часто
производится в формате MM/dd/yy, несмотря на то что в мире только США
используют такой тип форматирования. Это может стать большой проблемой
для программ, работающих в странах с другими форматами дат, а в случае
с Канадой дело обстоит еще хуже. Мы часто шутим, что наши «айтишники»
делятся на два вида: гордых патриотов, везде устанавливающих формат даты
dd/MM/yy, и тех, кто сдался и оставляет на компьютерах формат MM/dd/yy.
Но самое печальное, что и те, и другие зачастую работают в одних и тех же
компаниях, что приводит к разнице в настройках отображения дат на разных
компьютерах.
Важно также понимать, что эта проблема касается не только дат. Она также
затрагивает числовые данные и валюты, поскольку в разных странах используются разные разделители чисел и валютные символы. А на фоне всеобщей
глобализации разногласия в форматах поражают все большее количество
источников данных, которые мы как-то должны интерпретировать.
Хорошие новости состоят в том, что Power Query позволяет полностью
контролировать эти моменты во время загрузки данных. Хотя базовые предположения эта программа делает на основе тех же предпосылок, она допускает изменение шагов с целью корректировки способа интерпретации данных.
И делается это не с помощью применения шага Измененный тип (Changed
Type), а посредством указания локали, позволяющей определить характер
данных в источнике.
Импортирование файлов с разделителями
Процесс импорта файлов с разделителями, таких как CSV или разделенных
символами табуляции текстовых файлов, достаточно прямолинеен, к тому
же он полностью отвечает базовым принципам ETL. Мы уже рассматривали
136  Глава 5. Импортирование из плоских файлов
подобный пример в первой главе, а сейчас попробуем загрузить файл с чуть
более изощренными данными.
Источник данных
Начнем с импортирования файла с именем Ch05­Delimited.CSV. Фрагмент
содержимого этого файла в программе Notepad++ выглядит так, как показано
на рис. 5.3.
Рис. 5.3. Исходные данные, разделенные запятыми
Первый вопрос, которым вы должны задаваться при взгляде на эти данные, звучит так: в каком формате введены даты? Мы можем предположить,
что они соответствуют формату MM/dd/yy. Но как узнать наверняка? Power
Query просканирует первую тысячу записей из набора данных, на основе
чего сделает собственное предположение. Также неплохо было бы вернуться
в программу, с помощью которой данные были экспортированы, и провести
пару экспериментов. Хорошие новости заключаются в том, что вы можете
надеяться, что программа всегда будет выдавать одинаковые результаты при
одинаковых настройках.
Также вы могли заметить, что в файле содержатся числовые данные, с которыми в Европе придется повозиться, поскольку они не только включают в
себя символ $, но и используют запятые в качестве разделителя разрядов, а
точки – для отделения десятичной части числа.
Извлечение данных
Давайте приступим. Откройте новую рабочую книгу в Excel и выполните
следующие действия:
 создайте новый запрос путем нажатия на вкладке Данные (Data) на
кнопку Из текстового/CSV-файла (From CSV or Text);
 найдите в сопроводительных материалах к книге файл Ch05 Examples\
Ch05­Delimited.csv и дважды щелкните по нему;
 нажмите на кнопку Преобразовать данные (Transform Data), чтобы
открыть редактор Power Query.
Теперь окно предварительного просмотра должно выглядеть примерно
так, как показано на рис. 5.4.
Импортирование файлов с разделителями  137
Рис. 5.4. Редактор Power Query с загруженным файлом с разделителями
🍌 Примечание. Помните о том, что Power Query попытается преобразовать
типы данных в столбцах в соответствии с текущими региональными настройками в панели управления. В связи с этим в вашем случае данные могут выглядеть не совсем так, как на рис. 5.4.
Ну, как все прошло на вашем компьютере? Все сработало? В первой строке
находится дата 1 декабря 2008 года или другая? А что со столбцом Amount?
Там значения, текст или ошибки? Добро пожаловать в увлекательный мир
преобразования данных Power Query, ответы для всех разные и зависят от
региональных и иных настроек в панели управления.
Задача
В окне предварительного просмотра, показанном выше, видно, что в нашем случае данные из столбца Date были представлены как даты в формате
yyyy-MM-dd, соответствующем региональным настройкам в панели управления. Это здорово, но сами даты были интерпретированы неправильно.
Никаких ошибок нет, но первая же дата в списке (1 декабря 2008 года) оказалась представлена как 8 января 2012 года. Чтобы исправить это, необходимо
явным образом вмешаться в выполнение шага с именем Измененный тип
(Changed Type). Давайте удалим созданный шаг и создадим его с нуля таким
образом, чтобы он правильно работал у всех в мире, вне зависимости от их
региональных настроек. Итак, избавьтесь от существующего шага, нажав на
крестик справа от имени Измененный тип (Changed Type).
🙈 Предупреждение. Помните о том, что шаг Измененный тип уже был приме-
нен, а значит, типы данных столбцов также были установлены и не могут быть
изменены ретроспективно. Таким образом, чтобы переопределить действие
созданного шага при помощи локали, необходимо либо удалить его, либо
вставить новый шаг перед существующим.
После удаления шага с изменением типов данных окно предварительного
просмотра приобретет вид, показанный на рис. 5.5, отражающий состояние
данных после применения шага Повышенные заголовки (Promoted Headers).
138  Глава 5. Импортирование из плоских файлов
Рис. 5.5. Все столбцы имеют текстовый тип данных,
так что мы хорошо видим, с чем именно имеем дело
Использование локали для установки корректных
типов данных
Итак, нам необходимо получить полный контроль над полем с датами
и как-то сообщить Power Query, как именно интерпретировать значения и
перевести их в правильные порядковые номера дат. Для этого мы изменим
тип данных столбца с указанием локали (locale) источника, то есть укажем
Power Query, какой именно формат был использован при заполнении исходных данных:
 щелкните мышью по кнопке ABC слева от заголовка столбца Date;
 выберите пункт Используя локаль… (Using Locale...).
Откроется диалоговое окно Изменение типа по локали (Change Type with
Locale), показанное на рис. 5.6, в котором вы можете проинструктировать
Power Query на предмет того, какой формат использовался при создании
источника данных.
Рис. 5.6. При заполнении нашей колонки использовался
языковой стандарт Английский (США)
Импортирование файлов с разделителями  139
Если с первым выпадающим списком в этом окне все понятно, то второй
может вызвать определенные затруднения, поскольку в нем указывается и
язык, и страна. Правда, если выбрать здесь Английский (Великобритания)
или Английский (Австралия), стандарт дат будет одинаковым – d/M/y, так
что ничего страшного, если вы укажете страну неверно. Лучше побеспокоиться о том, чтобы в поле Примеры входных значений (Sample input value),
в котором появляются значения после выбора локали, данные отображались
правильно.
В нашем случае выбор прост – нам нужно выбрать языковой стандарт
Английский (США), поскольку только в этой стране используется формат
дат M/d/y.
После нажатия на кнопку OK данные в столбце Date будут отображены
правильно, что видно по рис. 5.7.
Рис. 5.7. Похоже, теперь речь идет о декабре 2008 года
Теперь позаботимся о том, чтобы значения в столбце Amount выглядели
нормально для кого-нибудь из Европы. И здесь мы также воспользуемся
методом установки типа данных с использованием локали:
 щелкните мышью по кнопке ABC слева от заголовка столбца Amount и
выберите пункт Используя локаль… (Using Locale...);
 в диалоговом окне Изменение типа по локали (Change Type with
Locale) в выпадающем списке Тип данных (Data type) выберите пункт
Валюта (Currency);
 во втором списке выберите значение Английский (Канада);
 нажмите на кнопку OK.
После этого значки доллара исчезнут (помните, что мы говорим только о
типах данных – форматировать значения вы можете в месте назначения так,
как вам угодно), и суммы выровняются по правому краю ячеек, как показано
на рис. 5.8.
Есть три важных момента, которые вам необходимо усвоить на этом
этапе.
1. Каждый раз, когда мы добавляем изменение типа данных с использованием локали, мы будем получать отдельный шаг на панели Примененные шаги. Такие действия никогда не объединяются в один шаг.
140  Глава 5. Импортирование из плоских файлов
Рис. 5.8. Данные после второго изменения типа данных с использованием локали
2. Типы данных в столбцах Date и Amount мы изменили в соответствии
с локалями разных стран. Причина того, почему мы можем это делать, состоит в том, что в данном случае нет никакой разницы между
канадским и американским долларами. Произведенное действие не
добавляет никаких метаданных в отношении валюты, а просто указывает Power Query, как прочитать сумму $1,000.00 и преобразовать ее в
корректное значение.
3. Типы данных для каждого столбца в наборе данных могут быть заданы
с использованием собственной локали, что добавляет гибкости при
импорте данных, пришедших из разных регионов.
🍌 Примечание. Помните, что основной целью изменения типов данных с ис-
пользованием локали является указание Power Query на то, как именно интерпретировать текстовые значения и преобразовывать текст в нужные типы
данных.
🙈 Предупреждение. Если вы работаете в компании, использующей множество
форматов для дат и чисел, мы рекомендуем все преобразования типов выполнять с использованием локали. Пользователи с совпадающими с источником данных настройками не пострадают, а остальным это сильно облегчит
жизнь.
Итак, нам осталось расправиться всего с одним столбцом – Account. Мы
зададим ему числовой тип данных и обновим имя запроса:
 измените тип данных столбца Account на Целое число (Whole Number);
 измените имя запроса на Transactions.
В результате у нас получилось целых три шага изменения типов данных,
при этом первые два выполняются с использованием локали, как видно на
рис. 5.9.
Импортирование файлов без разделителей  141
Рис. 5.9. Теперь запрос будет работать у всех!
В самом деле, получившийся запрос сможет использовать кто угодно, если,
конечно, изменит путь к исходному файлу Ch05­Delimited.csv в шаге Источник (Source).
Осталось закрыть запрос и загрузить его в место назначения.
🍌 Примечание. Если вы хотите изменить свои региональные настройки, то мо-
жете сделать это как в Excel, так и в Power BI. В Excel нажмите на вкладке
Данные (Data) на кнопку Получить данные (Get Data) и выберите пункт Параметры запроса (Query Options). В разделе Текущая книга (Current Workbook)
откройте пункт Региональные настройки (Regional Settings) и выберите свой
языковой стандарт. Все новые подключения по умолчанию будут создаваться с учетом выбранной локали. В Power BI Desktop на вкладке Файл (File)
в разделе Параметры и настройки (Options and Settings) выберите пункт
Параметры (Options). В Power BI опция Региональные настройки (Regional
Settings) присутствует и в разделе Глобальные (Global), и в разделе, касающемся текущего файла.
Импортирование файлов
без разделителей
Научившись организовывать настройки в панели управления, вы сможете
легко и просто импортировать файлы с разделителями. Конечно, иногда вам
будут доставаться довольно «грязные» данные, но они хотя бы будут разделены на столбцы, что значительно облегчит задачу загрузки.
К тому же если вам когда-нибудь приходилось импортировать неструктурированные данные без четко обозначенных разделителей, вы знаете,
насколько сложной может быть задача загрузки данных из файлов. Такие
файлы обычно приходят с установленными по умолчанию именами вроде
ASCII.TXT и содержат символы в той последовательности, в которой они
должны быть выведены. Отсюда следует полный букет проблем, включая, но
не ограничиваясь следующими:
142  Глава 5. Импортирование из плоских файлов
 символы выровнены по позициям, а не согласно разделителям;
 выравнивание носит непоследовательный характер;
 в тексте присутствуют непечатаемые символы, такие как управляющие
коды;
 повторяющиеся строки заголовков.
В обязанности многих специалистов по работе в Excel входят разбор и
очистка информации, поступающей в подобном виде, при помощи их любимой программы. И это еще до того, как они приступят непосредственно
к анализу данных.
Если вам это знакомо, вы, скорее всего, в курсе, как это обычно происходит:
 данные импортируются в Excel при помощи инструмента Из текста
(From Text);
 работая в диалоговом окне размером с почтовую марку, вы пытаетесь
разобраться, по какому принципу разделены столбцы и какие из них
надо пропустить;
 результаты вываливаются на рабочий лист, и их необходимо преобразовать в таблицу;
 полученную таблицу нужно отсортировать и отфильтровать, чтобы избавиться от оставшегося мусора;
 текст в столбцах необходимо подчистить и подрезать.
И самая радостная новость состоит в том, что в следующем месяце, когда
вам пришлют новый файл, вам придется выполнить всю эту захватывающую
работу заново. Может, есть какой-то обходной путь? Да, он есть, и вы его
уже нашли!
Подключение к файлу
Подключение к файлам без разделителей осуществляется точно так же, как
и к любым другим текстовым файлам:
 нажмите на выпадающую кнопку Получить данные (Get Data) и в
меню Из файла (From File) выберите пункт Из текстового/CSV-файла
(From Text/CSV);
 перейдите в папку Ch05 Examples и выберите файл GL Jan­Mar.TXT;
 нажмите на кнопку Преобразовать данные (Transform Data).
Вы увидите, что Power Query поместит все данные из текстового файла в
один столбец, как показано на рис. 5.10.
🍌 Примечание. Обратите внимание на многоточия в некоторых строках, указывающие на то, что в строке присутствует больше информации, чем выведено в данный момент. Если столбец слишком узкий, просто растяните его
мышью, захватив за правый край заголовка.
Импортирование файлов без разделителей  143
Рис. 5.10. Представление файла без разделителей в редакторе Power Query
🍌 Примечание. Если вы видите в ячейках скомканный вместе текст, перейдите
на вкладку Просмотр (View) и убедитесь, что установлены флажки Моноширинный (Monospace) и Показать пробелы (Show Whitespace). При обработке
подобных файлов необходимо, чтобы эти опции были включены.
При анализе содержимого окна предварительного просмотра вы заметите, что данные в файле не имеют какого-то четкого разделителя, и именно
поэтому Power Query не стал даже пытаться строить догадки и добавлять
в раздел с примененными шагами какие-то еще шаги, помимо Источника
(Source). Вместо этого он услужливо оставил весь процесс обработки данных
вам на откуп. И с учетом структуры представленного файла это было далеко
не худшим его решением.
Прежде чем приступить к обработке этого нетривиального файла, стоит
отметить, что подходить к этой задаче можно по-разному, и ни один способ
не будет единственно правильным. Пример в этой главе построен таким образом, чтобы вы преобразовывали данные, пользуясь в основном инструментами пользовательского интерфейса. Также это наиболее очевидный путь
для человека, работающего в Excel. Набравшись опыта, вы найдете гораздо
более быстрые пути достижения того же результата.
Очистка файлов без разделителей
Главной целью очистки файлов без разделителей является максимально
быстрое приведение их к табличному виду. В нашем случае абсолютно очевидно, что первые десять строк файла не несут для нас никакой смысловой
нагрузки, а в 11-й строке, похоже, находятся заголовки будущих столбцов.
Перейдите на вкладку Главная (Home), в выпадающей кнопке Удалить строки (Remove Rows) выберите пункт Удаление верхних строк (Remove Top
Rows) и введите число 10.
В результате первые строки будут удалены, как показано на рис. 5.11, и не
будут включены в итоговое решение.
144  Глава 5. Импортирование из плоских файлов
Рис. 5.11. Верхние строки удалены, и заголовки столбцов переместились наверх
Теперь нам необходимо определиться с направлением разбивки данных.
Мы могли бы пойти слева направо, но в наших данных полно ведущих пробелов и дублирующихся пробелов в середине строк. Было бы неплохо избавиться от этого всего.
В Excel обычной практикой является прогон значений в ячейках через
функции СЖПРОБЕЛЫ (TRIM) и ПЕЧСИМВ (CLEAN) для удаления ведущих,
замыкающих и дублирующихся пробелов, а также непечатаемых символов.
В Power Query есть похожий функционал, которым мы воспользуемся следующим образом:
 щелкните правой кнопкой мыши по заголовку столбца Column1 и
в меню Преобразование (Transform) выберите пункт Усечь (Trim);
 щелкните правой кнопкой мыши по заголовку столбца Column1 и в том
же меню Преобразование (Transform) выберите пункт Очистить
(Clean).
Теперь данные выглядят немного лучше, что видно по рис. 5.12.
Рис. 5.12. Текст усечен и очищен
Вы могли заметить, что операция усечения в Power Query работает не совсем
так, как в Excel. Там функция СЖПРОБЕЛЫ (TRIM) удаляет ведущие и замыкающие пробелы в тексте, а также исключает дублирующиеся пробелы внутри
содержимого. В Power Query усечение выполняет только первое действие, не
затрагивая повторяющиеся пробелы между словами.
Операция очистки данных в Power Query позволяет привести данные к
виду, получаемому в Excel в результате применения двух упомянутых выше
функций, хотя это не так просто заметить. Непечатаемые символы в Excel
отображаются в виде значков вопроса в квадратиках, тогда как в Power Query
Импортирование файлов без разделителей  145
они показываются в виде пробелов. Так или иначе, если вы попереключаетесь с шага Обрезанный текст (Trimmed Text) на Очищенный текст (Cleaned
Text), вы заметите, что пробелы в тексте Avis & Davis были очищены на шаге
Очищенный текст (Cleaned Text).
Разделение столбцов по позиции
Теперь приступим к разделению наших данных на колонки. Наш базовый
принцип будет состоять в разбиении строк по столбцам через заданное количество символов, с которым мы будем определяться по ходу действия и
при необходимости корректировать свои догадки. Поскольку в колонке с
датами присутствует десять значимых символов, давайте начнем с первого
разделителя на позиции 12. Перейдите на вкладку Главная (Home), в выпадающей кнопке Разделить столбец (Split Column) выберите пункт По
количеству символов (By number of characters), установите переключатель
в положение Каждый раз (Repeatedly), введите число символов 12 и нажмите
на кнопку OK.
По рис. 5.13 очевидно, что это не сработало. Со столбцом дат, может быть,
и все в порядке, но о других колонках этого не скажешь.
Рис. 5.13. Данные разделились не так, как мы хотели
Но это не проблема. Давайте попробуем еще разок:
 удалите шаг Измененный тип (Changed Type);
 нажмите на кнопку с изображением шестеренки справа от названия
шага Разделить столбец по положению (Split Column by Position);
 измените значение на 15 и нажмите на кнопку OK.
Теперь гораздо лучше, как видно на рис. 5.14.
🍌 Примечание. Также стоит отметить, что вы не обязаны устанавливать пере-
ключатель в положение Каждый раз (Repeatedly) при разделении данных на
столбцы. Если содержимое файла плохо структурировано, вы можете за одну
операцию отделять лишь один столбец слева или справа. Это позволит вам
максимально точно настроить процесс разделения столбцов.
146  Глава 5. Импортирование из плоских файлов
Рис. 5.14. После второй попытки разделить данные на столбцы все стало лучше
Выполним еще два изменения.
Поскольку шаг Измененный тип (Changed Type) просто объявляет все
столбцы текстовыми, хотя они не должны являться таковыми в итоге, мы
избавимся от него. Также необходимо выделить первую строку в данных в
качестве заголовков:
 удалите шаг Измененный тип (Changed Type);
 перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Использовать первую строку в качестве заголовков (Use
First Row as Headers).
Прелесть ошибок в Power Query
После произведенных действий наши данные стали выглядеть более
опрятно, хотя некоторые столбцы нам бы хотелось переименовать. На данной стадии обычно рекомендуется работать со столбцами слева направо,
выполняя максимально возможную очистку данных и следя за тем, чтобы
они оставались правильными.
Если опуститься вниз, можно обнаружить, что в наших данных полно ненужных строк, образованных в результате переносов страниц в документе.
Первый блок с проблемными данными начинается в строке 40, как видно на
рис. 5.15.
Рис. 5.15. Лишняя информация в исходных данных
Импортирование файлов без разделителей  147
Вопрос в том, как с этим быть. Здесь есть и даты, и текст, и пустые значения
(null). Давайте попробуем так: щелкните правой кнопкой мыши на заголовке
столбца Tran Date, в выпадающем меню Тип изменения (Change type) выберите пункт Используя локаль (Using Locale). В открывшемся диалоговом
окне в качестве типа данных колонки установите Дата (Date), а в качестве
языкового стандарта – Английский (США).
Как видно на рис. 5.16, после этого действия в заголовке столбца Tran Date
появилась красная полоса, а при прокрутке вниз в колонке были обнаружены
ошибки.
Рис. 5.16. В результате изменения типа данных столбца в нем появились ошибки
В главе 3 мы уже обсуждали способы избавления от ошибок, негласно согласившись с тем, что ошибки – это плохо. Но тогда мы не упомянули о том,
что в Power Query, в отличие от других программ, ошибки – это на самом
деле здорово! Дело в том, что мы можем контролировать их и реагировать
на их появление.
Если вы внимательно посмотрите на наш промежуточный результат, то
обнаружите, что ошибки возникли как раз в тех строках, от которых мы собирались избавиться. Кроме того, наличие значения null в колонке Tran Date
также указывает нам на строки, которые в итоговых данных нам не нужны.
Так давайте избавимся от этих строк следующим образом:
 выделите столбец Tran Date, перейдите на вкладку Главная (Home) и в
выпадающей кнопке Удалить строки (Remove Rows) выберите пункт
Удалить ошибки (Remove Errors);
 откройте окошко фильтрации в столбце Tran Date и снимите флажок
со значения (NULL).
Итог получился впечатляющим – колонка Tran Date больше не содержит
ошибок, что видно по рис. 5.17.
🙈 Предупреждение. Если в результате этих действий у вас осталось всего
42 строки и последняя содержит ошибки во всех столбцах, значит, указанные
два шага вы применили в обратной последовательности. Критически важно
отлавливать ошибки в столбце до того, как выполнять фильтрацию. Если применить фильтр к столбцу, в котором есть ошибки, набор данных будет урезан.
148  Глава 5. Импортирование из плоских файлов
Рис. 5.17. В столбце Tran Date остались только допустимые значения
Несмотря на то что мы добились определенного прогресса, в наших данных по-прежнему присутствуют строки, не несущие полезной смысловой
нагрузки. Проблема в том, что нам не хотелось бы удалять все эти даты,
поскольку некоторые из них могут иметь смысл. О, взгляните на строку 41!
Интересно, Power Query продержится до 1 марта 10123 года?
Давайте перейдем к следующему столбцу и посмотрим, может быть, получится исправить возникшие ошибки здесь:
 дважды щелкните мышью по заголовку столбца Tran Date и переименуйте его в Date;
 аналогичным образом переименуйте колонку Tran Amount в Amount;
 измените тип данных столбца Amount с использованием локали на
Валюту (Currency) с применением языкового стандарта Английский
(США).
Вы увидите, что Power Query предпримет попытку сделать все значения в
столбце числовыми, но потерпит неудачу, что вновь приведет к появлению
ошибок – на этот раз в столбце Amount. Убедившись в том, что ошибки появились только в строках, которые нам не нужны, сделайте следующее:
 выделите столбец Amount и на вкладке Главная (Home) в выпадающей кнопке Удалить строки (Remove Rows) выберите пункт Удалить
ошибки (Remove Errors);
 откройте окошко фильтрации в столбце Amount и снимите флажок со
значения (NULL).
Если теперь прокрутить ползунок в район 40-й строки, мы увидим, что все
ошибки и лишние строки исчезли.
Удаление лишних столбцов
Избавиться от лишних столбцов можно очень просто, но при этом необходимо следовать определенной процедуре, чтобы убедиться, что речь идет о
действительно пустых колонках. Это можно сделать так:
 откройте окно фильтрации для столбца;
 убедитесь, что все значения в списке пустые или null.
Импортирование файлов без разделителей  149
Также вы можете воспользоваться инструментами Качество столбца
(Column Quality) и Распределение столбцов (Column Distribution), расположенными на вкладке Просмотр (View). При их включении в вашем распоряжении будет очень показательный индикатор в заголовке столбца. Если
в столбце находится одно отдельное (distinct) значение, как показано на
рис. 5.18, вы можете быть уверены – то, что вы видите в окне предварительного просмотра, будет содержаться и в данных после их загрузки.
Рис. 5.18. Одно отдельное значение, но нет пустот. Это вообще нормально?
В случае с этим столбцом можно видеть, что хоть в нем и содержится одна
неповторяющаяся строка, он не заполнен пустыми значениями. Поскольку
в нашем исходном файле было много пробелов, а разбивали колонки мы
на основании количества символов, в результате значения в этом столбце
представляют собой последовательности из 15 пробелов. Это можно проверить, выбрав любую ячейку и выделив мышью невидимые символы в области предварительного просмотра значений внизу слева, как показано на
рис. 5.18. Так что формально это не пустые значения, но они нам все равно
не нужны.
Если просмотреть все колонки, можно обнаружить еще одну – с именем
Column9, – в которой содержатся только значения null. Эти два столбца можно
смело удалить:
 выделите третью колонку и нажмите на клавишу Delete;
 то же проделайте с девятой колонкой.
Объединение столбцов
На данный момент понятно, что наша изначальная стратегия разделения
столбцов была излишне агрессивной. Похоже, четыре столбца, которые показаны на рис. 5.19, были разлучены по ошибке.
150  Глава 5. Импортирование из плоских файлов
Рис. 5.19. Ошибочно разделенные столбцы
К счастью, жизнь на этом не останавливается – все еще можно исправить.
И для этого даже не нужно возвращаться в самое начало и все делать заново.
Достаточно снова объединить эти столбцы:
 выделите столбец Reference Infor, зажмите клавишу SHIFT и выделите
столбец Column8;
 щелкните правой кнопкой мыши по заголовку одного из выделенных
столбцов и выберите пункт Объединить столбцы (Merge Columns). Появится одноименное диалоговое окно, в котором вы сможете выбрать
разделитель данных при объединении и задать имя (нового) столбца.
В данном случае нам не требуется разделитель, а поскольку мы в дальнейшем опять будем разделять собранный вместе столбец, его имя для
нас тоже не имеет значения;
 нажмите на кнопку OK.
В результате четыре выделенные колонки превратились в одну с именем
Сведено (Merged), как показано на рис. 5.20.
Рис. 5.20. Шалтай-Болтай сидел на Power Query!
Разделение столбцов по разделителю
Теперь, когда мы собрали воедино исходный столбец, нам становится очевидно, что он должен был быть разбит по разделителю-дефису. Так давайте
разобьем его заново, на этот раз правильно. Но мы не знаем, может ли в
названии продавца встречаться дефис, так что постараемся снова не переусердствовать с разделением столбца:
Импортирование файлов без разделителей  151
 щелкните правой кнопкой мыши на заголовке столбца Сведено (Merged)
и в выпадающем меню Разделить столбец (Split Column) выберите
пункт По разделителю (By Delimiter);
 оставьте тип разделителя Пользовательский (Custom) и введите в
поле ниже знак дефиса (–);
 установите переключатель в положение Самый левый разделитель
(At the left-most delimiter).
🍌 Примечание. Вы не ограничены одним символом при выборе разделителя.
Фактически если вы хотите разделить содержимое столбца по целому слову,
вы можете указать его в качестве разделителя.
В результате столбец Сведено (Merged) будет разбит на два: Сведено.1
(Merged.1) и Сведено.2 (Merged.2). Давайте переименуем их во что-то более
осмысленное:
 измените имя столбца Сведено.1 (Merged.1) на Category;
 измените имя столбца Сведено.2 (Merged.2) на Vendor.
Итак, мы получили почти идеальные выходные данные, как видно по
рис. 5.21.
Рис. 5.21. Почти идеальный результат
Исключение дублирующихся пробелов
Последнее, что нам необходимо сделать, – это избавиться от повторяющихся пробелов, застрявших между словами в столбце Vendor. Поскольку мы
не можем полагаться на механизм усечения от Power Query, видимо, придется все делать самим:
 щелкните правой кнопкой мыши на заголовке столбца Vendor и выберите пункт Замена значений (Replace Values);
 введите в поле Значение для поиска (Value To Find) два пробела;
 введите в поле Заменить на (Replace With) один пробел.
В результате мы получим полностью очищенный набор данных, который
может быть загружен в таблицу.
152  Глава 5. Импортирование из плоских файлов
🍌 Примечание. К сожалению, в Power Query нет простого способа избавиться
от множественных пустот в тексте. Если вы считаете, что в вашем столбце могут быть строки с тремя и более пробелами подряд, вам придется запустить
описанный выше процесс несколько раз, чтобы полностью очистить данные.
Итак, мы готовы к тому, чтобы загрузить запрос в Excel и построить на его
основании отчет. Сделаем это при помощи сводной таблицы:
 измените имя запроса на Transactions;
 перейдите на вкладку Главная (Home), нажмите на текст под кнопкой
Закрыть и загрузить (Close & Load), а не на саму кнопку, и выберите
вариант Закрыть и загрузить в… (Close & Load To…). В открывшемся
диалоговом окне установите переключатель в положение Новый лист
(New Worksheet).
Минута славы Power Query
Теперь давайте остановимся на мгновение, чтобы узнать еще кое-что
очень важное. Ваши данные очищены. В отличие от стандартных методов
загрузки данных в Excel из текстовых файлов, дополнительной очистки не
потребуется. Загрузка произошла успешно, а данные были преобразованы
исключительно при помощи инструментов, доступных в пользовательском
интерфейсе. Все готово, чтобы воспользоваться результатами своего труда.
Щелкните мышью в любом месте рабочего листа и вставьте сводную таблицу в ячейку G2. Настройте сводную таблицу следующим образом:




поле Date перенесите в область строк и сгруппируйте по месяцам;
поле Vendor также перенесите в область строк;
поле Category перенесите в область столбцов;
поле Amount установите в качестве значений.
Сводная таблица, построенная в результате этих действий, показана на
рис. 5.22.
Рис. 5.22. Сводная таблица, построенная на основе текстового файла
Но позвольте! Чисто технически все, что мы делали в этой главе до сих пор,
можно сделать и средствами Excel. Так зачем нам этот Power Query? Только
из-за большого размера окна? Это удобно, конечно, но не критично.
Импортирование файлов без разделителей  153
Истинная ценность Power Query проявится в следующем квартале, когда
вы получите новый файл с данными. Что бы вы делали, если бы, как и прежде, работали только в Excel? Правильно, потратили бы еще целый день на
очистку, преобразование и загрузку обновленных данных. Но с Power Query
все меняется:
 на вкладке Главная (Home) нажмите на кнопку Настройки источника
данных (Data Source Settings);
 выберите источник и нажмите на кнопку Изменить источник (Change
Source);
 обновите путь к файлу на Ch05 Examples\GL Apr­Jun.TXT;
 нажмите на кнопку OK, а затем – на кнопку Закрыть;
 на вкладке Данные (Data) нажмите на кнопку Обновить все (Refresh All).
Результат запроса обновит таблицу, но нам нужно также принудительно
обновить сводную таблицу, так что выполните последнее действие еще раз.
🍌 Примечание. Данные, помещенные в модель данных (в Excel или Power BI),
не нуждаются в двойном обновлении для актуализации сводных таблиц и
визуализаций, построенных на их основании.
На рис. 5.23 наглядно показано преимущество Power Query.
Рис. 5.23. Обновленная сводная таблица за следующий квартал
Новые продавцы, новые транзакции, новые даты, и все работает без проблем! Это же настоящая революция, и сейчас вы точно думаете о том, как
обходились без этого раньше!
🍌 Примечание. Если бы вы просто заменили старый файл новым, вам бы даже
не пришлось менять путь к файлу. Вместо этого достаточно было бы дважды
обновить данные.
Глава
6
Импортирование
из файлов Excel
Несомненно, одним из самых простых способов начать обрабатывать информацию в табличном виде является открытие файла Excel и проход по
строкам и столбцам. Несмотря на то что Excel изначально не предназначен
для хранения данных, зачастую именно так его и используют, в связи с чем
Power Query воспринимает Excel в качестве одного из источников данных.
В отличие от плоских файлов, в которых данные хранятся на одном «листе», файлы Excel намного более многогранны. И дело не только в наличии
множества листов, но и в способах обращения к данным на них, включая
работу непосредственно с листами, таблицами в рамках этих листов или
именованными диапазонами.
При работе с данными из Excel есть два основных подхода:
 подключение к данным в активной рабочей книге;
 подключение к данным во внешней рабочей книге.
В этой главе мы подробно рассмотрим оба подхода, поскольку доступ к
данным в Excel напрямую зависит от используемого коннектора.
Данные в активной рабочей книге
Первый сценарий, который мы рассмотрим, будет касаться случая хранения
данных внутри активной в настоящий момент рабочей книги.
🍌 Примечание. Пример из этого раздела должен быть запущен из Excel, по-
скольку в Power BI нет рабочих листов, в связи с чем в нем не поддерживается этот способ импорта данных. Несмотря на это, мы рекомендуем пользователям и разработчикам Power BI прочитать данную секцию, ведь этот
коннектор предлагает некоторые опции, недоступные в Power BI.
При импорте из активной книги Power Query может читать данные только
из:
156  Глава 6. Импортирование из файлов Excel
 таблиц Excel;
 именованных диапазонов, включая динамические.
Сначала мы посмотрим, как можно извлекать из Excel данные, не оформленные в таблицы. Мы будем работать с файлом Ch06 Examples\Excel Data.xlsx,
содержащим четыре следующих листа с одинаковыми данными:




Table (данные оформлены в виде таблицы с именем Sales);
Unformatted (неформатированные данные на листе);
NamedRange (данные в виде именованного диапазона);
Dynamic (с формулой в ячейке H2).
Мы будем использовать эти четыре рабочих листа для демонстрации того,
какие опции позволяет применять Power Query при подключении к данным.
Подключение к таблицам Excel
Начнем с самого простого типа импорта – из таблицы Excel:
 откройте файл Ch06 Examples\Excel Data.xlsx;
 перейдите на рабочий лист Table.
Вы увидите отчет, оформленный в виде красивой таблицы Excel, как показано на рис. 6.1.
Рис. 6.1. Данные в Excel, оформленные в таблицу с именем Sales
Чтобы загрузить эти данные в Power Query, выполните следующие действия:
 щелкните по любой ячейке в таблице;
 создайте новый запрос, используя кнопку Из таблицы/диапазона
(From Table/Range) или Из листа (From Sheet).
🍌 Приложение. До версии Excel в составе Microsoft 365 кнопка Из листа (From
Sheet) называлась Из таблицы/диапазона (From Table/Range). Так или иначе,
вы всегда можете найти нужную опцию на вкладке Данные (Data) в выпадающей кнопке Получить данные (Get Data).
Данные в активной рабочей книге  157
В отличие от работы со многими другими коннекторами, в данном случае редактор Power Query будет открыт незамедлительно, как показано на
рис. 6.2, минуя окно предварительного просмотра. И это вполне логично,
поскольку вы уже видели данные, которые хотите импортировать.
Рис. 6.2. Данные загружаются в Power Query без их предварительного просмотра
🍌 Примечание. Если вы сравните шаги по умолчанию, примененные Power
Query при импорте данных из таблицы Excel с загрузкой из файла CSV, то
заметите, что шаг Повышенные заголовки (Promoted Headers) будет отсутствовать. Дело в том, что метаданные о заголовках в таблице Excel хранятся
на уровне схемы, так что на шаге Источник (Source) Power Query уже точно
знает, какие в таблице должны быть заголовки.
Как и в случае с любым другим источником, при импорте данных из таблицы Excel Power Query попытается определить типы данных для всех
столбцов. При этом вы должны понимать, что все правила форматирования,
установленные для рабочего листа Excel, игнорируются. Если значения в
столбце похожи на числовые, Power Query применит формат Десятичное
число (Decimal) или Целое число (Whole Number). Обычно это не представляет проблемы, но когда речь идет о датах, Power Query всегда будет
устанавливать тип Дата и время (DateTime), даже если порядковые номера
дат в колонке округлены до целого. Нам такая степень точности не нужна,
поэтому мы исключим ее путем изменения типа данных. Попутно мы присвоим последним трем столбцам тип Валюта (Currency):
 измените тип данных столбца Date на Дата (Date) с заменой текущего
шага;
 выделите столбец Cost, а затем, удерживая клавишу SHIFT, выделите
столбец Commission;
 щелкните правой кнопкой мыши на заголовке любого из выделенных
столбцов и в выпадающем меню Тип изменения (Change Type) выберите пункт Валюта (Currency) с заменой текущего шага.
После этого данные будут готовы к дальнейшей очистке и преобразованию. Поскольку в приведенном случае мы ставим себе целью продемонстрировать работу коннектора, мы пропустим этот этап, позаботившись лишь об
имени запроса.
158  Глава 6. Импортирование из файлов Excel
По умолчанию запрос унаследовал имя источника данных: Sales. Но проблема в том, что при загрузке запроса на лист созданная таблица получает
имя образующего ее запроса. А поскольку таблицы на листе должны обладать уникальными именами, возникнет конфликт. Чтобы избежать его, Power
Query назовет запрос Sales_2.
🙈 Предупреждение. При создании Power Query новой таблицы и переимено-
вании созданной таблицы во избежание конфликта имя исходного запроса
не изменяется. Это может затруднить отслеживание запросов в дальнейшем!
Чтобы исключить конфликт имен, давайте переименуем запрос перед выгрузкой на рабочий лист:
 измените имя запроса на FromTable;
 нажмите на кнопку Закрыть и загрузить (Close & Load).
🍌 Примечание. Нет никаких причин для дублирования таблицы без выпол-
нения каких-либо преобразований. Здесь мы это сделали исключительно с
целью демонстрации загрузки данных из Excel.
Подключение к табличным диапазонам
Следующий вид подключения, который мы рассмотрим, относится к ситуации, когда данные хранятся в Excel в табличном виде, но не оформлены в
виде таблиц, как видно на рис. 6.3. В нашем рабочем файле этот тип хранения
данных показан на рабочем листе с именем Unformatted.
Рис. 6.3. Данные, аналогичные первому примеру,
но не оформленные в виде таблицы
Данные в активной рабочей книге  159
Для импорта таких данных в Power Query необходимо выполнить похожие
действия:
 щелкните по любой (одной) ячейке в таблице;
 создайте новый запрос, используя кнопку Из таблицы/диапазона
(From Table/Range) или Из листа (From Sheet).
После этого Excel начнет процесс создания за вас таблицы на рабочем
листе, запросив у вас информацию о ее границах и наличии заголовков, как
показано на рис. 6.4.
Рис. 6.4. Если Power Query вам такое предложит, откажитесь,
нажав на Cancel!
🙈 Предупреждение. Если в диалоговом окне, показанном на рис. 6.4, нажать на
кнопку OK, Excel превратит данные в таблицу, но при этом даст ей случайное
имя вроде Таблица 1 (Table1), после чего будет немедленно открыт редактор
Power Query, – у вас даже не будет возможности определить для таблицы
более осмысленное имя. Но дело в том, что исходное имя таблицы жестко
прописывается в запросе, и если позже изменить его, запрос сломается. В результате вам придется вручную править путь в шаге Источник (Source), чтобы
обновить имя исходной таблицы. Так что, пока Microsoft не дает нам возможности указать имя таблицы в диалоговом окне, показанном на рис. 6.4, мы
советуем вам нажимать на кнопку Отмена (Cancel), чтобы настраивать все
вручную.
Если вы по ошибке нажали на кнопку OK, закройте окно редактора Power
Query с отказом от внесения изменений. Мы хотим, чтобы у вас все работало
нормально, поэтому рекомендуем создавать таблицу перед загрузкой данных в Power Query следующим образом:
 щелкните по любой (одной) ячейке в таблице;
 на вкладке Главная (Home) нажмите на кнопку Форматировать как
таблицу (Format as Table) и выберите цветовую схему (или нажмите
сочетание клавиш CTRL+T, если вас устраивает голубая схема, принятая по умолчанию);
Powered by TCPDF (www.tcpdf.org)
160  Глава 6. Импортирование из файлов Excel
 перейдите на вкладку Конструктор таблиц (Table Design);
 переименуйте таблицу в поле слева в SalesData (без пробелов).
Зачем все это делать? А затем, что имя таблицы играет важную роль в
структуре навигации вашей рабочей книги. Каждая таблица и именованный
диапазон могут быть выбраны в поле с именем слева от строки формул, как
показано на рис. 6.5, что немедленно перенесет вас к соответствующей области в книге. Только подумайте, насколько усложнилась бы навигация по
рабочей книге, если бы в этом списке присутствовали безликие имена вроде
Таблица1, Таблица2, Таблица3 и т. д. Давайте своим таблицам осмысленные
имена, и это значительно облегчит доступ к нужным диапазонам данных
в дальнейшей работе.
Рис. 6.5. В нашем списке уже есть три имени таблиц
Теперь, когда таблица оформлена и ей присвоено говорящее имя, можно
приступить к загрузке данных в Power Query:
 откройте список с именами таблиц и выберите созданное нами имя
SalesData, что приведет к выделению всей таблицы;
 создайте новый запрос, используя кнопку Из таблицы/диапазона
(From Table/Range) или Из листа (From Sheet);
 измените тип данных столбца Date на Дата (Date) с заменой текущего
шага;
 выделите столбец Cost, а затем, удерживая клавишу SHIFT, выделите
столбец Commission;
 щелкните правой кнопкой мыши на заголовке любого из выделенных
столбцов и в выпадающем меню Тип изменения (Change Type) выберите пункт Валюта (Currency) с заменой текущего шага;
 измените имя запроса на FromRange;
Данные в активной рабочей книге  161
 нажмите на кнопку Закрыть и загрузить (Close & Load), чтобы импортировать данные на новый лист.
Как бы ни был полезен этот функционал, есть в нем и разочаровывающий
момент, состоящий в том, что данные должны быть оформлены в виде таблицы. Может, можно при помощи этого инструмента извлекать данные из
других объектов Excel?
Подключение к именованным диапазонам
Извлечение данных из оформленных таблиц – это один из самых легких
способов загрузить в Power Query информацию, хранящуюся в Excel, но далеко не единственный.
Неудобства при работе с таблицами в Excel состоят в том, что в этом случае
заголовки жестко фиксируются (разбивая динамические заголовки таблиц,
установленные при помощи формул), задается определенная цветовая гамма
и производятся другие стилистические настройки без вашего ведома. Представьте, что вы потратили массу времени на проведение анализа и формирование таблицы и не хотите, чтобы к ней применялись какие-то стили.
Хорошая новость состоит в том, что вы также можете подключаться к диапазонам Excel, просто для этого нужно кое-что сделать. Секрет заключается
в создании именованного диапазона (named range) поверх данных. Давайте
посмотрим, как это можно сделать, на примере еще одного экземпляра тех
же данных.
Для начала выполните следующие действия:
 перейдите на рабочий лист с именем NamedRange;
 выделите ячейки в диапазоне A5:F42;
 установите курсор в поле Имя (Name), расположенное слева от строки
формул, введите Data и нажмите на клавишу Enter, как показано на
рис. 6.6.
Рис. 6.6. Создание именованного диапазона
162  Глава 6. Импортирование из файлов Excel
🍌 Примечание. После создания именованного диапазона вы можете выделять
его, выбирая из выпадающего списка соответствующее имя. Вне зависимости от того, где в рабочей книге вы в данный момент находитесь, вы будете
перемещены на этот рабочий лист, а выбранный именованный диапазон
окажется выделен.
Далее сделайте следующее:
 в списке диапазонов выберите Data;
 создайте новый запрос, используя кнопку Из таблицы/диапазона
(From Table/Range) или Из листа (From Sheet).
🍌 Примечание. Если именованный диапазон выделен на листе и выбран в
списке диапазонов, редактор Power Query будет открыт незамедлительно,
при этом исходные данные не будут стилизованы в виде таблицы, а обращение к диапазону будет выполнено по имени.
На этот раз интерфейс редактора Power Query, показанный на рис. 6.7,
будет больше напоминать процесс импорта файлов с разделителями, чем
загрузку данных из Excel.
Рис. 6.7. Данные, импортированные посредством именованного диапазона
Одной из особенностей таблиц Excel являются предустановленные заголовки. Поскольку именованные диапазоны этим свойством не обладают,
Power Query подключается к исходным данным и запускает анализ на предмет восприятия данных. Так же, как и ранее, при подключении к плоским
файлам он определяет, что в первой строке данных могут быть заголовки,
поднимает их, а затем выполняет попытку присвоения типов данных столбцам.
Чтобы очистить данные и привести к виду, аналогичному другим примерам из этого раздела, сделайте следующее:
 измените тип данных столбца Date на Дата (Date) с заменой текущего
шага;
 выделите столбец Cost, а затем, удерживая клавишу SHIFT, выделите
столбец Commission;
Данные в активной рабочей книге  163
 щелкните правой кнопкой мыши на заголовке любого из выделенных
столбцов и в выпадающем меню Тип изменения (Change Type) выберите пункт Валюта (Currency) с заменой текущего шага;
 измените имя запроса на FromNamedRange;
 нажмите на кнопку Закрыть и загрузить (Close & Load), чтобы импортировать данные на новый лист.
Динамические именованные диапазоны
Одним из главных преимуществ таблиц в Excel является то, что они автоматически расширяются по горизонтали и по вертикали при добавлении
новых данных. Но к их недостаткам, как мы уже говорили, можно отнести
не всегда уместное внешнее форматирование. В то же время именованные
диапазоны, не обладающие лишним форматированием, по умолчанию не
умеют подстраиваться под введенные данные. К счастью, есть обходной путь,
и заключается он в создании так называемых динамических именованных диапазонов (dynamic named range), которые умеют автоматически расширяться,
адаптируясь под данные.
Создание динамических именованных диапазонов недоступно с помощью
интерфейса, а требует установки динамического имени еще до начала работы с ними. Проделайте следующие действия:
 перейдите на рабочий лист Dynamic;
 на вкладке Формулы (Formulas) нажмите на кнопку Диспетчер имен
(Name Manager) и в открывшемся диалоговом окне нажмите на Создать (New);
 измените имя на DynamicRange;
 введите следующую формулу:
=Dynamic!$A$5:ИНДЕКС(Dynamic!$F:$F;ПОИСКПОЗ(99^99;Dynamic!$A:$A))
 нажмите на кнопку OK.
Именованный диапазон должен появиться в списке имен в диспетчере,
как показано на рис. 6.8.
Рис. 6.8. Диапазон с именем DynamicRange создан
164  Глава 6. Импортирование из файлов Excel
🍌 Примечание. Если вам лень вводить формулу целиком, мы оставили ее для
вас в ячейке H2 на листе Dynamic. Вам достаточно убрать апостроф (') перед
формулой.
Проблема состоит в том, что, хоть мы и можем обращаться к созданному
именованному диапазону в формулах, в выпадающем списке с именами
(слева от строки формул) он не появился. А если мы не можем выбрать его в
списке имен, то как нам подключиться к нему из Power Query?
Секрет состоит в создании пустого запроса и указании Power Query, к какому диапазону необходимо подключиться:
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
 в строке формул напишите следующий код:
=Excel.CurrentWorkbook()
🍌 Примечание. Если вы не видите строку формул, перейдите на вкладку Просмотр (View) и установите флажок Строка формул (Formula Bar).
После нажатия на клавишу Enter вы увидите список всех объектов текущей рабочей книги, к которым можно подключиться, как показано на
рис. 6.9.
Рис. 6.9. Список всех объектов в текущей рабочей книге
Последним в списке будет значиться созданный нами объект с именем
DynamicRange. Щелкните мышью по слову Table напротив нужного нам объекта в столбце Content, в результате чего будет раскрыт наш диапазон, как
показано на рис. 6.10.
Данные из других рабочих книг  165
Рис. 6.10. Раскрытый динамический диапазон в Power Query
Просматривая примененные шаги, можно обнаружить, что мы:
 подключились к текущей книге Excel на шаге Источник (Source);
 открыли содержимое диапазона DynamicRange на шаге Навигация
(Navigation).
Попутно Power Query по привычке сделал несколько предположений о
данных, повысив заголовки и установив типы данных для столбцов. Все, что
нам осталось сделать, – это подкорректировать типы данных и загрузить
информацию на рабочий лист:
 измените тип данных столбца Date на Дата (Date) с заменой текущего
шага;
 выделите столбец Cost, а затем, удерживая клавишу SHIFT, выделите
столбец Commission;
 щелкните правой кнопкой мыши на заголовке любого из выделенных
столбцов и в выпадающем меню Тип изменения (Change Type) выберите пункт Валюта (Currency) с заменой текущего шага;
 измените имя запроса на FromDynamicRange;
 нажмите на кнопку Закрыть и загрузить (Close & Load), чтобы импортировать данные на новый лист.
Подключение к рабочим листам Excel из той же книги
К сожалению, не существует коннектора для подключения к целому рабочему листу Excel из той же книги. Но и это ограничение можно обойти, создав область печати (Print Area) с захватом большей части листа. Поскольку
созданный объект с именем Область_печати (Print_Area) является именованным диапазоном, вы можете обращаться к нему через выпадающий список
имен и подключаться, используя метод, описанный в разделе загрузки данных из именованных диапазонов.
Данные из других рабочих книг
Все описанные выше техники реализуются непосредственно в рабочей книге
с данными. А что, если нужные нам данные в виде файла Excel появляются
166  Глава 6. Импортирование из файлов Excel
раз в месяц или мы используем для создания отчетов Power BI? В этих случаях
нам необходимо будет подключаться к файлам и применять их в качестве
источника данных, а не строить наше решение прямо внутри этих файлов.
В данном разделе мы будем работать с файлом Ch06 Examples\External
Workbook.xlsx, содержащим два рабочих листа: Table и Unstructured. Данные на
обоих листах одинаковые, но на листе Table они оформлены в виде таблицы
с именем Sales. На листе Unstructured присутствуют статический и динамический именованные диапазоны, а также созданная область печати.
Если открыть диспетчер имен, мы обнаружим четыре созданных объекта
в книге, как показано на рис. 6.11.
Рис. 6.11. Именованные объекты в файле External Workbook.xlsx
Подключение к файлу Excel
Для начала давайте посмотрим, что будет, если подключиться к внешнему
файлу Excel. В новой рабочей книге Excel и файле Power BI выполните следующие действия:
 убедитесь, что файл External Workbook.xlsx закрыт;
 подключитесь к данным, используя пункт Из книги (From Workbook)
в подменю Из файла (From File).
🙈 Предупреждение. Power Query не сможет прочитать данные из открытой в
данный момент книги. Убедитесь, что закрыли файл Excel, прежде чем подключаться к нему, иначе получите ошибку!
Откроется диалоговое окно Навигатор (Navigator), показанное на рис. 6.12,
в котором вы можете выбрать данные для импортирования.
Данные из других рабочих книг  167
Рис. 6.12. Доступные объекты из рабочей книги External Workbook.xlsx
Как видите, у нас есть возможность подключаться к объектам следующих
типов:
 таблицы (Sales);
 рабочие листы (Table и Unstructured);
 именованные диапазоны (Print_Area и NamedRange).
Чего вы не видите в списке доступных объектов, так это динамического
диапазона (DynamicName). К сожалению, при подключении к внешним файлам Excel у вас нет возможности воспользоваться коннектором для импорта
данных из динамических диапазонов.
В данный момент, если выбрать любой из предложенных объектов, будет
открыт редактор Power Query с принадлежащими этому объекту данными.
А что, если вам необходимо открыть сразу несколько объектов?
Правда, хочется по привычке установить флажок Несколько элементов
(Select Multiple)? И это сработает – в результате вы получите по одному запросу для каждого выбранного объекта. Проблема в том, что в этом случае
будут созданы отдельные подключения к источнику данных для каждого
запроса. И хотя вы можете обновлять все созданные подключения одновременно, воспользовавшись диалоговым окном Настройки источника данных (Data Source settings), вам наверняка хотелось бы иметь единое подключение к источнику и обращаться к нему при необходимости для получения
дополнительных данных. Так вы сможете обновлять источник при помощи
диалогового окна, упомянутого выше, или путем изменения шага Источник
(Source) в исходном запросе.
Для нашего примера мы воспользуемся вторым вариантом и построим
запрос, который будет подключаться к файлу, а затем ссылаться на таблицу,
рабочий лист или именованный диапазон. Для начала сделайте следующее:
 щелкните правой кнопкой мыши по названию файла и выберите пункт
Преобразовать данные (Transform Data);
 измените имя нового запроса на Excel File.
168  Глава 6. Импортирование из файлов Excel
Вы увидите таблицу с содержимым файла, показанную на рис. 6.13.
Рис. 6.13. Содержимое файла External Workbook.xlsx
Давайте отметим несколько важных моментов, глядя на это окно предварительного просмотра:
 в первом столбце показаны имена объектов из Excel;
 во втором столбце стоит слово Table, указывающее на то, что здесь
хранится содержимое конкретного извлеченного объекта;
 в столбце Item показана более детализированная информация об имени объекта, включая название рабочего листа в случае с областью
печати;
 колонка Kind содержит данные о типе объекта, хранящегося в столбце
Data;
 в столбце Hidden (не показанном на рис. 6.13) находится информация
о видимости объекта.
Вы должны обратить внимание на то, что слова Table в колонке Data написаны другим цветом по сравнению с остальным наполнением таблицы.
Это указывает на то, что по ним можно щелкнуть мышью, чтобы посмотреть
их содержимое.
Подключение к таблицам
Почему бы не начать с подключения к таблице во внешнем файле Excel?
Давайте создадим для этого новый запрос, ссылающийся на созданный нами
ранее запрос Excel File:
 раскройте панель навигатора в левой части экрана, щелкнув по слову
Запросы (Queries);
 щелкните правой кнопкой мыши по запросу Excel File и выберите пункт
Ссылка (Reference);
 дважды щелкните по появившемуся запросу Excel File (2) в окне навигатора и переименуйте его в Table;
 щелкните по ключевому слову Table для таблицы Sales (третья строка
в столбце Data), как показано на рис. 6.14.
Данные из других рабочих книг  169
Рис. 6.14. Обращение к детализации таблицы Sales
В результате вы увидите, что таблица из внешнего файла Excel загружается
точно так же, как и из текущей рабочей книги, что показано на рис. 6.15.
Рис. 6.15. Подключение к таблице во внешней книге
🍌 Примечание. Любопытно, что при подключении к внешнему файлу алго-
ритм определения типов данных сработал лучше – для столбца Date на этот
раз Power Query выбрал нужный нам тип Дата (Date), а не Дата и время
(DateTime).
Стоит отметить, что в этом случае примененные шаги при выделении
одного или нескольких объектов в источнике будут идентичными. При подключении к внешней рабочей книге Power Query всегда подключается к самой книге, после чего обращается к выбранному вами объекту и лишь затем
выполняет все действия по алгоритму. Единственным отличием будет то,
что на шаге Источник (Source) подключение будет осуществляться непосредственно к файлу, а не к запросу Excel File.
Подключение к именованным диапазонам
Теперь давайте попробуем подключиться к именованному диапазону:
 раскройте панель навигатора, щелкнув по слову Запросы (Queries),
и нажмите правой кнопкой мыши по запросу Excel File, выбрав пункт
Ссылка (Reference);
 дважды щелкните по появившемуся запросу Excel File (2) в окне навигатора и переименуйте его в Named Range;
170  Глава 6. Импортирование из файлов Excel
 щелкните по ключевому слову Table для объекта с именем NamedRange
(четвертая строка в столбце Data), как показано на рис. 6.16.
Рис. 6.16. Раскрываем детализацию по именованному диапазону NamedRange
Результат не должен вас удивить. Поскольку в именованном диапазоне
содержатся заголовки и строки данных на неструктурированном рабочем
листе, не оформленном в таблицу, Power Query, подключившись к объекту,
сделал разумное предположение о том, что в первой строке находятся заголовки таблицы, а также установил для столбцов типы данных. В этом случае
практически не будет разницы с ситуацией, когда данные находились в той
же рабочей книге, за исключением того, что столбец Date получил тип Дата
(Date), что видно по рис. 6.17.
Рис. 6.17. Импорт из именованного диапазона во внешней рабочей книге
Подключение к рабочим листам
Теперь давайте попробуем импортировать содержимое целого рабочего
листа, чего мы не могли сделать, находясь в той же книге:
 раскройте панель навигатора в левой части экрана;
 снова щелкните правой кнопкой мыши по запросу Excel File и выберите
пункт Ссылка (Reference);
 дважды щелкните по запросу Excel File (2) и переименуйте его на этот
раз в Worksheet;
 щелкните по ключевому слову Table для рабочего листа Unstructured
(вторая строка в столбце Data), как показано на рис. 6.18.
Данные из других рабочих книг  171
Как видите, на этот раз данные выглядят не слишком привлекательно.
Рис. 6.18. Что с этим всем делать?
В отличие от импортирования данных из таблицы или именованного диапазона, подключение к целому рабочему листу привело к загрузке всего используемого диапазона (used range). В этот диапазон включаются строки с
первой до последней заполненной и столбцы, начиная с A и заканчивая последним столбцом с данными. При этом все пустые ячейки на листе в Power
Query отображаются как null.
Исходя из примененных шагов, становится ясно, что после подключения к
файлу Excel и навигации к нужному нам листу было выполнено повышение
заголовков, что в данном случае не совсем уместно. Давайте вмешаемся в
процесс и хорошенько почистим данные:
 удалите шаг Измененный тип (Changed Type);
 удалите шаг Повышенные заголовки (Promoted Headers);
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Удалить строки (Remove Rows) выберите пункт Удаление верхних строк
(Remove Top Rows) и введите число 4;
 перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Использовать первую строку в качестве заголовков (Use
First Row as Headers).
Теперь, как видно на рис. 6.19, наши данные выглядят куда более приемлемо.
Рис. 6.19. Совсем другое дело!
172  Глава 6. Импортирование из файлов Excel
Есть одна проблемка. Если прокрутить окно предварительного просмотра
вправо, можно заметить, что последним в таблице размещается столбец с
именем Column7, целиком заполненный значениями null. Он не был включен
в именованный диапазон, но при чтении напрямую с листа вдруг появился.
Ну и что? Раз столбец полностью состоит из пустых значений, мы можем
просто удалить его! Или не можем?..
Здесь пришло время поговорить о том, как можно повысить надежность
своих решений и избежать в будущем возникновения ошибок на уровне шага
при изменении типов данных. Заметьте, что при повышении заголовков
Power Query автоматически добавил шаг Измененный тип (Changed Type),
жестко прописав имя столбца в коде, как показано на рис. 6.20.
Рис. 6.20. Что за проблема со столбцом Column7? Мы не можем просто удалить его?
Это может потенциально привести к возникновению ошибок в будущем,
если кто-то:
 создаст в исходных данных столбец Profit справа от столбца Commission.
В этом случае в качестве заголовка будет использовано слово Profit, а
не Column7;
 удалит лишние данные в этой колонке на рабочем листе. В результате
столбец Column7 даже не будет загружен в Power Query;
 сбросит используемый диапазон на листе, избавившись от всех лишних
столбцов и строк. В итоге границы используемого диапазона изменятся, и столбец Column7 импортироваться не будет.
Во всех перечисленных ситуациях в нашем запросе будет возникать ошибка на уровне шага в связи с отсутствием столбца Column7, имя которого, напомним, прописано в коде шага Измененный тип.
🍌 Примечание. Очень важно понимать, что мы демонстрируем этот аспект на
примере используемых диапазонов в Excel, которые чаще всего ведут себя
довольно стабильно и предсказуемо. Однако эта же ошибка может возникнуть, если данные в Excel поступают из отчетной системы, в которой может
меняться количество столбцов.
Данные из других рабочих книг  173
Вместо того чтобы надеяться на удачу, необходимо сделать все возможное,
чтобы сократить до минимума шанс возникновения ошибки на уровне шага
в будущем. Для этого лучшим способом является сохранение в явном виде
только тех столбцов, которые нам точно нужны, чтобы имя колонки Column7
даже не появлялось в коде примененных шагов Power Query:
 удалите шаг Измененный тип (Changed Type);
 выделите столбец Date, а затем, удерживая клавишу SHIFT, выделите
столбец Commission;
 щелкните правой кнопкой мыши по любому из выделенных заголовков
и выберите пункт Удалить другие столбцы (Remove Other columns);
 снова выделите все столбцы;
 на вкладке Преобразование (Transform) нажмите на кнопку Определить тип данных (Detect Data Type).
Использование инструмента удаления других столбцов, кроме выделенных, позволяет гарантировать, что в будущем в нашей таблице будут оставаться только нужные нам колонки, а все лишние будут удаляться. Также
мы избегаем жесткого прописывания названий ненужных столбцов в коде
шагов, что очень опасно.
Последнее, что нам необходимо проверить, – нет ли в конце нашего набора данных большого количества пустых строк. Если они есть, желательно
избавиться от них, выполнив следующие действия:
 выделите все колонки в наборе данных;
 на вкладке Главная (Home) в выпадающей кнопке Удалить строки
(Remove Rows) выберите пункт Удалить пустые строки (Remove Blank
Rows).
Также стоит отметить, что если пользователь в будущем создаст в исходных данных новый столбец с именем Profit, он не будет импортирован в
Power Query, поскольку отсеется на этапе удаления всех столбцов, кроме
нужных нам. Так что выбранный нами подход может преградить путь в выгрузку не только вредным, но и полезным данным. Кстати, это самая весомая
причина загружать данные из таблиц, а не из целых листов, когда есть такая
возможность.
🍌 Примечание. Если бы у вас был абсолютный контроль над исходными дан-
ными и полная гарантия, что количество столбцов в них не изменится со временем, вы могли бы не выполнять все эти шаги. Это уместно только в случае,
если вы не можете поручиться за надежность структуры исходных данных.
Теперь пришло время загрузить все созданные запросы на рабочий лист
или в модель данных Power BI. К сожалению, поскольку мы строили все запросы в одной сессии Power Query, место назначения в Excel мы также сможем выбрать одно. Но мы хотим, чтобы наши запросы были загружены на
рабочие листы, и для этого необходимо сделать следующее:
174  Глава 6. Импортирование из файлов Excel
 нажмите на вкладке Главная (Home) на кнопку Закрыть и загрузить
в… (Close & Load To…) и выберите вариант импорта в таблицу на новом
листе;
 щелкните правой кнопкой мыши по рабочему листу Excel File и удалите
его.
В результате каждый из наших запросов будет загружен на отдельный лист,
тогда как запрос Excel File останется только в виде подключения.
🍌 Примечание. Если вы работаете в Power BI, снимите флажок Включить за-
грузку (Enable Load) для запроса Excel File, перед тем как нажать на кнопку
Закрыть и применить (Close & Apply).
Заключительные мысли о подключении
к данным Excel
Когда это возможно, мы советуем импортировать данные из таблиц Excel,
а не из именованных диапазонов или целых рабочих листов. Взаимодействовать с таблицами гораздо проще, а решение в итоге получается более
надежным и простым в плане поддержки. Конечно, бывают случаи, когда
таблицами воспользоваться нельзя, например если файлы Excel создаются
автоматически. В этих ситуациях придется пользоваться тем, что есть.
Еще один важный вопрос, на который вам предстоит ответить при разработке решения с участием файлов Excel, состоит в том, где хранить исходные данные. Должны ли запросы находиться в той же рабочей книге, где и
данные, или данные лучше хранить в отдельном файле Excel и использовать
его в качестве источника?
В большинстве примеров из этой книги мы создаем запросы в той же
книге, где хранятся данные. Это сделано по большей части для удобства восприятия информации и относительной простоты решений. В то же время в
реальной жизни такой подход часто приводит к трудностям, связанным с
распространением и совместной работой над сценариями.
Среди преимуществ хранения исходных данных в отдельном файле Excel
можно отметить следующие:
 сразу несколько пользователей смогут обновлять данные в источнике
(даже одновременно, если вы применяете принципы совместного редактирования);
 легкость адаптации решения в случае переноса данных из Excel в полноценную базу данных. В этом случае вам необходимо будет просто
переместить данные и обновить запрос для подключения к новому
источнику;
 возможность создавать несколько систем отчетности на основе одного
источника данных Excel;
Заключительные мысли о подключении к данным Excel  175
 возможность считывать данные непосредственно с рабочих листов.
Из недостатков можно выделить следующие:
 невозможность считывать данные из динамических именованных диапазонов;
 необходимость следить за указанием правильных путей к источнику
данных для разных пользователей;
 невозможность использования совместного редактирования при написании запросов в Power Query.
В конечном счете лишь ваши требования определяют архитектуру используемого вами решения. Как правило, мы предпочитаем держать исходные
данные отдельно от бизнес-логики, если нет весомых причин поступать иначе.
Глава
7
Простые техники
преобразования данных
Основной головной болью для всех без исключения аналитиков данных является то, что, откуда бы ни поступали исходные сведения, они почти никогда
не будут обладать форматом, пригодным для анализа. Так что подключиться
к данным и извлечь их из источника – это лишь полдела, куда больше времени у вас будет уходить на очистку полученной информации и приведение
ее в вид, пригодный для дальнейшей работы.
Снимаем проклятие сводных данных
Давайте рассмотрим классический для Excel сценарий, в котором пользователь начал учитывать свои продажи по дням, получив в результате файл,
приведенный на рис. 7.1.
Рис. 7.1. Ужасно сведенный набор данных
Обычно именно такие исходные данные поступают к вам, и при этом пользователь слезно просит собрать на их основании разнообразные полезные
отчеты. Первое, что приходит в голову, – построить на основании этих данных сводную таблицу, но дело в том, что эти данные уже сведены!
Это одна из главных проблем для аналитиков в отношении входных данных. Сводные таблицы были изобретены с целью преобразования плоских
данных в сводный формат, на основании которого легко можно строить отчеты. Но дело в том, что люди со временем начали мыслить именно в формате
сводных таблиц, а не табличных данных, и именно в таком виде зачастую
ведут свою первичную документацию.
178  Глава 7. Простые техники преобразования данных
Многие думают, что такие данные достаточно транспонировать, чтобы
решить все проблемы, но это позволит лишь изменить внешний вид данных,
а не приведет их в вид, пригодный для анализа при помощи сводных таблиц,
что показано на рис. 7.2.
Рис. 7.2. Транспонированные данные (слева)
против полностью рассведенных данных (справа)
До недавнего времени проблема состояла в том, что в арсенале аналитиков
не было полноценного инструмента, позволяющего легко и быстро отменить сведение (unpivot) данных в таблице. В результате приходилось тратить
долгие часы и дни на то, чтобы привести исходные данные в приемлемый
вид.
Но давайте посмотрим, как все изменилось с появлением Power Query.
Откройте файл Ch07 Examples\UnPivot.xlsx, мы будем пытаться избавиться от
сведения данных в нем.
Подготовка данных
Как видите, данные в файле сохранены в виде красиво оформленной таблицы с именем SalesData, что облегчает подключение к ним как из той же
книги, так и из внешней, и даже из Power BI.
🍌 Примечание. Для простоты восприятия мы будем реализовывать наше решение в Excel, но вы должны понимать, что концепция отмены сведения
данных в таблицах работает везде, вне зависимости от инструмента.
Давайте для начала загрузим данные в Power Query. Для этого создайте
новый запрос, используя кнопку Из таблицы/диапазона (From Table/Range)
или Из листа (From Sheet) на вкладке Данные (Data).
Откроется редактор Power Query с запросом, состоящим из двух шагов: Источник (Source) и Измененный тип (Changed Type), как показано на
рис. 7.3.
Снимаем проклятие сводных данных  179
Рис. 7.3. В запрос был автоматически добавлен шаг с изменением типов данных
При разработке любого решения необходимо думать о том, что произойдет, если в будущем исходные данные изменятся. А в случае с разворачиванием данных это становится еще более важным. Спросите себя: а что будет
в следующем месяце? Останутся в исходном файле январские колонки или
будут только данные за февраль? А как насчет следующего года? У нас снова
появятся данные за 1 января, но будет ли это по-прежнему 2014 год?
Почему мы всем этим интересуемся? Дело в том, что в шаге Измененный
тип (Changed Type) все названия колонок зашиты прямо в код, и если в будущем столбцы с такими именами исчезнут из исходных данных, вы получите
ошибку на уровне шага, в результате чего загрузка будет остановлена, и вы
вынуждены будете решать эту проблему. А если ваше решение рассчитано
более чем на один временной период, вы обязательно столкнетесь с этой неприятностью. Наш совет? Если у вас нет жесткой необходимости определять
для столбцов типы данных перед разворачиванием данных, удалите все шаги
по изменению типов, затрагивающие столбцы, которые в будущем могут исчезнуть. Это спасет вас от пары нервных срывов.
Нашей главной задачей является отменить сведение исходных данных,
но попутно мы должны избавиться от одной лишней колонки. Речь идет о
столбце Total, который можно с легкостью удалить, чтобы затем воссоздать
в сводной таблице (или матрице, если вы используете Power BI). Давайте
очистим данные и попробуем избавиться от потенциальных проблем в
будущем:
 удалите шаг Измененный тип (Changed Type);
 выделите столбец Total (на рис. 7.3 не показан) и нажмите клавишу
Delete.
В результате у нас остались только нужные колонки: Sales Category и по
одной колонке для каждого дня.
Отмена свертывания других столбцов
Пришло время применить колдовские чары Power Query в области рассведения данных. Щелкните правой кнопкой мыши по столбцу Sales Category
и выберите пункт Отменить свертывание других столбцов (Unpivot Other
Columns).
180  Глава 7. Простые техники преобразования данных
🍌 Примечание. Для этого конкретного набора данных нам необходимо, что-
бы только содержимое столбца Sales Category повторялось в каждой строке,
но бывает, что нужно перед отменой свертывания оставить сразу несколько
столбцов. Несколько столбцов в запросе можно выделить при помощи клавиш SHIFT и CTRL.
Результат, показанный на рис. 7.4, просто ошеломляет, ведь нам больше
ничего не нужно делать.
Рис. 7.4. Практическая магия отмены свертывания данных в действии
Вы верите, что все может быть так просто?
Осталось выполнить пару действий, и наши данные будут пригодны для
анализа:
 измените имена столбцов Атрибут (Attribute) и Значение (Value) на
Date и Units соответственно;
 установите для столбцов Sales Category, Date и Units типы данных Текст
(Text), Дата (Date) и Целое число (Whole Number) соответственно;
 переименуйте запрос в Sales.
🍌 Примечание. Обратите внимание, что в данном случае нет необходимости
использовать изменение типов данных с использованием локали. Поскольку
данные уже находятся в Excel, Power Query правильно интерпретирует их
вне зависимости от ваших региональных настроек.
В результате данные должны выглядеть так, как показано на рис. 7.5.
Рис. 7.5. Серьезно? А так можно было?!
Снимаем проклятие сводных данных  181
Повторное сведение данных при помощи
сводной таблицы
Теперь, когда данные очищены и подготовлены к работе, давайте именно
это с ними и сделаем – поработаем. Загрузим их и построим пару сводных
таблиц:
 загрузите запрос на новый рабочий лист;
 выделите любую ячейку в таблице и в меню Вставка (Insert) нажмите
на кнопку Сводная таблица (PivotTable);
 разместите верхний левый угол сводной таблицы на этом же листе в
ячейке F1;
 перенесите поле Sales Category в область строк, Date – в область столбцов, а Units установите в качестве значений.
Теперь давайте сделаем сводную таблицу иного вида на основе тех же
данных:
 снова выделите любую ячейку в таблице и в меню Вставка (Insert) нажмите на кнопку Сводная таблица (PivotTable);
 на этот раз разместите верхний левый угол сводной таблицы на этом
же листе в ячейке F11;
 перенесите поля Sales Category и Date в область строк, а Units установите
в качестве значений;
 щелкните правой кнопкой мыши по ячейке F12 и в подменю Развернуть/свернуть (Expand/Collapse) выберите пункт Свернуть все поле
(Collapse Entire Field).
В результате мы получим два совершенно разных представления данных,
что видно по рис. 7.6.
Рис. 7.6. Две сводные таблицы на основе одних и тех же исходных данных
182  Глава 7. Простые техники преобразования данных
Есть ли жизнь после обновления данных?
Итак, вы, довольный собой, сохраняете файл и передаете его пользователю
для дальнейшей работы. Ему останется только обновлять результаты запроса
при необходимости.
По прошествии времени пользователь вносит изменения в исходные данные и снова приходит к вам с вашим файлом. Открыв файл, вы с трудом
сдерживаетесь, понимая, что только конечный пользователь мог посчитать
сделанные изменения, показанные на рис. 7.7, приемлемыми.
Рис. 7.7. Таблица, которую принес вам пользователь
Одного беглого взгляда на таблицу достаточно, чтобы понять, что у этой
каши из данных есть следующие проблемы:
 новый день добавлен после колонки с итогами;
 была добавлена новая категория с ретроспективными данными;
 пользователь не продлил строку с итогами на новую колонку.
Страшно представить, что будет, если попытаться обновить наш запрос с
этими кривыми данными. Что ж, давайте попробуем. Откройте лист Sales и
дважды нажмите на кнопку Обновить все (Refresh All) – один раз для запроса, второй – для сводных таблиц.
Результат, показанный на рис. 7.8, может вас удивить!
Рис. 7.8. Обновленные данные не только заполнились,
но еще и заполнились правильно!
Снимаем проклятие сводных данных  183
Итак, ваш запрос легко справился со всеми «косяками», допущенными
пользователем. Все итоги на своих местах, данные отсортированы правильно, и информация за прошлые периоды обновилась!
Разница между различными типами отмены
свертывания
Если вы успели заметить, в контекстном меню в Power Query присутствует
сразу три разновидности операции отмены свертывания данных, а именно
Отменить свертывание столбцов (Unpivot Columns), Отменить свертывание других столбцов (Unpivot Other Columns) и Отменить свертывание
только для выбранных столбцов (Unpivot Only Selected Columns).
Если отталкиваться лишь от терминологии, принятой в интерфейсе, как
вы считаете, что произошло бы с данными, если бы мы:
 выделили столбцы с 1 по 7 января?
 воспользовались командой Отменить свертывание столбцов
(Unpivot Columns)?
Правильный ответ состоит в том, что мы получили бы новый шаг с именем
Несвернутые столбцы (Unpivoted Columns), который привел бы к точно
таким же результатам, как применение команды Отменить свертывание
других столбцов (Unpivot Other Columns) к столбцу Sales Category. Но будет
ли в этом случае все в порядке при добавлении в исходную таблицу новой
даты 8 января?
Как это ни странно, будет. Хотя логично было бы предположить, что в ответ
на наше действие Power Query создаст шаг с инструкцией отмены свертывания по конкретным столбцам, но это не так. Вместо этого он проанализирует
набор данных, определит, что как минимум один столбец выделен не был,
и создаст шаг с отменой свертывания других столбцов применительно к колонкам, которые выделены не были.
С одной стороны, это хорошо, поскольку не позволяет вам допустить
ошибку, создав сценарий, который сломается при добавлении в набор данных новых столбцов. Фактически при использовании обеих опций – Отменить свертывание столбцов (Unpivot Columns) и Отменить свертывание
других столбцов (Unpivot Other Columns) – Power Query будет добавлять
безопасное действие, рассчитанное на то, что для всех неназванных столбцов
будет отменено свертывание.
А что, если вы хотите, чтобы отмена свертывания выполнялась для конкретного столбца, а новые столбцы, добавленные в будущем, не затрагивала?
Именно для этого случая и припасена команда Отменить свертывание
только для выбранных столбцов (Unpivot Only Selected Columns). Вместо
использования функции Table.UnpivotOtherColumns() эта команда будет всегда применять функцию Table.Unpivot(), в которой будут жестко заданы имена
столбцов, для которых необходимо отменить свертывание.
184  Глава 7. Простые техники преобразования данных
🍌 Примечание. Мы рекомендуем всегда пользоваться командами Отменить
свертывание других столбцов и Отменить свертывание только для выбранных столбцов. Так вы не потеряете в функциональности, а взамен получите
понятные имена шагов на панели примененных шагов, что поможет вам в
будущем лучше понять логику произведенных преобразований.
Сведение столбца
Строите ли вы сводную таблицу или матрицу, в большинстве случаев от вас
потребуются данные с отмененным свертыванием. Но бывают случаи, когда
для того, чтобы привести данные к формату с отмененным свертыванием,
необходимо сначала выполнить сведение. Давайте рассмотрим пример, приведенный в файле Ch07 Examples\Pivot.xlsx, фрагмент которого показан на
рис. 7.9.
Рис. 7.9. Данные с отмененным свертыванием
Как видите, в представленных данных полностью отменено свертывание.
А что, если вам необходимо получить для мер Actual и Budget отдельные
столбцы? Здесь на помощь придет инструмент сведения (pivot) данных. Давайте посмотрим, как с ним работать:
 создайте новый запрос, используя кнопку Из таблицы/диапазона
(From Table/Range) или Из листа (From Sheet) на вкладке Данные
(Data);
 измените тип данных столбца Date на Дата (Date) с заменой текущего
шага;
 измените имя запроса на Sales.
Теперь, когда подготовительные работы закончены, можно приступать
к разделению значений Actual и Budget в столбце Measure на отдельные столбцы:
 выделите столбец Measure;
 перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Столбец сведения (Pivot Column).
Сведение столбца  185
Откроется одноименное диалоговое окно, показанное на рис. 7.10.
Рис. 7.10. Настройка вывода при сведении столбца
При выполнении операции сведения столбца важно заранее выбрать тот
столбец, данные из которого будут использованы, поскольку в диалоговом
окне эти данные указать уже не получится. В самом диалоговом окне необходимо указать столбец, данные из которого будут агрегироваться на основании значений сводимого столбца.
🙈 Предупреждение. По умолчанию в поле Столбец значений (Values Сolumn)
в диалоговом окне всегда будет выбран первый столбец в наборе данных,
и это редко будет правильным выбором. Не забудьте выбрать нужную вам
колонку!
🍌 Примечание. В области Расширенные параметры (Advanced Options) можно
также указать, какой именно тип агрегации применять к данным в создаваемых столбцах. Как и в сводных таблицах в Excel, вы обнаружите, что по
умолчанию будет выбрана функция суммирования для числовых колонок и
подсчета количества элементов – для текстовых. Но, в отличие от Excel, здесь
вы также увидите вариант Не агрегировать (Do not aggregate), который мы
будем использовать в следующих главах книги.
Для завершения операции сведения столбца выполните следующие действия:
 в выпадающем списке Столбец значений (Values Column) выберите
значение Units;
 нажмите на кнопку OK.
186  Глава 7. Простые техники преобразования данных
В результате значения из столбца Measure будут разделены на два столбца
с именами Actual и Budget, как показано на рис. 7.11.
Рис. 7.11. Отдельные колонки Actual и Budget
Теперь полученные данные могут быть преобразованы при необходимости
или загружены в место назначения.
Разделение столбцов
Еще одной распространенной задачей, особенно при импорте из плоских
файлов, является разделение (split) точек данных из одного столбца на основании определенного разделителя или шаблона. К счастью, Power Query
предлагает достаточно богатые опции в зависимости от требуемого результата.
Давайте рассмотрим пример ужасной выгрузки, с которой в реальной жизни нам ни за что не хотелось бы встретиться. Исходные данные представлены
в файле Ch07 Examples\Splitting Data.txt, и после их загрузки в редактор Power
Query при помощи коннектора Из текстового/CSV-файла (From Text/CSV)
мы увидим то, что показано на рис. 7.12.
Рис. 7.12. Фу! Как с этим всем работать?!
Разделение столбцов  187
В этом файле есть две очевидные проблемы, с которыми необходимо считаться:
 позиции для разных поваров (Grill, Prep и Line) собраны в одной колонке, данные в которой разделены при помощи слешей;
 в столбце Days перечислены разные дни недели.
Кто и зачем составил такое восхитительное расписание работы поваров,
мы не знаем, но реальность такова, что нам придется чистить эти данные.
Наша цель – создать таблицу с одной строкой для каждого дня, сохранив при
этом информацию из столбцов Start, End и Hours. Кроме того, нам необходимо будет разделить поваров по отдельным колонкам.
Разделение столбца на несколько столбцов
Начнем, пожалуй, с поваров, так как с ними, кажется, расправиться будет
проще всего. Щелкните правой кнопкой мыши по заголовку столбца Cooks и
в выпадающем меню Разделить столбец (Split Column) выберите пункт По
разделителю (By Delimiter).
Нужная нам часть открывшегося диалогового окна Разделить столбец по
разделителю (Split Column by Delimiter) показана на рис. 7.13.
Рис. 7.13. Разделение столбца на несколько по разделителю
Здесь стоит отметить несколько важных моментов.
1. Power Query сканирует содержимое поля, пытаясь угадать, какой именно символ используется в качестве разделителя, и в большинстве случаев делает это корректно. Но вы всегда можете его поправить. В нашем случае он правильно предположил, что разделителем является
прямой слеш.
2. Выпадающий список предлагает вам выбор из наиболее часто используемых разделителей, а если нужный вам символ не нашелся, вы мо-
188  Глава 7. Простые техники преобразования данных
жете ввести его в поле ниже при выбранной опции Пользовательский
(Custom). Поскольку слеш не так часто используется в качестве разделителя, как запятая или символ табуляции, Power Query указал его в
поле для ручного ввода, выбрав в списке тип Пользовательский.
3. При указании пользовательского разделителя вы не ограничены использованием одного символа. По сути, вы можете указать здесь целое
слово, если того требует ваш набор данных.
Ниже в диалоговом окне вы можете выбрать способ разделения столбца на
составляющие. Можно произвести разделение лишь раз – по самому левому
или правому разделителю, – а можно пытаться разделять столбец по каждому
вхождению разделителя. Для нашего примера подойдет последний вариант,
поскольку у нас в столбце указано сразу три повара.
После нажатия на кнопку OK и переименования полученных в результате
столбцов в Grill, Prep и Line мы получим вывод, показанный на рис. 7.14.
Рис. 7.14. Повара разделены по своим столбцам
Теперь нам нужно разобраться с данными в столбце Days, чем мы сейчас
и займемся.
Разделение столбца на строки
Нам необходимо как-то разместить дни недели на отдельных строках.
Один способ сделать это заключается в разделении дней на столбцы с последующей отменой свертывания по ним. Но лучше воспользоваться удобной
опцией встроенного инструмента разделения столбцов, чтобы сделать это
за один шаг. Щелкните правой кнопкой мыши по заголовку столбца Days и
в выпадающем меню Разделить столбец (Split Column) выберите пункт По
разделителю (By Delimiter). На этот раз нам потребуется более тонкая настройка поведения этого инструмента.
Давайте пройдем по пунктам открывшегося диалогового окна, показанного на рис. 7.15.
Разделение столбцов  189
1. Разделителем дней недели в нашей колонке является символ перевода строки, что требует указания специального символа в соответствующем поле.
К счастью, Power Query сделал это за нас.
2. Разделять столбец мы будем, как и
преж де, по каждому вхождению разделителя. Но обратите внимание, что, в
отличие от столбца с поварами, в котором каждая ячейка содержала ровно три
элемента, в колонке с днями недели их
количество может быть разным.
3. По умолчанию функция разделения
столбца по разделителю разбивает данные на столбцы. Но мы можем переопределить это поведение Power Query
Рис. 7.15. На этот раз диалоговое
и указать, что нам нужно разделить
окно появилось с раскрытой
столбец на строки. Это делается при
секцией расширенных
помощи переключателя Разделение
параметров
на (Split into).
4. Флажок Разделить с помощью специальных символов (Split using
special characters) должен быть установлен, поскольку мы используем
спецсимволы для разбиения данных на строки. Если вы знаете, что
хотите разделить данные по специальному символу – будь то символ
табуляции, возврат каретки или перевод строки, – вы можете выбрать
его в выпадающем списке ниже, что приведет к вставке соответствующей последовательности символов в текстовое поле разделителя.
🍌 Примечание. Первое, что вы должны были отметить для себя, – это то,
что диалоговое окно Разделить столбец по разделителю (Split Column by
Delimiter) на этот раз открылось с раскрытой дополнительной секцией. Причина этого в том, какой именно символ разделителя Power Query обнаружил
в обрабатываемом вами столбце. В нашем случае им оказался перевод строки (line feed) или так называемый принудительный возврат каретки (hard
return). Если бы речь шла о банальной запятой, вам пришлось бы открывать
секцию с расширенными параметрами вручную.
🙈 Предупреждение. Работать со специальными символами бывает непросто,
поскольку не всегда сразу удается понять, с каким из них точно вы имеете
дело, особенно в случае с возвратом каретки и переводом строки. В результате вам необходимо выбрать правильный символ или комбинацию символов, чтобы все работало как надо. Если Power Query не удалось самому
правильно определить символ разделителя в столбце, остается действовать
методом проб и ошибок, чтобы идентифицировать нужный вам разделитель.
190  Глава 7. Простые техники преобразования данных
По сути, единственное, что нам пришлось изменить в настройках, выбранных Power Query по умолчанию, – это метод разделения данных – со столбцов
на строки. Сделав правильный выбор, мы смогли разбить на строки дни недели, как показано на рис. 7.16, что нам и требовалось изначально.
Рис. 7.16. Мы разделили поваров по дням недели!
Если бы на этом наши требования к данным были выполнены, мы бы могли
загрузить их, тем самым завершив обработку.
Разделение на столбцы с отменой свертывания
против разделения на строки
Сейчас наши данные немного расходятся с изначальными требованиями,
и, чтобы устранить последние недостатки, давайте отменим свертывание
столбцов с поварами. Это можно сделать всего в несколько щелчков мыши:
 выделите столбец Grill, зажмите клавишу Shift и затем выделите колонку Line;
 щелкните правой кнопкой мыши по заголовку одной из выделенных
колонок и нажмите на кнопку Отменить свертывание столбцов
(Unpivot Columns);
 переименуйте столбец Атрибут (Attribute) в Cook;
 переименуйте столбец Значение (Values) в Employee.
Результат должен выглядеть так, как показано на рис. 7.17.
Может, можно было сэкономить несколько щелчков мыши в процессе этого
преобразования данных? Кто-то может сказать, что вместо разделения поваров на столбцы с последующим их переименованием, отменой свертывания
и повторным переименованием можно было просто преобразовать исходный столбец в строки.
Да, мы могли это сделать, но в процессе мы бы недосчитались одной важной информационной составляющей, а именно специализации повара. Дело
в том, что эти сведения у нас содержатся только в названии столбца, а не в
его содержимом, что видно по рис. 7.18.
Фильтрация и сортировка  191
Рис. 7.17. Набор данных после отмены свертывания
Рис. 7.18. То, что Дон занимается грилем,
нам известно только из заголовка столбца
Тогда как разделение столбца Cook на строки привело бы к построчному
выделению всех поваров в исходных данных, специализация этих самых
поваров была бы утеряна, поскольку содержалась только в заголовке. Таким
образом, предварительное разделение данных на столбцы здесь было крайне
важно, ведь это позволило нам выделить специализацию повара в заголовки,
которые после отмены свертывания перекочевали в данные.
🍌 Примечание. Конечно, шаги, приведенные выше, предполагают, что повара
в столбце указаны в строго определенном порядке. Если это не так, то нам
потребуется иной подход. Скорее всего, мы бы разделили поваров на строки,
после чего извлекали бы их специализации путем объединения с другой
таблицей, о чем мы будем говорить в главе 10.
Приятно то, что использование Power Query позволяет решать одну и ту
же задачу совершенно разными способами. Иногда нам действительно понадобится выполнять дополнительные действия, чтобы итоговые данные
полностью отвечали заявленным требованиям.
Фильтрация и сортировка
В большинстве своем операции фильтрации (filtering) должны быть понятны
тем, кто работает с Power Query, поскольку они примерно в таком виде присутствуют в Excel и других офисных программах. В данном разделе мы рас-
192  Глава 7. Простые техники преобразования данных
смотрим базовые вещи и некоторые скрытые подводные камни, характерные
для операций фильтрации и сортировки (sorting) в Power Query.
Для начала импортируем данные из файла Ch07 Examples\FilterSort.csv.
Поскольку в этом файле присутствуют даты и числовые значения в американском формате, нам необходимо убедиться в том, что для столбцов Date
и Sales типы данных будут определены при помощи локали. Таким образом,
для выполнения операции импортирования вам необходимо проделать следующие действия:
 создайте новый запрос с помощью выбора Из текстового/CSV-файла
(From Text/CSV);
 удалите созданный шаг Измененный тип (Changed Type);
 измените тип данных поля Date с использованием локали. Для этого щелкните по его заголовку правой кнопкой мыши, в выпадающем
меню Тип изменения (Change type) выберите пункт Используя локаль (Using Locale) и в открывшемся диалоговом окне в качестве типа
данных колонки установите Дата (Date), а в качестве языкового стандарта – Английский (США);
 аналогичным образом измените тип данных для столбца Sales, выбрав
локализованный тип Валюта (Currency);
 измените тип данных столбца Quantity на Целое число (Whole Number).
Результат импорта с измененными типами данных должен выглядеть так,
как показано на рис. 7.19.
Рис. 7.19. Импорт файла FilterSort.csv
На рисунке показаны лишь первые 11 строк набора данных, а в целом
он содержит информацию за период с 1 января 2020 года до 31 мая 2026-го
в числе 53 500 строк. Нам так много данных для работы не нужно.
Фильтрация значений
Операция наложения фильтра на значения выполняется довольно просто.
Вам достаточно щелкнуть мышью по кнопке со стрелкой вниз в заголовке
столбца, снять флажки со значений, которые вы не хотите видеть в итоговом
Фильтрация и сортировка  193
запросе, или сначала снять выделение со
всех элементов, а затем отметить нужные.
Также вы можете воспользоваться полем
для поиска, в котором допустимо вводить
часть искомых значений и осуществлять
поиск по вхождению, как показано на
рис. 7.20.
Таким образом выполнять поиск очень
удобно, поскольку можно очень быстро
ограничить список до нескольких значений, после чего снять флажок Выделить
все результаты поиска (Select All) и отметить нужные вам элементы вручную.
🍌 Примечание. Если применить фильтр,
показанный на рис. 7.20, Power Query добавит в список примененных шагов новый шаг, ограничивающий список вхождениями подстроки «ia».
Рис. 7.20. Фильтрация
столбца State по вхождению
строки «ia»
🙈 Предупреждение. Обратите внимание, что заполнение строки поиска при-
ведет к применению фильтра на все значения, содержащие введенный шаблон. Специальные символы и математические операторы в строке поиска
недопустимы.
Вы можете столкнуться с проблемой при фильтрации наборов данных,
содержащих более тысячи значений в столбце. Поскольку Power Query по
умолчанию сканирует ограниченный набор данных, вы время от времени
будете видеть сообщение о том, что список неполный, с возможностью загрузить больше данных. При этом Power Query будет загружать информацию
до тех пор, пока не дойдет до границы в 1000 уникальных значений в столбце,
поскольку больше элементов просто не может быть отражено в выпадающем
списке. В этом случае вы увидите сообщение о достигнутом пределе, показанное на рис. 7.21.
Рис. 7.21. В столбце Sales находится больше 1000 уникальных значений
Сама проблема заключается в том, что вы не сможете использовать этот
метод фильтрации, если нужное вам значение находится за пределами тысячи уникальных элементов.
194  Глава 7. Простые техники преобразования данных
Если это ваш случай, не отчаивайтесь. Вам просто придется создать фильтр
вручную. В наших данных такой проблемы нет, но давайте представим, что
она есть. Создайте фильтр вручную следующим образом: нажмите на кнопку фильтрации в столбце State и в выпадающем меню Текстовые фильтры
(Text Filters) выберите пункт Содержит (Contains).
Откроется диалоговое окно Фильтрация строк (Filter Rows), показанное
на рис. 7.22, с помощью которого вы сможете создать фильтр вручную, даже
если нужные вам данные не присутствуют на панели фильтрации.
Рис. 7.22. Создание фильтра вхождения вручную
Этот инструмент часто приходит на помощь, если данные для отбора не
входят в список фильтрации или если вам необходимо создать более сложное условие с употреблением логических И и ИЛИ. А после переключения
в режим Подробнее (Advanced) диалоговое окно становится еще богаче, что
видно по рис. 7.23.
Рис. 7.23. Расширенный вид диалогового окна Фильтрация строк
Если в режиме Базовый (Basic) фильтры могут применяться только к выбранному столбцу, то в расширенном режиме – сразу к нескольким столбцам.
Фильтрация и сортировка  195
К тому же вы можете добавлять новые слои фильтров при помощи кнопки
Добавить предложение (Add Clause) и сочетать условия по своему усмотрению. Но имейте в виду, что фильтры И являются аддитивными, а фильтры
ИЛИ – альтернативными.
🍌 Примечание. Если вы хотите удалить или изменить порядок следования условий в фильтре, нажмите на кнопку с троеточием (...), которая появляется при
наведении мышью на условие.
Рис. 7.24. Результат применения фильтра на вхождение подстроки «ia»
в столбец State и с суммой продажи больше 1000
🙈 Предупреждение. При установке фильтра на несколько столбцов будет создан единственный шаг, при выборе которого иконка с фильтром будет появляться только у первого выбранного в фильтре столбца. Если вам необходимо тщательно отслеживать результаты применения каждого фильтра, вы
можете добавлять фильтры по отдельности.
Применение контекстных фильтров
На первый взгляд, выпадающие панели фильтрации ничем не отличаются
друг от друга, в каком бы столбце они ни были вызваны. Количество пунктов
одинаковое, и похожие списки с флажками в нижней части. Но если присмотреться, можно заметить, что выпадающее меню непосредственно над
строкой поиска меняет свое имя в зависимости от типа данных выбранного столбца и в соответствии с этим типом предлагает различные варианты
фильтрации данных.
Например:
 для текстового поля вы увидите выпадающее меню Текстовые фильтры (Text Filters) с вариантами фильтрации Равно (Equals), Начинается
с (Begins With), Заканчивается на (Ends With), Содержит (Contains),
а также аналогами с их отрицанием;
196  Глава 7. Простые техники преобразования данных
 для числового поля в меню Числовые фильтры (Number Filters) будут
находиться варианты Равно (Equals), Больше (Greater Than), Больше
или равно (Greater Than or Equal To), Меньше (Less Than), Меньше
или равно (Less Than or Equal To) и Между (Between).
Хотя каждый тип данных обладает своим набором вариантов для фильтрации, мы хотим остановиться на одном из наиболее важных и объемных – на
датах.
Список вариантов фильтра для дат, представленный на рис. 7.25, выглядит
пугающе большим, но большинство пунктов в нем понятны без объяснений.
Например:
 выбор января ожидаемо ограничит
список строками, относящимися к
первому месяцу года. Конечно, если
у вас в таблице собраны данные за
шесть лет, вы получите все записи,
соответствующие январю, вне зависимости от года, хотите вы этого или
нет;
 выбор пункта Является самой ранней (Is Earliest) оставит в запросе
только те строки, которые соответствуют самой ранней дате в отфильтрованном столбце;
 использование варианта Между
(Between) позволит жестко задать
начальную и конечную даты интервала.
Рис. 7.25. Как много всего!
Стоит отдельно отметить варианты фильтрации Этот (This), Прошлый
(Last) и Следующий (Next), показанные на рис. 7.25, применительно к конкретным временным интервалам. В отличие от других фильтров, основывающихся на данных, эти фильтры относятся к текущему значению даты и
времени, установленному на компьютере.
Допустим, сегодня 1 декабря 2021 года, и вы в своем решении настроили
фильтр, указывающий на Этот год (This Year) (пункт находится в подменю
Год (Year)).
5 января 2022 года, когда вы вернулись в офис после новогодних каникул, вы открываете свой отчет, чтобы подбить цифры за прошедший год,
и видите, что ваши продажи вдруг упали с 6 млн долларов до 10 тыс. Что
случилось? Как вы уже, наверное, догадались, системная дата на компьютере изменилась, и под текущим годом в отчете теперь подразумевается
не 2021-й, а 2022-й.
Кроме того, в отличие от Excel, где можно в фильтре столбца с датой выбрать конкретный год, месяц или день, даже если в наборе данных присутствует единственный столбец с датами, в Power Query такого иерархического
Фильтрация и сортировка  197
списка в вашем распоряжении не будет. Кроме того, в выпадающем подменю
Год (Year) вы не сможете выбрать конкретный номер года. А как же тогда
выбрать данные за 2021 год? Единственный вариант – использовать фильтр
Между (Between) следующим образом:
 щелкните по кнопке фильтрации в заголовке столбца Date и в выпадающем подменю Фильтры по дате (Date Filters) выберите пункт Между
(Between);
 установите значения полей в открывшемся диалоговом окне, как показано на рис. 7.26.
Рис. 7.26. Фильтрация данных за 2021 год
🍌 Примечание. В качестве альтернативы вы могли бы добавить в запрос стол-
бец с годом и фильтровать его по значению. Для этого выделите столбец
Date, на вкладке Добавление столбца (Add Column) нажмите на выпадающую кнопку Дата (Date) и в подменю Год (Year) выберите пункт Год (Year),
после чего отфильтруйте новый столбец по числовому значению 2021.
Единственным недостатком такого метода установки фильтров является
то, что он не будет динамическим. Таким образом, когда вам необходимо
будет установить фильтр на 2022 год, вам придется редактировать запрос
вручную.
Сортировка данных
Предпоследняя техника, которую мы рассмотрим в этой главе, касается
сортировки данных. Продолжая работу с предыдущим примером, мы хотим
упорядочить данные в запросе по столбцу State. Затем, в качестве второго
уровня сортировки, мы расположим в порядке возрастания даты.
Чтобы это сделать, выполните следующие несложные действия:
198  Глава 7. Простые техники преобразования данных
 щелкните по кнопке Фильтрации в заголовке столбца State и выберите
пункт Сортировка по возрастанию (Sort Ascending);
 то же самое сделайте с колонкой Date.
Результат выполнения сортировки показан на рис. 7.27.
Рис. 7.27. Сперва Power Query упорядочил список по полю State, а затем – по Date
Как видите, Power Query, в отличие от Excel, применяет последовательную
сортировку по умолчанию. Более того, рядом с кнопкой фильтрации в заголовках столбцов отображается порядковый номер примененной сортировки.
🍌 Примечание. При использовании темного режима (Dark Mode) в Excel иконки порядка сортировки едва видимы, но они есть.
Хотя сортировка данных бывает очень полезна и позволяет в более удобном виде просматривать исходные данные, необходимо понимать, что она
негативно сказывается на ресурсах. Вы должны спросить себя, действительно
ли вам так нужно, чтобы данные были упорядочены. Конечно, иногда это
просто необходимо для правильного представления данных. Но если данные
будут использоваться в сводной таблице модели данных в Excel или Power
BI, сортировка вам не понадобится, поскольку элементы визуализации позаботятся о ней за вас.
Группирование данных
Еще одной сложностью при работе с данными является их невероятно большой объем. Возьмите для примера файл из предыдущего примера. Он содержит 53 513 строк транзакционных данных за семь лет по 48 штатам. А что,
если нам нужна информация только по полям Total Sales и Total Units по
годам?
Конечно, мы можем загрузить все исходные данные и скормить их сводной
таблице или визуальному элементу матрица, но, возможно, нам никогда не
понадобится опускаться на более низкие уровни детализации. Так нужны ли
нам все данные?
Группирование данных  199
К счастью, Power Query располагает инструментом группировки (grouping)
данных, позволяющим объединить информацию еще на этапе ее преобразования и загрузить на нужном нам уровне гранулярности (granularity). Это
может быть очень полезно с целью уменьшения размера файла, и нам не
придется загружать данные, которые нам просто не нужны.
Давайте используем тот же файл с исходными данными, что и в предыдущем примере (Ch07 Examples\FilterSort.csv). Откройте новую рабочую книгу
Excel или файл Power BI и выполните следующие действия:
 создайте новый запрос с помощью выбора Из текстового/CSV-файла
(From Text/CSV);
 удалите созданный шаг Измененный тип (Changed Type);
 измените тип данных поля Date с использованием локали. Для этого щелкните по его заголовку правой кнопкой мыши, в выпадающем
меню Тип изменения (Change type) выберите пункт Используя локаль (Using Locale) и в открывшемся диалоговом окне в качестве типа
данных колонки установите Дата (Date), а в качестве языкового стандарта – Английский (США);
 аналогичным образом измените тип данных для столбца Sales, выбрав
локализованный тип Валюта (Currency);
 измените тип данных столбца Quantity на Целое число (Whole Number).
Результат импорта показан на рис. 7.28.
Рис. 7.28. Импорт файла FilterSort.csv
В данном случае мы не хотим анализировать данные на уровне дней и
месяцев, так что можно преобразовать столбец Date для отображения годов
следующим образом:
 выделите столбец Date, на вкладке Преобразование (Transform) нажмите на выпадающую кнопку Дата (Date) и в подменю Год (Year)
выберите пункт Год (Year).
Уже лучше, но у нас по-прежнему больше 53 тысяч записей в таблице.
Продолжим:
Powered by TCPDF (www.tcpdf.org)
200  Глава 7. Простые техники преобразования данных
 снова выделите столбец Date и на вкладке Преобразование (Transform)
нажмите на кнопку Группировать по (Group By);
 установите переключатель в положение Подробнее (Advanced).
Откроется диалоговое окно Группировать по (Group By), показанное на
рис. 7.29.
Рис. 7.29. Диалоговое окно группировки в расширенном режиме
🍌 Примечание. Причина того, почему мы сразу перешли в режим Подробнее,
состоит в том, что только в этом режиме можно добавлять новые группирования и агрегирования.
Как видите, столбец, который мы предварительно выделили (Date), был
помещен в область группирования. Если бы нам было нужно, мы могли бы
изменить существующий или добавить новые уровни группировки. В нашем
случае группировки по году вполне достаточно.
🍌 Примечание. При наведении мышью на поля в диалоговом окне справа от
них будет появляться кнопка с троеточием (...), с помощью которой можно
удалить уровень группировки или агрегации либо изменить порядок следования элементов.
Теперь, когда мы настроили правила группирования данных, необходимо
подумать о том, как будет правильнее их агрегировать. По умолчанию Power
Query предлагает нам агрегацию в виде подсчета количества строк в таблице.
Это не совсем то, что нам нужно, так что давайте изменим настройки таким образом, чтобы выполнялась группировка по полям Total Sales $ и Total
Quantity в разрезе годов. Для этого сделайте следующие настройки в секции
агрегирования:
Группирование данных  201
 введите в поле Имя нового столбца (New column name) вместо Количество (Count) Total Sales $;
 в выпадающем списке Операция (Operation) поменяйте Считать
строки (Count) на Сумма (Sum);
 в списке Столбец (Column) поменяйте Date на Sales;
 нажмите на кнопку Добавление агрегирования (Add Aggregation);
 настройте его так, как показано на рис. 7.30, чтобы возвращался столбец Total Quantity с расчетом суммы по полю Quantity.
Рис. 7.30. Группировка данных по полю Date с агрегированием по Sales и Quantity
После нажатия на кнопку OK данные будут агрегированы, в результате
чего в таблице останется всего семь строк, что видно по рис. 7.31.
Рис. 7.31. По одной строке для каждого года
Все очень здорово, но нам нужно сделать несколько замечаний по поводу
выполненной нами операции.
1. Столбцы из исходного набора данных, которые не были включены в
секции группирования и агрегирования (в нашем случае это State),
оказались удалены из итогового набора данных. Нет необходимости
удалять их вручную перед выполнением группирования.
202  Глава 7. Простые техники преобразования данных
2. Тогда как колонки, используемые в агрегировании, могут быть определены в диалоговом окне, уровни группировки здесь переименованы
быть не могут. Их можно переименовать до или после выполнения
операции группирования.
3. В данном примере мы использовали только функцию суммирования,
тогда как полный список функций агрегирования включает в себя,
помимо суммы, следующие варианты: Среднее (Average), Медиана
(Median), Мин. (Min), Макс. (Max), а также Считать строки (Count
Rows) и Количество уникальных строк (Count Distinct Rows).
🍌 Примечание. Есть и еще один вариант операции агрегирования, доступный в
диалоговом окне группирования, и это Все строки (All Rows). Эта загадочная
опция будет подробно описана в главе 13.
Итак, пришло время произвести заключительные действия с обрабатываемым набором данных и загрузить его в место назначения. Для этого выполните следующие действия:
 переименуйте столбец Date в Year;
 переименуйте запрос в Grouping;
 перейдите на вкладку Главная (Home) и нажмите на кнопку Закрыть
и загрузить (Close & Load) для импорта данных.
Одна из самых распространенных ошибок бизнес-аналитиков заключается в загрузке чрезмерного объема данных, большая часть которых им просто
не нужна. При импорте данных всегда задавайтесь вопросом о том, все ли
столбцы и строки, которые вы загружаете, вам действительно необходимы
для создания итогового запроса. Помните, что вы всегда можете вернуться
к шагу с группированием и изменить настройки, если поймете, что излишне
ограничили данные. Задумайтесь об этом еще раз – вы будете благодарить
нас за то, что не стали тянуть за собой лишние данные, – в конце концов, это
позволит вам сделать свое решение более надежным и эффективным.
Глава
8
Добавление данных
С чем аналитикам данных приходится сталкиваться постоянно, так это с
добавлением (appending) наборов данных друг к другу. При этом исходные
наборы данных могут находиться как в одном файле Excel, так и в разных –
задача остается неизменной и заключается в том, чтобы объединить данные
по вертикали в одну таблицу.
Распространенная задача, на примере которой можно продемонстрировать
этот инструмент, состоит в ежемесячном извлечении информации из центрального хранилища данных и ее объединении. Допустим, в феврале кто-то
извлек данные за январь и отправил их аналитику. Месяц спустя появились
данные за февраль, и их также направили аналитику для объединения с предыдущими сведениями. И этот цикл продолжается на протяжении всего года.
Обычно в классическом Excel подобная задача сводится к следующей последовательности действий:




импорт и приведение в табличный вид данных за январь;
преобразование данных в таблицу;
построение отчета на основании таблицы;
сохранение файла.
И дальше каждый месяц:
 импорт и приведение в табличный вид очередной порции данных;
 копирование данных и вставка в конец готовой таблицы;
 обновление отчетов и визуальных элементов.
Хотя этот процесс весьма рабочий, трудно назвать его интересным или захватывающим, к тому же он сопряжен с целым рядом проблем. В этой главе
мы не будем разбирать ошибки, которые допускают пользователи при преобразовании данных, а также покажем, как при помощи Power Query можно
легко и просто объединить по вертикали два и более наборов данных без необходимости выполнять операции копирования и вставки данных вручную.
Базовые операции по добавлению данных
В папке Ch08 Examples вы обнаружите три файла CSV: Jan 2008.csv, Feb 2008.
csv и Mar 2008.csv. Давайте загрузим их в Power Query и объединим. Для этого
выполните следующие действия:
204  Глава 8. Добавление данных
 создайте новый запрос с помощью выбора Из текстового/CSV-файла
(From Text/CSV);
 откройте файл Jan 2008.csv и нажмите на кнопку Преобразовать данные (Transform Data).
Файл будет открыт в редакторе Power Query. Также автоматически будут
выполнены следующие операции:
 заголовки будут повышены, так что столбцы получат имена Date,
Account, Dept и Amount;
 типы данных будут установлены как Дата (Date), Целое число (Whole
Number), Целое число (Whole Number) и Десятичное число (Decimal
Value) соответственно.
Для большей надежности мы удалим шаг с изменением типов данных и
создадим его вручную с использованием локали:
 удалите шаг Измененный тип (Changed Type);
 измените тип данных поля Date с использованием локали. Чтобы это
сделать, щелкните по заголовку столбца правой кнопкой мыши, в выпадающем меню Тип изменения (Change type) выберите пункт Используя локаль (Using Locale) и в открывшемся диалоговом окне в
качестве типа данных колонки установите Дата (Date), а в качестве
языкового стандарта – Английский (США);
 аналогичным образом измените тип данных для столбца Amount, выбрав вместо даты локализованный тип Валюта (Currency);
 измените тип данных столбца Account на Целое число (Whole Number);
 измените тип данных столбца Dept на Целое число (Whole Number).
В данный момент запрос будет выглядеть так, как показано на рис. 8.1.
Рис. 8.1. Данные по январю перед загрузкой
Поскольку в наши планы не входит формирование отчета только по январю, мы загрузим этот запрос в виде подключения для дальнейшего добавления данных.
Базовые операции по добавлению данных  205
🍌 Примечание. Помните, что в Power BI вы можете щелкнуть правой кнопкой
мыши по запросу и в контекстном меню снять флажок Включить загрузку
(Enable Load), тогда как в Excel вам необходимо воспользоваться опцией
Только создать подключение (Only Create Connection) при выборе действия
Закрыть и загрузить в… (Close & Load To…).
Теперь нужно повторить эти действия с файлами Feb 2008.csv и Mar 2008.
csv. В процессе импорта должны быть использованы те же шаги, и в результате у нас появятся три запроса, загруженных в виде подключения:
 Jan 2008;
 Feb 2008;
 Mar 2008.
По окончании этой операции все три запроса должны отображаться на панели Запросы и подключения (Queries & Connections) в Excel или на панели
навигатора в редакторе Power Query, как показано на рис. 8.2.
Рис. 8.2. Панель Запросы и подключения в Excel (слева)
и панель навигатора Power Query (справа)
Добавление двух таблиц
Теперь нам необходимо объединить данные из трех полученных запросов в единую таблицу. Один из способов сделать это – щелкнуть правой
кнопкой мыши по запросу на панели Запросы и подключения (Queries &
Connections) в Excel и выбрать пункт Добавить (Append Queries). Это приведет к открытию диалогового окна Добавление (Append), показанного на
рис. 8.3.
Хотя это наиболее простой и очевидный способ для добавления наборов
данных, мы крайне не рекомендуем им пользоваться. Да, с его помощью
можно объединить два запроса (и даже объединить запрос сам с собой при
необходимости). Можно и переключиться в режим добавления трех таблиц
и более. Но есть у этого способа и несколько минусов, самыми очевидными
из которых являются следующие.
206  Глава 8. Добавление данных
1. В Power BI нет панели Запросы и подключения, а всегда лучше учиться применять наиболее универсальные инструменты.
2. В результате добавления данных будет создан запрос с именем Добавить1 (Append 1), в котором объединение данных будет сведено в один
шаг, что затруднит поддержку данного решения.
Вместо этого способа добавления запросов мы рекомендовали бы вам
освоить метод, при котором создается ссылка на первую таблицу, а затем
выполняются операции добавления данных внутри редактора Power Query.
Главным отличием этого подхода является то, что он будет работать везде,
где есть Power Query, а для каждой присоединенной таблицы будет создаваться отдельный шаг на панели примененных шагов. Это позволит вам
в дальнейшем легче работать с запросом без необходимости разбираться
с несчетным количеством запросов, собранных в одном шаге Источник
(Source).
Рис. 8.3. Диалоговое окно Добавление
Мы используем запрос Jan 2008 в качестве базового и попробуем добавить
к нему запрос Feb 2008. Для этого выполните следующие действия:
 перейдите в режим редактирования любого из ваших запросов и разверните слева панель навигатора Power Query;
 щелкните правой кнопкой мыши по запросу Jan 2008 и выберите пункт
Ссылка (Reference);
 переименуйте запрос в Transactions;
 перейдите на вкладку Главная (Home) и нажмите на кнопку Добавить
запросы (Append Queries);
 выберите в выпадающем списке запрос Feb 2008 и нажмите на кнопку
OK.
На данном этапе результат должен выглядеть так, как показано на
рис. 8.4.
Базовые операции по добавлению данных  207
Рис. 8.4. Итог добавления запроса Feb 2008 к Jan 2008
🍌 Примечание. Если бы вы выполнили операцию добавления непосредствен-
но из интерфейса Excel (или выбрали бы запрос Jan 2008 и нажали на кнопку
Добавить запросы в новый (Append As New)), в новом запросе у вас появился
бы лишь один шаг Источник (Source). И хотя шагов будет меньше, чтобы понять, что на самом деле произошло, вам необходимо будет открыть шаг Источник (Source) и разбираться в коде запроса. В нашем же случае у вас будет
шаг Источник (Source) со ссылкой на январские данные и шаг Добавленный
запрос (Appended Query) с присоединенными данными по февралю.
Возможно, вы не удержитесь от соблазна прокрутить получившийся запрос вниз, чтобы убедиться,
Рис. 8.5. Power Query
что все ваши данные на месте. К сожалению, это не
показывает, сколько строк
сработает, поскольку Power Query по умолчанию не
отображается в данный
загружает в окно предварительного просмотра все
момент
доступные данные в запросе, а показывает лишь
их часть. Количество отображаемых строк может
варьироваться в зависимости от добавляемых столбцов, а информацию о
строках и столбцах можно увидеть в нижней левой части окна, как показано
на рис. 8.5.
Разумеется, у вас может возникнуть резонный вопрос: если я не вижу всех данных, как мне узнать, что
все сработало как надо? Ответ на этот вопрос кроется
в финализации запроса. Давайте загрузим данные на
лист Excel и посмотрим, что произойдет.
🍌 Примечание. Чтобы увидеть количество загружен-
ных записей в Power BI, перейдите на вкладку Данные (Data) и выберите таблицу в списке Поля (Fields).
Количество строк в таблице будет показано в нижней левой части окна.
С целью дополнительной проверки правильности загруженных данных можно собрать их в сводную таблицу. Для этого выполните следующие действия:
Рис. 8.6. На
панели Запросы
и подключения
показана
информация о 3887
загруженных строках
208  Глава 8. Добавление данных
 выделите любую ячейку в таблице Transactions и на вкладке Вставка
(Insert) нажмите на кнопку Сводная таблица (PivotTable);
 поместите левый верхний угол сводной таблицы в ячейку F2 на текущем рабочем листе;
 перенесите поле Amount в область значений;
 перенесите поле Date в область строк;
 щелкните правой кнопкой мыши по ячейке F3, выберите пункт Группировать (Group), в открывшемся диалоговом окне выберите только
вариант Месяцы (Months) и нажмите на кнопку OK.
По сводной таблице, показанной на рис. 8.7, вы поймете, что все ваши
данные по двум месяцам были корректно сведены воедино.
Рис. 8.7. Транзакции по январю и февралю собраны в одной сводной таблице
Добавление дополнительных таблиц
Теперь вам наверняка захочется добавить в нашу таблицу данные за март.
И на этом этапе пользователи Excel, которые предпочли воспользоваться
инструментом добавления данных на панели Запросы и подключения,
потерпят полный крах. Первое, что им захочется сделать, – это щелкнуть
правой кнопкой мыши по запросу Transactions и выбрать пункт Добавить
(Append). Проблема в том, что в этом случае будет создан новый запрос, а не
добавлен шаг к запросу Transactions. А поскольку сводная таблица базируется
на таблице Transactions, нам необходимо именно добавить шаг в соответствующий запрос, а не создавать новый.
Чтобы добавить мартовские данные в запрос Transactions, нужно его отредактировать. На данном этапе нам придется сделать выбор: изменить
существующий шаг Добавленный запрос (Appended Query) или добавить
новый. Ответ зависит от того, как много данных вы планируете добавлять
к своему запросу в течение времени, а также от того, насколько вам важно,
чтобы с запросом было удобно работать в будущем.
Скажем, если вы рассчитываете на 12 добавлений и не хотите, чтобы в запросе было слишком много шагов, вы можете пойти по такому пути:
 нажмите на кнопку с изображением шестеренки справа от шага Добавленный запрос (Appended Query) и в открывшемся диалоговом окне
установите переключатель в положение Три таблицы или больше
(Three or more Tables);
Базовые операции по добавлению данных  209
 выберите все таблицы, которые хотите объединить с текущей, и нажмите на кнопку Добавить (Add), как показано на рис. 8.8.
Рис. 8.8. Добавление нескольких таблиц на одном шаге
В противном случае, если вы желаете, чтобы на каждом шаге добавлялся
только один запрос, вам придется выполнять приведенные ниже действия
каждый раз при добавлении запроса к источнику данных:
 перейдите в режим редактирования запроса Transactions;
 на вкладке Главная (Home) нажмите на кнопку Добавить запросы
(Append Queries);
 выберите в выпадающем списке запрос, который хотите добавить, и
нажмите на кнопку OK, как показано на рис. 8.9.
Рис. 8.9. Добавление по одному запросу за раз для создания отдельных шагов
210  Глава 8. Добавление данных
Если вы хотите, чтобы поддерживать
ваши запросы было еще легче, вы можете
щелкнуть правой кнопкой мыши по шагу
добавления и выбрать пункт Свойства
(Properties). В открывшемся окне вы можете
для большего удобства изменить имя шага
и снабдить шаг описанием, которое будет высвечиваться при наведении мышью
на него, как показано на рис. 8.10.
Рис. 8.10. Шаги с измененными
именами и всплывающими
подсказками
🙈 Предупреждение. Вы можете таким образом переименовать любые шаги,
кроме шага Источник (Source). Дать другое имя шагу Источник можно только
в коде на языке M.
🍌 Примечание. Разработчики в отношении к именованию шагов в Power Query
делятся на два лагеря. Бывает трудно удержаться от соблазна дать шагу более понятное имя, чем в оригинале. Но профессионалам в результате может
потребоваться больше времени, чтобы разобраться, что на самом деле происходит на шаге с нестандартным именем. Наш совет? Учитесь ассоциировать имена шагов, принятые по умолчанию, с выполняемыми действиями, но
используйте описания для выражения своих намерений.
Вне зависимости от того, каким способом вы решили воспользоваться для
добавления данных за март, пришло время загрузить полученный результат
на лист и проверить, все ли сработало.
И здесь мы снова встречаемся с уже известной нам проблемой Power Query
при загрузке данных в Excel. Как видно на рис. 8.11, в запросе Transactions (а
значит, и в таблице Excel) содержится 6084 строки, представляющие данные
из трех файлов. При этом внешний вид сводной таблицы не изменился.
Рис. 8.11. Таблица с транзакциями изменилась, а сводная таблица – нет
Объединение запросов с разными заголовками  211
Это не особенно большая проблема, скорее легкое неудобство, о котором
необходимо помнить. Если вы загружаете данные в таблицу Excel, на основании которой строится сводная таблица, вам нужно вручную обновить
сводную таблицу для актуализации информации. Щелкните правой кнопкой
мыши по сводной таблице и выберите пункт Обновить (Refresh). Результат
обновления показан на рис. 8.12.
Рис. 8.12. Теперь в сводной таблице содержатся данные с января по март
🍌 Примечание. Помните: если данные загружаются в модель данных Excel или
Power BI, одной операции обновления будет достаточно для актуализации
источника данных и любых сводных таблиц и визуальных элементов.
Очевидно, что ежемесячное редактирование файла с добавлением и изменением источника данных и последующим добавлением данных в запрос
Transactions очень быстро наскучит вам. В главе 9 мы посмотрим, как можно
упростить этот процесс. Но добавление данных с ручной корректировкой
процесса является важным навыком на пути освоения Power Query.
Объединение запросов с разными
заголовками
Если заголовки столбцов в объединяемых запросах ничем не отличаются,
процесс добавления данных пройдет так, как вы и ожидаете. А что делать,
если колонки называются по-разному?
В случае, представленном на рис. 8.13, столбец Date в мартовской таблице
был переименован в TranDate, а аналитик этого не заметил. Объединение
данных из файлов Jan 2008 и Feb 2008 прошло отлично, но когда он добавил
информацию за март, что-то пошло не так.
212  Глава 8. Добавление данных
Рис. 8.13. Откуда Power Query узнает, что данные из столбца TranDate
должны быть добавлены к столбцу Date?
При добавлении двух таблиц Power Query сначала загружает данные из
первого запроса. После этого он сканирует заголовки второго и последующих
запросов. Для отсутствующих заголовков создаются новые столбцы. Затем
столбцы заполняются данными, а в ячейки с отсутствующими значениями
вставляются значения null.
В случае с показанным выше сценарием созданный столбец с именем
TranDate (впервые появившийся в файле с мартовскими данными) был заполнен значениями null в строках за январь и февраль, поскольку в файлах
за эти месяцы отсутствовала колонка с таким именем.
В то же время в файле за март нет столбца Date – вместо него появилась
колонка TranDate. Именно поэтому при добавлении данных за март этот
столбец был заполнен значениями null.
Чтобы исправить эту ситуацию, необходимо сделать следующее:
 перейдите в режим редактирования запроса Mar 2008 и переименуйте
столбец TranDate в Date;
 отредактируйте запрос Transactions;
 перейдите на вкладку Главная (Home) и нажмите на кнопку Обновить
предварительный просмотр (Refresh Preview).
Честно говоря, окно предварительного просмотра должно обновляться
автоматически, но приведенные выше шаги позволяют это сделать принудительно.
🍌 Примечание. Хотите проверить? Отредактируйте один из месячных запро-
сов, переименовав один из столбцов. Затем вернитесь в запрос Transactions –
и увидите новый столбец.
Добавление таблиц и диапазонов в текущем файле  213
Добавление таблиц и диапазонов
в текущем файле
Хотя извлечение и добавление данных из внешних файлов является довольно распространенной задачей в мире аналитики, пользователям Excel зачастую приходится решать задачу объединения данных внутри одной рабочей
книги.
При добавлении небольшого количества таблиц вы можете воспользоваться алгоритмом, который мы уже обсудили, а именно:
 создать промежуточные (в режиме подключения) запросы для каждого
источника данных;
 создать ссылку на один запрос;
 добавить остальные запросы.
Но что делать, если вы хотите построить систему, в которой Excel будет
выступать в роли псевдобазы данных, в которой пользователи будут ежемесячно создавать таблицы и хранить транзакции по месяцам в той же рабочей
книге? Вы хотели бы, чтобы вам приходилось вручную править запрос для
добавления новых таблиц по месяцам? Разумеется, нет. Можно ли настроить
процесс так, чтобы новые таблицы автоматически добавлялись при обновлении?
Ответ на этот вопрос будет положительным с той оговоркой, что вам придется воспользоваться функцией Excel.CurrentWorkbook(), которую мы уже
применяли в главе 6 для чтения данных из динамических именованных
диапазонов. Давайте рассмотрим конкретные примеры, а начнем с файла
Ch08 Examples\Append Tables.xlsx.
В этом файле содержатся три таблицы с информацией о выданных в каждом месяце подарочных сертификатах на услуги спа-салона. В имени каждого рабочего листа присутствуют название месяца и года, разделенные пробелом, а их содержимое отражает выдачу сертификатов в этом конкретном
месяце. Что касается имен таблиц, в которые оформлены данные на рабочих листах, то они также имеют в своем названии месяц и год, но на этот
раз разделителем между ними является символ подчеркивания (Jan_2008,
Feb_2008 и т. д.), поскольку пробелы нельзя употреблять в названиях таблиц. Каждый месяц администратор создает новый рабочий лист и таблицу,
именуя их по образу предыдущих листов.
Единственное, чего в теле этих таблиц не
хватает, – это указания даты выпуска или
окончания срока действия сертификата.
Данные о сертификатах за январь показаны на рис. 8.14.
Можно ли построить работу так, чтобы
все создаваемые таблицы автоматически
включались в учет, без необходимости
объяснять администратору, как работать
Рис. 8.14. Рабочий лист по январю
с Power Query?
2008 года
214  Глава 8. Добавление данных
Консолидация таблиц
К сожалению, в Excel нет кнопки для создания запроса к видимым объектам в текущей рабочей книге, так что нам придется создать такой запрос
самостоятельно. Для этого выполните следующие действия:
 создайте новый запрос, нажав на вкладке Данные (Data) на кнопку Получить данные (Get Data) и в подменю Из других источников (From
Other Sources) выбрав пункт Пустой запрос (Blank Query);
 переименуйте запрос в Certificates;
 в строке формул введите следующую формулу:
=Excel.CurrentWorkbook()
Вы увидите список таблиц из текущей рабочей книги и сможете посмотреть их содержимое, используя уже известный вам трюк. Щелкните мышью
в поле Content справа от слова Table, как показано на рис. 8.15.
Рис. 8.15. Предварительный просмотр содержимого таблицы Jan_2008
Если внимательно присмотреться к заголовку столбца Content, можно
обнаружить в его правой части кнопку с изображением двух расходящихся стрелок. Это очень полезный инструмент, позволяющий вам раскрыть и
добавить все таблицы за один шаг. Эта операция называется Развернуть
(Expand), и она будет выполнена для всех строк в запросе.
Давайте попробуем:
 нажмите на кнопку со стрелками, чтобы развернуть столбец Content;
 снимите флажок Использовать исходное имя столбца как префикс
(Use original column name as prefix) и нажмите на кнопку OK.
В результате мы развернем все данные с сохранением исходного столбца
Name, как показано на рис. 8.16.
Добавление таблиц и диапазонов в текущем файле  215
Рис. 8.16. Наши подтаблицы были развернуты и добавлены
🍌 Примечание. Обратите внимание, что названия столбцов и данные в них при
разворачивании будут отвечать правилам, описанным в предыдущем разделе, т. е. при неправильном именовании столбца вы обнаружите в итоговом
наборе колонки со значениями null.
Теперь нам необходимо преобразовать содержимое столбца Name в дату,
отражающую конец конкретного месяца. Поскольку строка Jan_2008 не может
быть воспринята как дата, мы будем использовать небольшие трюки:
 щелкните правой кнопкой мыши по заголовку столбца Name и выберите пункт Замена значений (Replace values);
 при помощи открывшегося диалогового окна замените символ подчеркивания на последовательность символов « 1, » (пробел, единица,
запятая и пробел);
 выделите все столбцы и на вкладке Преобразование (Transform) нажмите на кнопку Определить тип данных (Detect Data Type);
 снова выделите столбец Name, на вкладке Преобразование (Transform)
нажмите на выпадающую кнопку Дата (Date) и в подменю Месяц
(Month) выберите пункт Конец месяца (End of Month);
 щелкните правой кнопкой мыши по заголовку столбца Name, выберите
пункт Переименовать (Rename) и введите новое имя Month End.
Результат этой операции показан на рис. 8.17.
Рис. 8.17. Готовый запрос
216  Глава 8. Добавление данных
Вроде все выглядит неплохо, но почему-то при нажатии на кнопку Закрыть и загрузить (Close & Load) возникает ошибка. А если щелкнуть
мышью по кнопке обновления данных рядом с запросом, ошибка не исчезнет – более того, их количество возрастет до 63, как видно на рис. 8.18!
Рис. 8.18. 63 ошибки? Все ведь выглядело нормально!
Что же случилось? Давайте вернемся назад и пройдем по запросу. Но перед
этим убедитесь, что ваш рабочий лист Certificates находится последним в
списке листов, как показано на рис. 8.19.
Рис. 8.19. Лист Certificates должен располагаться в конце списка
🍌 Примечание. Обычно нас не должно волновать, где именно располагается
лист, но в данном случае это гарантирует нам, что вы увидите появляющиеся
ошибки там же, где мы будем их показывать.
После переноса рабочего листа в конец списка перейдите в режим редактирования запроса и выделите шаг Источник (Source).
В данный момент вы увидите, что к нашему списку листов добавился еще
один с именем Certificates, показанный на рис. 8.20, который мы сами создали
в результате вывода запроса.
Рис. 8.20. Наш новый запрос показывается в списке всех запросов рабочей книги
Добавление таблиц и диапазонов в текущем файле  217
🍌 Примечание. Если вы не видите в списке таблицу Certificates, возможно,
Power Query кешировал данные в окне предварительного просмотра. Чтобы
получить актуальные данные, перейдите на вкладку Главная (Home) и нажмите на кнопку Обновить предварительный просмотр (Refresh Preview). Вы
должны всегда делать это, когда отлаживаете свои запросы.
🙈 Предупреждение. При использовании функции =Excel.CurrentWorkbook() для
перечисления таблиц или диапазонов всегда помните, что полученный в результате запрос при обновлении также будет добавлен в этот список. Чтобы
справиться с такой ситуацией, вам придется применять различные шаги в
зависимости от вашей структуры данных.
А теперь давайте пройдем по шагам запроса и посмотрим, что у нас происходит.
Выделите шаг Замененное значение (Replaced Value), как показано на
рис. 8.21. Вы не заметили ничего странного?
Рис. 8.21. Следующим шагом мы будем приводить столбец Name к виду даты
При выполнении следующего шага Измененный тип (Changed Type) Power
Query попытается преобразовать содержимое столбца Name в даты, и очевидно, что со строкой «Certificates» ему это сделать не удастся. В результате
в этих ячейках появятся ошибки, что видно по рис. 8.22.
Рис. 8.22. Неправильные даты были преобразованы в ошибки
218  Глава 8. Добавление данных
Такое поведение Power Query нам даже на руку, поскольку все строки с
этого листа были просто преобразованы в ошибки, которые мы можем отфильтровать, как показано ниже:
 убедитесь, что у вас выделен шаг Измененный тип (Changed Type);
 выделите столбец Name и на вкладке Главная (Home) в выпадающей кнопке Удалить строки (Remove Rows) выберите пункт Удалить
ошибки (Remove Errors);
 подтвердите, что вы хотите вставить новый шаг в середину вашего
запроса;
 на вкладке Главная (Home) нажмите на кнопку Закрыть и загрузить
(Close & Load).
После этого вы увидите сообщение о том, что были успешно загружены
62 строки без единой ошибки, как показано на рис. 8.23.
Рис. 8.23. Загружены 62 строки из трех таблиц
Разработанное нами решение должно работать в автоматическом режиме
при добавлении в рабочую книгу таблиц, имена которых будут следовать
шаблону Месяц_Год. Остается только надеяться, что наш внимательный администратор будет называть таблицы с данными корректно. А с учетом того,
что это не самый хорошо заметный элемент, ошибки такого рода могут проскальзывать.
Консолидация диапазонов и рабочих листов
А что, если наши данные не будут оформлены в таблицы, а администратор
будет сохранять их просто на рабочих листах с определенными именами?
С этим можно справиться, хотя, как мы уже упоминали в главе 6, в Power
Query нет встроенной функции для чтения с рабочих листов в активной книге. Нам придется поработать с именованными диапазонами… точнее, особыми именованными диапазонами (specific named range). Специфика этого решения будет состоять в определении областей печати (Print Area), поскольку
у них есть свои динамические имена, которые можно отловить при помощи
функции Excel.CurrentWorkbook(). Выполните следующие действия:
 выберите рабочий лист Jan 2008 и на вкладке Разметка страницы
(Page Layout) нажмите на кнопку Печатать заголовки (Print Titles);
Добавление таблиц и диапазонов в текущем файле  219
 в поле Выводить на печать диапазон (Print area) укажите диапазон
A:D и нажмите на кнопку OK;
 повторите эти действия для рабочих листов Feb 2008 и Mar 2008;
 создайте новый запрос, нажав на вкладке Данные (Data) на кнопку Получить данные (Get Data) и в подменю Из других источников (From
Other Sources) выбрав пункт Пустой запрос (Blank Query);
 переименуйте запрос в FromWorksheets;
 в строке формул введите следующую формулу:
=Excel.CurrentWorkbook()
Вы увидите список таблиц и именованных диапазонов, включая области
печати, как показано на рис. 8.24.
Рис. 8.24. Функция Excel.CurrentWorkbook() показывает области печати
Поскольку мы извлекли одновременно и таблицы, и области печати, давайте отфильтруем ненужное и развернем данные, чтобы посмотреть, что
получится:
 нажмите на кнопку фильтрации в заголовке столбца Name и в подменю
Текстовые фильтры (Text Filters) выберите пункт Заканчивается на
(Ends With) и введите в соответствующее поле текст Область_печати
(Print_Area);
 вызовите инструмент замены значений из столбца Name и замените
вхождение ‘!Область_печати (‘!Print_Area) на пустое значение;
 замените оставшийся апостроф (‘) на пустое значение;
 разверните содержимое столбца Content, как мы уже делали, сняв предварительно флажок Использовать исходное имя столбца как префикс (Use original column name as prefix).
Обратите внимание, что в данном случае все получилось несколько иначе,
как видно на рис. 8.25. Но в целом нам удалось прочитать все данные с рабочих листов при помощи областей печати.
220  Глава 8. Добавление данных
Рис. 8.25. Необработанные данные с рабочих листов
Очевидно, что в данном случае нам предстоит серьезно поработать над
тем, чтобы очистить полученные данные и преобразовать их к виду исходных таблиц. Но работой нас не испугать!
Первое, что хочется отметить, – это опасность повышения первой строки
для использования ее в качестве заголовков. Дело в том, что кто-то, кому не
так важна история транзакций, может удалить данные за февраль, что приведет к ошибке. По этой причине мы будем именовать наши столбцы вручную, намеренно вызывать появление ошибок при помощи установки типов
данных и затем отфильтровывать их.
Что ж, приступим:
 удалите пустую колонку с именем Column4;
 переименуйте столбцы следующим образом: Certificate, Value, Service
и Month End;
 щелкните правой кнопкой мыши по заголовку столбца Month End, выберите пункт Замена значений (Replace values) и замените одиночный символ пробела на последовательность символов « 1, » (пробел,
единица, запятая и пробел);
 установите для столбца Certificate тип данных Целое число (Whole
Number);
 установите для столбца Value тип данных Целое число (Whole Number);
 установите для столбца Service тип данных Текст (Text);
 установите для столбца Month End тип данных Дата (Date);
 выделите все столбцы и на вкладке Главная (Home) в выпадающей
кнопке Удалить строки (Remove Rows) выберите пункт Удалить
ошибки (Remove Errors);
 нажмите на кнопку фильтрации в заголовке столбца Certificate и снимите флажок NULL;
 выделите столбец Month End, на вкладке Преобразование (Transform)
нажмите на выпадающую кнопку Дата (Date) и в подменю Месяц
(Month) выберите пункт Конец месяца (End of Month);
 перейдите на вкладку Главная (Home) и нажмите на кнопку Закрыть
и загрузить (Close & Load).
Вы обнаружите, что в результате у вас загрузится ровно столько же
строк (62), как и в случае с запросом Certificates, что видно по рис. 8.26.
Заключительные мысли о добавлении запросов  221
Рис. 8.26. Два подхода, один результат!
Работая с областями печати, желательно ограничивать их только тем диапазоном, с которым вы хотите работать. Во-первых, это позволит сократить
время обработки запроса в Power Query. Кроме того, в окне расширения данных столбцы именуются как Column#, что может привести к выбору лишних
колонок, которые следовало заранее удалить.
Используйте =Excel.CurrentWorkbook() с осторожностью
Реализуя решения при помощи функции Excel.CurrentWorkbook(), стоит
помнить о том, что она считывает все объекты из текущего файла. А поскольку это напрямую влияет на цепь вычислений, мы можем столкнуться
с эффектом рекурсии, проявляющимся в том, что созданные нами таблицы
могут восприниматься Power Query как исходные таблицы с данными.
Подобные проблемы проявляются при обновлении данных, когда запрос
пытается загрузить сам себя, тем самым дублируя данные на выходе. Используя этот подход, важно помнить о такой особенности. Защититься от этого
можно разными способами, начиная от отсеивания ошибок при помощи
фильтров по ключевым столбцам и заканчивая использованием определенных стандартов именования для входных и выходных столбцов, что позволит
отфильтровать те из них, которые вам не нужны.
🍌 Примечание. Какой метод вы бы ни выбрали, рекомендуем вам тщательно
проверить его работу при помощи повторных обновлений и только после
этого использовать на практике.
Заключительные мысли о добавлении запросов
Пользу от умения добавлять запросы друг к другу трудно переоценить. Только подумайте, что с этим навыком вы легко можете взять три отдельных файла, импортировать их, объединить в одну таблицу Transactions и построить на
ее основании сводную таблицу или визуальный элемент в Power BI. Это ведь
может быть полноценным бизнес-решением на базе трех отдельных файлов.
222  Глава 8. Добавление данных
А когда вам нужно будет обновить данные, достаточно будет нажать на
кнопку обновления, и все. Power Query инициирует обновление таблицы
Transactions, а та, в свою очередь, актуализирует исходные таблицы с данными.
А теперь представьте, что похожее решение может быть построено не на
базе файлов за определенные временные интервалы, а на основе данных о
различных товарах: товаре 1, товаре 2, товаре 3… Мы строим свое решение,
загружая файлы CSV, содержащие нужные нам данные, и формируя на их
основе важные отчеты. Проходит месяц, и нам приходят файлы с новыми
транзакциями по товарам.
Все, что вы делаете, – это кладете их поверх старых файлов и нажимаете
на кнопку обновления. И все.
Нет, серьезно, и все!
При этом стоит помнить, что процесс добавления запросов не ограничивается работой с внешними файлами, хотя это, конечно, его стихия. Как вы
видели, можно построить полноценное решение с объединением таблиц и
областей печати из той же рабочей книги с созданием итогового списка для
проведения аналитики.
В обоих случаях вы получите огромный выигрыш во времени по сравнению с традиционными методами в Excel. Кроме того, вы обезопасите себя от
ошибочных действий пользователя, связанных с копированием и вставкой
данных. Power Query не использует в своей работе операции копирования и
вставки. Он просто добавляет наборы данных друг к другу, удаляя дублирующиеся заголовки. Таким образом, вы получаете оптимальное с точки зрения
скорости и надежности решение.
Но давайте будем честны. До сих пор мы узнали, как вручную добавлять
данные из внешних источников, а также разобрали пример автоматически
обновляющегося решения на основе данных из той же рабочей книги. А можно ли объединить эти приемы и создать сценарий, который будет автоматически собирать файлы из папки без необходимости добавлять их в Power
Query вручную? Конечно, можно, и именно об этом мы поговорим в главе 9.
Глава
9
Объединение файлов
Применение классических методов объединения наборов данных из нескольких файлов на практике может быть весьма утомительным занятием,
сопряженным со всевозможными ошибками. Каждый файл нужно отдельно
импортировать, преобразовать, скопировать и вставить в общую таблицу.
В зависимости от того, насколько сложные преобразования нужно выполнить
и как много файлов необходимо обработать, решение может получиться либо
не очень, либо очень выматывающим.
Мы уже видели, как Power Query позволяет избегать опасностей, связанных с копированием и вставкой, но, как бы ни были обширны возможности
импортирования и добавления файлов по одному, эти операции таят в себе
следующие проблемы:
 загружать несколько файлов вручную может быть очень утомительно;
 при многократном повторе действий по преобразованию данных
очень легко допустить ошибку.
Но есть и хорошие новости, состоящие в том, что Power Query обладает
инструментом, способным решить обе эти проблемы.
Практический пример
В данной главе мы рассмотрим практический пример, включающий импортирование, отмену свертывания и добавление ежеквартальных перечней
требующихся деталей для производственной компании. Производственные
филиалы каждый квартал составляют отчетность с указанием в имени файла
названия филиала, и эти файлы сохраняются в папках со структурой, показанной на рис. 9.1.
Рис. 9.1. По четыре файла на квартал расположены в папке Ch09 Examples\Source Data
224  Глава 9. Объединение файлов
Внутри каждой рабочей книги содержится рабочий лист с именем Forecast,
в котором представлена показанная на рис. 9.2 сводная структура данных.
Стоит заметить, что данные на этом листе отформатированы в виде таблицы
Excel, но на самом деле это просто диапазон, тогда как в книге также присутствует и таблица с именем Parts, расположенная на листе Matrix.
Рис. 9.2. Данные с листа Forecast рабочей книги 2019 Q1\East.xlsx
Наша цель – создать автоматически обновляемое решение, в котором данные будут представлены в виде, показанном на рис. 9.3.
Рис. 9.3. Требуемая таблица
Это не самый простой сценарий, в котором можно выделить следующие
нюансы и задачи:
 все файлы собраны во вложенных папках директории Ch09 Examples\
Source Files;
 содержимое каждого файла нуждается в отмене свертывания перед
добавлением;
 не все филиалы производят одну и ту же продукцию (Product), так что
количество столбцов в файлах может быть разным;
 необходимо сохранять название филиала или имени файла;
 нужно учитывать временные интервалы, содержащиеся в именах папок с данными;
 необходимо иметь возможность обновлять решение при добавлении
новой папки с данными.
Описание процесса  225
Вскоре вы увидите, что Power Query легко позволит справиться со всеми
этими сложностями.
Описание процесса
Перед тем как окунуться в механику построения решения, давайте рассмотрим подход к подобному сценарию с точки зрения Power Query в целом.
Методология объединения файлов
Шаблон процесса объединения файлов можно условно разбить на пять шагов:





шаг 0: подключение к папке;
шаг 1: фильтрация и страховка на будущее;
шаг 2: объединение файлов;
шаг 3: преобразование данных в запросе примера;
шаг 4: преобразование данных в мастер-запросе.
В этой главе мы пройдем по всем перечисленным шагам и покажем, как
они работают и почему они так важны. Но прежде необходимо разобраться
с архитектурой нашего решения.
Архитектура запросов при объединении файлов
Многих пользователей пугает тот факт, что Power Query выполняет объединение файлов не в одном запросе. Вместо этого при нажатии на соответствующую кнопку вам предлагается выбрать пример файла, после чего
автоматически создается четыре вспомогательных запроса. Если пользователь этого не ожидает, для него это может быть слишком!
Если предположить, что вы уже создали запрос FilesList с перечнем файлов
для объединения и мастер-запрос для итоговых результатов (об этом мы будем говорить далее в данной главе), архитектура запросов должна выглядеть
так, как показано на рис. 9.4.
Рис. 9.4. Четыре новых запроса (в нижней части рисунка)
были созданы в процессе объединения файлов
226  Глава 9. Объединение файлов
Несмотря на то что все созданные запросы играют важную роль в процессе
объединения файлов, три из них будут помещены в папку Вспомогательные
запросы (Helper Queries), и вы никогда не будете их касаться. Эти запросы
легко идентифицировать по следующим признакам:
1) они сохраняются в директории Вспомогательные запросы (Helper
Queries);
2) они обозначаются значком, отличным от таблицы.
Если взглянуть на диаграмму, показанную на рис. 9.4, можно заметить, что
три из перечисленных запросов помечены значком таблицы:
 FilesList. Этот запрос, созданный автором, содержит список файлов,
которые вы хотите объединить. Как вы узнаете вскоре, он может быть
представлен как отдельный запрос или в составе мастер-запроса (по
вашему усмотрению). Вне зависимости от того, какой вариант вы выберете, это будет ключевая точка для запуска объединения файлов;
 Transform Sample. На этапе объединения файлов у вас будет запрошен файл, который будет использоваться в качестве примера, и этот
запрос ссылается на выбранный файл, демонстрируя вам его содержимое. Цель этого – дать вам возможность выполнить преобразования
в файле еще до того, как файлы будут добавлены в единую таблицу.
Шаги, выполняемые на данном этапе, автоматически прописываются
в созданной функции Преобразовать файл (Transform File), чтобы они
могли быть применены ко всем файлам в папке;
 мастер-запрос. Цель создания этого запроса состоит в том, чтобы
взять каждый файл из шага или запроса FilesList, передать его на вход
функции Преобразовать файл (Transform File), основываясь на шагах
из запроса Transform Sample, и вернуть файл в измененном виде. После
этого происходит разворачивание таблиц и добавление их в единую
объемную таблицу данных с возможностью при необходимости провести еще один этап преобразований.
Все это звучит довольно сложно, но скоро вы поймете, что такой подход
предоставляет нам максимальную гибкость, а использовать его довольно
легко после полного понимания сути происходящего. К тому же он обеспечивает нас следующими возможностями:
 выполнять преобразование данных до момента добавления таблиц;
 выполнять преобразование данных после добавления таблиц;
 сохранять нужные нам свойства файлов, включая имена и даты.
🍌 Примечание. Этот метод работает не только с файлами Excel. Его можно при-
менять для любых других коннекторов в Power Query (с подключением к
файлам CSV, TXT, PDF и многим другим).
Давайте приступим к воплощению описанного плана на примере наших
данных.
Шаг 0: подключение к папке  227
Шаг 0: подключение к папке
Первое, что нам необходимо сделать, – это подключиться к папке с данными.
Мы уже говорили в первой главе, что каждый раз, когда вы подключаетесь к
данным, Power Query проходит четыре шага, показанных на рис. 9.5.
Настройка
Аутентификация
Предварительный просмотр
Назначение
запроса
Рис. 9.5. Подключение к источнику данных
Начнем с этапа Настройка, где происходят выбор и конфигурирование
коннектора, который мы собираемся использовать для подключения к папке. После этого Power Query проверяет, потребуется ли аутентификация для
соединения с источником данных, и при необходимости запрашивает ее у
вас. Выполнив проверку того, что у вас есть доступ к источнику, Power Query
покажет вам окно предварительного просмотра. На этом этапе вы можете
выбрать между загрузкой данных и открытием редактора Power Query для
преобразования данных перед их загрузкой.
Причина того, почему мы снова это упомянули, и причина присутствия
шага 0 в нашей методологии заключается в том, что вы можете использовать
разные коннекторы при подключении к папкам в зависимости от системы, в
которой они хранятся. Тогда как входная точка будет разная в разных системах (Windows, SharePoint, Azure), решения по объединению файлов будут в
предварительном просмотре использовать одну и ту же схему данных, приведенную в табл. 9.1.
Таблица 9.1. Схема данных при подключении к папке
Столбец
Содержание
Content
Ссылка на файл
Name
Имя файла
Extension
Тип файла
Date accessed
Дата последнего доступа к файлу
Date modified
Дата последнего изменения файла
Date created
Дата создания файла
Attributes
Запись с такими атрибутами, как размер файла, видимость и т. д.
Folder Path
Полный путь к файлу
228  Глава 9. Объединение файлов
Пройдя шаги настройки и аутентификации для конкретного источника
данных, вы увидите, что остальные шаги из этой главы могут быть применены практически к любому источнику.
Подключение к локальной/сетевой папке
Самый простой сценарий, который можно себе вообразить при объединении файлов, – это когда все исходные файлы находятся в директории на
локальном или сетевом диске. Поскольку на данный момент Windows уже
приняла вашу аутентификацию, никаких дополнительных действий у вас
запрашивать не будут.
В данной главе мы будем использовать этот способ для подключения в
папке Ch09 Examples\Source Data. Для этого выполните следующие действия:
 создайте новый запрос, выбрав в меню Из файла (From File) пункт Из
папки (From Folder);
 найдите и выберите вашу папку Ch09 Examples\Source Data.
После этого откроется окно предварительного просмотра, показанное на
рис. 9.6, в котором будут перечислены все файлы не только из выбранной
вами папки, но и из всех вложенных в нее директорий.
Рис. 9.6. Окно предварительного просмотра со всеми файлами из папки,
включая вложенные директории
Важно отметить, что столбцы в этом окне предварительного просмотра в
точности соответствуют схеме, приведенной в табл. 9.1.
Что касается подключения к локальной папке, это все. Осталось выбрать,
куда вы хотите загрузить полученные данные. Поскольку нам нужно еще поработать с извлеченными файлами, мы нажмем на кнопку Преобразовать
данные (Transform Data).
Шаг 0: подключение к папке  229
🍌 Примечание. Коннектор Из папки (From Folder) может быть использован для
загрузки файлов из локальной или сетевой папки, а также для извлечения
данных по UNC-пути (для доступа к сетевым ресурсам).
Подключение к папке SharePoint
Если вы храните свои данные на сайте SharePoint, вы должны знать, что в
вашем распоряжении есть два способа подключения к ним:
1. Если вы синхронизируете папку на свой компьютер, то можете использовать коннектор подключения к локальным папкам, рассмотренный
нами ранее.
2. Если хотите подключаться к облачной версии папок, можно использовать специальный коннектор SharePoint.
Конечно, коннектор SharePoint работает медленнее, чем подключение к
локальной папке, из-за необходимости во время выполнения запросов загружать данные, зато в этом случае вам не придется хранить файлы на локальном диске. Чтобы подключиться к данным с помощью этого коннектора,
выполните следующие действия:
 создайте новый запрос, выбрав в меню Из файла (From File) пункт Из
папки SharePoint (From SharePoint Folder);
 введите корневой URL сайта (не папки или библиотеки).
Сложность здесь состоит в том, что, в отличие от подключения к локальной
папке, вы не можете соединяться с директориями напрямую. Вместо этого
вы должны подключиться к корневому каталогу, а затем указать нужную вам
папку. Как же найти ссылку на корневой каталог?
Самый простой способ состоит в подключении к SharePoint при помощи
вашего любимого браузера и анализе ссылки. Найдите второй слеш слева от
слова Forms и скопируйте все, что находится слева от него, как показано на
рис. 9.7.
сюда подключаемся
это игнорируем
Рис. 9.7. Извлечение корневого URL из ссылки на SharePoint
Таким образом, если ваш домен выглядит так: https://monkey.sharepoint.
com, то подключаться вы должны к адресу https://monkey.sharepoint.com/sites/
projects.
🍌 Примечание. Если в вашей компании используется Microsoft 365, ваш домен
SharePoint будет иметь вид <tenant>.sharepoint.com. Если вашим хранилищем SharePoint управляет собственный отдел ИТ, адрес может быть любым.
230  Глава 9. Объединение файлов
После подтверждения URL вам необходимо будет пройти аутентификацию, как показано на рис. 9.8, если вы ранее никогда не подключались к
этому домену. На этом этапе вам потребуется ввести правильные данные.
Рис. 9.8. Подключение к SharePoint в Office365
Здесь вам важно будет правильно выбрать тип аккаунта для подключения.
Поскольку SharePoint может быть настроен разными способами, мы не можем точно знать, какой метод подключения будет правильным для вас, но
следующие подсказки могут помочь вам сделать верный выбор:
 если ваш SharePoint размещается в Office365, вам необходимо выбрать
Microsoft Account и подключаться с помощью электронного адреса,
который вы используете для Office365;
 если вашим SharePoint управляет местный отдел ИТ и вы никогда не
подключались к нему ранее, вы можете попробовать выбрать метод
Anonymous. В случае неудачи попытайтесь подключиться с помощью
учетной записи Windows.
🍌 Примечание. Не уверены, используется ли в вашей компании Office365?
А ваш домен заканчивается на sharepoint.com? Если да, то выбирайте вариант
Microsoft Account и подключайтесь с помощью своего рабочего электронного адреса.
🙈 Предупреждение. Учетные данные сохраняются на вашем компьютере, так
что при выборе неправильного варианта подключения они могут оказаться
в кеше. Чтобы изменить учетные данные, нажмите в редакторе Power Query
на кнопку Настройки источника данных (Data Source Settings) и установите
переключатель в положение Глобальные разрешения (Global Permissions).
Выберите свой домен и нажмите на кнопку Очистить разрешения (Clear
Permissions). При следующем подключении у вас снова будут запрошены
учетные данные.
Шаг 0: подключение к папке  231
После успешной аутентификации Power Query выполнит попытку подключения к папке. Если введенный вами адрес оказался верным, будет открыто
окно предварительного просмотра. В противном случае – если вы ввели неправильную ссылку на корневой каталог или добавили к ней имя папки – вы
получите сообщение об ошибке и вынуждены будете все делать заново.
🍌 Примечание. Существует еще один нюанс при подключении к SharePoint, и
состоит он в том, что кто-то может хранить свои документы прямо в корневом каталоге домена SharePoint. Для подключения к этим файлам вы также должны использовать коннектор Из папки SharePoint (From SharePoint
Folder), но при этом вводить URL вида https://<SharePointDomain> (без последующих папок).
Подключение к OneDrive для бизнеса
Самый большой секрет OneDrive для бизнеса (OneDrive for Business) состоит в том, что он, по сути, представляет собой личный сайт, размещенный
на SharePoint. Из этого следует, что вы можете подключаться к папкам этой
службы так же точно, как к сайту SharePoint: либо посредством коннектора
Из папки (если данные синхронизированы с вашим локальным компьютером), либо с помощью коннектора Из папки SharePoint.
Здесь важно понимать, к какому адресу следует подключаться, поскольку
он будет отличаться от вашей привычной ссылки на хранилище SharePoint.
При подключении с помощью коннектора Из папки SharePoint формат
адреса будет выглядеть так: https://<SharePointDomain>/personal/<email>. Вы
также должны быть в курсе, что все символы «.» и «@» в вашем электронном
адресе будут заменены на символы подчеркивания.
🍌 Примечание. Если в вашей компании используется Microsoft 365, адрес ва-
шего домена в SharePoint будет иметь формат <tenant>-my.sharepoint.com,
а если хранилищем SharePoint управляет отдел ИТ, адрес может быть любым. Проще всего для получения корректного адреса будет подключиться
к OneDrive для бизнеса с помощью браузера и скопировать всю ссылку до
конца адреса электронной почты.
Подключение к другим файловым системам
Хотя мы рассмотрели самые популярные коннекторы для извлечения данных, существуют и другие виды подключений, возвращающие ту же схему
данных, включая, но не ограничиваясь Blob Storage и Azure Data Lake первого
и второго поколений. Каждый из этих коннекторов требует указания собственной ссылки и прохождения аутентификации, но после подключения
последовательность действий будет такая же, как раньше.
232  Глава 9. Объединение файлов
А что, если вы храните свои данные в других системах интернет-хранилищ?
Это могут быть, к примеру, Google Drive, DropBox, Box, Onedrive (Personal)
или другие системы. Даже если в вашем распоряжении нет специального
коннектора для подключения к данным в таких специфических хранилищах,
поставщик службы наверняка позаботился об инструментах синхронизирования ваших данных с локальными папками, к которым вы можете подключиться посредством обычного коннектора Из папки.
Шаг 1: фильтрация и страховка на будущее
После завершения шага 0 и успешного подключения к папке с данными пришло время взглянуть на список доступных файлов в папке и вложенных
директориях. Сложность в том, что в этот список будут включены все без
исключения файлы, находящиеся в иерархии папок, при этом Power Query
может объединять за один раз только файлы одного типа.
Чтобы предотвратить возможные ошибки, связанные с попыткой объединения файлов разных типов, нам необходимо убедиться в том, что мы
ограничили список файлов одним конкретным типом. Это стоит делать, даже
если в данный момент в списке находятся только нужные вам файлы, ведь
вы никогда не знаете, когда именно парню из бухгалтерии взбредет в голову
поместить свои файлы MP3 в одну папку с документами Excel. Кроме того,
как мы уже говорили, Power Query является регистрозависимым инструментом, и если вы ограничите выбор файлами .xlsx, в какой-то момент у того же
самого парня залипнет клавиша CAPS LOCK, и он вдруг начнет сохранять
файлы с расширениями .XLSX, которые не пройдут ваш отбор. Получается,
нам необходимо выработать методы, которые помогут предотвратить такие
ситуации в будущем.
Методология шага 1
На этом шаге мы попытаемся отфильтровать только те файлы, которые
нам необходимо объединить, и предотвратить возможные ситуации в будущем, способные привести к возникновению ошибок. Наши действия должны
включать в себя:
 фильтрацию до определенного уровня вложенности папок (при необходимости);
 преобразование расширения файлов к нижнему регистру;
 отбор нужного нам расширения;
 отсеивание временных файлов (имена которых начинаются с символа
тильда ~ );
 выполнение дополнительной фильтрации;
 по желанию: переименование запроса в FilesList и его загрузку в виде
подключения.
Давайте пройдемся по нашему плану более детально.
Шаг 1: фильтрация и страховка на будущее  233
Применение шага 1 к нашему примеру
При подключении к директории с использованием коннектора Из папки
(From Folder) у нас есть возможность опуститься до нужного уровня в иерархии документов. Это очень удобно, поскольку позволяет добраться до папки
с необходимыми нам файлами. В то же время при подключении к данным,
хранящимся в SharePoint или Azure, у вас не будет такой привилегии, и вам
придется пробираться по иерархии при помощи фильтров. Например, вы
можете наложить определенный фильтр на столбец с именем Folder Path,
но и здесь есть небольшая загвоздка, состоящая в том, что в каждой ячейке
указан полный путь к файлу. И если в локальной файловой системе можно
легко считать эти пути, при хранении данных в SharePoint каждому имени
файла будет предшествовать полный путь к сайту. Чтобы справиться с этим,
мы рекомендуем вам воспользоваться следующим способом, дабы сократить
список файлов до нужной папки:
 щелкните правой кнопкой мыши по заголовку столбца Folder Path и
выберите пункт Замена значений (Replace Values);
 в открывшемся диалоговом окне в поле Значение для поиска (Value
to Find) введите исходный путь к файлу или сайту с завершающим
символом разделения папок;
 поле Заменить на (Replace with) оставьте пустым.
Таким образом, если вы работаете с файлами из папки C:\Master Your Data\
Ch09 Examples\Source Data, в поле Значение для поиска вам необходимо
ввести C:\Master Your Data\Ch09 Examples\Source Data\.
После нажатия на кнопку OK вы увидите, что содержимое столбца Folder
Path сократилось, как показано на рис. 9.9.
Рис. 9.9. В столбце Folder Path осталось только имя нужной нам папки
Если вы подключаетесь к локальной папке и можете сразу достигнуть нужного вам уровня иерархии, вам это вообще делать не нужно. Но если вы
работаете с SharePoint, OneDrive или Azure, этот подход позволит вам быстро и легко отфильтровать структуру папок. Для более глубоких путей или
сценариев со множеством файлов вам может понадобиться несколько раз
повторить этот процесс, чтобы добраться до нужной директории.
1. Замените на пустоту текущий путь к папке.
2. Отфильтруйте следующий уровень иерархии.
3. Вернитесь к пункту 1, пока не достигнете нужной вам директории.
234  Глава 9. Объединение файлов
Добравшись до папки, в которой хранятся нужные вам файлы, необходимо
убедиться, что их список ограничен только одним типом. На этом этапе нам
нужно гарантировать, что мы не столкнемся с проблемой расширений, написанных в разных регистрах, и убрать из списка временные файлы, особенно
если мы работаем с файлами Excel. Сделать это можно следующим образом:
 щелкните правой кнопкой мыши по заголовку столбца Extension и в
меню Преобразование (Transform) выберите пункт нижний регистр
(lowercase);
 нажмите на кнопку фильтрации в заголовке столбца Extension и в меню
Текстовые фильтры (Text Filters) выберите пункт Равно (Equals);
 установите переключатель в положение Подробнее (Advanced) и установите значения полей следующим образом:
 для поля Extension выберите оператор равно (equals) и введите значение .xlsx;
 для поля Name выберите оператор не начинается с (does not begin
with) и введите символ ~ (тильда), как показано на рис. 9.10.
Рис. 9.10. Страховка на будущее путем фильтрации полей
🍌 Примечание. При открытии файла Excel на локальном диске в той же пап-
ке создается его временная копия, имя которой предваряется символом ~
(тильда). Данный файл исчезает после закрытия рабочей книги, но в случае
возникновения сбоев этого может не произойти. Чтобы нам эти временные
файлы не мешали, мы исключаем их при помощи фильтра. Если вы импортируете файлы, отличные от Excel, можете пропустить этот шаг, но не будет
ничего плохого, если вы его оставите.
Теперь вы должны внимательно проанализировать оставшиеся в списке
файлы. Чтобы файлы успешно объединились, они не только должны быть
одного типа, но также должны обладать идентичной структурой данных. Если
Шаг 2: объединение файлов  235
в вашем списке остались файлы с очевидно разными структурами (например,
финансовые отчеты, отчеты о продажах и файлы с прогнозами), вероятно,
вам потребуется дополнительно отфильтровать их, чтобы остались только те
из них, которые могут быть объединены.
🍌 Примечание. Помните, что вы можете осуществлять фильтрацию по именам
файлов, названиям папок и даже по датам. Но самым правильным и легким
способом оставить в выгрузке только нужные вам файлы является предварительная настройка структуры папки таким образом, чтобы в ней были собраны файлы в понятном и пригодном для фильтрации виде.
В нашем случае мы оставили в списке только файлы Excel. И хотя они находятся в разных подпапках внутри директории Source Data, для нас это не
проблема.
Последний шаг является опциональным и включает в себя:
 переименование запроса в FilesList;
 загрузку запроса в виде подключения, как показано на рис. 9.11.
Такой подход в своих сценариях, базирующихся на импорте файлов из
папок, предпочитает использовать Кен. Он обеспечивает два очевидных преимущества:
 у вас появляется место, где вы можете в удобном виде просмотреть,
какие файлы были объединены, без необходимости пробираться через
запрос в поисках нужной информации;
 путь к файлам указывается в явном виде лишь один раз.
Мы свое решение покажем с использованием этого метода, но вы всегда
можете пропустить этот шаг и двигаться дальше, все будет работать и так.
Рис. 9.11. Мы решили загрузить запрос
с именем FilesList в виде подключения
Шаг 2: объединение файлов
Итак, мы получили список файлов для объединения, теперь пришло время
заняться этой работой.
236  Глава 9. Объединение файлов
Методология шага 2
На этом шаге мы выполним следующие действия:
 по желанию: сделаем ссылку на запрос FilesList при создании мастерзапроса;
 переименуем мастер-запрос;
 нажмем на кнопку Объединить файлы (Combine Files);
 выберем файл с примером.
Именно на этом этапе Power Query вступает в игру со своей магией, включающей создание четырех вспомогательных запросов и добавление множества
шагов в мастер-запрос.
Применение шага 2 к нашему примеру
Мы советуем вам всегда переименовывать мастер-запрос до запуска процесса объединения файлов, поскольку его имя будет использовано в нескольких папках и запросах. Это значительно облегчит вам жизнь, особенно если
в вашем решении будет сразу несколько операций объединения файлов. При
этом важно дать запросу простое и понятное имя – не слишком длинное и
такое, которое вы были бы не против загрузить на рабочий лист Excel или в
модель данных. В нашем примере речь идет о списке деталей, которые необходимо заказать, так что имена Parts Required или Parts Order подошли бы
идеально. Но мы решили сделать имя запроса покороче и назвали его просто
Orders.
Так какой запрос у нас является мастер-запросом? Это зависит от того, решили ли вы выполнять опциональный шаг по созданию отдельного запроса
со ссылкой на FilesList:
 если вы загрузили FilesList в качестве промежуточного запроса, мастерзапрос изначально будет носить имя FilesList (2), а создан он будет со
ссылкой на базовый запрос FilesList (правой кнопкой мыши -> Ссылка);
 в противном случае именно запрос FilesList и станет вашим мастерзапросом.
Определившись с тем, какой запрос вы будете использовать в качестве
мастер-запроса, можно приступать к процессу объединения файлов:
 выделите мастер-запрос и переименуйте его в Orders;
 нажмите на кнопку Объединить файлы (Combine Files) в виде двух
стрелок вниз в заголовке столбца Content.
После нажатия на кнопку Объединить файлы (#1 на рис. 9.12) откроется
окно предварительного просмотра, в котором вам будет предложено выбрать
пример файла (#2). Выбор файла приведет к отображению списка его компонентов (#3) и заполнению окошка справа предварительными данными по
любому выбранному объекту (#4).
Шаг 2: объединение файлов  237
Рис. 9.12. Объединение папки с файлами Excel
🍌 Примечание. К числу недостатков создания отдельного запроса со ссылкой
на FilesList можно отнести то, что в этом случае в списке примеров вы сможете выбрать только Первый файл (First File). Если же пропустить этот шаг,
в списке будут доступны все файлы в папке. Это может казаться большой
потерей, пока вы не поймете, что все же можете выбрать любой файл из
папки – для этого нужно просто вернуться к запросу FilesList и отсортировать
или отфильтровать его, чтобы нужный вам файл оказался первым в списке.
После этого вы сможете выбрать его.
Если присмотреться к структуре наших рабочих листов, можно обнаружить, что они содержат таблицу с именем Parts и два рабочих листа с именами Forecast и Matrix. К сожалению, несмотря на то что таблица Parts выглядит
очень опрятной и хорошо структурированной, она, по сути, служит в качестве
таблицы поиска для диапазона, расположенного на листе Forecast. Так что,
похоже, нам придется импортировать далеко не самую привлекательную
таблицу с листа Forecast и производить ее очистку вручную. Что ж, давайте
приступим:
 выберите рабочий лист Forecast и нажмите на кнопку OK.
Power Query ненадолго задумается, после чего объединит файлы и выдаст
результат, показанный на рис. 9.13.
Здесь есть о чем поговорить…
По сути, Power Query создал коллекцию вспомогательных запросов (helper
query), после чего добавил шаги в мастер-запрос для оперирования ими. Слева на панели Запросы (Queries) вы увидите папку с именем Вспомогательные запросы (Helper Queries), содержащую элементы Параметр (Parameter),
Пример файла (Sample File) и функцию Преобразовать файл (Transform File).
238  Глава 9. Объединение файлов
А под ними расположился очень важный запрос Преобразовать пример файла
(Transform Sample File).
Рис. 9.13. Вдруг у нас появилось четыре новых запроса
и пять новых шагов в мастер-запросе!
Также стоит отметить, что в окне предварительного просмотра попрежнему остался выделен мастер-запрос – запрос, который находился в фокусе до объединения файлов. Мы посмотрим внимательнее на шаги справа,
когда дойдем до четвертого шага в нашем списке. Но сейчас важно отметить,
что Power Query извлек и объединил содержимое листов Forecast из каждого
файла. Если бы данные на этих листах были нормально организованы и их
можно было красиво собрать вместе, было бы здорово. Но вы только взгляните на рис. 9.13! Power Query пришлось объединить вместе два сводных набора
данных с разными заголовками.
Если бы вы на данный момент уже прочитали эту книгу, то вы бы знали,
что даже с таким набором данных можно справиться в одном запросе. И все
же сделать это было бы не так просто. Возможно, лучше было бы отменить
свертывание данных еще до их добавления, чтобы избежать этой головной
боли? Хорошая новость состоит в том, что мы вполне можем это сделать.
Более того, с созданными вспомогательными запросами сделать это будет
очень просто!
🍌 Совет от профессионала. У вас может сложиться впечатление, что на этапе
объединения файлов вы можете получить доступ только к одному объекту из
каждого файла. Но это не так. Если вам необходимо объединить несколько
листов из нескольких рабочих книг или, допустим, только вторые листы в
книгах, вы можете это сделать. Для этого щелкните правой кнопкой мыши
по папке в области предварительного просмотра и выберите пункт Преобразовать данные (Transform Data). Это позволит извлечь таблицу со списком
всех объектов рабочей книги подобно тому, как мы делали это в главах 6 и 8
при помощи функции CurrentWorkbook().
Шаг 3: преобразование данных в запросе примера  239
Шаг 3: преобразование данных
в запросе примера
После объединения файлов нам необходимо подчистить данные. Для нормализации набора данных давайте выполним следующие действия:
 разобьем данные на столбцы;
 уберем из набора данных ненужные строки и столбцы;
 очистим данные для анализа.
Конечно, к каждому набору данных требуется особый подход, но конечная
цель всегда одна – преобразовать исходные данные таким образом, чтобы
на пересечении строк и столбцов располагались отдельные точки данных, а
столбцы носили понятные смысловые имена.
Почему нужно использовать запрос
«Преобразовать пример файла»?
Как преобразовывать данные – это очень важный вопрос, но сначала нужно ответить на вопрос о том, где выполнять эти преобразования, поскольку
в нашей расширенной коллекции запросов есть два места, где можно это
делать:
 запрос Преобразовать пример файла (Transform Sample File);
 мастер-запрос (Orders).
Мы советуем вам максимально возможное количество преобразований
выполнять именно в запросе Преобразовать пример файла, а не в мастер-запросе. Главным преимуществом такого выбора является то, что в этом случае
вы сможете построить свой запрос на основе одного файла примера, что значительно облегчит процесс очистки данных. Так можно избежать излишнего
усложнения работы с уже объединенными данными, поскольку ваши преобразования будут применяться к файлам еще до выполнения объединения.
В случае с операциями сведения, отмены свертывания или группировки это
может привести к существенному упрощению процесса.
И что еще более интересно, при выполнении преобразований в запросе
Преобразовать пример файла все ваши шаги синхронизируются с функцией
Преобразовать файл (Transform File). Затем эта функция вызывается для
всех файлов в списке перед их объединением, и это происходит автомагически!
🍌 Примечание. Используйте для очистки данных запрос Преобразовать пример файла всегда, когда это возможно.
Powered by TCPDF (www.tcpdf.org)
240  Глава 9. Объединение файлов
Использование запроса «Преобразовать пример файла»
Итак, давайте, наконец, воспользуемся запросом Преобразовать пример
файла для очистки одного из рабочих листов. Щелкните по этому запросу на
панели навигатора, и вам откроется картина, показанная на рис. 9.14.
Рис. 9.14. Все 13 строк в запросе основаны на первом файле из запроса FilesList
При первом открытии запроса Преобразовать пример файла важно отметить шаги, которые Power Query создал для вас автоматически. В данном
случае это шаги:
 Источник (Source), в котором содержится таблица со всеми объектами,
доступными в файле Excel;
 Навигация (Navigation), отражающий содержимое рабочего листа
Forecast;
 Повышенные заголовки (Promoted Headers), в котором первая строка
запроса возводится в ранг заголовков.
При внимательном взгляде на данные можно заметить, что ни строка,
повышенная до заголовков, ни следующие пять строк в запросе не несут
никакой смысловой нагрузки. Заголовки, которые нам нужны, на самом деле
содержатся в седьмой строке таблицы (включая строку, ставшую заголовками). Давайте это исправим:
 удалите шаг Повышенные заголовки (Promoted Headers);
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Удалить строки (Remove Rows) выберите пункт Удаление верхних строк
(Remove Top Rows) и введите число 6;
 теперь перейдите на вкладку Преобразование (Transform) и нажмите
на кнопку Использовать первую строку в качестве заголовков (Use
First Row as Headers).
Похоже, на этом этапе, отраженном на рис. 9.15, Power Query сделал что-то
очень опасное. Вы заметили это?
Шаг 3: преобразование данных в запросе примера  241
Рис. 9.15. Какой шаг вы не создавали?
Каждый раз, когда вы повышаете заголовки, Power Query прилежно пытается определить типы данных в столбцах. Иногда это может быть полезно, но
в то же время в этом случае имена столбцов оказываются жестко прописаны
прямо в шаге запроса. В чем проблема? Мы говорили об этом в начале главы – не все филиалы производят одинаковую продукцию, так что количество
столбцов в каждом запросе может быть своим.
Что произойдет при обработке файла филиала, который не производит
продукцию A, B или C, как в случае с филиалом North, информация по которому приведена на рис. 9.16? Правильно, возникнет ошибка на уровне шага.
Рис. 9.16. Понимание данных, с которыми вы работаете,
позволяет избежать проблем
🍌 Примечание. Будьте осторожны при внесении изменений в запрос Преоб-
разовать пример файла, особенно в случае, если имена столбцов могут отличаться в разных файлах. Лишний раз перепроверьте, чтобы в запросе были
явно указаны только имена столбцов, которые будут присутствовать во всех
без исключения файлах.
На самом деле на этом этапе нам вовсе не обязательно определять типы
данных в столбцах, так что давайте просто продолжим готовить данные к
отмене свертывания:
 удалите шаг Измененный тип (Changed Type);
 отфильтруйте столбец Part Nbr, сняв флажок со значения Total;
242  Глава 9. Объединение файлов
 найдите столбец Total и удалите его;
 щелкните правой кнопкой мыши по заголовку столбца Part Nbr и выберите пункт Отменить свертывание других столбцов (Unpivot Other
columns).
В результате вы получите набор данных, показанный на рис. 9.17.
Рис. 9.17. Набор данных после отмены свертывания
🍌 Примечание. Постойте… А не прописали ли мы в явном виде название столб-
ца Total при его удалении? Прописали. А это безопасно? В ответе на этот
вопрос могут быть свои нюансы, но если в файлах филиалов East и North
есть столбец Total, вероятно, мы можем сделать предположение о том, что он
будет присутствовать и в остальных файлах. Если такое предположение сделать нельзя, допустимо просто оставить столбец в данных, отменить свертывание, а затем отфильтровать значение Total в столбце Атрибут (Attribute),
чтобы в случае отсутствия такой колонки не возникали ошибки.
После отмены свертывания данных нам остается изменить названия
столбцов и установить типы данных. Для этого выполните следующие действия:
 переименуйте столбец Атрибут (Attribute) в Product;
 переименуйте столбец Значение (Value) в Units;
 выделите все столбцы, перейдите на вкладку Преобразование
(Transform) и нажмите на кнопку Определить тип данных (Detect
Data Type).
В результате вы получите набор данных, представленный на рис. 9.18.
При работе с запросом к одному файлу довольно просто предвидеть и
решить все потенциальные проблемы, связанные с явным указанием имен
столбцов в шагах. В мастер-запросе сделать это было бы гораздо более проблематично.
Шаг 4: преобразование данных в мастер-запросе  243
Рис. 9.18. Итоговый набор данных из 36 строк для файла примера
🙈 Предупреждение. А что будет, если забыть об этой проблеме и допустить
возникновение ошибки на уровне шага при выполнении операции объединения файлов? Конечно, вам придется прибегнуть к помощи отладки
запроса. Вернитесь к запросу FilesList и вставляйте временные шаги для сохранения или удаления верхних x строк, пока не обнаружите, какой запрос
стал источником проблемы. Когда он окажется первым в списке FilesList, вы
можете запустить отладку в запросе Преобразовать пример файла (Transform
Sample File), чтобы понять, что пошло не так.
Шаг 4: преобразование данных в мастер-запросе
Теперь можно вернуться к мастер-запросу и посмотреть результаты нашей
работы. Открыв запрос, вы увидите… ошибку на уровне шага.
Исправление ошибки на уровне шага в мастер-запросе
К сожалению, вид ошибки, показанный на рис. 9.19, нам хорошо знаком.
Рис. 9.19. Что за ерунда?
Причина ошибки кроется в шаге Измененный тип (Changed Type) мастерзапроса. Помните ту первую строку, которую Power Query повысил до заголовков? Тогда мы получили имена колонок Production Forecast, Column 2 и
т. д. И тогда же Power Query создал шаг Измененный тип в мастер-запросе с
явным указанием этих имен. В чем здесь проблема? В том, что мы удалили
те имена столбцов, а повысили заголовки из другой строки.
244  Глава 9. Объединение файлов
Это довольно распространенная ошибка, которая может быть очень легко
исправлена путем удаления шага Измененный тип и повторного его создания.
Рис. 9.20. Прощай, ошибка на уровне шага! Привет, данные!
🍌 Совет от профессионала. Если вы знаете, что вам придется переименовывать
столбцы в запросе Преобразовать пример файла (Transform Sample File), вы
можете даже удалить шаг Измененный тип в мастер-запросе перед его закрытием.
Сохранение свойств файлов
Хотя в итоговом виде в запросе Преобразовать пример файла содержалось всего 36 строк, сейчас в окне предварительного просмотра мы видим
288 строк, что говорит о том, что преобразование было применено ко всем
файлам в нашем списке, после чего они были объединены в одну таблицу.
Это очень здорово, но одна проблема все-таки осталась.
Каждый из файлов принадлежал своему филиалу, но при этом имя филиала никак не отражено в содержимом файла, только в его названии. Проблема
состоит в том, что мы где-то по пути потеряли имя филиала. Кроме того, в
каждом файле содержится дата окончания квартала. Эти данные находятся
в верхних строках, которые мы удаляем при выполнении запроса Преобразовать пример файла. Мы могли применить такой подход, поскольку все файлы
у нас располагаются в строгой иерархии папок с названиями, соответствующими шаблону yyyy­qq. Но, опять же, по пути мы растеряли и информацию
о содержащих файлы папках. Как же нам все это вернуть?
В этой связи очень уместно будет взглянуть на шаги, которые Power Query
создал для нас в мастер-запросе при объединении файлов, и первый из них
называется Отфильтрованные скрытые файлы1 (Filtered Hidden Files1).
🍌 Примечание. Шаг с именем Отфильтрованные скрытые файлы1 будет сто-
ять вторым в списке, если вы предпочли создать отдельный запрос FilesList.
В противном случае вы сможете найти его внутри запроса сразу после вызова процедуры объединения файлов.
Шаг 4: преобразование данных в мастер-запросе  245
Давайте посмотрим, что делают автоматически созданные шаги:
 Отфильтрованные скрытые файлы1 (Filtered Hidden Files1). Добавляет
фильтр для удаления из списка скрытых (hidden) файлов. Да, Power
Query перечисляет в числе прочих скрытые и системные файлы;
 Вызвать настраиваемую функцию1 (Invoke Custom Function1). Добавляет столбец, заполненный на основании вызова функции Преобразовать файл (Transform File), которая была создана на базе ваших
действий в запросе Преобразовать пример файла (Transform Sample
File). В результате выполнения этого шага появится колонка с табличными объектами, заполненными преобразованными данными из
каждого файла;
 Другие удаленные столбцы1 (Removed Other Columns1). На этом шаге
из таблицы удаляются все столбцы, кроме созданного на предыдущем
шаге. Именно здесь мы теряем имена файлов и папок;
 Столбец расширенной таблицы1 (Expanded Table Column1). На данном
шаге мы разворачиваем столбец, добавленный ранее. В результате содержимое всех файлов оказывается объединенным в одну таблицу.
Теперь, когда мы понимаем, что происходит на каждом из шагов, нам необходимо отредактировать шаг Другие удаленные столбцы1, чтобы сохранить
нужные нам свойства файлов, которые Power Query счел ненужными:
 выделите шаг Другие удаленные столбцы1 (Removed Other Columns1) и
нажмите на кнопку с изображением шестеренки справа от него;
 в открывшемся диалоговом окне, показанном на рис. 9.21, установите
флажки Name и Folder Path и нажмите на кнопку OK.
Как видно на рис. 9.21, мы восстановили в таблице столбцы с именами
файлов и путями к ним.
Рис. 9.21. Возвращение утраченных столбцов
246  Глава 9. Объединение файлов
Добавление дополнительных шагов
Теперь мы можем произвести дополнительные изменения в запросе для
обозначения действий, которые необходимо выполнить с каждым файлом.
Проделайте следующее:
 выделите шаг Столбец расширенной таблицы1 (Expanded Table
Column1), чтобы нам не предлагали после каждого действия вставлять
новый шаг;
 переименуйте столбец Name в Division;
 щелкните правой кнопкой мыши на заголовке столбца Division и выберите пункт Замена значений… (Replace Values…). Замените вхождение «.xlsx» на пустую строку;
 щелкните правой кнопкой мыши на заголовке столбца Folder Path и в
выпадающем меню Разделить столбец (Split Column) выберите пункт
По разделителю (By Delimiter). Выберите вариант разделения столбцов по левому пробелу.
🙈 Предупреждение. При разделении столбцов Power Query автоматически до-
бавляет шаг с изменением типов данных. Вы должны сами решить, нужен
вам этот шаг или нет. Если вы считаете, что в будущем он может доставить
вам неприятности, лучше будет удалить его и применить типы данных непосредственно перед загрузкой в место назначения.
Поскольку шаг с изменением типов данных здесь нам не нужен, мы избавимся от него, несмотря на то что видимых проблем он не доставляет:
удалите шаг Измененный тип (Changed Type);
переименуйте столбец Folder Path.1 в Year;
переименуйте столбец Folder Path.2 в Quarter;
щелкните правой кнопкой мыши на заголовке столбца Quarter и выберите пункт Замена значений… (Replace Values…). Замените обратный
слеш (\) на пустую строку;
 выделите все столбцы, перейдите на вкладку Преобразование
(Transform) и нажмите на кнопку Определить тип данных (Detect
Data Type).




На этом мы завершаем работу с мастер-запросом, итоговый вид которого
показан на рис. 9.22. Мы отменили свертывание и объединили данные, сохранив при этом ключевые части из имени файла и пути к папке, необходимые нам для дальнейшего анализа.
🙈 Предупреждение. Типы данных никогда не переносятся из запроса с преобразованием файла. Всегда устанавливайте их на заключительном шаге
перед загрузкой данных на рабочий лист или в модель данных.
Шаг 4: преобразование данных в мастер-запросе  247
Рис. 9.22. Первые столбцы в нашем наборе данных были извлечены
из метаданных об имени файла и пути к нему
Поскольку процесс преобразования данных мы уже завершили, загрузим
их в место назначения для дальнейшего анализа при помощи отчетов. На
этот раз мы осуществим загрузку в модель данных:
 в Power BI нажмите на кнопку Закрыть и применить (Close & Apply);
 в Excel перейдите на вкладку Главная (Home), нажмите на текст под
кнопкой Закрыть и загрузить (Close & Load), а не на саму кнопку, и
выберите вариант Закрыть и загрузить в… (Close & Load To…). Установите переключатель в положение Только создать подключение
(Only Create Connection) и флажок Добавить эти данные в модель
данных (Add this data to the Data Model), как показано на рис. 9.23.
Рис. 9.23. Загрузка данных в модель
Вы заметите, что, несмотря на создание множества запросов в одной сессии, только мастер-запрос будет загружен в место назначения. Все вспомо-
248  Глава 9. Объединение файлов
гательные запросы, включая Преобразовать пример файла (Transform Sample
File), по умолчанию загружаются в виде подключений (подготовительных
запросов).
Обновление
После загрузки данных мы можем попробовать построить повторно используемое бизнес-решение.
Использование данных
Для демонстрации полного цикла от импорта до обновления нам необходимо построить какой-то быстрый отчет с использованием матрицы или
сводной таблицы. Шаги по созданию такого отчета будут зависеть от приложения, которое вы используете.
Если вы используете Power BI, выполните следующие действия:
 на вкладке Отчет (Report) нажмите на кнопку Матрица (Matrix) на
панели Визуализации (Visualizations).
Если вы работаете в Excel:
 выделите ячейку B3 на пустом рабочем листе и на вкладке Вставка
(Insert) нажмите на кнопку Сводная таблица (PivotTable);
 подтвердите, что вы хотите использовать данные из модели, и нажмите
на кнопку OK.
После создания объекта перенесите поля таблицы Orders справа в следующие области:
 Units – в область значений;
 Part Nbr – в область строк;
 Year, Quarter – в область столбцов.
Результат (как для Excel, так и для Power BI) показан на рис. 9.24. Предполагается, что в Power BI вы нажали на кнопку разворачивания данных (Expand),
отмеченную стрелкой, для показа информации по кварталам.
Рис. 9.24. Сравнение результатов в Excel и Power BI
Добавление новых файлов  249
Добавление новых файлов
Пришло время узнать, что будет, если добавить к вашим данным новый файл.
Если открыть папку Ch09 Examples в проводнике Windows, то можно заметить, что не все папки с данными находятся внутри директории Source Data,
к которой мы подключаемся, – есть и отдельно лежащая папка с именем
2019 Q4, в которой находятся наиболее свежие сведения по нашим филиалам.
Перенесите эту папку в Source Data, чтобы данные по всем четырем кварталам оказались собраны вместе, как показано на рис. 9.25.
Рис. 9.25. Пришло время добавить новые данные
После этого вернитесь в отчет и обновите данные следующим образом:
 в Power BI перейдите на вкладку Главная (Home) и нажмите на кнопку
Обновить (Refresh);
 в Excel откройте вкладку Данные (Data) и нажмите на кнопку Обновить все (Refresh All).
Через пару секунд вы увидите, что в отчете появятся данные за четвертый
квартал, как показано на рис. 9.26.
Рис. 9.26. 3… 2… 1… Данные обновились!
Как же это невероятно круто! Мы можем не только легко и просто добавлять множество файлов к исходным данным, мы даже построили динамическую бизнес-платформу, которая при появлении новых данных обновляется
всего при помощи нескольких щелчков мыши!
250  Глава 9. Объединение файлов
Здесь важно понимать, что у вас есть разные варианты для построения и
обновления решения в зависимости от того, как вы получаете новые данные. Взгляните на диаграмму, изображенную на рис. 9.27, которая демонстрирует гибкость обновления решения при взаимодействии с внешними
данными.
Отдельные файлы
Все файлы в папке
Сохраните
новый файл
поверх
оригинала
Сохраните
новый файл
с новым именем
Откройте
решение
Редактируйте
запрос
Сохраните
новый файл
в той же папке
Преимущества
Повторное
использование
бизнес-логики и отчетов
Откройте
решение
Обновите путь
источника
к новому файлу
Закройте
редактор
Power Query
Нажмите Обновить
Обновление визуальных
элементов
Рис. 9.27. Методы обновления решения при подключении к внешним данным
Получаете ли вы обновленные файлы с данными, которые кладутся поверх или рядом с предыдущими версиями файлов и используются вместо
них, или хотите построить масштабное решение с нарастающими данными,
Power Query вам поможет!
Повышение эффективности с помощью
сохранения верхних строк
Какими бы универсальными ни казались решения, реализованные при помощи коннектора Из папки (From Folder), вы должны понимать, что при
бесконечно долгом добавлении все новых и новых файлов в исходную папку скорость их обработки будет неизбежно снижаться. Всем понятно, что
на обработку ста файлов потребуется больше времени, чем на обработку
десяти, особенно с учетом того, что мы не можем настроить Power Query на
обновление только новых или измененных файлов. Таким образом, каждый
раз, когда вы нажимаете на кнопку обновления, Power Query загружает ВСЕ
данные из ВСЕХ файлов в папке.
Представьте, что будет, если созданное нами решение проработает в компании десять лет. Это 16 файлов в год (четыре филиала и четыре квартала).
Получается, что к концу 2030 года в вашей папке будет находиться 176 файлов. Конечно, наши файлы в примере очень малы по размеру, а что, если на
обработку каждого из них потребуется порядка пяти секунд? В результате
получим более 14 минут ожидания обновления нашего решения, а это целая
вечность.
Повышение эффективности с помощью сохранения верхних строк  251
Первым делом при проектировании подобных сценариев вы должны задать себе вопрос о том, нужны ли вам все эти данные. Действительно ли вам в
2030 году будет интересно, что там было в 2019-м? Если вы будете проводить
сравнение только с предыдущим годом, файлов в папке у вас будет в худшем
случае 32. Так почему бы не остановиться на таком сценарии?
Чтобы ограничить количество обрабатываемых файлов, вам необходимо
вернуться на шаг со списком файлов и:
 отсортировать файлы по дате от позднего к раннему;
 воспользоваться инструментом Сохранить верхние строки (Keep Top
Rows) для обновления ограниченного количества файлов.
Главный вопрос здесь состоит в том, какое поле выбрать для выполнения
сортировки. В нашем случае будет достаточно сортировать файлы по столбцу
Folder Path, поскольку папки у нас названы в точном соответствии с датами
содержащихся в них файлов. Если структура директорий не предполагает
такой строгой зависимости, придется полагаться на специальные поля Date
Created или Date Modified.
🍌 Примечание. Помните, что количество обрабатываемых файлов может варь-
ироваться от одного до нужного вам числа в зависимости от ваших требований. Во многих проектах мы сталкивались с необходимостью сохранять
данные за последние 24 месяца.
🙈 Предупреждение. Если вы просто копируете и вставляете файлы в исход-
ную папку, можно довольно безопасно использовать для сортировки поле
Date Created. Но имейте в виду, что в поле Date Created может стоять и более
поздняя дата, чем в Date Modified. Дело в том, что при копировании и вставке
в качестве даты создания файла устанавливается момент его переноса в
новую папку, тогда как дата его последнего изменения может остаться более
ранней, если файл не правился после вставки. Полагаться исключительно на
поле Last modified тоже бывает опасно, поскольку даже простого открытия
файла может быть достаточно, чтобы дата его изменения перезаписалась.
Глава
10
Объединение данных
Одной из классических задач для специалистов по работе с данными является объединение (merging) нескольких наборов данных в один для создания
сводной таблицы. Тогда как профессионалы SQL для этого традиционно применяют различные модификации оператора Join, в Excel упорно продолжают
пользоваться ВПР (VLOOKUP) и сочетанием ИНДЕКС (INDEX) с ПОИСКПОЗ
(MATCH) – функциями, которые до сих пор пугают многих пользователей.
С выходом на арену Power Query в арсенале пользователей Excel появился
еще один способ объединения двух таблиц в одну по горизонтали, не подразумевающий изучения операторов Join в SQL, непонятных функций Excel
и принципов создания реляционных баз данных.
Основы объединения данных
В нашем примере мы рассмотрим вариант объединения данных из двух источников: таблицы с транзакциями по продажам (Sales) и таблицы с описанием товаров (Inventory). Местом хранения этих таблиц будет Excel, хотя нас
это интересует только с точки зрения выбора правильного коннектора при
подключении к источнику.
Необходимость объединения двух этих таблиц объясняется тем, что в таблице Sales содержатся дата продажи (Date), код товара (SKU), бренд (Brand)
и количество проданных единиц (Units), тогда как никакого упоминания о
цене и себестоимости товаров нет. Зато эта и другая полезная информация
о товарах присутствует в таблице Inventory, как показано на рис. 10.1.
Рис. 10.1. Таблицы Sales и Inventory
Наша задача – объединить эти таблицы в одну с целью получения полной
информации о продаваемых товарах.
254  Глава 10. Объединение данных
Создание подготовительных запросов
Будете ли вы использовать данные, находящиеся в файле Ch10 Examples\
Merging Basics.xlsx, из него самого или предпочтете подключаться к исходным таблицам из другого файла Excel или Power BI – дело ваше. В любом из
этих вариантов вам придется создать подготовительные запросы для обеих
таблиц:
 создайте запросы, подключающиеся к каждой из двух таблиц в файле
Ch10 Examples\Merging Basics.xlsx;
 сохраните запросы в виде подготовительных, как показано на рис. 10.2,
для чего отмените их загрузку или выберите загрузку только в виде
подключения.
🍌 Примечание. Для объединения или добавления запросов в Excel эти запросы должны быть созданы. Простого наличия соответствующих таблиц в
рабочей книге Excel недостаточно, поскольку изначально Power Query не
располагает компонентом, ассоциированным с таблицей, – его необходимо
создать явным образом.
Итак, у вас есть два простых запроса, требующих объединения.
Рис. 10.2. Запросы Sales и Inventory готовы к объединению
Выполнение объединения запросов
Как и в случае с добавлением запросов, пользователи Excel могут объединять запросы, воспользовавшись контекстным меню для запроса на панели
Запросы и подключения (Queries & Connections). И так же, как и при добавлении запросов, это приведет к созданию единственного примененного
шага в Power Query с именем Источник (Source), в котором будет выполнено
нужное нам объединение запросов. Поскольку это может затруднить понимание процесса, мы предварительно создадим ссылку на запрос, чтобы
можно было видеть каждый шаг в запросе отдельно:
 щелкните правой кнопкой мыши по запросу Sales и выберите пункт
Ссылка (Reference);
Основы объединения данных  255
 переименуйте запрос в Transactions;
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Объединить запросы (Merge Queries) выберите пункт Объединить запросы (Merge Queries) (не Объединить запросы в новый (Merge
Queries as New)).
🍌 Примечание. Пункт Объединить запросы в новый (Merge Queries as New)
выполнит те же действия, что и вариант объединения данных из контекстного меню панели Запросы и подключения (Queries & Connections), то есть
создаст отдельный запрос с единственным шагом.
Откроется диалоговое окно Слияние (Merge), в котором вы можете выбрать таблицу, которую хотите объединить с выбранной.
По умолчанию активный запрос (в нашем случае это Transactions, созданный на основе Sales) будет выбран в верхней части диалогового окна. Ниже
вы увидите окно предварительного просмотра запроса и выпадающий список, в котором необходимо выбрать запрос для объединения.
🍌 Примечание. Любопытно, что у вас есть возможность объединить запрос сам
с собой, и это бывает полезно в определенных ситуациях, о которых мы подробно поговорим в главе 14.
Поскольку активным в нашем случае является запрос Sales, мы в качестве
присоединяемого к нему выберем запрос Inventory:
 выберите в выпадающем списке таблицу Inventory;
 в выпадающем списке Тип соединения (Join Kind) оставьте значение
по умолчанию Внешнее соединение слева (Left Outer);
 флажок Использовать нечеткие соответствия для слияния (Fuzzy
Matching) оставьте неустановленным.
Как это ни удивительно, но после всего этого кнопка OK не активируется,
что видно по рис. 10.3.
Дело в том, что мы не указали Power Query, по каким столбцам необходимо
выполнять объединение запросов.
В идеале в качестве столбца для объединения таблиц должна выступать
колонка, в которой в одной таблице находятся уникальные значения, а во
второй – повторяющиеся. Такая связь именуется «один ко многим» (one-tomany), и в этом случае шансы на то, что результат объединения таблиц вас
удовлетворит, будут весьма высоки.
🍌 Примечание. Как вы вскоре увидите, Power Query также поддерживает связи
типа «один к одному» и «многие ко многим».
256  Глава 10. Объединение данных
Рис. 10.3. Таблицы мы выбрали, а что же забыли?
В нашем случае в столбце с именем SKU содержатся уникальные значения
в таблице Inventory, а в таблице Sales они повторяются, так что давайте используем это поле для объединения:
 выберите столбец SKU в обеих таблицах;
 нажмите на кнопку OK.
Откроется редактор Power Query, в котором в запросе Transactions вы
увидите одну дополнительную колонку с именем Inventory, как показано на
рис. 10.4.
Рис. 10.4. Новый столбец, содержащий таблицы
с соответствующими данными из запроса Inventory
Типы соединений  257
Мы уже знаем, что нужно делать со столбцами, в которых хранятся таблицы, – конечно, разворачивать их! Другой вопрос – какие колонки из присоединяемой таблицы нам нужны. Поскольку в нашей таблице Sales уже есть
столбцы SKU и Brand, второй раз нам их добавлять не нужно, так что давайте
избавимся от них на этапе объединения:
 щелкните по иконке Развернуть (Expand) в правой части заголовка
столбца Inventory;
 снимите флажки с полей SKU и Brand;
 снимите флажок использования исходного имени столбца в качестве
префикса и нажмите на кнопку OK.
Как видно на рис. 10.5, столбцы с подробностями о продаваемых товарах
оказались присоединены к нашему запросу Sales.
Рис. 10.5. Выбранные поля из таблицы Inventory присоединились к таблице Sales
В итоговый запрос вошли 20 записей – по одной для каждой продажи в исходной таблице Transaction. По сути, выполненное нами действие в точности
повторяет использование функции ВПР (VLOOKUP) с точным поиском в Excel
или оператора Left Outer Join в SQL.
Типы соединений
Профессионалы SQL прекрасно знают, что объединить две таблицы можно
огромным множеством способов. К сожалению, от разработчиков и пользователей Excel этот факт зачастую остается скрытым, поскольку они в большинстве случаев выполняют операцию Left Outer Join (ВПР). В Power Query вы
получаете в свое распоряжение полный спектр типов соединения (Join Type)
таблиц прямо в диалоговом окне слияния. Такая свобода выбора позволяет
нам осуществлять поиск не только совпадающих значений, но и несовпадающих, что бывает очень полезно.
Давайте рассмотрим две таблицы, представленные на рис. 10.6.
258  Глава 10. Объединение данных
Рис. 10.6. Можно ли объединить эти записи?
Данные в этих таблицах связаны между собой, но не без любопытных нюансов.
Присмотримся к таблице Chart of Accounts, располагающейся справа. Здесь
представлен уникальный список счетов в системе, но его уникальность может
быть обеспечена только сочетанием столбцов Account и Dept. Если вы внимательно присмотритесь к содержимому столбца Account в этой таблице, то
заметите, что значения в первых четырех строках повторяются в следующих
четырех, что говорит о наличии дубликатов. В столбце Dept первые четыре
строки содержат значение 150, а следующие четыре – 250. Если мысленно
собрать содержимое этих двух столбцов вместе с разделителем, дубликаты
тут же исчезнут, смотрите сами: 64010-150, 64020-150, 64010-250 и т. д. Такой
же шаблон можно наблюдать и в таблице Transactions, находящейся слева.
Это означает, что мы можем сопоставить данные в таблицах Transactions и
Chart of the Accounts, если сможем оперировать для связки составным ключом
(composite key), как показано на рис. 10.7.
Рис. 10.7. Наша цель – сопоставить имя аккаунта по комбинации полей Account и Dept
Второй нюанс кроется в выделенных строках на рисунке. Как видите,
в таблице Chart of Accounts отсутствуют строки для сочетания значений
64015-150 и 64010-350. Также в таблице Transactions не представлены записи
для счетов Special и Pull Cart.
Типы соединений  259
В нашем конкретном случае эти несоответствия носят разный характер.
В таблице Chart of Accounts хранится список счетов, которые МОГУТ быть
использованы в транзакциях. Таким образом, если счет присутствует в таблице Chart of Accounts, но не используется в таблице Transactions, это вполне
нормальная ситуация. С другой стороны, если комбинация значений в полях
Account и Dept заявлена в таблице Transactions, но отсутствует в таблице Chart
of Accounts, это серьезная проблема!
🍌 Примечание. Подобные проблемы могут возникать и в других предметных
областях, где необходимо осуществлять проверку соответствия и сравнивать
два списка. Это могут быть клиенты и их лимиты кредитования, продажи и
заказы, детали и цены. Список примеров можно продолжать бесконечно.
Далее мы рассмотрим семь разновидностей соединений, которые могут
использоваться при слиянии данных в таблицах.
🍌 Примечание. Помните, что при объединении данных огромную роль играют
типы данных. Перед выполнением слияния убедитесь в том, что в столбцах,
по которым вы планируете выполнять объединение, типы данных указаны
корректно и одинаково.
На данный момент вы должны уже довольно ловко создавать подготовительные запросы в режиме подключения, так что мы не будем подробно останавливаться на этом процессе. Вы можете открыть файл Ch10 Examples\Join
Types.xlsx, в котором, как видно на рис. 10.8, уже созданы подготовительные
запросы для таблиц Transactions и COA (Chart of Accounts).
Рис. 10.8. Запросы Transactions и COA
260  Глава 10. Объединение данных
Внешнее соединение слева
Первым мы рассмотрим тип соединения, выбираемый по умолчанию: внешнее соединение
слева (Left Outer Join). В результате объединения
таблиц этим методом из левой (верхней) таблицы выбираются все записи, а из правой (нижней) – только совпадающие. Строки из правой
таблицы, для которых не нашлось соответствия,
просто игнорируются.
Для создания этого типа соединения выполните следующие действия:
Рис. 10.9. Внешнее соединение
слева. Все записи из
левой таблицы и только
совпадающие из правой
 определитесь с тем, какая таблица у вас в связи будет расположена
слева. Мы будем использовать таблицу Transactions;
 щелкните правой кнопкой мыши по левому запросу и выберите пункт
Ссылка (Reference);
 переименуйте образованный запрос в Left Outer;
 перейдите на вкладку Главная (Home) и нажмите на кнопку Объединить запросы (Merge Queries);
 выберите в выпадающем списке правую таблицу – COA.
Сейчас мы должны сделать паузу и разобраться с первым из двух нюансов,
которые мы упоминали ранее. Мы планируем устанавливать связь между
таблицами на основании двух столбцов: Account и Dept. И хотя мы могли
бы соединить их в один столбец, используя разделитель, на самом деле в
этом нет ни малейшей необходимости. Просто щелкните мышью по столбцу
Account, а затем, удерживая клавишу CTRL, щелкните по столбцу Dept. Во
второй таблице повторите те же действия, как показано на рис. 10.10.
Порядок выбора столбцов, входящих в составной ключ, будет отображаться
справа от заголовка (1, 2 и т. д.) в той последовательности, в которой вы их
выбирали. Помните, что в исходных таблицах столбцы, используемые для
связи, не обязаны располагаться в одинаковом порядке – достаточно выбрать
их в одной последовательности.
🍌 Примечание. Хотя внешне вы этого не видите, внутренне значения столбцов,
выбранных вами в качестве составного ключа, объединяются при помощи
неявного разделителя. При этом разделитель используется для того, чтобы
Power Query всегда корректно выполнял объединение. Допустим, если у вас
есть идентификаторы товаров от 1 до 11 и идентификаторы отделов 1 дo 11,
неявный разделитель поможет избежать неопределенности при образовании составного ключа 111. Вместо этого составной ключ может выглядеть
как 1-11 или 11-1, что позволит однозначно определить связь.
Типы соединений  261
Рис. 10.10. Объединение таблиц с использованием составного ключа
🙈 Предупреждение. В нижней части диалогового окна выводится информация
о том, сколько совпадений обнаружил Power Query по введенным вами критериям на основании данных в окне предварительного просмотра. И хотя в
нашем случае эта информация оказалась корректной (только шесть из восьми строк в левой таблице нашли соответствия в правой таблице), вы должны
помнить, что в окне предварительного просмотра может находиться 1000
или меньше строк для каждого из набора данных. Это означает, что при выводе информации о слабом соответствии двух таблиц на самом деле соответствие между ними может быть куда большим.
Теперь можно нажать на кнопку OK, тем самым подтверждая создание
объединения. Это приведет к добавлению в запрос колонки с именем COA,
выбранным в соответствии с названием правой таблицы в объединении.
Осталось развернуть созданный столбец, выбрав нужные для добавления в
таблицу столбцы. Для этого щелкните по иконке Развернуть (Expand) в правой части заголовка столбца COA, установите флажок использования исходного имени таблицы в качестве префикса и нажмите на кнопку OK.
Результат объединения таблиц показан на рис. 10.11.
262  Глава 10. Объединение данных
Рис. 10.11. Результат выполнения внешнего соединения слева
Основные моменты, которые следует понимать, исходя из итоговой таблицы:
 в первых шести строках содержится вся информация из левой таблицы
(Transactions) и соответствующие данные из правой (COA);
 в строках 7 и 8 выводится информация из таблицы Transactions, а в
ячейках, соответствующих таблице COA, значения отсутствуют (null);
 после загрузки данных на рабочий лист или в модель данных все значения null превратятся в пустые ячейки.
В обычной ситуации вы вряд ли оставляли бы в итоговой таблице столбцы
Account и Dept из левой таблицы, но в данном случае мы это сделали, чтобы
показать, что в этих колонках значения отсутствуют по причине того, что в
таблице COA для этих строк не были найдены совпадения.
Внешнее соединение справа
Как мы говорили ранее, по умолчанию при
объединении таблиц Power Query предлагает
использовать в качестве типа соединения внешнее соединение слева. Здесь же мы рассмотрим
его брата-близнеца – внешнее соединение справа
(Right Outer Join).
Для создания этого типа соединения выполните следующие действия:
Рис. 10.12. Внешнее
соединение справа. Все записи
из правой таблицы и только
совпадающие из левой
 определитесь с тем, какая таблица у вас в
связи будет расположена слева. Мы будем
использовать таблицу Transactions;
 щелкните правой кнопкой мыши по левому запросу и выберите пункт
Ссылка (Reference);
 переименуйте образованный запрос в Right Outer;
 перейдите на вкладку Главная (Home) и нажмите на кнопку Объединить запросы (Merge Queries);
 выберите в выпадающем списке правую таблицу – COA;
Типы соединений  263
 зажмите клавишу CTRL и выберите поочередно столбцы Account и Dept
в обеих таблицах;
 в выпадающем списке Тип соединения (Join Kind) выберите вариант
Внешнее соединение справа (Right Outer) и нажмите на кнопку OK.
Здесь важно пояснить один момент, который вас может удивить. Присмотритесь внимательно к данным, показанным на рис. 10.13. Видите, в одной
из строк значения во всех столбцах null, а в столбце COA находится таблица?
Рис. 10.13. В строке 5 многовато значений null
Хотя это может вам показаться странным, такое поведение вполне объяснимо и означает, что у нас есть элементы в правой таблице, которым не
нашлось соответствия в левой. Давайте развернем таблицы и посмотрим,
что будет:
 щелкните по иконке Развернуть (Expand) в правой части заголовка
столбца COA, установите флажок использования исходного имени
столбца в качестве префикса и нажмите на кнопку OK.
Результат будет выглядеть так, как показано на рис. 10.14.
Рис. 10.14. Итоги внешнего соединения справа
На этот раз все ячейки в колонках с префиксом COA оказались заполнены, но, поскольку по счетам Special и Pull Cart транзакций не было, в левых
столбцах по ним стоят значения null.
264  Глава 10. Объединение данных
Полное внешнее соединение
Давайте посмотрим, что получится, если мы
будем использовать при объединении тех же
таблиц Полное внешнее соединение (Full Outer
Join). Пройдем по тому же алгоритму, используя
другой тип соединения:
 определитесь с тем, какая таблица у вас в
Рис. 10.15. Полное внешнее
связи будет расположена слева. Мы будем
соединение. Все записи из
использовать таблицу Transactions;
обеих таблиц
 щелкните правой кнопкой мыши по левому запросу и выберите пункт Ссылка
(Reference);
 переименуйте образованный запрос в Full Outer;
 перейдите на вкладку Главная (Home) и нажмите на кнопку Объединить запросы (Merge Queries);
 выберите в выпадающем списке правую таблицу – COA;
 зажмите клавишу CTRL и выберите поочередно столбцы Account и Dept
в обеих таблицах;
 в выпадающем списке Тип соединения (Join Kind) выберите вариант
Полное внешнее (Full Outer) и нажмите на кнопку OK;
 щелкните по иконке Развернуть (Expand) в правой части заголовка
столбца COA, установите флажок использования исходного имени
столбца в качестве префикса и нажмите на кнопку OK.
Результат такого объединения показан на рис. 10.16.
Рис. 10.16. Итог полного внешнего объединения таблиц
Обратите внимание, что в этом случае мы собираем не только записи,
у которых есть соответствия в противоположной таблице. Вместо этого в
итоговый набор данных были включены и строки из левой таблицы, которым
не нашлось пары справа (9 и 10), и строки из правой без совпадений слева
(5 и 7). Этот тип соединения бывает очень полезен при необходимости выполнить полный обзор двух списков в поисках элементов без соответствий.
Типы соединений  265
🍌 Примечание. Этот тип соединения также объясняет, почему при сравнении
двух списков вам часто хочется раскрыть столбцы из правой таблицы, на
которых основывается связь. Если в строках нет соответствий с левой таблицей, единственное место, где можно увидеть ключи, – это правая часть
соединения.
Внутреннее соединение
На этот раз самостоятельно пройдите процедуру создания связи между таблицами, указав при этом тип соединения – внутреннее
(Inner Join). Результат объединения данных
показан на рис. 10.18.
При таком типе соединения в результирующий набор данных попадает существенно
меньше строк. Причина этого проста – мы отбрасываем все строки, для которых не нашлось
соответствия в противоположной таблице.
Рис. 10.17. Внутреннее
соединение. Только записи,
присутствующие в обеих
таблицах
Рис. 10.18. Итог внутреннего объединения
Антисоединение слева
Типы соединений, которые мы рассматривали до сих пор, в основном были направлены на
идентификацию совпадений в данных. Но когда
нам необходимо проанализировать два списка
на предмет их различий, нас больше интересуют не совпадения данных, а их расхождения.
Любопытно, но в складском учете мы обычно
Рис. 10.19. Антисоединение
тратим уйму времени на поиск совпадений,
слева. Только те записи из
чтобы в итоге удалить их из анализа, поскольку
левой таблицы, для которых
на самом деле нас интересуют именно расхожнет совпадений в правой
дения в остатках!
Результат, показанный на рис. 10.20, был получен в результате объединения тех же данных, что и раньше, но с использованием антисоединения слева
(Left Anti Join).
266  Глава 10. Объединение данных
Рис. 10.20. Итог выполнения антисоединения слева
Вы заметили, что в итоговый набор данных попали лишь две строки – это
как раз те две транзакции, для которых не нашлось соответствия комбинации
столбцов Account и Dept в таблице Chart of Accounts.
🍌 Примечание. Если ваша единственная цель – получить данные из левой таб-
лицы, не имеющие совпадений с правой таблицей, нет никакой необходимости разворачивать полученные результаты объединения. Вместо этого вы можете просто удалить присоединенную колонку из правой таблицы, поскольку
в ней будут исключительно значения null.
Антисоединение справа
Используйте тот же шаблон объединения
данных, что и раньше, но в выпадающем списке выберите Антисоединение справа (Right Anti
Join). Результат будет таким, как на рис. 10.22.
Как видите, в итоговый набор попали только
знакомые нам счета Special и Pull Cart, по которым не было ни одной транзакции.
Рис. 10.21. Антисоединение
справа. Только те записи из
правой таблицы, для которых
нет совпадений в левой
Рис. 10.22. Итог выполнения антисоединения справа
🍌 Примечание. Будьте готовы к тому, что при выполнении антисоединения
справа вы всегда будет получать единственную строку со значениями null в
левых колонках и единственным табличным значением в присоединенном
справа столбце. Это вполне ожидаемо, поскольку для заполненных значений в правой таблице просто не нашлось соответствий в левой. Если ваша
цель – оставить в запросе только найденные значения, не имеющие совпадений слева, вы можете щелкнуть правой кнопкой мыши по заголовку правого
столбца и выбрать пункт Удалить другие столбцы (Remove Other Columns)
перед его разворачиванием.
Типы соединений  267
Полное антисоединение
Еще одним очень полезным типом соединения, особенно если вам нужно определить записи, не имеющие соответствий в противоположных таблицах, является полное антисоединение
(Full Anti Join). Жаль, что этот тип соединения
нельзя выбрать в привычном уже нам выпадающем списке при объединении запросов. Но не
отчаивайтесь, ведь это соединение очень легко
воссоздать. Для этого выполните следующие
действия:
Рис. 10.23. Полное
антисоединение. Все записи
без совпадений
 создайте антисоединение слева;
 создайте антисоединение справа;
 сделайте ссылку на запрос с антисоединением слева, чтобы создать
новый запрос;
 на вкладке Главная (Home) нажмите на кнопку Append Queries (Добавить запросы), выберите запрос с антисоединением справа и нажмите
на кнопку OK.
Результат этого действия будет полной противоположностью итогу внутреннего объединения таблиц, в котором показываются только записи, имеющие соответствия в противоположных таблицах. Здесь же останутся лишь
строки, не нашедшие себе пары, что видно по рис. 10.24.
Рис. 10.24. При полном антисоединении остаются только записи без совпадений
Как видите, строки 1 и 2 пришли к нам из антисоединения слева, а
строки 3 и 4 – из антисоединения справа. Это очень полезный тип соединения, позволяющий создать полный список исключений на основании
двух таблиц.
🍌 Примечание. Помните о том, что при добавлении запросов столбцы, отсутст-
вующие в базовом запросе, будут созданы в добавленном запросе и заполнены значениями null. Если удалить пустые колонки в антисоединениях
слева и справа, этот шаблон по-прежнему останется рабочим, при условии
что имена столбцов в антисоединении справа не будут встречаться в антисоединении слева.
268  Глава 10. Объединение данных
Декартовы произведения
Как бы вы ни называли этот тип объединения – декартовым произведением
(Cartesian Product), связью «многие ко многим» (many-to-many join) или перекрестным соединением (cross join), – он позволяет извлечь все значения из
двух списков и создать на их основании записи со всеми возможными их
сочетаниями. Простейший пример перекрестного соединения показан на
рис. 10.25, где мы сочетаем все товары и цвета.
Рис. 10.25. Результат декартова произведения таблиц Color и Product
Методология
Создать декартово произведение в Power Query можно довольно просто,
воспользовавшись следующей инструкцией:
 для каждой таблицы слияния:
• подключитесь к источнику данных и выполните необходимую
очистку;
• на вкладке Добавление столбца (Add Column) нажмите на кнопку
Настраиваемый столбец (Custom Column);
• назовите столбец MergeKey и введите формулу: =1;
 щелкните правой кнопкой мыши по одной из таблиц и выберите пункт
Ссылка (Reference);
 объедините две таблицы с использованием внешнего соединения слева
(Left Outer Join) на основании столбца MergeKey;
 удалите столбец MergeKey;
 разверните присоединенный столбец, выбрав все поля, кроме MergeKey.
🍌 Примечание. Можно было бы избежать добавления в обе таблицы столбца
MergeKey путем создания настраиваемого столбца с указанием в формуле
имени другой таблицы. Это вполне рабочий прием, но метод с использованием столбца MergeKey будет быстрее – по нашим оценкам, процентов на 30.
Пример
Вооружившись методологией, описанной выше, давайте создадим декартово произведение на основе таблиц, представленных в файле Ch10 Examples\
Декартовы произведения  269
Cartesian Products. Наша цель – распределить ежемесячные расходы по месяцам и создать сводный бюджет на год, как показано на рис. 10.26.
Рис. 10.26. Как нам быстро собрать годовой бюджет?
В соответствии с описанной инструкцией начнем с подготовки данных.
Сначала займемся таблицей Expenses, которая на рис. 10.26 находится слева:
 подключитесь к таблице данных;
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 введите имя столбца MergeKey и следующую формулу для столбца: =1 ,
как показано на рис. 10.27;
 загрузите запрос в виде подключения.
Рис. 10.27. Создание столбца MergeKey в запросе Expenses
Теперь необходимо сделать то же самое с таблицей Months – добавить столбец MergeKey, как показано на рис. 10.28, и загрузить в виде подключения.
270  Глава 10. Объединение данных
Рис. 10.28. Таблица Months подготовлена для объединения
Сейчас нам нужно принять решение о том, какую таблицу использовать в
левой части объединения (какие столбцы будут располагаться в итоговом выводе слева), и выполнить слияние. Мы будем использовать в качестве левой
таблицы Expenses, чтобы вывод был максимально приближен к желаемому
результату на картинке. Выполните следующие действия:
 щелкните правой кнопкой мыши по запросу Expenses и выберите пункт
Ссылка (Reference);
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Объединить запросы (Merge Queries) выберите пункт Объединить запросы (Merge Queries);
 выберите в выпадающем списке таблицу Months, выделите в обеих
таблицах столбец MergeKey и нажмите на кнопку OK;
 удалите столбец MergeKey;
 разверните все столбцы из таблицы Months, за исключением MergeKey.
В результате вы получите таблицу с распределением повторяющихся расходов по всем месяцам в таблице Months, как показано на рис. 10.29.
Рис. 10.29. Годовой бюджет готов
Теперь при добавлении нового месяца в таблицу Months или статьи расходов в таблицу Expenses годовой бюджет можно обновить всего в один клик.
Декартовы произведения  271
🍌 Примечание. Показанная в этом разделе техника может быть использована
при условии, что все расходы из таблицы Expense будут одинаковыми для
всех месяцев. В реальной жизни при планировании бюджета у нас есть множество исключений из этого правила, но это не проблема. Мы всегда можем
создать отдельный запрос (или запросы) для приведения дополнительных
расходов к нашей структуре колонок, после чего добавить все запросы в
единую таблицу.
Случайные декартовы произведения
В предыдущем разделе мы показали, как можно использовать декартово
произведение на практике. К сожалению, не всегда его образование производится намеренно – зачастую перекрестные соединения получаются случайно.
Представьте, что кто-то по ошибке дважды добавил в таблицу Months январь
2021 года. После обновления данных в итоговой таблице окажется две записи
по январю 2021 года для каждого вида расходов, поскольку каждый месяц
будет объединен с каждой записью в таблице Expenses.
В данном случае обезопасить себя от такой ситуации не так сложно, достаточно в таблице Months щелкнуть правой кнопкой мыши по столбцу Months и
выбрать пункт Удалить дубликаты (Remove Duplicates). Это весьма логично,
поскольку нам не нужно выполнять планирование расходов на один и тот же
месяц дважды.
Но к избавлению от дубликатов перед выполнением операции объединения данных нужно подходить с осторожностью. Возвращаясь к первому примеру из этой главы, можно заметить, что попытка объединения таблиц Sales
и Inventory по столбцу Brand, присутствующему в обеих таблицах, привела
бы к образованию декартова произведения, что обусловило бы появление
дублирующихся продаж в выводе. Причина этого в том, что дубликаты строк
по бренду присутствуют как в таблице Sales (что вполне ожидаемо), так и в
таблице Inventory, как показано на рис. 10.30.
Рис. 10.30. В отличие от поля SKU, столбец Brand в качестве ключа
при объединении таблиц даст декартово произведение
272  Глава 10. Объединение данных
Вы, наверное, понимаете, что в таблице Inventory избавиться от дубликатов
по бренду мы не можем, поскольку это приведет к удалению одного из двух
товаров от поставщика. Очевидно, что исключение дубликатов в таблице
Sales приведет к похожим проблемам.
Во избежание случайного образования декартовых произведений рекомендуется обращаться к профилю столбцов для сравнения количества отдельных (Distinct) и уникальных (Unique) значений в столбце. Если они равны
(как в случае с SKU), столбец можно безопасно использовать в качестве ключа
правой таблицы при объединении без риска образования декартова произведения. Если количество отдельных и уникальных значений в столбце не
совпадает (как в случае с Brand), опасность возникновения перекрестного соединения существует – к этому приведет совпадение значений этого столбца
в левой и правой таблицах.
Объединения с приблизительными
совпадениями
Хотя Power Query предоставляет немало инструментов для объединения
таблиц с точным совпадением (exact match), для анализа приблизительных
совпадений (approximate match) никаких готовых механизмов у нас нет.
Обратите внимание, что мы говорим не о нечетком совпадении (fuzzy
match), о котором будет сказано далее, а о случаях, когда нам необходимо
найти и вернуть значение, равное или находящееся между двумя точками
данных. Пользователи Excel узнают здесь использование функции ВПР
(VLOOKUP) в режиме поиска приблизительных совпадений, как показано
на рис. 10.31.
Рис. 10.31. Поиск ближайшей цены без превышения
В этом примере покупатель получает лучшую цену при увеличении количества приобретаемых товаров. Проблема в том, что в нашем наборе данных
не обозначена точная цена при приобретении 2755 товаров, так что мы будем выбирать цену из интервала от 2500 до 5000 товаров. Пока количество
Объединения с приблизительными совпадениями  273
товаров не достигнет 5000, мы будем использовать цену $5,65 для заказов, в
которых приобретается более 2500 единиц товаров.
🍌 Примечание. Вы заметили, что на рис. 10.31 мы пометили столбцы внизу
ключевыми словами. Определить столбцы Key и Return довольно просто, поскольку в таблице поиска (Lookup table) обычно находятся только они. В то
же время столбцов ID может быть несколько в зависимости от ширины таблицы Source table.
Методология
Большинство пользователей Power Query для решения этой задачи попробовали бы применять стандартные описанные выше алгоритмы объединения таблиц. Мы же пойдем другим путем. Наша инструкция по выполнению
такого объединения будет включать следующие пункты.
Шаг 1: подключитесь к таблицам поиска и исходных данных:
 подключитесь и очистите ваши данные, как обычно.
Шаг 2: подготовьте таблицу поиска:
 переименуйте ключевые столбцы [Key], чтобы они совпадали в
обеих таблицах.
Шаг 3: выполните соответствие:
 создайте ссылку на таблицу­источник (Source table);
 на вкладке Главная (Home) нажмите на кнопку Добавить запросы (Append) и выберите таблицу поиска (Lookup table);
 в элементах фильтрации в ключевом столбце установите сортировку по возрастанию (Sort Ascending);
 в элементах фильтрации в столбце (столбцах) [ID] также установите сортировку по возрастанию;
 щелкните правой кнопкой мыши по заголовку столбца [Return]
и в выпадающем меню Заполнить (Fill) выберите пункт Вниз
(Down);
 в элементах фильтрации в столбце [ID] снимите флажок null.
Это очень краткая инструкция, но ее достаточно, чтобы выполнить операцию поиска приблизительных совпадений в Power Query.
Пример
Исходные данные для этого примера, показанные на рис. 10.32, можно
найти в папке Ch10 Examples\Approximate Match.xlsx. Наша цель – создать таблицу, изображенную справа, при помощи методов поиска приблизительных
совпадений, и для этого мы пройдем по описанному выше алгоритму.
274  Глава 10. Объединение данных
Рис. 10.32. Исходные данные и конечная цель
На первом шаге нам необходимо создать отдельные запросы для подключения к таблицам Prices и Orders. Наша задача сводится к тому, чтобы получить данные в очищенном табличном формате с правильным содержанием
и именами столбцов. Поскольку эти условия в нашем случае и так выполняются, достаточно будет просто осуществить подключение к данным.
По готовности запросов можно переходить ко второму шагу, который
включает в себя приведение ключевых столбцов к единым именам в обеих
таблицах. Чтобы это сделать, давайте внимательно присмотримся к таблицам:
 исходная таблица (Source table): в нашем случае это таблица Orders
(показанная на рис. 10.32 посередине), поскольку в ней содержится
информация, которую мы собираемся обогатить. В качестве ID у нас
будет выступать столбец Order ID, а в качестве ключа – столбец Quantity;
 таблица поиска (Lookup table): у нас это таблица Prices, показанная
слева. Именно в ней содержатся значения, которые мы собираемся
возвращать в исходную таблицу. А именно мы собираемся вернуть
значение из столбца Price Per, для вычисления которого необходимо
сравнить ключевой столбец в исходной таблице (Quantity) с ключом в
таблице поиска (Units).
Поскольку имена ключевых столбцов у нас не совпадают, мы для начала
решим эту проблему. Чтобы не ставить под угрозу наши исходные данные,
мы сделаем это изменение непосредственно в Power Query:
 перейдите в режим редактирования запроса Prices;
 переименуйте столбец Units в Quantity, как показано на рис. 10.33.
Рис. 10.33. Обновленная таблица поиска (Prices)
Объединения с приблизительными совпадениями  275
🍌 Примечание. Мы решили переименовать ключевой столбец в таблице по-
иска, но с таким же успехом могли сделать это и в исходной таблице. Цель
у нас простая – сделать так, чтобы ключевые столбцы в обеих таблицах назывались одинаково.
Теперь, когда исходные данные полностью подготовлены, можно переходить к шагу 3, на котором устанавливается соответствие между таблицами:
 щелкните правой кнопкой мыши по исходной таблице (Orders) и выберите пункт Ссылка (Reference);
 на вкладке Главная (Home) нажмите на кнопку Append Queries (Добавить запросы), выберите запрос Prices и нажмите на кнопку OK.
Результат, если прокрутить его вниз, должен выглядеть так, как на рис. 10.34.
Рис. 10.34. Добавление таблицы поиска к исходной таблице
Как мы уже знаем, при добавлении таблиц колонки с одинаковыми именами сращиваются, тогда как различающиеся столбцы добавляются к результирующему набору данных. Именно поэтому нам так было необходимо позаботиться о том, чтобы ключевые столбцы в таблицах назывались одинаково.
Также вы могли заметить, что для всех заказов в исходной таблице в столбце
Price Per стоят значения null, а в таблице источника такие же значения стоят
в столбце Order ID.
🍌 Примечание. Причина того, почему мы начали действовать от таблиц источ-
ника, состоит в том, что нам привычнее видеть столбцы из нее слева в итоговом наборе данных. Если вы решите идти от таблицы поиска и присоединять
к ней таблицу источника, все по-прежнему будет работать.
276  Глава 10. Объединение данных
🙈 Предупреждение. Если в вашей исходной таблице больше 1000 строк, вы
можете не увидеть добавленной к ней таблицы поиска в окне предварительного просмотра. Не беспокойтесь об этом. Просто следуйте методологии. Даже если на предварительном этапе вы чего-то не видите, на этапе
загрузки данных все выполненные операции будут применены ко всем без
исключения строкам, и все сработает!
Теперь мы переходим к шагам, на которых и происходит все волшебство:
 нажмите на кнопку фильтрации в заголовке столбца Quantity и установите сортировку по возрастанию;
 то же самое сделайте в столбце Order ID.
В данный момент таблица будет выглядеть так, как показано на рис. 10.35, –
строки из запроса Prices будут располагаться непосредственно перед соответствующими им строками из запроса Orders.
Рис. 10.35. Поиск приблизительных совпадений почти завершен
Вся магия здесь кроется в шаге сортировки таблицы по ключевому полю
(Quantity), на котором строки с ценами перемешиваются с исходными данными по заказам в порядке возрастания. Второй шаг сортировки по идентификатору заказа (или нескольким колонкам, если у вас не один критерий
сортировки) позволяет удостовериться в том, что строки из таблицы Prices
всегда будут предшествовать строкам из таблицы Orders. В случае с дублирующимися значениями, как в строках 7 и 8 в нашем примере, этот шаг
гарантирует нам правильный порядок строк.
Итак, мы всего в двух шагах от финиша:
 щелкните правой кнопкой мыши по заголовку столбца Price Per и в выпадающем меню Заполнить (Fill) выберите пункт Вниз (Down);
 нажмите на кнопку фильтрации в заголовке столбца Order ID и снимите
флажок с элемента null;
Поиск нечетких соответствий  277
 выделите столбцы Quantity и Price Per и на вкладке Добавление столбца (Add Column) нажмите на выпадающую кнопку Стандартный
(Standard) и выберите вариант Умножить (Multiply);
 переименуйте столбец Умножение (Multiplication) в Revenue.
Вот и все. От строк из таблицы Prices мы избавились, а по заказам цены
проставились, и даже общие суммы появились, что требовалось в задании.
Результат показан на рис. 10.36.
Рис. 10.36. Мы успешно воспроизвели функционал функции ВПР (VLOOKUP) из Excel
Поиск нечетких соответствий
Все объединения таблиц, о которых мы до сих пор говорили в этой главе,
подразумевали полное равенство сравниваемых данных или вхождение в
диапазоны. Пока вы работаете с данными, сгенерированными компьютером,
вас это должно устраивать. Но что, если вам придется тем или иным образом
сравнивать данные, введенные человеком, с автоматически сгенерированными?
Опечатки, использование разных регистров, аббревиатур, пунктуации –
это лишь часть несоответствий, с которыми вы можете столкнуться на этом
тернистом пути. Поскольку встроенные в Power Query механизмы объединения таблиц предусматривают лишь точное совпадение объединяемых
данных, сравнивать списки, показанные на рис. 10.37, может быть проблематично.
Рис. 10.37. Таблица Products (слева) создана вручную,
а таблица Pricing (справа) сгенерирована автоматически
Исходный файл для примера из этого раздела находится в файле Ch10
Examples\Fuzzy Match.xlsx.
278  Глава 10. Объединение данных
На первый взгляд, все выглядит нормально, однако при выполнении стандартного внешнего соединения слева (Left Outer Join) в Power Query на основании столбцов Products[Item] и Pricing[Item] только по одной строке из исходных данных установилось соответствие, что видно по рис. 10.38.
Рис. 10.38. Это какая-то ерунда – цена появилась только для монитора Мэри
Получается, наша идея не сработала. И это логично, ведь в наших таблицах почти нет полных соответствий: в одном месте в слове Laptop добавлена
буква s, в другом оно написано в нижнем регистре, кроме того, компьютеру
трудно понять, что слова Screen и Monitor могут означать одно и то же.
В большинстве инструментов нам пришлось бы отправляться в таблицу
Products и чистить ее, приводя все в соответствие. Но в Power Query в нашем
распоряжении есть один механизм, позволяющий осуществлять поиск нечетких соответствий (Fuzzy Matching).
🍌 Примечание. Если вы выполняете сбор данных от пользователей в тексто-
вом виде, вам практически всегда желательно использовать некий механизм
проверки данных, чтобы не позволить некорректным данным пробраться
в систему. Это лучше, чем пытаться впоследствии использовать инструмент
нечеткого поиска. К сожалению, проверять данные на входе не всегда возможно, так что уметь пользоваться механизмом, описанным в этом разделе,
вам просто необходимо.
Основы нечеткого поиска
Выполнять поиск нечетких соответствий в Power Query весьма просто.
Для этого во время создания стандартного соединения необходимо установить флажок Использовать нечеткие соответствия для слияния (Use fuzzy
matching to perform the merge), как показано на рис. 10.39.
Рис. 10.39. Превращение четкого поиска в нечеткий
Поиск нечетких соответствий  279
Одно лишь это действие позволит вам, как видите на рис. 10.40, избавиться почти от всех значений null при связывании таблиц по столбцам
Products[Item] и Pricing[Item].
Рис. 10.40. Результат действия инструмента нечеткого поиска в Power Query
Как видите, в этом случае Power Query сумел установить соответствия для
четырех элементов набора данных из шести. Но как он это сделал?
Power Query использует алгоритм определения подобности Жаккара (Jaccard
similarity algorithm) для идентификации сходства между двумя экземплярами, которые считаются сопоставимыми при достижении метрикой значения
80 %. Следуя этому алгоритму, было выявлено, что слова Laptops и laptop в
достаточной степени похожи на Laptop из справочника, несмотря на лишнюю
букву и несовпадения регистра. Также этот алгоритм позволяет закрыть глаза
на перестановку некоторых букв (friend против freind) и незначительные различия в пунктуации (mrs против mrs.).
Работая с алгоритмами нечеткого поиска, очень важно понимать, что чем
длиннее слова анализируются и чем больше в них похожих символов, тем
больше вероятность признания их идентичными. Чтобы лучше это понять,
посмотрите на слова ниже и попробуйте определить степень их схожести:
 Dogs и Cogs;
 Bookkeeperz и Bookkeepers.
Хотя в обоих случаях предложенные слова отличаются исключительно
одной буквой, при меньшем количестве символов в слове мы не можем быть
полностью уверены, что это опечатка.
🍌 Примечание. Режим поиска нечетких соответствий поддерживается только
при выполнении объединения таблиц по текстовым полям. Если вам необходимо произвести нечеткий поиск по полям других типов, нужно для начала
привести их к текстовому формату.
Таблицы преобразования
Тогда как нечеткий поиск позволяет отчасти закрыть стоящие перед нами
задачи, вы сами видите, что всех проблем он не решает. В предыдущем примере без соответствий остались пары слов Mice и Mouse, а также Screen и
Powered by TCPDF (www.tcpdf.org)
280  Глава 10. Объединение данных
Monitor. Эти слова недостаточно близки по написанию и просто не проходят порог алгоритма определения подобности. Что же делать?
Секрет кроется в возможности создать так называемую таблицу преобразования (transformation table),
показанную на рис. 10.41, по которой можно выстроить переходы от одних слов к другим.
Рис. 10.41.
Простая таблица
преобразования
🍌 Примечание. Хотя имя этой таблицы не так важно, она должна содержать
столбцы From и To для выполнения корректных преобразований.
В нашем примере таблица преобразования будет называться Translations, и
загрузим мы ее в Power Query в виде подключения. После этого нам останется
использовать ее при создании объединения таблиц следующим образом:
 создайте запрос, объединяющий две наши таблицы;
 установите флажок Использовать нечеткие соответствия для слияния (Use fuzzy matching to perform the merge);
 раскройте раздел Параметры нечеткого соответствия (Fuzzy
matching options);
 прокрутите вниз и в выпадающем списке Таблица преобразования
(Transformation Table) выберите таблицу Translation.
Как видно на рис. 10.42, после разворачивания результатов объединения
таблиц все данные оказались заполнены как нужно.
Рис. 10.42. Наконец-то мы установили соответствие между всеми данными
🍌 Примечание. Снова оговоримся, что всегда лучше использовать некие меха-
низмы проверки ввода данных, чем впоследствии выполнять поиск нечетких
соответствий. Но по крайней мере теперь у нас есть инструмент, в котором
мы можем ввести данные в столбцы From и To и получить ожидаемый результат на выходе.
Поиск нечетких соответствий  281
Управление порогом подобия
Как мы уже упоминали ранее, Power Query применяет алгоритм определения подобности Жаккара при определении степени похожести двух текстовых элементов, и коэффициент 80 % и выше считается удовлетворительным
для предположения об идентичности сравниваемых объектов. Но вы также
можете повлиять на этот порог, после которого строки могут считаться подобными. Чем выше порог, тем более строгими будут требования к идентичности элементов. Иными словами, если установить порог в единицу (100 %),
идентичными будут считаться только абсолютно одинаковые строки.
В единицу это значение при выполнении нечеткого поиска устанавливать
нет никакого смысла. Вы можете, наоборот, ослабить требования к идентичности строк, снизив порог. Но перед тем как делать это, вы должны быть
уверены в том, что осознаете все возможные минусы данного подхода.
Допустим, вам необходимо установить соответствие между сотрудниками
(Employees) в таблицах Products и Depts, показанных на рис. 10.43.
Рис. 10.43. Таблицы Products (слева) и Depts (справа)
Проблема в том, что оператор, фиксирующий продажи, решил ввести в
своей таблице полное имя Donald A, тогда как в отделе кадров сократили его
до Don A. Как такое расхождение в написании будет воспринято системой?
Как оказалось, даже поиск нечетких соответствий нам не помог, что отражено на рис. 10.44.
Рис. 10.44. Погодите, кто такой этот Дональд?
На самом деле сходство между строковыми значениями Don A и Donald A
лежит в интервале от 50 % до 59 %. Это гораздо меньше, чем 80 %, принятые
в качестве порога по умолчанию, в связи с чем эти строки не считаются похожими.
282  Глава 10. Объединение данных
Мы уже знаем, что можем решить эту проблему, создав отдельную таблицу соответствий
с псевдонимами нашего Дональда. Но мы все
любим, когда у нас есть варианты, и давайте
попробуем задействовать для этой задачи меРис. 10.45. Ослабление порога
ханизм изменения принятого по умолчанию
подобия значений
порогового значения.
Эта опция, как и создание таблицы преобразования, находится в разделе
Параметры нечеткого соответствия (Fuzzy matching options), что видно
на рис. 10.45.
В нашем случае уменьшение порога подобия (Similarity threshold) до 0,6
(60 %) не сработает, а значение 0,5 (50 %) будет в самый раз, что видно по
рис. 10.46.
Рис. 10.46. Наконец-то мы подобрали Дональду его альтер эго
На первый взгляд, все прекрасно! Мы ведь смогли установить соответствие
между именами Donald и Don без помощи дополнительных таблиц преобразования. Но присмотритесь к результату, показанному на рис. 10.46. Что-то
тут не так…
Перед выполнением объединения у нас в таблицах было шесть продаж и
шесть сотрудников, и в результате мы получали ровно шесть строк в результирующем наборе. Так почему сейчас у нас получилось семь строк?
Если внимательно посмотреть на строки 4 и 5, можно заметить, что в них
сотрудники Ron и Don B верно нашли свои соответствия в таблице Depts. Но
в строке 6 сотруднику Don B также была поставлена в соответствие строка
Ron!
Получается, что мы настолько ослабили бдительность, установив заведомо низкий порог подобия, что итог соответствия стал ложноположительным
(false positive). Кроме того, в результате наших действий случайным образом
было создано декартово произведение!
🙈 Предупреждение. Старайтесь не уменьшать значение порога подобия без
крайней необходимости. Это очень чувствительный механизм, настройка которого может привести к искажению исходных данных и образованию перекрестных соединений.
Поиск нечетких соответствий  283
Стоит отметить, что базовые настройки порога подобия также могут приводить к непредсказуемым результатам при объединении таблиц с использованием нечеткого поиска (все же 80 % – это не 100 %). В то же время команда разработчиков Power Query постаралась свести к минимуму количество
ложноположительных срабатываний при использовании значения порога
по умолчанию, сохранив при этом возможность осуществлять нечеткий поиск. Советуем вам менять порог, только если вы четко понимаете, зачем это
делаете, и сможете наглядно оценить результаты операции.
Стратегии поддержки решений с нечетким поиском
Разработчики часто задаются вопросом о том, как им поддерживать целостность решений, полагающихся на выполнение поиска с нечетким соответствием. Это действительно может пугать, особенно если речь идет об
относительно новом сценарии, в котором продолжают возникать ошибки.
Чтобы минимизировать количество ошибок при использовании этого инструмента, мы рекомендуем вам придерживаться следующих несложных
правил:
 перед объединением данных приведите текстовое содержание полей
в максимально приближенный вид с точки зрения специальных символов и шаблонов. Например, если вы знаете, что в вашей автоматически сгенерированной таблице никогда не используется символ #
перед адресами, а в таблице источника адреса могут быть написаны
с применением этого символа, предварительно замените этот знак в
нужном столбце на пустую строку;
 воспользуйтесь шаблонами с описанными ранее в этой главе антисоединениями для создания таблицы Exceptions (неизвестные термины),
с которой можно будет сверяться после обновлений;
 напишите формулу в Excel или на DAX для подсчета количества неопознанных элементов (строк) в таблице Exceptions и выводите это
значение в отчете для лучшей наглядности. Таким образом, после каждого обновления вы сможете проверять, не отклонилось ли количество
таких элементов от нуля. В противном случае ваша таблица преобразований должна быть дополнена новыми строками.
Такое решение позволит вам не только определять, есть ли в таблице неопознанные элементы, но и выводить их полный список при необходимости.
При появлении неизвестных ранее вхождений вам нужно внести их в таблицу преобразования вместе со значениями, которым они соответствуют.
При этом мы настоятельно советуем при переносе сведений из таблицы
Exceptions в таблицу соответствий пользоваться не ручным вводом, а операциями копирования и вставки, чтобы при переносе данных не вкрались
опечатки. Если вы все обновления введете корректно, соответствия между
элементами должны восстановиться.
В зависимости от того, насколько чистые или грязные у вас данные, а также
от того, как часто вы их обновляете, вы будете видеть, как количество несо-
284  Глава 10. Объединение данных
ответствий будет уменьшаться с каждым обновлением. Причина этого проста: в процессе работы вы собираете словарь терминов, который постепенно
становится все надежнее.
🍌 Примечание. Алгоритм поиска с нечеткими соответствиями реализован не
только в инструменте объединения запросов, но также в механизме группировки и в относительно недавно появившемся инструменте Значения кластера (Cluster Values). На момент написания книги этот функционал реализован только в версии Power Query Online, но команда разработчиков делает
все, чтобы весь спектр их продуктов содержал одинаковые возможности, так
что в ближайшем будущем эти механизмы должны появиться и в вашей версии Power Query.
Глава
11
Источники данных
в интернете
Одним из главных достоинств Power Query является возможность извлекать
данные из интернета и с их помощью обогащать наши собственные корпоративные источники данных.
В интернете данные обычно хранятся в двух видах:
1) в виде файлов в веб-репозитории;
2) в виде веб-страниц HTML.
Учитывая то, что в первом случае файлы обычно хранятся в форматах, которые Power Query прекрасно понимает (CSV, XLSX и т. д.), извлечь данные из
них не составит труда. Второй вариант не так прост, поскольку веб-страницы
могут не обладать четкой структурой. Команда разработчиков Power Query
постоянно работает над средствами получения и обработки данных из интернета, и на момент написания книги они выпустили предварительную
версию инструмента извлечения данных из веб­таблиц (web table inference)
для Power BI, призванного облегчить доступ к информации в интернете.
Подключение к файлам данных в интернете
Предположим, вы нашли в интернете файл, размещенный по следующей
ссылке, и хотите подключиться к нему: https://data.cityofnewyork.us/api/views/
c3uy-2p5r/files/fb52d9bb-0a7c-4cc4-824e-1930c818e5d1?download=true&
filename=NYCCAS_Air_Quality_Indicators_Open_Data.xlsx.
Несмотря на то что это файл xlsx, вы не можете использовать для подключения к нему привычный коннектор Excel, поскольку он размещен в сети, а
не в локальной папке на вашем компьютере. Вместо этого вам придется воспользоваться коннектором Из интернета (From Web) следующим образом:
 создайте новый запрос, нажав на вкладке Данные (Data) на кнопку
Получить данные и выбрав в подменю Из других источников (From
Other Sources) пункт Из интернета (From Web);
 введите указанный выше путь в поле URL-адрес (URL) и нажмите на
кнопку OK, как показано на рис. 11.1.
286  Глава 11. Источники данных в интернете
Рис. 11.1. Подключение к файлу Excel, размещенному в интернете
Если вы ранее не подключались к этому сайту, вас попросят пройти аутентификацию.
🍌 Примечание. На сайте cityofnewyork.us представлено большое количество
наборов данных, находящихся в свободном доступе и не требующих аутентификации. Выберите режим Анонимно (Anonymous) при подключении
к этому источнику.
После прохождения шага с аутентификацией все будет очень похоже на
процедуру подключения к локальному файлу Excel, как показано на рис. 11.2.
Рис. 11.2. Excel из… да какая разница?
В этом состоит прелесть подхода разработчиков Power Query к своему инструменту. Несмотря на то что коннектор используется другой, в остальном
процесс подключения полностью идентичен соединению с локально сохраненным файлом. Поэтому мы не будем выполнять никаких преобразований
данных – важно, чтобы вы поняли, что подключаться и извлекать данные из
файлов, хранящихся в интернете, очень легко.
Подключение к веб-страницам  287
Подключение к веб-страницам
Допустим, вы хотите извлечь информацию обо всех доступных наборах данных на сайте Нью-Йорка. У вас есть следующая ссылка: https://data.cityofnewyork.us/browse?limitTo=datasets.
🍌 Примечание. Поскольку мы не властны над содержимым этого сайта, в мо-
мент выхода книги оно может утратить свою актуальность, а может и вовсе
исчезнуть. На этот случай мы заранее сохранили копию данных в сопроводительных файлах. Просто откройте в браузере приложенный файл NYC
Open Data.html, скопируйте ссылку в адресной строке и используйте ее вместо приведенной выше ссылки.
На этой странице приведен список доступных на сайте наборов данных с
кратким описанием каждого из них, как показано на рис. 11.3.
Рис. 11.3. Данные сайта NYC OpenData, открытые в браузере Microsoft Edge
Подключение к данным на веб-странице
🍌 Примечание. На момент написания книги новый инструмент извлечения
данных из веб-таблиц (web table inference) присутствовал в Power BI Desktop
только в виде ознакомительной предварительной версии, а в Excel его не
было вовсе. Если ваш экран будет выглядеть иначе, чем показано здесь, значит, у вас еще нет нужного обновления. В этом случае вы увидите окна, показанные в разделе «Подключение к страницам без таблиц» далее в этой главе.
288  Глава 11. Источники данных в интернете
Чтобы подключиться к веб­странице, выполните те же действия, что делали
при подключении к файлу в интернете, а именно:
 нажмите на кнопку Получить данные (Get Data), выберите коннектор
для получения данных из интернета и нажмите на кнопку OK;
 выберите анонимный тип подключения, если предложат пройти аутентификацию.
Перед вами снова появится окно с предварительным просмотром, но на
этот раз опций для выбора будет побольше, что видно по рис. 11.4.
Рис. 11.4. Подключение к веб-странице с помощью Power Query
Естественные и предлагаемые таблицы
Первое, что бросается в глаза при открытии этого окна, – это то, что на
данной странице отсутствуют четко определенные таблицы. В противном
случае мы бы на левой панели навигатора увидели их в разделе Таблицы
HTML (HTML Tables). Вместо этого мы видим раздел Предлагаемые таблицы (Suggested Tables), в котором содержатся таблицы, которые движок Power
Query извлек на основании стилей CSS в коде HTML.
После выбора Таблицы 1 (Table 1) в левом списке Power Query отобразит
окно предварительного просмотра с имеющейся в таблице информацией.
Если это именно то, что вам нужно, вы можете установить флажок напротив
таблицы и либо загрузить данные, либо отправить их на преобразование.
Кроме того, у вас есть возможность переключиться на вкладку Вебпредставление (Web View) в правой части окна, чтобы увидеть, как
Подключение к веб-страницам  289
выбранная таблица выглядит в браузере. Этот вид таблицы показан на
рис. 11.5.
Рис. 11.5. Предпросмотр таблицы в виде веб-представления
Добавление таблиц с использованием примеров
А что, если вам понадобится получить больший контроль за тем, как именно интерпретируются полученные данные? Здесь вам на помощь придет
кнопка Добавление таблиц с использованием примеров (Add Table Using
Examples), расположенная в нижней части окна. Нажав на нее, вы увидите
новое диалоговое окно с областью предварительного просмотра вверху и
одной пустой колонкой внизу. Работает это следующим образом: вы вводите
в ячейку то, что хотите извлечь для первой записи, а остальное делает Power
Query, как показано на рис. 11.6.
Работая с этим инструментом, лишний раз убеждаешься в правильности
поговорки «Чем меньше, тем лучше». Введите часть строки, которую хотите извлечь, после чего дважды щелкните мышью по желаемому варианту
или выделите его и нажмите на клавишу Enter. После небольшой задержки
столбец будет заполнен значениями, которые Power Query извлек для вас по
введенному шаблону. Если какой-то из предложенных элементов оказался
неверным, вы всегда можете щелкнуть по нему и скорректировать значение.
🙈 Предупреждение. Если в заполненных по вашим требованиям ячейках оказалось много значений null, значит, движок Power Query не смог понять логику, которую вы вложили в свой запрос.
290  Глава 11. Источники данных в интернете
Рис. 11.6. Извлечение заголовков из набора данных
По окончании работы с первым столбцом дважды щелкните мышью по
его заголовку, чтобы переименовать его, после чего нажмите на значок «+»
справа, если хотите добавить еще одну колонку. На рис. 11.7 показано представление с тремя столбцами Data Set, Views и Last Update, заполненными на
основе первой записи в наборе данных.
Рис. 11.7. Извлечение данных посредством добавления таблиц с использованием примеров
Подключение к страницам без таблиц  291
После завершения работы по извлечению данных созданная вами таблица
появится в разделе Пользовательские таблицы (Custom Tables) в окне навигатора, как показано на рис. 11.8. Теперь вы можете выбрать ее и нажать
на кнопку Загрузить (Load) или Преобразовать данные (Transform Data) в
зависимости от ваших требований.
Рис. 11.8. Созданная вами таблица была автоматически выбрана для импорта
Подключение к страницам без таблиц
Хотя мы искренне надеемся, что механизм добавления таблиц с использованием примеров появится в Excel еще до момента выхода этой книги, надежд
на это не так много. В этом случае, если вам необходимо будет подключиться и извлечь данные с веб-страницы, не содержащей четко определенных
таблиц при помощи соответствующих тегов, вам останется пробиваться к
желаемому результату через элементы HTML практически в ручном режиме.
Удовольствия от этого процесса – примерно как от бесконечного брожения по
подземному лабиринту со свечой в руках, когда на всех табличках написано
«Выход там».
Лучший способ выбраться из подобной ситуации – открыть браузер, включить в нем инструменты разработчика и попытаться самостоятельно найти
на странице элементы, которые вам нужны. В этом примере мы будем работать со страницей по адресу https://data.cityofnewyork.us/Housing-Development/DOB-Job-Application-Filings/ic3t-wcy2.
🍌 Примечание. Копия этой страницы сохранена в файле с именем DOB Job
Application Filings.html.
292  Глава 11. Источники данных в интернете
Наша цель – извлечь данные из таблицы, показанной на рис. 11.9.
Рис. 11.9. Эта таблица не отображается в окне предварительного просмотра
🍌 Примечание. Хотя эта таблица была обнаружена новым инструментом из-
влечения данных из веб-таблиц в Power BI, стандартный коннектор Excel
на момент написания книги ее не показывал. Поскольку такая ситуация возможна даже после обновления коннектора, вам просто необходимо научиться самостоятельно осуществлять навигацию по элементам HTML в Power
Query. Но предупреждаем: это не для слабонервных!
Как узнать, что вы близки к тому, чтобы застрять в этой кроличьей норе?
Варианта два:
1) таблица, которая вам нужна, не показывается ни в разделе естественных таблиц HTML, ни в разделе предлагаемых;
2) вы не можете создать нужную вам таблицу при помощи механизма
добавления таблиц с использованием примеров.
Нам было легко воссоздать этот сценарий в Excel, поскольку у нас еще нет
доступа к новым инструментам. Итак, подключение к указанной выше вебстранице привело к появлению диалогового окна, показанного на рис. 11.10.
Рис. 11.10. Показаны только четыре таблицы HTML, а той, которая нам нужна, нет
Подключение к страницам без таблиц  293
Для определения путей к нужным элементам в таблице откройте Microsoft
Edge или Chrome и нажмите на клавишу F12, чтобы отобразить инструменты
разработчика (Developer Tools).
Чтобы обнаружить нужный элемент, выполните следующие действия:
 перейдите в режим инспектора элементов, как показано на рис. 11.11,
нажав на соответствующую кнопку в левом верхнем углу окна или воспользовавшись сочетанием клавиш Ctrl+Shift+C;
 перемещайте мышь по странице, выделяя элементы;
 найдите нужный вам элемент и щелкните по нему левой кнопкой
мыши, чтобы в окне Elements оказалась выделена соответствующая
строка, как показано на рис. 11.11.
Рис. 11.11. Навигация по аду HTML
Теперь вы можете приступать ко второй, самой изнурительной части плана – повторению навигации в Power Query. Для этого выполните следующие
действия:
 создайте новый запрос, нажав на вкладке Данные (Data) на кнопку
Получить данные и выбрав в подменю Из других источников (From
Other Sources) пункт Из интернета (From Web);
 введите URL-адрес https://data.cityofnewyork.us/Housing-Development/
DOB-Job-Application-Filings/ic3t-wcy2, нажмите на кнопку OK, выберите
в левой части таблицу Document и нажмите на кнопку Преобразовать
данные (Transform Data).
В редакторе откроется табличка с единственной строкой и полным отсутствием информации, показанная на рис. 11.12.
294  Глава 11. Источники данных в интернете
Рис. 11.12. Душераздирающее зрелище
Здесь нужно очень внимательно повторить все шаги, которые вы сделали в
веб-представлении, чтобы добраться в Power Query к нужному вам элементу
Table. Между навигацией в веб-представлении и поиском элементов в Power
Query есть что-то общее, но все равно на этом этапе можно очень легко заблудиться.
Для облегчения процесса необходимо учитывать, что в столбце Name в
Power Query указывается элемент, который присутствует в инструментах разработчика в браузере. К примеру, здесь у нас в колонке Name стоит значение
HTML, и в браузере мы видели тег <html… Эти два элемента указывают на
один объект.
Щелкните на слове Table в колонке Children, чтобы перейти на следующий
уровень иерархии, показанный на рис. 11.13.
Рис. 11.13. Дочерние элементы HTML
Теперь нам стали доступны теги HEAD и BODY. Нам необходимо пробиться
внутрь последнего, так что мы щелкаем по соответствующему элементу Table
и проваливаемся ниже.
Проблема бывает в том, что, в отличие от HTML, в котором все теги содержат имена, в Power Query мы их не видим, что может приводить к большой
путанице. Кроме того, на панели примененных шагов мы не видим шаги для
каждого действия – они просто собираются воедино, что не позволяет нам
вернуться на шаг назад. Таким образом, в случае ошибки нам просто придется начинать все заново.
Но это еще не худшая часть процесса, поскольку в конце пути обнаруживается, что одни элементы содержат сырой текст, а другие – текст, заключенный в тег <span>, как показано на рис. 11.14, что требует дополнительных
манипуляций.
Подключение к страницам без таблиц  295
Рис. 11.14. Легче не становится – даже в столбцах таблиц
могут присутствовать разные форматы данных
Поскольку описание методов по очистке этого процесса и приведения данных в порядок выходит за рамки этой книги, мы не будем на нем подробно
останавливаться. Все шаги данной процедуры мы сохранили в файле Ch11
Examples\From Web – The Hard Way.xlsx, а сам запрос назвали TheHardWay.
Ниже приведены действия, которые были проделаны на шаге Navigation.
Начали мы с исходной таблицы, показанной на рис. 11.15.
Рис. 11.15. Исходная таблица документа
Раскройте таблицы, нажимая на ссылку Table в колонке Children последовательно для следующих строк:















HTML (строка 1);
Body (строка 3);
Main (строка 6);
DIV (строка 4);
DIV (строка 2);
DIV (строка 1);
DIV (строка 2);
DIV (строка 1);
SECTION (строка 1);
DIV (строка 2);
DIV (строка 2);
DIV (строка 2);
TABLE (строка 2);
TBODY (строка 1);
TR (строка 1).
296  Глава 11. Источники данных в интернете
Если вы аккуратно спуститесь по этой лестнице тегов, то придете к тому
же результату, что и в шаге Navigation в запросе TheHardWay, и сможете выполнить все оставшиеся шаги.
Необходимо признать, что пробраться через все эти дебри тегов и выполнить поставленную задачу все же можно, хотя, как мы уже писали, для этого
нужно обладать огромным запасом терпения и выдержки.
Предостережения при работе с данными
из интернета
В целом подключение и работу с данными, хранящимися в интернете, можно
назвать слабой стороной Power Query по сравнению со всем богатством его
арсенала. Но приятно то, что, как мы уже видели на примере работы с Power
BI, в этой области есть серьезные улучшения. И еще раз выражаем надежду
на то, что все прогрессивные инструменты к тому времени, как вы будете
держать эту книгу в руках, уже появятся в Excel.
В то же время стоит помнить, что даже с самыми современными коннекторами работа с данными, размещенными на удаленных серверах, будет
сопряжена с определенными сложностями.
То, о чем мы расскажем далее, ни в коем случае не стоит рассматривать как
противопоказания к работе с внешними данными. Мы лишь хотим предупредить вас и вооружить на случай непредвиденных моментов, чтобы вы
видели не только преимущества, но и недостатки проектов, базирующихся
на данных из интернета.
Сбор данных
Строить решения на базе Power Query для работы с данными, хранящимися
на веб-страницах, бывает довольно проблематично. Как мы уже видели на
примере сценария с использованием Power BI, инструмент загрузки данных
приемлемо работает только при наличии четкой структуры тегов или стилей
CSS. В этом случае вы будете получать на выходе естественные или предлагаемые таблицы, и все будет достаточно просто. В противном случае вам
придется пускаться во все тяжкие по аду из тегов HTML. Кроме того, сложности состоят не только в использовании тегов и стилей. При применении
определенной оптимизации веб-страницы могут загружать свое содержимое
по требованию, и Power Query может просто не видеть всех данных, поскольку структура страницы в таких случаях загружается до ее содержимого.
Мы очень надеемся, что команда разработчиков Power Query продолжит
работать в этой области, добавляя все новые инструменты, чтобы никому
больше не приходилось проходить все круги HTML-ада.
Целостность данных
Еще одним важным аспектом при работе с данными в интернете является
их целостность и надежность. Остерегайтесь использовать в своей работе
Предостережения при работе с данными из интернета  297
данные, располагающиеся на сайте Wikipedia и подобных ему, с которыми у
вас нет деловых контактов.
В демонстрационных проектах данные зачастую импортируются из
Wikipedia, но полагаться на них в реальных сценариях может быть очень
опасно. Хотя администрация сайта прилагает большие усилия по обеспечению достоверности данных, на данный момент информация там во многом
далека от актуальности.
Еще один аспект использования данных из интернета состоит в их своевременном обновлении. Представьте, что вы потратили много времени на
написание запроса, обращающегося к внешним данным, а в результате поняли, что владелец/куратор данных их просто не обновил. Нужно быть всегда уверенным в том, что при обновлении данных в сценарии вы получите
наиболее актуальную информацию, а не устаревшую много дней назад. Все
ваши бизнес-решения должны приниматься исключительно на основании
актуальных сведений, и это то, за чем необходимо пристально следить.
Надежность решения
Есть и еще один очень важный аспект при работе с внешними данными,
находящийся вне вашего контроля. Как и любая компания, включая вашу,
компания, поставляющая данные, будет любыми силами стараться угодить
своим клиентам. К сожалению для нас, это обычно означает, что оформление их сайтов будет время от времени меняться. Они будут наполнять свои
страницы новыми возможностями и делать их более привлекательными для
пользователей. Увы, иногда подобные изменения ведут к нарушению доступа
к данным – зачастую без предупреждений и как раз тогда, когда у вас совершенно нет времени исправить возникшую проблему.
Глава
12
Реляционные
источники данных
Если вы работаете в организации, хранящей информацию в традиционных
реляционных базах данных (database), считайте, что вам повезло, поскольку
это идеальный источник данных. При этом у вас будет полноценный доступ
к наиболее актуальным сведениям, а в плане эффективности импорта базы
данных еще и намного превосходят обычные файлы.
Подключение к базам данных
Power Query обладает широким спектром возможностей для подключения к
базам данных без необходимости устанавливать дополнительные драйверы.
При этом коннекторы для подключения к базам данных в Excel и Power BI
разбиты на три группы:
 Получить данные (Get Data)  Из базы данных (From Database);
 Получить данные (Get Data)  Из Azure (From Azure);
 Получить данные (Get Data)  Из других источников (From Other
Sources).
Если вы не можете найти нужный вам коннектор, не отчаивайтесь. Если
вы установите драйвер ODBC от вашего поставщика данных, то сможете без
проблем подключаться к базе с помощью коннектора Из других источников
(From Other Sources)  Из ODBC (ODBC).
Соединение с БД
Поскольку подключение к большинству баз данных выполняется похожим
образом, мы для примера возьмем базу данных Microsoft Access. Это будет
база данных в формате SQL, размещенная в веб-службе Microsoft Azure, что
позволит вам работать с ней из любой точки планеты.
В нашем примере мы подключимся к базе данных AdventureWorks и проанализируем общие продажи по годам и регионам.
Подключение к базам данных  299
🍌 Примечание. Чтобы у вас гарантированно не возникло проблем с подклю-
чением к базе данных, советуем вам сначала ознакомиться с приведенными ниже инструкциями (вплоть до раздела Управление учетными данными),
прежде чем выполнять соединение.
Для начала вам необходимо будет выполнить следующие шаги:
 создайте новый запрос, нажав на вкладке Данные (Data) на кнопку
Получить данные и выбрав в подменю Из Azure (From Azure) пункт
Из базы данных SQL Azure (From Microsoft Azure SQL Database);
 подключитесь к базе данных, используя следующие параметры, как
показано на рис. 12.1:
• Сервер (Server): xlgdemos.database.windows.net;
• База данных (Database): AdventureWorks.
Рис. 12.1. Подключение к базе данных Azure
🙈 Предупреждение. В разделе Расширенные параметры (Advanced Options)
вы можете ввести запрос в поле Инструкция SQL (SQL statement) и выбрать
другие опции, специфические для конкретного коннектора. Избегайте этого
раздела, если вы не ниндзя SQL, способный писать предельно эффективный
код, или не получили соответствующих инструкций по подключению к вашей
базе данных от администратора.
После этого откроется диалоговое окно для ввода учетных данных
(credentials) при подключении к базе данных. Здесь у вас будет определенный выбор.
300  Глава 12. Реляционные источники данных
Вариант по умолчанию – использовать учетные данные Windows, которые
вы применяете для входа в операционную систему. Если вы работаете с базой
данных, размещенной внутри компании, и администраторы разрешили
подключение с использованием учетной записи Windows, это ваш выбор.
Но в большинстве случаев вам необходимо связаться с сотрудниками отдела
ИТ для предоставления вам сведений для подключения к базе.
Кроме того, на той же вкладке вы можете ввести другие учетные данные
для подключения к базе данных. Это может быть полезно при подключении
к БД с чужого компьютера.
В нашем случае мы будем использовать подключение посредством вкладки База данных (Database) из-за специфических настроек безопасности при
создании ID пользователей. Итак, выполните следующие действия:
1. Переключитесь на вкладку База данных (Database).
2. В поле Имя пользователя (Username) введите: DataMaster.
3. В поле Пароль (Password) введите: D4t4M@ster!
После ввода данных нажмите на кнопку Подключение (Connect), как показано на рис. 12.2.
Рис. 12.2. Подключение к базе данных с использованием
имени пользователя и пароля
🍌 Примечание. Учетные данные, которые вы используете для входа, сохраняются в зашифрованном файле, находящемся в настройках вашего локального пользователя. Это означает, что ваши логин и пароль не передаются
(и в настоящее время не могут быть переданы) вместе с решением, когда оно
посылается по почте или просто открывается другим пользователем. Служба
безопасности отвечает за то, чтобы у каждого пользователя была своя учетная запись для доступа к данным и их обновления.
Подключение к базам данных  301
Управление учетными данными
Если вы вдруг ошибетесь при указании имени подключения, базы данных,
имени пользователя или пароля и захотите изменить их, вы можете сделать
это следующим образом:
 в Excel: на вкладке Главная (Home) нажмите на выпадающую кнопку
Получить данные (Get Data) и выберите пункт Параметры источника данных (Data Source Settings);
 в Power BI: на вкладке Главная (Home) нажмите на выпадающую кнопку Преобразование данных (Transform Data) и выберите пункт Настройки источника данных (Data Source Settings).
После этого откроется диалоговое окно с параметрами доступа к данным,
показанное на рис. 12.3.
Рис. 12.3. Окно настройки источников данных с установленным
фильтром по «adventure»
Переключатели в верхней части окна отвечают за область видимости
источников данных – в текущем файле (рабочей книге) или в глобальном
окружении. При этом полный список источников со временем может очень
сильно вырасти, так что поле поиска здесь очень кстати, при помощи него
можно отфильтровать только нужные вам источники. На рис. 12.3 мы установили фильтр по слову «adventure», помня о том, что оно было в пути к базе
данных Azure.
В нижней части окна присутствуют три следующие кнопки:
 Изменить источник (Change Source). Эта кнопка поможет вам, если вы
ошиблись при вводе ссылки и хотите изменить ее или просто желаете
направить запросы на другую базу данных или сервер;
302  Глава 12. Реляционные источники данных
 Править разрешения (Edit Permissions). Нажав на эту кнопку, вы сможете откорректировать имя пользователя и пароль, а также посмотреть
и изменить тип учетных данных для подключения к базе данных;
 Очистить разрешения (Clear Permissions). Этой кнопкой можно воспользоваться, если необходимо удалить источник данных из списка
кешированных подключений, чтобы при следующем соединении вновь
пришлось вводить учетные данные. Это отличный выбор, если вы сделали что-то не так при подключении и хотите начать заново.
Нажав на кнопку Править разрешения (Edit Permissions), можно изменить тип учетных данных при подключении, как показано на рис. 12.4.
Рис. 12.4. Настройки источника данных для базы данных Azure
Здесь вы можете нажать на кнопку Изменить (Edit) в разделе Учетные
данные (Credentials), чтобы ввести новые имя пользователя и пароль для
подключения к источнику.
Не можете подключиться к нашей базе данных?
Мы намеренно решили разместить нашу базу данных на платформе
Windows Azure, чтобы она могла быть доступна всегда. И мы были верны
этому решению начиная с первого издания этой книги. С тех пор мы получили немало сообщений от читателей с жалобами на то, что они не могут
подключиться к данному источнику. Чаще всего проблема возникала по одной из следующих причин:
Подключение к базам данных  303
 забыли выбрать тип ввода учетных данных;
 неправильно ввели имя пользователя или пароль;
 доступ к базе блокировался корпоративным брандмауэром или VPN.
🍌 Примечание. Конечно, иногда наша база данных может быть недоступна, но
в большинстве случаев проблемы с доступом к ней наших читателей объяснялись перечисленными выше причинами.
На случай, если вы не сможете подключиться к нашей базе данных, в сопроводительных файлах имеется ее версия в формате Microsoft Access. Для
доступа к ней вместо коннектора SQL Azure используйте стандартный коннектор Access Database. Вы увидите, что особой разницы между ними нет.
Использование навигатора
После подключения Power Query к базе данных вы увидите привычное уже
вам диалоговое окно Навигатор (Navigator), в котором можете выбрать нужные вам таблицы. Мы в нашем примере будем извлекать данные из таблиц
SalesOrders. Поскольку в нашей базе данных слишком много таблиц, давайте
воспользуемся механизмом поиска для ограничения списка:
 введите в поле поиска строку salesorder;
 выделите таблицу SalesLT.SalesOrderHeader.
В правой части окна откроется область предварительного просмотра с
данными из выбранной таблицы, как показано на рис. 12.5.
Рис. 12.5. Использование диалогового окна Навигатор
Представленная информация кажется нам достаточной, так что давайте
нажмем на кнопку Преобразовать данные (Transform Data) и посмотрим,
что мы из нее сможем извлечь.
304  Глава 12. Реляционные источники данных
Исследование данных
Первое, что бросается в глаза при открытии редактора Power Query, – это
два созданных шага на панели примененных шагов: Источник (Source) и Навигация (Navigation). Если выделить шаг Источник, вы увидите в окне предварительного просмотра все объекты в базе данных, а на шаге Навигация
происходит открытие самой выбранной нами таблицы.
Второе, что стоит отметить, – это масса лишних данных, от которых нам
нужно избавиться. Давайте сделаем это:
 выделите столбцы OrderDate, SalesOrderNumber, SubTotal, TaxAmt,
Freight, SalesLT.Customer и SalesLT.SalesOrderDetail;
 щелкните правой кнопкой мыши по любому из выделенных заголовков и выберите пункт Удалить другие столбцы (Remove Other
columns);
 выделите столбец OrderDate, на вкладке Преобразование (Transform)
нажмите на выпадающую кнопку Дата (Date) и в подменю Год (Year)
выберите пункт Год (Year);
 щелкните правой кнопкой мыши на заголовке столбца OrderDate, выберите пункт Переименовать (Rename) и введите новое имя Year;
 щелкните правой кнопкой мыши на заголовке столбца SalesOrderNumber,
выберите пункт Переименовать (Rename) и введите новое имя Order#.
Теперь таблица выглядит более опрятно, как видно на рис. 12.6.
Рис. 12.6. Очищенная таблица SalesOrderHeader
Итак, заголовки наших столбцов полностью осмыслены, если не считать
двух столбцов с префиксами SalesLT. Фактически в этих колонках показываются связанные данные из другой таблицы базы данных, а не информация
из выбранной таблицы SalesOrderHeader!
В этом заключается одна из прелестей подключения к базам данных.
В большинстве случаев при извлечении информации из баз данных будет
происходить автоматическая идентификация связей между таблицами, что
позволит вам обращаться к связанным записям без необходимости настраивать сами связи или объединять таблицы вручную. Но что скрывается за
значениями столбцов SalesLT.Customer и SalesLT.SalesOrderDetail? Что это за
Value и Table?
Подключение к базам данных  305
Если обратиться к структуре базы данных, к которой мы подключились,
можно заметить, что между таблицами Customer и SalesOrderHeader установлена связь типа «один ко многим» (одному покупателю могут соответствовать несколько заказов, тогда как один заказ может принадлежать только
одному покупателю). По сути, под ключевым словом Value в нашей таблице
скрывается запись из таблицы Customer, содержащая все связанные значения
с выделенным заказом, как показано на рис. 12.7.
Рис. 12.7. В столбце SalesLT.Customer содержатся записи о клиентах,
соответствующих заказам
Также, если щелкнуть справа от слова Table в столбце SalesOrderDetail, в
нижней части окна откроется предварительный просмотр со строками, принадлежащими конкретному заказу, как показано на рис. 12.8.
Рис. 12.8. В заказе с номером 71774 содержится несколько товаров
Хотя таблицы SalesOrderHeader и SalesOrderDetail тоже объединены связью
типа «один ко многим», в этом случае уникальные значения содержатся
именно в таблице SalesOrderHeader, к которой мы в данный момент подключены.
🍌 Примечание. Зачем вам все это нужно? Это позволит вам использовать связи, созданные в базе данных, для объединения данных из разных таблиц, не
прибегая к технике, описанной в главе 10.
306  Глава 12. Реляционные источники данных
Давайте еще немного почистим наши данные:
 выделите столбец SalesLT.SalesOrderDetail и удалите его;
 щелкните по кнопке с двумя стрелками в правой части заголовка
столбца SalesLT.Customer;
 оставьте выделенным только столбец SalesPerson и нажмите на кнопку
OK;
 щелкните правой кнопкой мыши на заголовке столбца SalesPerson и
выберите пункт Замена значений… (Replace Values…);
 в открывшемся диалоговом окне замените вхождение «adventureworks\» на пустую строку.
Теперь ваш запрос должен выглядеть так, как показано на рис. 12.9.
Рис. 12.9. Неужели мы объединили данные из разных таблиц,
даже не прибегая к механизму объединения?
🍌 Примечание. Мы извлекли единственный столбец из связанной таблицы, но
могли пойти дальше и даже проникнуть во внешние столбцы связанной таблицы.
Пришло время завершить подготовку запроса и построить на его основании отчет. Поскольку вы работаете в Excel, выполните следующие действия:
 переименуйте запрос в OrdersBySalesPerson;
 выделите все столбцы и на вкладке Преобразование (Transform) нажмите на кнопку Определить тип данных (Detect Data Type);
 нажмите на вкладке Главная (Home) на кнопку Закрыть и загрузить
в… (Close & Load To…) и выберите вариант импорта в таблицу на новом
листе.
Теперь, когда мы извлекли нужные нам данные на лист, построим на их
основании сводную таблицу для подведения итогов:
 выделите любую ячейку в созданной таблице и на вкладке Вставка
(Insert) нажмите на кнопку Сводная таблица (PivotTable);
 разместите сводную таблицу на том же листе с верхним левым углом
в ячейке H2.
Свертывание запросов  307
Теперь настройте сводную таблицу следующим образом:
 в область строк: SalesPerson, Order#;
 в область значений: SubTotal, Tax Amt, Freight;
 установите для столбцов финансовый тип данных без лишних символов и десятичных знаков.
В результате мы получим сводную таблицу, показанную на рис. 12.10.
Рис. 12.10. Сводная таблица на основе базы данных Windows Azure SQL
Преимущество такого решения состоит в возможности добавить на лист
дополнительные срезы и сводные диаграммы для наиболее комфортного
отображения извлеченной из базы данных информации. Но главный его бонус заключается в волшебной кнопке Обновить все (Refresh All), с помощью
которой мы можем получать информацию из внешней базы данных всего в
один клик!
Свертывание запросов
Одной из самых приятных особенностей подключения к базам данных является возможность использовать механизм свертывания запросов (query
folding) для оптимизации их выполнения. Хотя эта технология встроена в
Power Query и запускается по умолчанию, не требуя от нас никаких дополнительных действий, мы также можем случайно, сами того не желая, отключить
ее, тем самым заставив Excel полагаться только на себя. И чтобы понять, как
не допустить этого, необходимо разобраться в том, что из себя представляет
механизм свертывания запросов и как он работает.
308  Глава 12. Реляционные источники данных
Что такое свертывание запросов?
Мы далеко не всегда задумываемся о том, что происходит за сценой, когда
нажимаем на кнопки выбора, фильтрации, сортировки и группировки данных. Но, как вы уже знаете, в Power Query все наши действия записываются в
виде примененных шагов, что позволяет выполнять их повторно, как макрос.
О чем вы, возможно, не догадываетесь, так это о том, что Power Query все
запросы, какие только может, пытается транслировать в машинные запросы
(native query) на языке, родном для используемой базы данных (SQL), которые впоследствии отправляет базе данных.
Но что еще более интересно, сервер, поддерживающий операцию свертывания запросов, получая исходные запросы от Power Query, старается преобразовать их в оптимальный с точки зрения эффективности вид. Это можно
отследить на примере, когда первым запросом поступает команда на извлечение всех записей из таблицы, а затем – требование оставить информацию
только по отделу с номером 150.
В результате оптимизации сервер, вместо того чтобы извлекать миллион
записей, после чего оставлять только 1500 нужных, сразу выполняет следующий запрос на получение данных с учетом фильтрации:
Select * From tblTransactions WHERE Dept = '150'
Экономия, как вы понимаете, получается просто огромной. Шутка ли – нам
не пришлось вытаскивать из базы данных лишних 998 500 записей!
И хотя не все запросы к базам данных могут быть свернуты, подавляющее
большинство из них может, что позволяет перенести львиную долю нагрузки
по обработке исходных данных на сервер.
Как же узнать, что свертывание запросов работает? Возвращаясь к нашему
предыдущему запросу, вы могли заметить в контекстном меню примененных шагов один любопытный пункт с названием Просмотреть машинный
запрос (View Native Query). На рис. 12.11 показан результат выбора этого
пункта меню применительно к шагу удаления других столбцов.
Рис. 12.11. Просмотр запроса SQL, который будет отправлен базе данных
Свертывание запросов  309
Здесь мы показали преобразование шага в машинный код на ранней
стадии запроса, но вы можете заметить, что подобные трансформации выполняются и на последующих шагах вплоть до шага Замененное значение
(Replaced Value), что видно на рис. 12.12.
Рис. 12.12. Шаги, выполняемые в интерфейсе пользователя,
тоже могут быть свернуты в запросы SQL
Если пункт контекстного меню Просмотреть
машинный запрос (View Native Query) доступен,
вы можете быть уверены, что свертывание запроса для данного шага выполняется. Но попробуйте
щелкнуть правой кнопкой мыши по шагу Измененный тип (Changed Type), как показано на рис. 12.13.
Как видите, нужный нам пункт меню на этом шаге
неактивен, что означает невозможность транслировать шаг в запрос на языке SQL. При обновлении
данных Power Query извлечет запрос SQL с предыдущего шага, пошлет его на сервер, а выполнение
оставшихся шагов продолжит с использованием ресурсов локального процессора и памяти.
Рис. 12.13. Пункт
преобразования в
машинный запрос
недоступен
🍌 Примечание. Отсутствие этого пункта меню не всегда означает, что шаг не
был транслирован в машинный запрос, но это единственный на данный момент доступный индикатор в Excel и Power BI Desktop.
310  Глава 12. Реляционные источники данных
🙈 Предупреждение. Очень важно понимать, что как только цепь свертывания
запросов была прервана, все остальные шаги будут выполняться локально.
В связи с этим нужно всегда стремиться максимально продлить серию шагов,
успешно транслирующихся в машинные запросы.
Мы ждем не дождемся, когда в
Excel и Power BI Desktop появятся
понятные индикаторы свертывания запросов. На рис. 12.14 показано, как они реализованы в Power
Query Online.
Эти индикаторы предоставляют
гораздо более наглядный инструмент по сравнению с нынешней
необходимостью щелкать правой
Рис. 12.14. Индикаторы свертывания запросов
кнопкой мыши по всем шагам запросов. К примеру, на рис. 12.14 отчетливо видно, что с шага Navigation и до
Changed column type свертывание запросов выполняется успешно, а цепочка
разрывается только на последнем шаге Kept bottom rows.
Какие технологии поддерживает механизм
свертывания запросов?
С учетом того, что список коннекторов, использующихся в Power Query,
постоянно растет, мы просто не можем физически предоставить вам исчерпывающий перечень тех из них, которые поддерживают или не поддерживают возможность свертывания запросов. Что важно понимать относительно технологии свертывания запросов, так это то, что она предусматривает
перенос вычислительных мощностей с клиента на источник данных, что
предполагает наличие на стороне сервера вычислительного движка. Именно
поэтому механизм свертывания запросов наиболее предпочтительно работает с базами данных – в их арсенале присутствует и движок хранилища,
и вычислительный движок. Можете заучить как правило, что с файлами технология свертывания запросов не работает, а значит, если вы подключаетесь
к файлам, можете не ждать, что вожделенный пункт меню будет активен. В то
же время, если вы будете работать с базой данных, свертывание запросов
может быть вам доступно.
Одним из исключений из правила о том, что с файлами технология свертывания запросов не работает, является Microsoft Access. Access, несмотря
на то что данные физически хранит в файле, поддерживает этот механизм.
Однако с учетом того, что в этом случае файл физически хранится на вашей
локальной машине, такого прироста производительности, как при работе с
полноценными серверными базами данных, можно не ожидать.
Кроме того, вы должны понимать, что не все базы данных поддерживают
технологию свертывания запросов. Если база, к которой вы подключаетесь,
Свертывание запросов  311
входит в число исключений, Power Query будет просто загружать полный
набор данных и выполнять все шаги собственными силами. При этом все
по-прежнему будет работать, хотя о высокой эффективности такого подхода
не может быть и речи.
Также необходимо помнить о том, что не все коннекторы одинаковы. Одним из наиболее проблемных из них считается коннектор ODBC. Да, он может выручить вас, когда вы не можете подключиться к своему источнику
данных с помощью других средств, но самым большим минусом этого коннектора, как ни странно, является его универсальность. Это означает, что
никакой особой оптимизации под ваш конкретный набор данных от этого
коннектора можно не ждать, а значит, и операция свертывания запросов
может прерваться в любой момент. Наш совет: используйте коннектор ODBC
только в тех случаях, когда для вашего источника не предусмотрен родной
коннектор, и внимательнейшим образом следите за процессом выполнения
свертывания запросов по наличию пункта меню трансляции шагов в машинные запросы.
Распространенные мифы относительно
свертывания запросов
По опыту мы можем сказать, что тема эффективного извлечения информации из баз данных и применения механизма свертывания запросов породила
сразу несколько распространенных мифов, которые мы сейчас постараемся
развеять.
Миф 1. Наиболее эффективный способ извлечь информацию из
базы данных состоит в написании единого запроса SQL с выполнением всех операций в рамках одного шага в Power Query.
Очень печально, что этот миф так сильно распространился и обрел столько сторонников. В одной компании мы видели, как внештатный айтишник
применил этот подход, написав очень сложный запрос на языке SQL и «зашив» его в коннектор с использованием расширенного редактора. И как, все
работало? Надо сказать, да, решение работало довольно быстро. Мог ли программист написать более эффективный запрос на SQL по сравнению с Power
Query? Разумеется.
Но вышло так, что компании пришлось изменить бизнес-логику этого процесса. Естественно, они нанимали внештатного программиста не от больших
знаний в области SQL. И что он им сказал в ответ на просьбу адаптировать
свое решение? Правильно, он предложил заплатить ему за это по увеличенному тарифу или потратить долгие часы и исправить все своими силами.
К слову, они пошли по второму пути и в результате решили проблему.
Могли ли в компании добавить собственные шаги к запросу в Power Query,
чтобы адаптировать решение под новые требования? Могли. Но с учетом
того, что на первом шаге программист разместил собственное выражение
SQL, свертывание запросов после него мгновенно прерывалось, что мешало
написанию эффективного решения.
312  Глава 12. Реляционные источники данных
А что было бы, если бы программист построил свое решение на базе интерфейса пользователя? В этом случае местным специалистам потребовалось бы
несколько минут, чтобы изменить сценарий под новые бизнес-требования,
и все остались бы довольны.
Миф 2. Шаг, на котором завершается свертывание запросов, всегда будет прерывать свертывание.
К сожалению (или к счастью), здесь не все такое черно-белое. В реальности
Power Query генерирует код SQL, используя определенный алгоритм, и иногда порядок шагов может не позволить ему это сделать корректно. Очевидно,
что в этом случае свертывание запросов будет прервано.
Однако это не значит, что стоит поднимать лапки вверх. Иногда достаточно незначительного изменения порядка следования шагов (при помощи
контекстного меню), чтобы свертывание запросов возобновилось.
Миф 3. У кого-то есть сверхсекретный список шагов, на которых
точно будет выполнено свертывание запросов.
Это очень распространенное заблуждение. Мы не хотим вас расстраивать,
но, увы, никакого сверхсекретного списка просто не существует. Почему?
Потому что инструкции, которые будут транслироваться в машинные запросы, зависят от используемого коннектора Power Query, а также от последовательности шагов. Чем больше вы будете работать с базами данных,
тем лучше будете понимать, какие именно шаги могут приводить к обрыву
свертывания запросов. Но волшебного перечня всех возможных сценариев
просто в природе не существует.
Миф 4. Свертывание не распространяется по цепочке запросов.
Это просто не так. В противном случае это бросало бы серьезную тень сомнения на описание структуры запросов, приведенное в главе 2. Если хотите
убедиться, что свертывание запросов прекрасно работает с несколькими запросами, это очень легко сделать следующим образом:
 вернитесь к примеру из этой главы (или откройте файл Ch12 Examples\
AdventureWorks­Complete file);
 перейдите в режим редактирования запроса;
 щелкните правой кнопкой мыши на шаге Другие удаленные столбцы
(Removed Other Columns) и выберите пункт Извлечь предыдущий
(Extract Previous);
 назовите новый запрос Database.
Итак, вы создали цепочку из двух запросов с переходом от Database к
OrdersBySalesPerson. Перейдите к запросу OrdersBySalesPerson и щелкните
правой кнопкой мыши на шаге Замененное значение (Replaced Value). Пункт
меню Просмотреть машинный запрос (View Native Query) по-прежнему
будет активен.
Уровни конфиденциальности  313
Миф 5. Если я могу подключиться, не важно, какой коннектор
я для этого использую.
Последствия этого распространенного мифа едва не убили целый бизнеспроект одного из наших клиентов. Сотрудники их отдела ИТ настоятельно
рекомендовали всем подключаться к базе данных SQL при помощи коннектора ODBC вместо встроенного в Power Query коннектора SQL Server.
Поначалу все было нормально. Пользователи подключались к базе, мгновенно фильтровали и извлекали порядка миллиона записей за прошлую
неделю и строили отчеты, исходя из собственных нужд. Их любовь с Power
Query была взаимной, и жили они душа в душу. Но со временем решение
начало занимать все больше и больше времени, и в какой-то момент на обновление данных перестало хватать восьми часов рабочего дня.
Как оказалось, проблема состояла в том, что отдел ИТ рекомендовал пользователям подключаться из Power Query к базе Microsoft SQL Server посредством стандартного коннектора ODBC, который они установили и настроили.
А такая связка, как выяснилось, приводит к обрыву свертывания запросов
в момент фильтрации данных. Для нас это было большим шоком, поскольку мы никак не ожидали подобного эффекта. В результате пользователи в
момент обновления просто загружали в память Excel весь объем данных из
многих миллионов строк, после чего выполнялась операция фильтрации.
Решение? Все очень просто. Необходимо было использовать родной коннектор SQL при подключении к базе данных, а не стандартный механизм
ODBC. Вот и все. Мы просто заменили коннектор, и обновление запросов
стало занимать всего пару минут.
Уровни конфиденциальности
На каком-то этапе освоения Power Query вы непременно столкнетесь с необходимостью определения уровня конфиденциальности (privacy level) для вашего источника данных. Какие же существуют уровни конфиденциальности,
и почему это имеет значение? На самом деле эта тема очень тесно связана со
свертыванием запросов и тем, как работает данный процесс.
Общее заблуждение заключается в том, что каждый машинный запрос,
который мы видим, отправляется в базу данных. Это не так, поскольку отправляется только финальный валидный запрос. При этом каждый запрос
посылает в базу данных два своих представления (submission).
Хотя с точки зрения технической реализации это может быть не совсем
верно, вы можете рассматривать первое представление как отправку параметров базе данных, а также извлечение предварительного набора данных
для формирования текущих переменных вроде «последней доступной даты»
или «имени первого покупателя». Далее Power Query обновляет, свертывает
и собирает запрос, после чего отправляет его в базу для извлечения данных.
Причина, по которой вам необходимо все это понимать, заключается в
том, что в зависимости от того, как у вас построен запрос, какие-то ваши
данные могут быть посланы источнику. А поскольку ваши данные могут содержать конфиденциальную информацию, вполне очевидно, что это не всег-
314  Глава 12. Реляционные источники данных
да допустимо, особенно если вам придется отправлять данные за пределы
подконтрольной вам сети.
Команда разработчиков Power Query ответила на эти опасения возможностью задавать для каждого источника данных один из следующих уровней
конфиденциальности:
 частный (Private): источник с таким уровнем конфиденциальности
полностью изолирован от других источников данных. Может содержать
секретную информацию;
 организационный (Organizational): такие источники изолированы от
источников данных с общим уровнем конфиденциальности, но видны
из других источников с организационным уровнем;
 общий (Public): данные в таких источниках видны любым другим источникам.
В идеале вам необходимо для всех ваших источников данных установить
собственный уровень конфиденциальности, чтобы ваши секретные данные
не проникали в источники, не предназначенные для их просмотра.
При комбинировании источников данных всегда выполняются следующие
проверки в отношении уровней конфиденциальности:
 данные из общих источников могут быть отправлены в источники с
частным или организационным уровнем конфиденциальности;
 данные из организационных источников могут быть отправлены в источники с таким же уровнем конфиденциальности (но не с частным
или общим);
 данные из частных источников не могут быть отправлены никуда (даже
в другие частные источники).
В теории, если у вас есть рабочий лист Excel с организационным уровнем
конфиденциальности, вы не сможете посылать данные из него на публичные веб-сайты. В то же время, если ваш лист Excel помечен как общий и вы
посылаете его в корпоративную базу данных с организационным уровнем
конфиденциальности, проблем не возникнет, поскольку общие данные могут
свободно передаваться в источники с организационным уровнем.
На самом деле работать с уровнями конфиденциальности бывает очень
непросто. А в случае чего Power Query будет выдавать вам самую неприятную
ошибку, содержание которой показано на рис. 12.15.
Рис. 12.15. Нет ничего хуже, чем такая ошибка в Power Query
🍌 Примечание. В главе 19 мы поговорим об ошибках Formula.Firewall более
подробно.
Уровни конфиденциальности  315
Объявление уровней конфиденциальности данных
Установить уровень конфиденциальности для источника данных не представляет труда. Когда вам нужно будет это сделать, Power Query сам напомнит
вам об этом при помощи диалогового окна, показанного на рис. 12.16.
Рис. 12.16. Сообщение о необходимости предоставить сведения
о конфиденциальности данных
Важно понимать, что настройки безопасности не ограничиваются работой
с базами данных. Эти механизмы призваны защищать вашу информацию от
утечки между любыми источниками. В примере, показанном на рис. 12.16,
мы использовали функцию для подключения запроса FilesList к SharePoint, в
результате чего появилось предупреждение о необходимости задать уровень
конфиденциальности данных. Следующим вы увидите диалоговое окно, в
котором сможете сделать необходимые настройки для каждого источника
данных в вашей рабочей книге.
🙈 Предупреждение. При открытии рабочей книги Power Query выполняет про-
верку того, изменился ли пользователь с момента последнего ее сохранения.
Если это так, настройки конфиденциальности сбрасываются, и их необходимо сделать заново. Если вы работаете в Excel и предполагаете, что эта
особенность может стать для вас настоящей головной болью, по следующей
ссылке вы сможете обнаружить решение с использованием VBA, помогающее напомнить пользователю о том, что ему нужно сделать, чтобы избавиться от этой проблемы: https://bit.ly/3cjNIhP.
Управление уровнями конфиденциальности данных
Если вам необходимо просмотреть или изменить уровни конфиденциальности источников данных, вы можете сделать это в том же окне, где настраи-
316  Глава 12. Реляционные источники данных
вали учетные данные. Откройте диалоговое окно Настройки источника
данных (Data Source Settings), выберите нужный вам источник и нажмите
на кнопку Править разрешения (Edit Permissions).
В открывшемся окне, показанном на рис. 12.17, вы сможете изменить уровень конфиденциальности для выбранного источника.
Рис. 12.17. Управление уровнями конфиденциальности для базы данных Azure
Конфиденциальность и производительность
Хотя намерения, лежащие в основе настройки уровней конфиденциальности данных, иначе как положительными не назовешь (кому хочется подвергать свои секретные сведения утечке?), реализация этого механизма может доставлять серьезные неудобства. В лучшем случае движок обеспечения
безопасности существенно снизит производительность решения, а в худшем
приведет к возникновению ошибок, связанных с Formula.Firewall, что помешает совместному использованию данных.
Посмотрите на диаграмму, изображенную на рис. 12.18. Здесь показано
среднее время выполнения двух запросов из пяти попыток.
Важно учесть, что оба запроса манипулируют исходными данными в таблицах Excel в той же рабочей книге, в которой располагаются сами запросы.
Иными словами, нет никакой необходимости устанавливать уровни конфиденциальности при объединении этих источников, поскольку все наши данные располагаются в одном файле. Если бы мы использовали эту информацию совместно с базой данных, возможно, нам бы понадобилось выполнить
эти настройки. Но когда все данные содержатся в одном источнике, в этом
нет никакого смысла.
Уровни конфиденциальности  317
Рис. 12.18. Сравнение времени обновления двух запросов на базе Excel
Несмотря на это, вы видите, что с отключенной проверкой конфиденциальности (желтые ящики с усами на диаграмме) запросы выполняются
быстрее, а иногда существенно.
🍌 Примечание. Эта диаграмма была построена в Excel с использованием надстройки Кена под названием Monkey Tools. Узнать больше об этой надстройке и скачать бесплатную версию вы можете на сайте Кена по адресу https://
xlguru.ca/monkeytools.
Отключение движка конфиденциальности
Прежде чем отключать движок конфиденциальности, убедитесь в том, что
вы понимаете все плюсы и минусы этого действия, сведенные в табл. 12.1.
Таблица 12.1. За и против отключения механизма проверки
конфиденциальности в Power Query
За
Против
Более быстрые обновления
Потенциальная утечка данных
Исключение ошибок, связанных
с Formula.Firewall
Возможная блокировка обновлений
по расписанию в Power BI
Если в процессе работы вы взаимодействуете с внешними данными, размещенными в интернете или за пределами вашей зоны влияния, ваши данные
могут быть подвержены риску. Кроме того, если вы планируете публиковать
свою модель данных Power BI и настраивать обновление по расписанию, вы,
скорее всего, обнаружите, что служба Power BI (Power BI service) не позволит
вам изменить настройки безопасности.
318  Глава 12. Реляционные источники данных
С другой стороны, если вы строите решение, полностью размещенное
внутри вашей корпоративной сети, отключение движка конфиденциальности может дать вам определенные бонусы. Во-первых, вам будет проще вести
процесс разработки, поскольку вам не придется беспокоиться о возникновении ошибок, связанных с работой брандмауэра конфиденциальности данных
(о котором мы поговорим далее в этой книге). Во-вторых, запросы будут
обновляться быстрее.
Настройка конфиденциальности производится в диалоговом окне Параметры запроса (Query Options), до которого можно добраться следующим
образом:
 Excel: нажмите на вкладке Данные (Data) на кнопку Получить данные
(Get Data) и выберите пункт Параметры запроса (Query Options);
 Power BI: на вкладке Файл (File) откройте раздел Параметры и настройки (Options & settings) и выберите пункт Параметры (Options).
Вы также обнаружите, что настройку конфиденциальности можно произвести на двух вкладках: Глобальные (Global) и Текущая книга/файл (Current
Workbook/File). Взгляните на вкладку глобальных настроек, показанную на
рис. 12.19.
Рис. 12.19. Обзор глобальных настроек конфиденциальности в Excel
Как видите, здесь у вас есть три выбора:
1. Всегда объединять данные в соответствии с настройками уровня
конфиденциальности для каждого источника (Always combine data
according to your Privacy Level settings for each source). Этот вариант
позволит наследовать настройки конфиденциальности для каждого
Уровни конфиденциальности  319
источника данных на основании уровня, установленного в окне конфигурирования учетных данных.
2. Объединение данных в соответствии с настройками уровня конфиденциальности каждого файла (Combine data according to each
file’s Privacy Level settings). Это вариант по умолчанию, которого мы
рекомендуем вам придерживаться.
3. Всегда игнорировать параметры уровней конфиденциальности
(Always ignore Privacy Level settings). Этот вариант привлекает многих,
но мы на самом деле не рекомендуем им злоупотреблять.
Причина того, почему мы не являемся поклонниками последнего варианта, кроется в возможной утечке конфиденциальных данных без предупреждения. Это то же самое, что в Excel 2003 и более ранних версиях отключить
безопасность макросов VBA, чтобы не получать назойливых напоминаний.
Это работает, но одновременно страдает безопасность данных. Вряд ли комуто захочется рисковать своей карьерой ради того, чтобы запросы в Power
Query обновлялись быстрее.
Вместо того чтобы отключать проверку конфиденциальности на глобальном уровне, мы рекомендуем делать это для конкретных проектов при необходимости. Это позволит защитить ваши данные, и вы сами сможете выбирать, для каких решений идти на такой риск. Выбрать эту настройку можно
на вкладке Конфиденциальность (Privacy) в разделе Текущая книга/файл
(Current Workbook/File), как показано на рис. 12.20.
Рис. 12.20. Подходящее место для отключения проверок конфиденциальности
Первый вариант на этой вкладке выбран по умолчанию и означает, что вы
будете получать предупреждения о настройках конфиденциальности отдельно применительно к каждому неустановленному источнику данных. Также
Powered by TCPDF (www.tcpdf.org)
320  Глава 12. Реляционные источники данных
в этом случае проверка безопасности будет выполняться при выполнении
объединения данных, хотите вы того или нет.
Второй вариант позволит вам отключить проверку конфиденциальности
для конкретного проекта, и именно его мы вам рекомендуем использовать
при необходимости.
Оптимизация
Power Query может работать медленно, особенно если вы вынуждены оставлять механизмы проверки конфиденциальности включенными. Это довольно прискорбный факт, о котором в Microsoft знают и делают все, чтобы устранить данный недочет. Но пока это не сделано, мы можем дать вам несколько
советов по повышению быстродействия этого мощного инструмента.
1. Никогда не используйте универсальный коннектор ODBC при подключении к базе данных, если для нее предусмотрен свой отдельный
коннектор. При использовании коннектора ODBC вероятность того,
что свертывание ваших запросов будет неожиданно прерываться, заметно возрастет.
2. Избегайте написания конкретной инструкции на языке SQL при настройке исходного запроса. Единственное исключение из этого правила – если вы в совершенстве владеете SQL и способны написать более
эффективный код по сравнению с шагами запросов, для которых выполнено свертывание. Предоставляя на вход выражение SQL, вы мгновенно исключаете любые возможности по свертыванию запросов для
всех последующих шагов, что может в будущем негативно сказаться на
эффективности решения.
🙈 Предупреждение. Свертывание запросов часто отключается в строках, в которых выражение на языке M или SQL написано вручную. Но хуже то, что это
может привести к дальнейшей отмене свертывания запросов.
3. Перенесите максимально возможную долю вычислений на сторону
базы данных. Если используемая база данных поддерживает свертывание запросов, это поможет вам обеспечить перенос большей части
нагрузки на сервер, чтобы Power Query не приходилось выполнять
сложные вычисления на локальном компьютере. Поскольку серверы
баз данных изначально рассчитаны на высокую скорость обработки
данных, это позволит существенно повысить эффективность рабочего
процесса.
4. Стремитесь выполнять как можно больше инструкций при помощи
команд пользовательского интерфейса Power Query, а не собственных
скриптов на языке M. Несмотря на огромный соблазн динамического
использования параметров для управления фильтрами (особенно пос-
Оптимизация  321
ле того, как научитесь это делать, прочитав данную книгу), помните
о том, что эти действия неизбежно приведут к отмене свертывания
запросов.
🍌 Примечание. Не забывайте, что Power Query не относится к числу инстру-
ментов вроде SQL Server Management Studio (SSMS), помогающих управлять
базами данных. Этот продукт изначально разрабатывался в помощь бизнесаналитикам, не слишком хорошо знакомым с синтаксисом языка SQL, чтобы
они могли свободно извлекать, фильтровать, сортировать и манипулировать
данными. Первостепенная задача Power Query – построить запрос SQL за
вас.
Глава
13
Преобразование
табличных данных
Одним из главных преимуществ Power Query является его способность очищать данные и преобразовывать их из нетабличного вида в табличный, который используется в моделях данных и таблицах Excel. Иногда же исходные
данные поступают к нам в табличном, но совершенно не удовлетворяющем
нас виде, требующем дальнейших преобразований. В главе 7 мы уже коснулись некоторых техник, позволяющих трансформировать структуру исходных данных. Здесь мы сосредоточимся на шаблонах для выполнения преобразований, которые поначалу могут показаться вам пугающими.
Одной из самых больших трудностей, с которыми мы столкнулись при составлении списка описываемых шаблонов, явилось их именование, поскольку мы так и не нашли подходящих словосочетаний в ключевых поисковых
запросах. В результате мы решили называть их в соответствии с используемыми в них инструментами. Именно поэтому мы снабдили каждый раздел
однотипными изображениями по типу «до и после» – с данными в исходном
и желаемом виде. Это поможет вам быстро находить нужные шаблоны под
конкретную задачу.
Сложные шаблоны сведения данных
Вне зависимости от названия каждый шаблон, описанный в этом разделе, так
или иначе будет использовать инструмент сведения данных (Pivot), встроенный в Power Query, для преобразования исходных данных в вид, пригодный
для дальнейшего анализа.
Сведение сгруппированных данных
Первый шаблон, который мы вам представим, одновременно является и
одним из наиболее важных – не только потому, что он чаще иных встречается
на практике, но и по причине того, что его можно использовать и в других
шаблонах. Мы дали этому шаблону имя Сведение сгруппированных данных
(Pivoting Stacked Data), а цель его состоит в преобразовании одноколоночного представления данных в табличный формат, как показано на рис. 13.1.
324  Глава 13. Преобразование табличных данных
Преобразовать это …
… в это …
Рис. 13.1. Как бы нам привести такой вывод к табличному формату?
Перед тем как окунуться с головой в предстоящий пример, давайте внимательно посмотрим на данные, которые нам предстоит преобразовывать,
поскольку они обладают своими характерными особенностями. Этот конкретный набор данных описывает транзакции, произведенные по кредитным картам, но формат, в котором представлена информация, встречается
в большом количестве областей. Присмотритесь к фрагменту данных, показанному на рис. 13.2.
Заголовок
Запись 1
Запись 2
Запись 3
Рис. 13.2. Первые несколько строк сгруппированных данных
Вы наверняка обратили внимание, что, за исключением первой строки, которая, судя по всему, представляет собой заголовки, данные следуют четкому
шаблону. В первой строке повторяющихся блоков мы видим указание даты
транзакции, далее представлен продавец, затем сумма, и замыкает группу
пустая строка. Этот шаблон повторяется для второй строки, третьей и т. д.
Если отбросить заголовки, перед нами останутся сгруппированные данные в
чистом виде, где каждая запись включает в себя четыре строки, и эти блоки
встречаются нам до конца файла.
Сложные шаблоны сведения данных  325
🙈 Предупреждение. Повторяющийся шаблон – это как раз то, что нам нужно,
чтобы применить к набору данных однотипные операции обработки. Вы понимаете, что эти блоки не обязаны состоять из четырех строк, важна лишь
последовательность в данных на протяжении всего файла. Если хотя бы в
одной записи будет на одну строку больше, шаблон не сработает.
Исходные данные, соответствующие определенному шаблону, привести к
табличному виду можно при помощи следующего алгоритма:
Шаг 1. Добавьте столбцы с идентификаторами транзакций и строк:
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую кнопку Столбец индекса (Index Column) и выберите
пункт От 0 (From 0);
 выделите созданную колонку Индекс (Index), перейдите на вкладку Добавить столбец (Add Column), в выпадающей кнопке Стандартный (Standard) выберите пункт Разделить (целое число)
(Integer-Divide) и в открывшемся диалоговом окне введите нужный делитель;
 выделите столбец Индекс (Index), на вкладке Преобразование
(Transform) в выпадающей кнопке Стандартный (Standard) выберите пункт Остаток от деления (Modulo) и в диалоговом окне
введите нужный делитель.
Шаг 2. Сверните данные:
 выделите столбец Индекс (Index) и на вкладке Преобразование (Transform) нажмите на кнопку Столбец сведения (Pivot
Column);
 выберите в выпадающем списке столбец с данными;
 раскройте раздел Расширенные параметры (Advanced options)
и выберите в выпадающем списке в качестве агрегации пункт Не
агрегировать (Don’t Aggregate).
Шаг 3. Очистите данные:
 щелкните правой кнопкой мыши по столбцу Целочисленное деление (Integer-Division) и выберите пункт Удалить (Remove);
 переименуйте созданные столбцы;
 установите нужные вам типы данных.
🍌 Примечание. Этот шаблон может быть применен к любым однородным наборам данных, при этом делитель будет зависеть от количества строк в записи в каждом отдельном случае.
326  Глава 13. Преобразование табличных данных
Давайте попробуем применить наш шаблон на практике.
Для начала импортируйте представленный ниже набор данных в новую
рабочую книгу, после чего приступайте к выполнению первого шага:
 создайте новый запрос с помощью выбора Из текстового/CSV-файла
(From Text/CSV) и укажите путь к файлу Ch13 Examples\Stacked Data.txt;
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую кнопку Столбец индекса (Index Column) и выберите пункт От 0
(From 0).
В созданном столбце с именем Индекс (Index) будет находиться сквозной
идентификатор строк исходного файла.
Следующие два шага предполагают выполнение несложных математических действий с созданным столбцом. Мы не собираемся здесь проводить для
вас урок математики, но если вы вдруг подзабыли то, чему учились в младшей школе, рис. 13.3 поможет вам восстановить в памяти основные моменты.
Частное
Делитель
Делимое
Произведение (делитель*делимое)
Остаток от деления
Рис. 13.3. Помните деление с остатком?
Нам в нашем сценарии необходимо рассчитать и частное, и остаток от деления. Делимое получить очень просто – это значение столбца Индекс (Index),
но как узнать, какой использовать делитель? Этот вопрос является ключевым
в работе нашего шаблона, так что очень важно установить его правильно.
Фактически значение, которое нам необходимо использовать в качестве
делителя, находится в созданном столбце Индекс в первой строке второй
записи. В нашем случае это число 4, что видно по рис. 13.4.
Первая строка второй записи
Рис. 13.4. Поиск первой строки второй записи
Сложные шаблоны сведения данных  327
🙈 Предупреждение. Очень важно использовать именно значение из столбца
Индекс, а не из колонки слева от первого столбца, в которой отображены
номера строк в таблице, поскольку для нашего шаблона важно использовать математику на базе индексов, начинающихся с нуля. Именно поэтому
при создании столбца с индексом мы выбрали пункт От 0 (From 0), а не От 1
(From 1).
Определившись с делителем, мы можем завершить первый шаг нашего
шаблона:
 выделите колонку Индекс (Index), перейдите на вкладку Добавить
столбец (Add Column), в выпадающей кнопке Стандартный (Standard)
выберите пункт Разделить (целое число) (Integer-Divide) и в открывшемся диалоговом окне введите 4;
 выделите столбец Индекс (Index), на вкладке Преобразование
(Transform) в выпадающей кнопке Стандартный (Standard) выберите
пункт Остаток от деления (Modulo) и в диалоговом окне также введите 4.
Если вы все сделали правильно, ваши данные после этого будут выглядеть
так, как на рис. 13.5.
Рис. 13.5. Данные после выполнения первого шага
Обратите внимание, что в столбце Целочисленное деление (Integer-Division)
содержатся нули для всех строк первой записи, единицы – для второй и т. д.
По сути, в этом столбце содержатся идентификаторы записей в наборе данных.
Мы также изменили колонку Индекс, в которой оказались представлены
остатки от деления, в результате чего значения нумеруют не все строки в
328  Глава 13. Преобразование табличных данных
таблице, а строки в рамках каждой записи. Таким образом, в этой колонке
значения будут возрастать от нуля до числа, на единицу меньшего, чем выбранный нами ранее делитель. Вы должны понимать, что нулевое значение
в столбце Индекс теперь относится к дате транзакции, 1 – к продавцу, 2 – к
сумме, а 3 – к завершающей пустой строке.
Теперь, когда наши данные подготовлены, можно переходить к шагу 2:
 выделите столбец Индекс (Index) и на вкладке Преобразование
(Transform) нажмите на кнопку Столбец сведения (Pivot Column);
 выберите в выпадающем списке Столбец значений (Values Column)
поле Transactions;
 раскройте раздел Расширенные параметры (Advanced options) и выберите в выпадающем списке в качестве агрегации пункт Не агрегировать (Don’t Aggregate), как показано на рис. 13.6.
Рис. 13.6. Сведение данных
После нажатия на кнопку OK вы увидите чистую магию, показанную на
рис. 13.7.
Рис. 13.7. Чистый восторг!
Сложные шаблоны сведения данных  329
Если внимательно присмотреться к результату, несложно определить, куда
делись все наши прежние данные:
 значения из столбца Индекс (идентификатор строк в рамках записей)
перекочевали в заголовки столбцов;
 значения из столбца Целочисленное деление (Integer-Division) оказались
собраны в первом столбце набора данных;
 данные из колонки Transactions распределились по таблице в матричном формате.
Ну как вам? Осталось перейти к третьему шагу и почистить наш набор
данных:
 удалите столбец Целочисленное деление (Integer-Division);
 удалите все остальные столбцы, которые вам больше не нужны (мы
удалим столбец 3);
 дайте столбцам подобающие имена (Date, Vendor, Amount);
 установите подходящие типы данных (мы для колонки с датой используем преобразование типа с применением американской локали, в
формате которой заведены данные).
В результате этих действий наши данные обретут вид, показанный на
рис. 13.8.
Рис. 13.8. Наши данные преобразованы в нужный вид
Это один из наших любимых шаблонов. Частично из-за того, что он производит на свет кристально чистую магию, но также по причине его применимости в других полезных шаблонах. Теперь всякий раз, когда вы будете
иметь дело с повторяющимися исходными данными, вы сможете применить
показанный в этом разделе шаблон.
Прежде чем идти дальше, сделаем пару важных замечаний по поводу этого
шаблона:
 если в ваших исходных данных первая строка содержит заголовки, вы
можете повысить ее самостоятельно. Здесь мы этого не делали ввиду
отсутствия заголовков;
330  Глава 13. Преобразование табличных данных
 в нашем наборе данных содержались повторяющиеся пустые строки
после каждой записи. Многие поддаются соблазну и отфильтровывают
их перед сведением данных. Хотя это может сработать, потенциально
это способно и привести к проблемам, если в составе наших данных
могут присутствовать пустые строки (к примеру, если у одного из продавцов не введено имя). В этом случае вы сместите данные, а значит,
можете не ждать никакой магии после сведения таблицы. Именно поэтому мы рекомендуем вам избавляться от этих строк-разделителей
уже после выполнения сведения.
Сведение вертикально сгруппированных данных
Следующая концепция организации исходных данных, которую мы рассмотрим, – это вертикально сгруппированные наборы данных (vertically stacked
set of data). На рис. 13.9 представлены данные, как и в предыдущем примере,
разбитые на блоки записей, стоящие друг под другом. Отличие состоит в том,
что в данном случае каждый набор разбит на столбцы.
Преобразовать это …
Заголовок
Набор 1
Набор 2
Набор 3
… в это …
Рис. 13.9. Вертикально сгруппированные данные для сведения
Давайте посмотрим, как можно разобрать многостолбчатый сгруппированный набор данных:
 откройте или подключитесь к книге Ch13 Examples\Vertical Sets – Begin.
xlsx;
 создайте запрос на основе (синей) таблицы данных.
С этой задачей можно справиться множеством способов. Мы выберем способ, который можно реализовать исключительно при помощи интерфейса
пользователя. Секрет этого подхода кроется в первых трех шагах:
Сложные шаблоны сведения данных  331
 перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Транспонировать (Transpose);
 добавьте столбец с индексом, начинающимся с нуля;
 щелкните правой кнопкой мыши по столбцу Индекс (Index) и выберите пункт Отменить свертывание других столбцов (Unpivot Other
Columns).
Результат этих действий будет выглядеть так, как показано на рис. 13.10.
Рис. 13.10. Что-то интересное происходит в столбце Значение (Value)
Весь трюк здесь состоял в транспонировании данных перед отменой их
свертывания. В результате мы получили один столбец сгруппированных
значений, а с ним мы уже умеем расправляться. Давайте используем рассмотренный ранее шаблон сведения сгруппированных данных, чтобы разобраться с этой задачей:
 щелкните правой кнопкой мыши на столбце Значение (Value) и выберите пункт Удалить другие столбцы (Remove Other columns);
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую кнопку Столбец индекса (Index Column) и выберите пункт От 0
(From 0);
 выделите созданную колонку Индекс (Index), перейдите на вкладку Добавить столбец (Add Column), в выпадающей кнопке Стандартный
(Standard) выберите пункт Разделить (целое число) (Integer-Divide)
и в открывшемся диалоговом окне введите 3;
 выделите столбец Индекс (Index), на вкладке Преобразование
(Transform) в выпадающей кнопке Стандартный (Standard) выберите
пункт Остаток от деления (Modulo) и в диалоговом окне также введите 3;
 выделите столбец Индекс (Index) и на вкладке Преобразование
(Transform) нажмите на кнопку Столбец сведения (Pivot Column);
332  Глава 13. Преобразование табличных данных
 выберите в выпадающем списке столбец Значение (Value), раскройте
раздел Расширенные параметры (Advanced options) и выберите в выпадающем списке в качестве агрегации пункт Не агрегировать (Don’t
Aggregate);
 щелкните правой кнопкой мыши по столбцу Целочисленное деление
(Integer-Division) и выберите пункт Удалить (Remove);
 переименуйте созданные столбцы в Category, Date и Amount;
 установите для столбцов типы данных Текст (Text), Дата (Date) и Целое число (Whole Number) соответственно.
🍌 Примечание. В данном примере мы использовали делитель 3. Именно такое
количество строк присутствует в каждом блоке записей, и увидеть его можно на этапе добавления столбца индексирования в таблицу (как и раньше,
в первой строке второй записи).
Итак, теперь ваши данные, представленные на рис. 13.11, готовы к загрузке
и анализу.
Рис. 13.11. Результат отмены свертывания данных
При выполнении различных преобразований данных в Power Query вы
должны всегда держать в голове разные шаблоны для использования. К примеру, всякий раз, когда вы видите сгруппированные данные в одном столбце,
вы должны призывать на помощь рассмотренный выше шаблон.
Сведение горизонтально сгруппированных данных
А что, если данные сгруппированы не вертикально, а горизонтально
(horizontally stacked set)? Примерно так, как показано на рис. 13.12.
Сложные шаблоны сведения данных  333
Преобразовать это …
ID строк
Набор 1
Набор 2
Набор 3
… в это …
Рис. 13.12. Как свернуть горизонтально сгруппированный набор данных?
🍌 Примечание. Признаться откровенно, это просто ужасный формат хранения
данных, даже не отвечающий правилам нормализации. Если бы вы попытались преобразовать такие исходные данные в таблицу в Excel, то получили
бы измененные названия столбцов вроде Date, Date1, Date2 и т. д., поскольку
все колонки в таблице должны обладать уникальными именами. То же самое
произошло бы, если бы вы загрузили эти данные в Power Query и повысили
заголовки.
Алгоритм сведения данных для этого случая приведен ниже, но его, возможно, придется подкорректировать под вашу конкретную задачу.
Шаг 1. Подготовьте данные:
 загрузите исходные данные в Power Query, по возможности избегая повышения первой строки;
 в ваших данных присутствует столбец с идентификатором строк
(Row ID)?
• если да, то щелкните правой кнопкой мыши по столбцу Row ID
и выберите пункт Отменить свертывание других столбцов
(Unpivot Other Columns);
• если нет, то выделите все столбцы, щелкните по одному из них
правой кнопкой мыши и выберите пункт Отменить свертывание столбцов (Unpivot Columns);
 удалите столбец Атрибут (Attribute).
Шаг 2. Выполните шаблон сведения сгруппированных данных, описанный
ранее, с агрегированием столбца Значение (Value).
Шаг 3. Очистите данные:
 если ваши заголовки были повышены:
• дайте числовым столбцам подходящие имена;
334  Глава 13. Преобразование табличных данных
 если заголовки остались в данных:
• используйте первую строку в качестве заголовков;
• удалите верхние строки, используя в качестве количества
строк определенный ранее делитель;
• выполните дополнительную очистку данных, если необходимо.
🍌 Примечание. Если вы решите запомнить всего один шаблон в Power Query,
запомните шаблон сведения сгруппированных данных.
Итак, давайте посмотрим на наш шаблон в действии, начиная с первого
шага. В новой рабочей книге Excel или в новом файле Power BI выполните
следующие действия:
 создайте новый запрос с помощью выбора Из текстового/CSV-файла
(From Text/CSV) и укажите путь к файлу Ch13 Examples\CourseSchedule.
csv;
 удалите шаги Измененный тип (Changed Type) и Повышенные заголовки
(Promoted Headers);
 выделите первые два столбца (наши столбцы-идентификаторы строк),
щелкните на одном из них правой кнопкой мыши и выберите пункт
Отменить свертывание других столбцов (Unpivot Other Columns);
 выделите столбец Атрибут (Attribute) и удалите его.
В данный момент ваш запрос должен выглядеть так, как показано на
рис. 13.13.
Рис. 13.13. Первый шаг сведения горизонтально сгруппированных
данных с заголовками внутри содержимого
Сложные шаблоны сведения данных  335
Теперь, когда исходные данные подготовлены, можно приступать ко второму шагу, на котором мы будем использовать делитель 2:
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую кнопку Столбец индекса (Index Column) и выберите пункт От 0
(From 0);
 выделите созданную колонку Индекс (Index), перейдите на вкладку Добавить столбец (Add Column), в выпадающей кнопке Стандартный
(Standard) выберите пункт Разделить (целое число) (Integer-Divide)
и в открывшемся диалоговом окне введите 2;
 выделите столбец Индекс (Index), на вкладке Преобразование
(Transform) в выпадающей кнопке Стандартный (Standard) выберите
пункт Остаток от деления (Modulo) и в диалоговом окне также введите 2;
 выделите столбец Индекс (Index) и на вкладке Преобразование
(Transform) нажмите на кнопку Столбец сведения (Pivot Column);
 выберите в выпадающем списке столбец Значение (Value), раскройте
раздел Расширенные параметры (Advanced options) и выберите в выпадающем списке в качестве агрегации пункт Не агрегировать (Don’t
Aggregate);
 щелкните правой кнопкой мыши по столбцу Целочисленное деление
(Integer-Division) и выберите пункт Удалить (Remove).
На этом этапе ваш запрос должен выглядеть как на рис. 13.14.
Рис. 13.14. Как удачно мы свели исходные данные
Теперь приступим к третьему шагу – очистке данных. Здесь необходимо
повысить заголовки и выполнить дополнительные действия по очистке набора данных. Но перед тем как продолжать, давайте посмотрим, как мы загружали данные.
336  Глава 13. Преобразование табличных данных
После импорта данных мы намеренно избавились от шагов Измененный
тип (Changed Type) и Повышенные заголовки (Promoted Headers). Если бы мы
их оставили, в нашем наборе данных по-прежнему были бы столбцы с именами 0 и 1, однако в первой строке стоял бы курс Intro to Excel, а не заголовок
Course. Эти заголовки были бы сведены в столбец Атрибут (Attribute), который мы удалили в конце первого шага. Это означает, что если бы мы оставили
повышенные заголовки, нам необходимо было бы вручную переименовать
столбцы 0 и 1. Это не самая большая проблема, но вы просто должны быть
в курсе.
Поскольку мы удалили шаг повышения заголовков, они остались в наших
данных, что обусловило присутствие первых трех строк в нашем итоговом
запросе. Давайте расправимся с ними: повысьте заголовки, после чего удалите две верхние строки.
🍌 Примечание. Удобство этого подхода заключается в том, что здесь мы используем то же значение делителя, которое вычислили в шаблоне сведения
сгруппированных данных, так что никаких дополнительных действий вам
выполнять не придется.
Вне зависимости от того, вручную вы переименовали столбцы или воспользовались заключительными шагами нашего шаблона, теперь ваш запрос
должен выглядеть как на рис. 13.15.
Рис. 13.15. Преобразование данных почти завершено
Нам осталось лишь отфильтровать пустые значения в столбце Date, установить нужные типы данных, переименовать запрос и загрузить его в место
назначения. И прелесть всего этого заключается в том, что даже если кто-то
расширит источник данных, добавив к нему новые наборы, они все будут
автоматически загружены в момент обновления данных!
Сложные шаблоны отмены свертывания данных  337
🍌 Примечание. В зависимости от источника данных вы можете не видеть пус-
тых строк, показанных на рис. 13.15. В нашем случае Power Query интерпретировал пустые записи как пустые строки, поэтому они сохранились во
время операции сведения. Если бы значения во время импорта были интерпретированы как null, они бы исчезли при выполнении сведения данных.
Шаги, выполненные в рамках описываемого в этом разделе шаблона, сохранены в запросе HeadersInData в файле Ch13 Examples\Horizontal Sets – Complete
file. Для полноты картины мы также включили в файл запрос HeadersPromoted
с версией шаблона для повышенных на первом шаге сценария заголовков.
Сложные шаблоны отмены свертывания данных
Все предыдущие примеры из этой книги, так или иначе связанные с операцией отмены свертывания данных (unpivoting), были довольно простыми,
поскольку были рассчитаны на один уровень заголовков. В этом разделе мы
рассмотрим более сложные примеры со сведением данных с несколькими
уровнями заголовков. Как всегда, сначала мы обратимся к методологии работы, а затем реализуем ее на практике, после чего попытаемся повысить
ее эффективность.
Отмена свертывания данных с подкатегориями
Под данными с подкатегориями (subcategorized data) мы подразумеваем
любой набор данных, в котором заголовки состоят более чем из одной строки, как показано на рис. 13.16.
Преобразовать это …
Заголовок
… в это …
Рис. 13.16. Данные с несколькими уровнями заголовков
338  Глава 13. Преобразование табличных данных
Основная трудность при работе с такими данными состоит в том, что Power
Query поддерживает лишь один уровень заголовков. А здесь у нас не только две строки заголовков, но нам также нужно как-то разбить значения по
апрелю и маю на три колонки.
Шаблон, который мы здесь представим, должен работать с заголовками
любого уровня вложенности.
Шаги в нем будут следующие:
1. Включите заголовки в данные (при необходимости).
2. Транспонируйте набор данных.
3. Заполните нужные столбцы вверх/вниз.
4. Объедините исходные заголовки при помощи разделителя (смотрите
примечание ниже).
5. Транспонируйте данные (приведите их в исходную форму).
6. В столбцах, в которых в первой строке остался только разделитель, замените его на будущий заголовок.
7. Повысьте первую строку до заголовка.
8. Выполните дополнительную очистку данных перед отменой свертывания.
9. Выполните операцию отмены свертывания.
10. Разделите столбец Атрибут (Attribute) по использованному ранее разделителю.
11. Выполните финальную очистку данных.
🍌 Примечание. Самое важное в этом шаблоне – использовать в качестве разделителей символы, не встречающиеся в вашем наборе данных.
Давайте испытаем этот шаблон на практике, подключившись к данным из
файла Financial Statement.xlsx. Итак, в новой рабочей книге или файле Power
BI сделайте следующее:
 создайте новый запрос с помощью выбора коннектора Из книги (From
Workbook) и укажите путь к файлу Ch13 Examples\Financial Statement.
xlsx;
 выберите слева таблицу Pivoted и нажмите на кнопку Преобразовать
данные (Transform Data).
Теперь сделайте паузу и внимательно посмотрите на данные, представленные на рис. 13.17.
Сложные шаблоны отмены свертывания данных  339
Рис. 13.17. Исходный вид данных с подкатегориями
Шаг 1. На первом шаге вы должны убедиться, что все строки, представляющие заголовки, располагаются в окне предварительного просмотра, а
не в заголовках столбцов, и предпринять необходимые действия, если
это не так. Power Query славится своей любовью к повышению заголовков. Обычно это нормально, но только не в этом шаблоне. Почему?
Да потому, что в процессе обработки данных вы просто потеряете эти
заголовки.
В нашем случае после импорта данных из Excel Power Query автоматически повысил первую строку в ранг заголовков, а это привело к тому,
что первый столбец теперь называется UnPivot Data with Sub Categories,
а не Column1. Давайте изменим это путем выполнения следующих
действий:
 удалите шаги Измененный тип (Changed Type) и Повышенные заголовки (Promoted Headers);
 перейдите на вкладку Главная (Home) и в выпадающей кнопке
Удалить строки (Remove Rows) выберите пункт Удаление верхних строк (Remove Top Rows) и введите число 2.
Это позволит избавиться от двух верхних пустых строк и оставит заголовок первого уровня в первой строке, а второго – во второй, что нам
и нужно. Это показано на рис. 13.18.
Рис. 13.18. Теперь мы видим наши заголовки (а с ними и проблемы)
Формат заголовков, показанный в этом примере, встречается повсеместно при работе с данными с подкатегориями. Находились ли заголовки верхнего уровня в исходном файле в объединенных ячейках,
были ли отцентрованы или расположены над ячейкой с подзаголовком
Actual, в любом из этих случаев после импорта в Power Query они при-
340  Глава 13. Преобразование табличных данных
мут вид, показанный на рис. 13.18, – со значениями null, идущими до
следующего заголовка верхнего уровня.
🍌 Примечание. Если вы работаете с набором данных, включающим заголовки
как часть схемы, Power Query установит заголовки столбцов без их повышения. В этом случае вам необходимо вручную опустить заголовки, сделав их
частью данных. Для этого перейдите на вкладку Преобразование (Transform),
нажмите на выпадающую кнопку Использовать первую строку в качестве
заголовков (Use First Row as Headers) и выберите пункт Использовать заголовки как первую строку (Use Headers as First Row).
Очевидно, что нам необходимо заполнить эти значения null вправо
строками, соответствующими названиям месяцев (April и May), после
чего объединить первые две строки. Если бы нам удалось это сделать,
мы могли бы использовать объединенные строки в качестве заголовков, после чего отменить свертывание столбцов. Звучит неплохо, если
не считать, что Power Query не умеет заполнять данные по горизонтали, и объединение можно выполнять только по столбцам, а не по
строкам. Как же быть? Продолжим изыскания на шаге 2…
Шаг 2. Теперь нам необходимо транспонировать данные. Для этого
перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Транспонировать (Transpose).
В результате наши данные будут повернуты на 90 градусов – строки
станут столбцами, а столбцы – строками, как показано на рис. 13.19.
Набор 1
Набор 2
Набор 3
Набор 4...
Столбец 1
Столбец 2
Столбец 6
Рис. 13.19. Транспонирование позволяет поменять местами строки и столбцы
В таком виде данные выглядят весьма странно, зато у нас появилась
возможность сделать то, что было недоступно в исходном формате, –
выстроить однострочный заголовок. Продолжим…
Шаг 3. Значение April нам нужно протянуть в первом столбце на строки
от третьей до пятой, а May – от шестой до восьмой. Сделать это теперь
довольно просто:
Сложные шаблоны отмены свертывания данных  341
 щелкните правой кнопкой по заголовку столбца Column1 и в выпадающем меню Заполнить (Fill) выберите пункт Вниз (Down).
Это позволит распространить значения April и May на ячейки, в которых находятся значения null, в результате чего вид данных обретет
форму, показанную на рис. 13.20.
Рис. 13.20. Названия месяцев заполнили нужные ячейки всего в два клика
🍌 Примечание. Инструмент Заполнить (Fill) может использоваться для распространения значений вверх и вниз, но только в отношении ячеек со значениями null. Если в ваших ячейках находятся пустые строки, вам необходимо
будет предварительно заменить их на ключевые слова null перед выполнением замены.
Шаг 4. Теперь нам нужно объединить исходные заголовки при помощи
разделителя, при этом в качестве разделителя нам подойдет не любой
символ. Здесь очень важно выбрать символ или их сочетание, не встречающиеся в наборе данных. Причина в том, что позже мы будем выполнять поиск по этим разделителям, и нам не хотелось бы попасться
на ложноположительных срабатываниях.
Зачастую достаточно в виде разделителя использовать символ вертикальной черты (|), который обычно вводится путем нажатия клавиш
SHIFT + \ и редко используется в тексте. Если вы опасаетесь, что этот
символ может встретиться в ваших данных, вы можете использовать
любой другой по своему усмотрению. Помню, мы раньше часто использовали сочетание символов -||- для подобных целей.
Итак, давайте объединим наши заголовки в один столбец следующим
образом:
 выделите столбцы Column1 и Column2 и на вкладке Преобразование (Transform) нажмите на кнопку Объединить столбцы
(Merge Columns);
342  Глава 13. Преобразование табличных данных
 в открывшемся диалоговом окне выберите в выпадающем списке вариант Пользовательский (Custom), введите символ вертикальной черты и нажмите на кнопку OK.
В результате будет образован объединенный столбец с именем Сведено
(Merged), в котором будут собраны заголовки с выбранным разделителем. Для ячеек, в которых находились значения null, в новом столбце
будет стоять просто разделитель, что видно на рис. 13.21.
Рис. 13.21. Это именно то, что нам нужно
В результате у нас получился прекрасный кандидат на звание заголовка таблицы. Давайте выполним следующие два шага.
Шаг 5. Транспонируйте данные в исходный вид таким образом:
 перейдите на вкладку Преобразование (Transform) и нажмите
на кнопку Транспонировать (Transpose).
Шаг 6. Посмотрите на содержимое первой строки, претендующей на заголовки. Неплохо было бы заменить ячейки с единственным разделителем на подходящие имена столбцов:
 щелкните правой кнопкой мыши по заголовку столбца Column 1,
выберите пункт Замена значений (Replace Values) и замените
символ вертикальной черты на слово Class;
 сделайте то же самое для столбца Column 2, заменив вертикальную черту на слово Category.
В результате выполнения шагов с первого по шестой мы получили
прекрасный заголовок для таблицы, который по-прежнему находится
в первой строке таблицы, что видно по рис. 13.22.
Рис. 13.22. Прекрасные были бы заголовки, не так ли?
Сложные шаблоны отмены свертывания данных  343
Используя в качестве разделителя символ, который не встречается в
данных, мы получили возможность самостоятельно дать имена столбцам, которые не были определены заранее. А там, где у нас были двухстрочные заголовки, мы умудрились объединить их вместе. Например,
в столбце Column3 в первой строке содержится текст April|Actual, а в
столбце Column4 – April|Budget.
Что ж, можно приступать к седьмому шагу.
Шаг 7. Повысьте заголовки привычным уже способом:
 перейдите на вкладку Преобразование (Transform) и нажмите
на кнопку Использовать первую строку в качестве заголовков
(Use First Row as Headers).
Шаг 8. Этот шаг мы зарезервировали для действий по дополнительной
очистке данных перед выполнением отмены свертывания столбцов.
В каждом наборе данных требования по очистке будут свои. В нашем
случае достаточно заполнить вниз значения в столбце Class, а также
исключить итоги и подытоги, которых не должно быть в нормализованном наборе данных:
 щелкните правой кнопкой мыши по заголовку столбца Class и
в выпадающем меню Заполнить (Fill) выберите пункт Вниз
(Down);
 в элементах фильтрации в столбце Category снимите флажок null.
Как видно на рис. 13.23, данные оказались представлены в приемлемом
виде.
Рис. 13.23. С правильными заголовками и очищенными данными
мы готовы к отмене свертывания столбцов
Шаг 9. Что ж, пришло время отменить свертывание данных:
 выделите столбцы Class и Category, щелкните на одном из них
правой кнопкой мыши и выберите пункт Отменить свертывание других столбцов (Unpivot Other Columns).
Результат выполнения этой операции показан на рис. 13.24.
344  Глава 13. Преобразование табличных данных
Рис. 13.24. После отмены свертывания данные все еще не выглядят
достаточно нормализованными
На этом этапе важно понимать, что наши заголовки и подзаголовки
по-прежнему располагаются в одном столбце. Но, как мы знаем, это
не особенно большая проблема, особенно с учетом того, что мы используем разделитель, не встречающийся в наших данных.
Шаг 10. Разделите столбец Атрибут (Attribute) по разделителю следующим образом:
 щелкните правой кнопкой мыши на заголовке столбца Атрибут (Attribute) и в выпадающем меню Разделить столбец (Split
Column) выберите пункт По разделителю (By Delimiter), установив переключатель в положение По каждому вхождению разделителя (at Each occurrence).
Теперь наши данные выглядят так, как показано на рис. 13.25.
Рис. 13.25. Все готово, осталось подчистить данные!
Перед переходом к заключительному шагу нам хотелось бы отметить
одну важную вещь. Как вы заметили, на предыдущем шаге мы попросили вас в диалоговом окне разделения данных установить переключатель в положение По каждому вхождению разделителя (at Each
occurrence), и это не случайно. Поскольку мы использовали в качестве
Сложные шаблоны отмены свертывания данных  345
разделителя символ, не встречающийся в наших данных, мы можем
разбить колонки на столько столбцов, на сколько пожелаем. Иными
словами, этот шаблон будет работать как для двух уровней заголовков,
так и для двадцати двух. Хотя мы искренне надеемся, что вам не придет
в голову работать с таким количеством подгрупп.
Шаг 11. Выполните финальную очистку данных.
На этом этапе мы окончательно приводим данные в порядок и загружаем их в место назначения. В нашем случае этот шаг будет включать
в себя следующие действия:
 переименуйте столбец Атрибут.1 (Attribute.1) в Month;
 переименуйте столбец Атрибут.2 (Attribute.2) в Measure;
 установите нужные типы данных.
Если вы впоследствии в сводной таблице или при помощи языка DAX
сможете восстановить расчеты для разницы между планом и фактом,
можете также удалить значения Variance $ из переименованного столбца Measure.
Эффективная отмена свертывания данных
с подкатегориями
Теперь, когда вы научились работать с многострочными заголовками, пришло время поговорить об эффективности выбранного метода. Если с небольшими наборами данных предложенный подход будет работать прекрасно,
то при увеличении объема данных могут проявиться следующие проблемы:
 затрачиваемое на выполнение шаблона время может увеличиться;
 после транспонирования данных вы можете увидеть всего несколько
строк данных (а иногда лишь одну).
Если первый недостаток в основном будет нервировать конечных пользователей, то второй может доставить немало хлопот разработчикам. В конце
концов, как вам узнать, стоит ли заполнять значения вниз, если вы их не
видите? При этом сам шаблон продолжит работать, просто его будет трудно
правильно построить.
Причин появления этих ошибок две:
1) Power Query отдает предпочтение длинным и узким таблицам (с малым
количеством столбцов) по сравнению с короткими, но широкими;
2) транспонирование данных представляет собой весьма затратную вычислительную операцию, а в этом шаблоне ее приходится выполнять
дважды.
Несмотря на это, не все потеряно. Наш шаблон все же работает, нужно
просто немного оптимизировать его и убедиться в том, что мы транспонируем минимально возможное количество данных. Представьте на секунду,
что в ваших данных миллион строк и три уровня заголовков. Вместо того
346  Глава 13. Преобразование табличных данных
чтобы транспонировать миллион строк в столбцы и обратно, лучше поработать только с тремя строками, представляющими заголовки. Так Power Query
придется выполнить гораздо меньше работы.
Чтобы реализовать нашу задумку, мы разобьем наш шаблон на четыре
отдельных запроса, что в результате позволит выполнять операцию гораздо
быстрее. Если вы считаете, что в вашем сценарии потенциально могут возникнуть проблемы со скоростью, вы можете изначально спроектировать
запросы таким образом. Если нет – никогда не поздно перестроить уже существующую концепцию под ту, что показана на рис. 13.26.
Только подключение
Запрос
Headers
Загрузка
Шаги запроса
Ссылка на RawData
Сохранить Х верхних строк
Шаги шаблона от 2 до 6
Запрос
RawData
Запрос
Output
Шаги запроса
Шаги запроса
Ссылка на Headers
Добавление запроса Data
Шаги шаблона от 7 до конца
Подключение к данным
Шаг шаблона 1
Установка типов данных
Запрос
Data
Шаги запроса
Ссылка на RawData
Удалить Х верхних строк
Рис. 13.26. Отмена свертывания в объемных наборах данных
Если помните, мы изначально пронумеровали шаги в нашем шаблоне.
И на рис. 13.26 мы строго привязались к этим номерам шагов, чтобы было
понятно, какие из них на каком этапе выполняются.
🍌 Примечание. Если вы решите построить такую структуру запросов с нуля в
Excel, мы рекомендуем вам изначально загружать ваши запросы в виде подключений, а затем для запроса Output выбрать место назначения таблицу
или модель данных. Если пропустить этот шаг, есть риск, что все четыре таблицы загрузятся на отдельные листы, что приведет к необходимости дважды
загружать ваш исходный набор данных.
Изменение запроса отмены свертывания
данных с подкатегориями
В этом разделе мы обратимся к уже созданному ранее запросу и постараемся модернизировать его с целью ускорения.
Сложные шаблоны отмены свертывания данных  347
🍌 Примечание. Полностью собранный запрос находится в сопроводительном
файле Ch13 Examples\Unpivoting Subcategories – Catchup.
Первое, что мы сделаем, – это создадим запрос Raw Data. Поскольку в этот
запрос будет включен только первый шаг шаблона, сделайте следующее:
 перейдите в режим редактирования запроса Unpivoted;
 щелкните правой кнопкой мыши на шаге Транспонированная таблица
(Transposed Table) и выберите пункт Извлечь предыдущий (Extract
Previous);
 назовите новый запрос Raw Data.
🍌 Примечание. Команда Извлечь предыдущий (Extract Previous) оставляет в
новом запросе все шаги вплоть до выделенного, не включая его. А поскольку
мы хотим выделить только действия, включенные в первый шаг шаблона,
мы должны при извлечении выделить первое действие второго шага, а это
именно Транспонированная таблица (Transposed Table).
Если теперь выбрать запрос Raw Data, вы увидите, что он содержит набор
данных со строками заголовков, входящими в данные.
Перед тем как продолжить, давайте создадим копию запроса Unpivoted.
Это позволит нам сохранить исходный запрос для дальнейшей проверки и
создать его более эффективную версию:
 на левой панели Запросы (Queries) щелкните правой кнопкой мыши
по запросу Unpivoted и выберите пункт Дублировать (Duplicate);
 переименуйте запрос Unpivoted (2) в Output.
Теперь давайте извлечем шаги по созданию заголовков. Убедитесь, что в
данный момент у вас открыт запрос Output, и сделайте следующее:
 щелкните правой кнопкой мыши по шагу Повышенные заголовки
(Promoted Headers), соответствующему нашему шагу 7, и выберите
пункт Извлечь предыдущий (Extract Previous);
 озаглавьте новый запрос Headers;
 выберите запрос Headers на панели Запросы (Queries).
На данный момент мы разделили наши запросы, но в запросе Headers попрежнему выполняется транспонирование всех исходных данных. Нужно
это исправить:
 выделите шаг Источник (Source);
 на вкладке Главная (Home) нажмите на выпадающую кнопку Сохранить строки (Keep Rows) и выберите пункт Сохранить верхние
строки (Keep Top Rows), указав в поле количества сохраняемых строк
цифру 2.
348  Глава 13. Преобразование табличных данных
Разумеется, это число напрямую зависит от вашего набора данных. Поскольку у нас только два уровня заголовков, мы использовали именно это
число. Если вы пройдетесь по оставшимся действиям запроса, то увидите,
что у нас по-прежнему выполняются шаги нашего шаблона со второго по
шестой, что в результате приводит к виду, показанному на рис. 13.27.
Рис. 13.27. Теперь в нашем запросе Headers лишь одна строка с заголовками
Если теперь вернуться к запросу Output, вы увидите, что в нем содержатся
правильные заголовки, но отсутствуют данные. Это вполне ожидаемо, поскольку мы сами чуть ранее их удалили. Пришло время вернуть их назад:
 на левой панели Запросы (Queries) щелкните правой кнопкой мыши
по запросу Raw Data и выберите пункт Ссылка (Reference);
 переименуйте созданный запрос в Data.
Убедитесь, что выбран запрос Data, и выполните следующие действия:
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Удалить строки (Remove Rows) выберите пункт Удаление верхних строк
(Remove Top Rows) и введите число 2.
Рис. 13.28. Глядите-ка, нет заголовков!
С запросом Data все, но нужно держать в голове пару моментов:
1) количество удаляемых строк всегда должно совпадать с количеством
сохраненных строк в запросе Headers;
2) вам необходимо убедиться, что этот запрос будет загружаться в виде
подключения, или вам придется ждать, когда он загрузит все данные,
в дополнение к запросу Output.
Итак, теперь у нас есть все, чтобы собрать решение воедино. Для этого выполните следующие действия:
Сложные шаблоны отмены свертывания данных  349
 выберите запрос Output;
 перейдите на вкладку Главная (Home), нажмите на кнопку Добавить
запросы (Append Queries), выберите запрос Data и нажмите на кнопку OK.
🍌 Примечание. Убедитесь, что вы выбрали именно пункт Добавить запросы
(Append Queries), а не Добавить запросы в новый (Append Queries as New),
поскольку мы хотим оставить результаты внутри запроса Output.
В результате произведенных действий мы разделили один запрос на четыре, но при этом существенно повысили эффективность решения в целом.
Теперь оно будет работать быстро как для маленьких, так и для больших
наборов данных.
Сохранение значений null при отмене
свертывания данных
Еще одной особенностью операции отмены свертывания, которая может
доставить вам неудобства, является ее обращение со значениями null. Рассмотрим пример на рис. 13.29, где пользователь щелкнул правой кнопкой
мыши по полю Product и выбрал пункт Отменить свертывание других
столбцов (Unpivot Other Columns).
Рис. 13.29. Кто-нибудь видел мое манго?
В 99 % случаев мы будем более чем счастливы от того, что при выполнении
операции отмены свертывания значения null пропадают. Но что делать, если
нам необходимо сохранить эти записи в итоговом наборе данных?
Оказывается, и для этого специфического случая есть свой шаблон, и состоит он в следующих действиях:
 выделите столбец со значениями null;
 по желанию приведите его к типу Текст (Text);
 щелкните правой кнопкой мыши по заголовку столбца, выберите пункт
Замена значений (Replace values) и замените null на выбранный заполнитель (placeholder);
 выполните отмену свертывания столбца(ов);
 щелкните правой кнопкой мыши по заголовку столбца Значение (Value),
выберите пункт Замена значений (Replace values) и выполните обрат-
350  Глава 13. Преобразование табличных данных
ную замену заполнителей на null;
 переименуйте столбцы Атрибут (Attribute) и Значение (Value);
 по желанию верните столбцу Значение (Value) исходный тип данных.
В целом, как видите, это довольно простой шаблон, но в нем есть один важный нюанс, состоящий в том, что заполнитель для значений null всегда будет
ограничен типом данных столбца. Это не проблема для текстовых колонок,
но для данных других типов может стать настоящим камнем преткновения
и вести к искажению исходной информации.
Давайте посмотрим, какие действия нужно выполнить, чтобы сохранить
значения null в нашем предыдущем примере:
 щелкните правой кнопкой мыши по столбцу In Stock и выполните замену значений null на | (вертикальная черта);
 щелкните правой кнопкой мыши по полю Product и выберите пункт
Отменить свертывание других столбцов (Unpivot Other Columns);
 щелкните правой кнопкой мыши по заголовку столбца Значение (Value)
и выполните обратную замену символов вертикальной черты на null;
 переименуйте столбцы Атрибут (Attribute) и Значение (Value) в Status
и Result соответственно.
🍌 Примечание. Все примеры из этого раздела собраны в файлах Ch13 Examples\
Preserving Nulls – Complete.
Как видно на рис. 13.30, этого шаблона достаточно, чтобы после отмены
свертывания сохранить в наборе данных наши манго.
Рис. 13.30. А вот и манго!
Как и в случае с отменой свертывания данных с подкатегориями, секрет
здесь состоит в выборе в качестве заполнителя символа, который не встречается в ваших данных. В этом случае мы можем не опасаться того, что в наших
исходных данных произойдет подмена.
Но, к сожалению, использование показанного здесь подхода может быть
сопряжено с трудностями при работе с нетекстовыми данными по причине
того, что заполнитель ограничен типом данных исходного столбца. Иными
словами, если в вашем столбце, в котором вы хотите сохранить значения
null, данные хранятся в целочисленном формате, именно в таком формате
должен быть и выбранный вами заполнитель. Почему это может быть источ-
Сложные шаблоны отмены свертывания данных  351
ником проблем? Представьте себе другой набор данных, в котором продажи
выражены в числовом формате, как показано на рис. 13.31. Обычно пользователи предпочитают заменять значения null нулями, поскольку чаще всего
эти величины означают одно и то же. Но взгляните, что произойдет, если в
исходном наборе данных у вас уже присутствуют нулевые значения.
Рис. 13.31. А у яблок (Apple) не должен сохраниться ноль?
Сложности здесь состоят в том, что ноль и null, несмотря на то что похожи, все же означают разные вещи. Ноль указывает на наличие конкретного
числового значения, тогда как null – на его отсутствие. Именно поэтому обратная замена нулевых значений на null в конце шаблона может привести к
искажению исходных данных.
🍌 Примечание. Это может показаться странным, но нулевые значения в продажах могут появиться в результате возвратов, что вполне приемлемо. В то
же время, если мы анализируем выручку, там нули также могут встречаться в
случае подарков.
Конечно, вы можете пропустить последнее действие с обратной заменой
нулей на null, чтобы оставить для яблок и манго нули, – в конце концов,
продаж по ним не было. Но что делать, если нам важно сохранить различия
между нулевыми значениями и null, как показано на рис. 13.32?
Рис. 13.32. Сохранение значений null при отмене свертывания числовых столбцов
В этом примере исходные данные сохранились в целости и сохранности, а
удалось сделать это при помощи промежуточной смены типов данных следующим образом:
 измените тип данных столбца Sales на Текст (Text);
 щелкните правой кнопкой мыши по столбцу Sales и выполните замену
значений null на | (вертикальная черта);
352  Глава 13. Преобразование табличных данных
 щелкните правой кнопкой мыши по полю Product и выберите пункт
Отменить свертывание других столбцов (Unpivot Other Columns);
 щелкните правой кнопкой мыши по заголовку столбца Значение (Value)
и выполните обратную замену символов вертикальной черты на null;
 измените тип данных столбца Значение (Value) на Десятичное число
(Decimal Number);
 переименуйте столбцы Атрибут (Attribute) и Значение (Value) в Measure
и Unit соответственно.
🍌 Примечание. Этот прием с преобразованием в текст может использоваться
для любых нетекстовых данных, включая числа и даты.
Продвинутые техники группирования данных
В примере из главы 7 мы показывали, как при помощи Power Query можно
легко и быстро осуществить группировку простого набора данных. Здесь же
мы обратимся к более сложным случаям с применением инструмента Все
строки (All Rows). С первого взгляда этот тип агрегирования может показаться каким-то очень загадочным и мистическим, но, применив его один
раз на практике, вы прочувствуете всю его мощь.
Все примеры из этого раздела будут построены на основе данных, импортированных из файла Ch13 Examples\BeerSales.txt, которые показаны на
рис. 13.33.
Рис. 13.33. Исходные данные для изучения различных техник группирования
Процент от целого
Для демонстрации всей мощи процесса группирования данных начнем с
использования Power Query для расчета доли значений в каждой строке набора данных от общего итога. Откройте новую рабочую книгу и выполните
следующие действия:
Продвинутые техники группирования данных  353
 создайте новый запрос с помощью выбора Из текстового/CSV-файла
(From Text/CSV), указав путь к файлу Ch13 Examples\BeerSales.txt, и нажмите на кнопку Преобразовать данные (Transform Data);
 на вкладке Преобразование (Transform) нажмите на кнопку Группировать по (Group By) и установите переключатель в положение Подробнее (Advanced).
Для вычисления доли строки от общих продаж нам необходимо сделать две
вещи: вычислить сумму продаж и получить значение по продаже из каждой
строки.
Чтобы корректно настроить опции группировки, сделайте следующее:
 наведите мышью на выпадающий список, в котором выбрано поле
Class, нажмите на появившуюся справа кнопку с троеточием и выберите пункт Удалить (Delete);
 настройте первый столбец, назвав его Total Sales, выбрав в качестве
операции вариант Сумма (Sum), а в качестве исходного столбца –
Sales;
 добавьте агрегирование при помощи соответствующей кнопки, назвав
столбец Data и выбрав в выпадающем списке Операция (Operation)
пункт Все строки (All Rows), как показано на рис. 13.34.
Рис. 13.34. Создание общего итога для набора данных
То, что мы сделали, может показаться странным, поскольку мы не добавили ни одного уровня группировки, да еще и выбрали этот непонятный
вид операции Все строки (All Rows), даже не позволяющий указать столбец.
Избавившись от всех группирующих столбцов, мы указали Power Query, что
354  Глава 13. Преобразование табличных данных
хотим рассчитать общую сумму по столбцу, который выбрали для агрегирования, по всей таблице, не разбивая ее на категории товаров или отдельные
продукты. Что касается загадочной операции с названием Все строки (All
Rows), ее чары откроются вам только после нажатия на кнопку OK.
Рис. 13.35. Столбец Total Sales (без группировок) и таблица
с нашими исходными данными
Агрегация Все строки поистине чудесна: она позволяет сохранить в виде
таблицы исходные строки, на основании которых были вычислены сгруппированные значения. Это означает, что мы можем не только рассчитать общие
итоги, но и восстановить при необходимости все первоначальные данные:
 нажмите на кнопку Развернуть (Expand) в заголовке столбца Data,
снимите флажок использования исходного имени столбца в качестве
префикса и нажмите на кнопку OK.
Теперь, как вы понимаете, чтобы получить долю продаж в каждой строке
от общей суммы, достаточно разделить содержимое колонки Sales на Total
Sales:
 выделите колонку Sales, перейдите на вкладку Добавить столбец (Add
Column) и в выпадающей кнопке Стандартный (Standard) выберите
пункт Разделить (Divide);
 в выпадающей кнопке слева от текстового поля выберите пункт Использовать значения в столбце (Use values in a column) и укажите
колонку Total Sales;
 переименуйте новый столбец в % of Total Sales.
В результате этих действий в запросе появится новый столбец с именем
% of Total Sales и заполненными значениями долей значений в строках от
общей суммы, как показано на рис. 13.36. Все, что нам осталось, – это загрузить итог вычислений в место назначения и отформатировать, как нам
требуется.
Продвинутые техники группирования данных  355
Рис. 13.36. Новый столбец, созданный в результате выполнения группировки
🍌 Примечание. Стоит отметить, что в большинстве случаев подобные расчеты
стоит выполнять при помощи сводных таблиц или мер DAX, но Power Query
дает вам возможность сделать это на уровне источника данных, если необходимо.
Ранжирование данных
Существуют разные способы ранжирования (ranking) данных, и в большинстве из них применяется операция группирования. Мы проиллюстрируем
это на примере ранжирования нашего предыдущего набора данных тремя
способами. Но сначала подготовим наши исходные данные:
 снова создайте запрос с помощью выбора Из текстового/CSV-файла
(From Text/CSV), указав путь к файлу Ch13 Examples\BeerSales.txt, и нажмите на кнопку Преобразовать данные (Transform Data);
 выделите столбец Class и удалите его, в данном примере он нам не
понадобится.
🍌 Примечание. При желании вы можете отредактировать предыдущий запрос
% of Sales, выбрав шаг Сгруппированные строки (Grouped Rows) и выделив
предыдущие шаги в отдельный запрос с именем Raw Data – Beer Sales. После
этого вы можете щелкнуть правой кнопкой мыши по созданному запросу и
создать ссылку на него, после чего избавиться от столбца Class.
Начнем мы с базового ранжирования – с упорядочиванием продаж по
суммам в порядке убывания. При этом если у двух товаров встретится одинаковая сумма продажи, эти товары должны быть отсортированы в алфавитном порядке. Такой метод называется порядковым ранжированием (ordinal
ranking) и реализуется при помощи следующего простого алгоритма:
356  Глава 13. Преобразование табличных данных
 откройте панель фильтрации для столбца Sales и включите сортировку
по убыванию (Sort Descending);
 для столбца Item включите сортировку по возрастанию (Sort
Ascending), чтобы товары упорядочивались при равенстве сумм;
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую кнопку Столбец индекса (Index Column) и выберите пункт От 1
(From 1);
 переименуйте столбец Индекс (Index) в Rank­Ordinal.
Как видите, провести порядковое ранжирование очень просто, и результат
будет таким, как показано на рис. 13.37.
Рис. 13.37. Порядковое ранжирование с сортировкой одинаковых вхождений
Применительно к такому виду ранжирования важно понимать, что каждый элемент в наборе данных получает свой уникальный индекс. При этом
нам не нужно заботиться о том, как вести себя в случае совпадения индексов, поскольку этого никогда не произойдет. А что, если нам необходимо
применить метод стандартного конкурентного ранжирования (Standard
Competition Ranking), в котором одинаковые значения получают минимальный из свободных рангов, оставляя ПОСЛЕ себя промежутки в последовательности чисел до следующего элемента?
Для реализации такого вида ранжирования нам для начала необходимо
построить порядковое ранжирование, после чего применить нехитрые шаги
с использованием операции группирования:
 выделите столбец с фактами (в нашем случае это Sales), после чего на
вкладке Преобразование (Transform) нажмите на кнопку Группировать по (Group By) и установите переключатель в положение Подробнее (Advanced);
 в открывшемся диалоговом окне нам необходимо настроить два агрегирования:
Продвинутые техники группирования данных  357
•
•
столбец с именем Rank­Std Comp будет применять операцию Мин
(Min) к столбцу Rank­Ordinal;
столбец Data, как и в предыдущем примере, будет использовать
вариант Все строки (All Rows);
 нажмите на кнопку OK.
Здесь мы видим еще одну грань применения операции Все строки. Поскольку в результате ее применения создается не значение, а таблица, очевидно, что эта таблица может состоять сразу из нескольких строк, сгруппированных по определенному критерию. Кроме того, как видно на рис. 13.38,
мы можем в окне предварительного просмотра наблюдать результат выполнения этой операции, что помогает проверить ее на наличие ошибок.
Рис. 13.38. Проверяем, что элементам присвоился минимальный ранг
В нашем наборе данных у двух товаров наблюдается одинаковая сумма
продажи – 557, в результате чего для определения ранга мы извлекли минимальное значение для этих двух записей. Здесь важно понимать, что в
следующей строке (с суммой продаж 100) присутствует только один элемент,
для которого минимальное значение ранга равно 6.
Теперь давайте развернем эти таблицы в столбце Data, чтобы восстановить
содержимое остальных колонок:
 нажмите на кнопку Развернуть (Expand) в заголовке столбца Data;
 снимите флажок использования исходного имени столбца в качестве
префикса;
 выделите только поля Item и Rank­Ordinal, поскольку столбец Sales у
нас уже есть;
 нажмите на кнопку OK.
Результат выполнения этих действий показан на рис. 13.39.
358  Глава 13. Преобразование табличных данных
Рис. 13.39. Выполнение стандартного конкурентного ранжирования
при помощи Power Query
Заметьте, что товары с суммой продаж 557 получили одинаковый ранг 4,
далее следует товар со значением 6 в столбце Rank­Ordinal, а следующие позиции с равными суммами (96) отмечены рангом 7.
Хотя существует множество способов ранжирования элементов, мы хотим показать еще лишь один, получивший название плотное ранжирование
(dense ranking). Разница между ним и предыдущим вариантом состоит в том,
что при плотном ранжировании не создаются разрывы в последовательностях рангов после парных элементов.
Кроме того, реализация плотного ранжирования не предполагает предварительного создания порядкового ранжирования и даже не требует
сортировки данных. Шаблон его создания предусматривает следующие
шаги:
 выделите столбец с фактами (в нашем случае это Sales), после чего на
вкладке Преобразование (Transform) нажмите на кнопку Группировать по (Group By) и установите переключатель в положение Подробнее (Advanced);
 в открывшемся диалоговом окне настройте агрегирование с именем
столбца Data и операцией Все строки (All Rows);
 добавьте столбец с индексом, начинающимся с единицы, и назовите
его Rank;
 разверните в столбце Data все поля, за исключением Sales.
Вместо того чтобы создавать ранжирование с нуля, мы просто добавим
новый ранг в существующее решение. Для этого необходимо добавить новый
столбец с индексом до разворачивания столбца Data:
 выделите шаг Сгруппированные строки (Grouped Rows);
Продвинутые техники группирования данных  359
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую
кнопку Столбец индекса (Index Column) и выберите пункт От 1
(From 1);
 переименуйте столбец Индекс (Index) в Rank-Dense;
🍌 Примечание. Главное отличие в шаблонах реализации стандартного конкурентного ранжирования и плотного ранжирования состоит в том, что в
первом случае столбец с индексом добавляется до группировки, а во втором – после.
 выделите шаг Развернутый элемент Data (Expanded Data).
На рис. 13.40 мы переместили столбцы так, чтобы сохранилась хронология
создания нами рангов с использованием разных методов. Кроме того, мы
подсветили строки с повторяющимися значениями, а также разницу в рангах
между разными колонками.
Рис. 13.40. Сравнение трех методов ранжирования
Как видите, рассмотренные нами методы ранжирования отличаются не
так сильно, но они полностью отвечают заявленным требованиям, а при реализации последних двух из них была использована техника группирования
данных.
Нумерация сгруппированных строк
(номера строк по секциям)
В нашем заключительном примере из этой главы мы хотели бы добавить
порядковое ранжирование к нашим данным, но только в рамках одной категории, как показано на рис. 13.41.
Powered by TCPDF (www.tcpdf.org)
360  Глава 13. Преобразование табличных данных
Группа 1
Группа 2
Группа 3
Рис. 13.41. Наша цель – пронумеровать строки внутри групп
Как вы уже, наверное, догадались, здесь мы будем использовать технику группирования данных, но как нам ограничить ранжирование заданной
группой?
Для начала давайте подключимся к источнику данных. В зависимости от
того, выполняли ли вы предыдущие примеры из этой главы, вы можете выбрать один из приведенных ниже вариантов:
 создайте запрос с помощью коннектора Из текстового/CSV-файла
(From Text/CSV), указав путь к файлу Ch13 Examples\BeerSales.txt, и нажмите на кнопку Преобразовать данные (Transform Data);
 создайте ссылку на запрос Raw Data – Beer Sales, если уже создали его
при выполнении предыдущего примера.
Подключившись к данным, мы сначала подготовим их, после чего сгруппируем по столбцу Class, поскольку именно в нем содержатся данные для
секционирования:
 для столбца Class включите сортировку по возрастанию (Sort
Ascending);
 для столбца Sales включите сортировку по убыванию (Sort Descending);
 для столбца Item включите сортировку по возрастанию (Sort
Ascending), чтобы упорядочить данные в случае равенства сумм;
 выделите столбец Class и на вкладке Преобразование (Transform) нажмите на кнопку Группировать по (Group By);
 в открывшемся диалоговом окне настройте агрегирование с именем
столбца Data и операцией Все строки (All Rows).
Продвинутые техники группирования данных  361
После этого в таблице останутся три строки, а в столбце Data будет
располагаться содержимое всех групп в виде таблиц, как показано на
рис. 13.42.
Рис. 13.42. Просмотр строк из группы Ale
Теперь нам необходимо пронумеровать строки внутри групп. Проблема в
том, что это нельзя реализовать только при помощи интерфейса пользователя, а значит, нам придется немного поразвлекаться с формулами, чтобы
решить нашу задачу. В данном случае формула будет базироваться на следующем шаблоне:
=Table.AddIndexColumn([Data], "<имя столбца>", 1, 1)
🍌 Примечание. Прочитав следующие главы, вы сможете лучше понять всю механику происходящего. Сейчас же вам достаточно знать, что это просто такой
шаблон. До сих пор мы называли наш столбец с операцией Все строки (All
Rows) Data. Единственное, что нужно изменить здесь, – это имя столбца.
Давайте изменим имя столбца на Group Rank и посмотрим, как это все
будет на практике:
 на вкладке Добавление столбца (Add Column) нажмите на кнопку
Настраиваемый столбец (Custom Column);
 введите следующую формулу:
=Table.AddIndexColumn([Data], "Group Rank", 1, 1)
 нажмите на кнопку OK (не беспокойтесь о переименовании колонки).
362  Глава 13. Преобразование табличных данных
В результате в запросе будет создан новый столбец с именем Пользовательский (Custom), содержащий табличные значения. В отличие от таблиц в
колонке Data (созданной при группировании данных), в этих таблицах присутствует столбец индекса Group Rank с порядковым ранжированием внутри
групп, что видно на рис. 13.43.
Рис. 13.43. В таблице содержатся ранги в рамках каждой
отдельной группы товаров
🍌 Примечание. Давайте остановимся и сделаем одно важное замечание. Мы
не только решили поставленную задачу, но и узнали, что не все прихоти могут быть воплощены в жизнь посредством интерфейса пользователя Power
Query. Пусть для вас это будет дополнительной мотивацией к углубленному
изучению формул Power Query и языка M.
Что ж, пришло время завершить наш пример. Поскольку столбец Class,
который мы использовали для группировки, входит в состав наших исходных
данных, таблицы внутри колонки Пользовательский (Custom) содержат не
только новый столбец Group Rank, но и всю информацию, которую необходимо вернуть конечному пользователю. А это значит, что нам нужна только
одна эта колонка, вернее данные, находящиеся внутри нее:
 щелкните правой кнопкой мыши по столбцу Пользовательский
(Custom) и выберите пункт Удалить другие столбцы (Remove Other
columns);
 разверните столбец, сняв флажок использования имени столбца в качестве префикса;
 выделите все столбцы и на вкладке Преобразование (Transform) нажмите на кнопку Определить тип данных (Detect Data Type).
Продвинутые техники группирования данных  363
Рис. 13.44. Теперь наши строки отсортированы и пронумерованы
с соблюдением границ между группами
Все, что вам осталось сделать, – это придумать имя запросу и загрузить его
в нужное место назначения.
Глава
14
Условная логика
в Power Query
С приобретением опыта работы в Power Query вы все чаще будете встречаться с необходимостью реализовывать особую логику в столбцах запросов. В данной главе мы не только рассмотрим мастер применения условной
логики (Conditional Logic) в Power Query, но и научимся определять правила
вручную, что позволит создавать более сложные условия.
Основы условной логики
В этом примере мы попытаемся решить проблемы, связанные с расписанием
работы, импортированным из файла Ch14 Examples\Timesheet.txt.
Описание набора данных
На рис. 14.1 показан набор данных, который мы постараемся нормализовать.
Сотрудник
ID сотрудника
Расписание
для
Сотрудника 3
Часы
работы
за день
… еще записи …
Итоги
Следующий
сотрудник
Рис. 14.1. Расшифровка структуры файла с расписанием
Основы условной логики  365
По поводу этой структуры данных можно говорить долго, но мы выделим
основные моменты:
 секция для каждого сотрудника начинается с заголовка, в котором его
имя и фамилия разбиты на два столбца, после чего следует его идентификатор. К сожалению, мы не знаем нижней границы идентификатора,
а значит, где-то в файле может встретиться и сотрудник с идентификатором 1;
 расписание сотрудника может включать в себя от одной до 14 строк, в
зависимости от того, сколько он работал за отчетные две недели;
 расписание для каждого сотрудника заканчивается строкой с итогами,
в которой указано общее количество записей для сотрудника и отработанные им часы.
Нам необходимо преобразовать исходный файл с данными в вид, показанный на рис. 14.2.
Рис. 14.2. Нормализованный формат расписания
Главная сложность здесь состоит в том, чтобы правильно сопоставить сотрудника с его строками расписания. Проблема в том, что в нашем распоряжении нет четкого ограничителя для нужных нам данных. Мы не можем полагаться на содержимое столбца Hrs, поскольку идентификатор сотрудника
также представляет собой число, которое легко можно спутать с количеством
отработанных им часов. Мы также не можем использовать в качестве критерия количество строк, ведь оно может отличаться для каждого сотрудника.
Что же делать?
Подключение к данным
Для начала необходимо подключиться к данным и посмотреть, как они
выглядят в Power Query, – возможно, это даст нам какие-то идеи. В новой
рабочей книге Excel или в пустом файле Power BI проделайте следующее:
 создайте запрос с помощью выбора Из текстового/CSV-файла (From
Text/CSV), указав путь к файлу Ch14 Examples\Timesheet.txt, и нажмите
на кнопку Преобразовать данные (Transform Data);
 перейдите на вкладку Главная (Home), в выпадающей кнопке Удалить строки (Remove Rows) выберите пункт Удаление верхних строк
(Remove Top Rows) и введите число 4;
 перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Использовать первую строку в качестве заголовков (Use
First Row as Headers).
366  Глава 14. Условная логика в Power Query
Также мы подготовим наши исходные данные для использования в следующих двух примерах:
 переименуйте запрос в Raw Data – Timesheet;
 загрузите запрос в место назначения как подключение;
 щелкните правой кнопкой мыши по запросу на панели Запросы
(Queries) и выберите пункт Ссылка (Reference);
 переименуйте новый запрос в Basics.
На рис. 14.3 показан исходный вид данных со всеми их недостатками.
Рис. 14.3. Имя и фамилия Джона Томпсона (John Thompson)
записаны в столбцах Work Date и Out
Создание условной логики при помощи интерфейса
пользователя
Успешная очистка данных зачастую требует проведения определенных
экспериментов. Давайте посмотрим, что мы знаем о наших данных. Нам
нужно получить новый столбец, в котором имя и фамилия будут представлены через запятую. Это можно сделать путем объединения столбцов. Также
мы знаем, что данные в столбцах Work Date и Out должны быть представлены
в виде даты и времени. Что ж, давайте приступим:
 выделите столбцы Work Date и Out и на вкладке Добавление столбца (Add Column) нажмите на кнопку Объединить столбцы (Merge
Columns);
 в открывшемся диалоговом окне выберите в выпадающем списке вариант Пользовательский (Custom), введите в поле ниже запятую и
пробел и нажмите на кнопку OK;
 измените тип данных столбца Work Date на Дата (Date);
 измените тип данных столбца Out на Время (Time).
В результате произведенных изменений данные должны выглядеть так,
как показано на рис. 14.4.
Поначалу кажется, что мы сделали что-то не то. В конце концов, мы породили массу ошибок в запросе. К тому же в объединенном столбце, в котором
имя и фамилия сотрудника следуют через запятую, находится много ненужной информации. Но мы все это сделали намеренно.
Основы условной логики  367
Рис. 14.4. Верным путем идем?
🍌 Примечание. Вспомните, что в главе 3, в которой обсуждались типы данных,
мы говорили, что изменение типа может приводить к появлению ошибок в
данных. Именно это здесь и произошло. Установив для столбца Work Date
тип Дата (Date), мы фактически попросили Power Query попытаться преобразовать строку Thompson в дату. Разумеется, Power Query с этим заданием
не справился, в результате чего была сгенерирована ошибка. То же самое
произошло и с преобразованием строки John к типу данных Время (Time).
Зачем мы это сделали? А затем, чтобы обозначить точку входа в нашу условную логику. Из-за обилия разнородной информации в столбце Hrs (здесь
вам и часы, и итоги, и идентификатор сотрудника) мы не можем написать
правило, которое позволило бы извлечь только ID сотрудников. Но мы можем
делать выводы на основе типов данных столбцов. Фактически мы намеренно
генерируем ошибки в данных, чтобы определить, в каких строках столбцы
Work Date и Out содержат корректные дату и время соответственно.
Но давайте честно: никому не нравятся ошибки в данных, так что вперед –
избавимся от них:
 щелкните правой кнопкой мыши по заголовку столбца Work Date, выберите пункт меню Заменить ошибки (Replace Errors) и укажите значение null;
 то же самое сделайте и со столбцом Out.
Теперь, как видно по рис. 14.5, у нас есть кое-что, на чем можно основывать
условную логику.
Рис. 14.5. По сути, мы перенесли имя и фамилию сотрудника
в новый столбец и очистили данные о нем в прежних колонках
368  Глава 14. Условная логика в Power Query
Пришло время воспользоваться мастером создания условной логики в Power
Query. Для этого выполните следующие действия:
 на вкладке Добавление столбца (Add Column) нажмите на кнопку
Условный столбец (Conditional Logic);
 настройте новый столбец с именем Worker, используя правило: Если
(If) Work Date = null, Тогда (Then) взять столбец Сведено (Merged), В противном случае (Else) – null, как показано на рис. 14.6.
Рис. 14.6. Настройка условного столбца
Чтобы выбрать столбец Сведено (Merged) в области Вывод (Output), выберите в выпадающей кнопке слева от поля вместо Введите значение (Enter a
value) вариант Выберите столбец (Select a column). После этого вы сможете
в выпадающем списке справа указать столбец Сведено (Merged).
🍌 Примечание. В правилах условного столбца мы можем легко оперировать
значениями null, но ошибки отлавливать не можем. Именно поэтому мы
предварительно преобразовали образовавшиеся в результате изменения
типов данных ошибочные значения в null.
После нажатия на кнопку OK вы увидите, что к нашей таблице добавился
достаточно опрятный столбец Worker с именами и фамилиями сотрудников
и значениями null, показанный на рис. 14.7.
Рис. 14.7. Новый столбец Worker
Условная проверка в ручном режиме  369
Прекрасно. Мы почти завершили очистку данных, осталось заполнить значения null именами сотрудников. Для этого выполните следующие действия:
 щелкните правой кнопкой мыши по заголовку столбца Worker и в выпадающем меню Заполнить (Fill) выберите пункт Вниз (Down);
 в элементах фильтрации в столбце Work Date снимите флажок null;
 удалите столбец Сведено (Merged);
 установите для столбца Worker тип Текст (Text).
В результате у нас получился полностью очищенный набор данных, показанный на рис. 14.8, который будет работать даже в случае, если при обновлении количество сотрудников и отработанных ими дней изменится.
Рис. 14.8. Сложная очистка данных, выполненная исключительно
при помощи средств пользовательского интерфейса
🍌 Примечание. Далее в этой главе мы рассмотрим другие подходы к реализации условной логики в Power Query. Но вы должны помнить, что почти
для любой задачи найдутся инструменты в интерфейсе пользователя Power
Query – нужно просто хорошо поискать.
Условная проверка в ручном режиме
При всех очевидных достоинствах мастера создания условной логики в Power
Query у него есть один серьезный недостаток, заключающийся в ограниченности вывода конкретным текстом, содержимым столбца или простейшими
формулами. Если вы хотите в своих условных столбцах использовать всю
мощь формул, вам придется воспользоваться инструментом создания настраиваемых столбцов (Custom Column). Сложность здесь состоит в том, что
синтаксис условной функции IF() отличается от аналогичных функций в Excel
или DAX.
370  Глава 14. Условная логика в Power Query
Представьте, что нам необходимо в предыдущем запросе выделить переработку часов для каждого сотрудника, при условии что нормой является
8-часовой рабочий день. Мы могли бы сделать это следующим образом:
 создать условный столбец с именем Reg Hours и формулой:
if [Hrs] > 8 then 8 else [Hrs]
 вычесть значения новой колонки из значений столбца Hrs, образовав
новый столбец OT Hours.
Это потребовало бы создания двух шагов, но в целом сработало бы. Но что,
если вам не нужен столбец Reg Hours? Иными словами, если вас интересует
только количество переработанных часов.
В идеале можно было бы использовать условный столбец с формулой вроде
следующей:
if [Hrs] > 8 then [Hrs] – 8 else 0
Однако, ввиду предлагаемого выбора из фиксированного значения или существующего столбца для вывода в создаваемой колонке похоже, что реализовать такое решение при помощи рассмотренного ранее диалогового окна
невозможно. Но даже если это возможно, вам вряд ли захотелось бы писать
сложную условную логику в таком маленьком поле для ввода. На самом деле
реализовать это можно, но на практике сложную условную логику мы привыкли прописывать вручную посредством создания настраиваемых столбцов.
🍌 Примечание. По правде говоря, вы можете реализовывать сложную логику
непосредственно в условном столбце. Для этого достаточно предварить формулу оператором и ввести ее вручную – например, в нашем случае можно
написать в поле вывода формулу =[Hrs]-8.
Давайте решим нашу задачу, сначала создав столбец OT Hours, а затем
используя его в расчетах при добавлении колонки Reg Hours. Начнем с создания дубликата запроса Basics из предыдущего примера и добавления к нему
необходимой логики:
 на панели Запросы (Queries) щелкните правой кнопкой мыши по запросу Basics и выберите пункт Дублировать (Duplicate);
 переименуйте запрос в Manual Tests;
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 в качестве имени нового столбца укажите OT Hours.
Теперь попробуем написать корректную формулу.
Если у вас есть опыт оперирования формулами в Excel или DAX, вам наверняка захочется написать нечто в таком роде:
=IF( [Hrs] > 8, [Hrs] – 8, 0)
Условная проверка в ручном режиме  371
Увы, Power Query не позволит вам даже сохранить такую формулу. Более
того, он не сможет скорректировать ее или предложить правильную условную конструкцию.
Дело в том, что Power Query является регистрозависимым инструментом,
что не позволяет ему опознать условную функцию за словом IF. Если бы
у вас была возможность сохранить эту формулу, вы получили бы ошибку,
сообщающую о неправильном вводе имени функции. Итак, с регистром разобрались – вводить функцию if следует строчными буквами. Кроме того,
в отличие от формул в Excel и DAX, в Power Query параметры функций не
заключаются в круглые скобки и не отделяются запятыми. Таким образом,
корректный синтаксис для нашей формулы будет выглядеть так:
=if [Hrs] > 8 then [Hrs] – 8 else 0
🍌 Примечание. Также вы можете воспользоваться следующей конструкцией с
отрицанием: =if not ([Hrs] > 8) then 0 else [Hrs] – 8.
Давайте выделим ключевые моменты при вводе формул в процессе создания настраиваемых столбцов:
 при работе с логическими функциями в Power Query необходимо записывать их в полном виде и строчными буквами;
 вы можете нажимать на клавишу Enter для разделения формул на строки;
 двойной щелчок мышью по имени поля в области Доступные столбцы
(Available columns) поможет перенести его название в формулу;
 нажав на клавишу Escape, вы можете отказаться от предложенной системой интеллектуального ввода (Intellisense) подсказки, тогда как клавиши Пробел, Tab и Enter помогут принять предложение и сэкономить
немного времени.
С переносом на три строки наша формула будет выглядеть так, как показано на рис. 14.9.
Теперь мы можем вычесть полученные значения из содержимого колонки
Hrs, что позволит заполнить столбец Reg Hours:
 выделите столбец Hrs, удерживайте клавишу CTRL и выделите столбец
OT Hours;
 на вкладке Добавление столбца (Add Column) нажмите на выпадающую кнопку Стандартный (Standard) и выберите вариант Вычесть
(Subtract);
 переименуйте столбец Вычитание (Subtraction) в Reg Hours;
 удалите столбец Hrs;
 выделите все столбцы и на вкладке Преобразование (Transform) нажмите на кнопку Определить тип данных (Detect Data Type).
Теперь ваши данные должны выглядеть так, как показано на рис. 14.10.
372  Глава 14. Условная логика в Power Query
Рис. 14.9. Создание настраиваемого столбца OT Hours
Рис. 14.10. Часы работы сотрудников разделены на норму и переработку
Здесь важно понимать, что эту задачу вполне можно решить и исключительно при помощи инструментов пользовательского интерфейса. С другой
стороны, в более сложных сценариях вам может потребоваться выполнить
для этого гораздо больше действий. Умение писать условные выражения
самостоятельно поможет вам производить достаточно сложные вычисления
за минимальное количество шагов.
Воспроизведение функции Excel
ЕСЛИОШИБКА (IFERROR)
В нашем первом примере мы намеренно спровоцировали появление в запросе ошибок с последующей заменой их значениями null, что позволило нам
Воспроизведение функции Excel ЕСЛИОШИБКА (IFERROR)  373
реализовать основанную на этом условную логику. Сейчас мы воспроизведем
этот пример, но постараемся уложиться в меньшее количество шагов. Давайте посмотрим, как это можно сделать:
 на панели Запросы (Queries) щелкните правой кнопкой мыши по запросу Raw Data ­ Timesheets и выберите пункт Ссылка (Reference);
 переименуйте созданный запрос в IFError.
В настоящий момент наш запрос должен выглядеть так, как показано на
рис. 14.11.
Рис. 14.11. Помните эту табличку?
Теперь мы понимаем, что приведение столбца Out к типу данных Время
(Time) тут же вызовет ошибку в первой строке, поскольку слово John не может быть выражено как время без потери информации. Вместо того чтобы
дублировать столбец и пробовать это сделать, не лучше ли будет попытаться воспроизвести действие знакомой многим по работе с Excel функции
ЕСЛИОШИБКА (IFERROR)? Это позволило бы нам вернуть время там, где это
возможно, и альтернативное значение в противном случае.
Как вы, наверное, догадываетесь, Power Query не поддерживает функцию
IFERROR. Нет, iferror тоже не пробуйте, не получится. Синтаксис аналогичной
функции в Power Query выглядит так:
try <пробный результат> otherwise <альтернативный результат>
🍌 Примечание. Синтаксис try напоминает другие языки программирования,
в которых используется инструкция try/catch.
Как это работает? Сначала Power Query попытается выполнить выражение,
следующее за ключевым словом try. Если оно может быть выполнено без
ошибок, вернется вычисленный результат. В противном случае будет возвращен альтернативный результат, указанный после ключевого слова otherwise.
Теперь вопрос: а что мы будем пытаться (try) сделать?
В нашем случае нам необходимо постараться привести столбец к выбранному типу данных, что поможет понять, что делать дальше. Давайте попробуем:
374  Глава 14. Условная логика в Power Query
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 в качестве имени нового столбца укажите Worker;
 введите следующую формулу: try Time.From([Out]) otherwise null.
🍌 Примечание. Приведение данных из одного типа в другой в Power Query
может быть выполнено путем указания нужного типа с последующим ключевым словом From с заключенным в скобки именем столбца. Например, Time.
From(), Date.From(), Number.From() и т. д. Мы решили для простоты ограничиться
приведением к типу Время (Time), чтобы избежать необходимости использования локали для дат.
Результат должен быть похож на то, что показано на рис. 14.12.
Рис. 14.12. Погодите! Это же не имена сотрудников!
Похоже, что инструкция try сработала как надо, ведь на месте ошибок мы
получили значения null. Но, кажется, это не совсем то, чего мы ожидали…
Нам бы хотелось, чтобы на месте null стояло имя сотрудника, а на месте
времени – null. Как этого добиться? Давайте обернем нашу конструкцию try
в блок с условной логикой для проверки результата на null. Если это так,
объединим значения из столбцов Work Date и Out при помощи оператора &,
в противном случае вернем значение null:
 отредактируйте уже созданный шаг добавления настраиваемого столбца;
 измените формулу следующим образом:
if ( try Time.From([Out]) otherwise null ) = null
then [Work Date] & ", " & [Out]
else null
🍌 Примечание. Чтобы формула возвращала корректный результат, необходимо заключить выражение try в круглые скобки. Пробелы вокруг выражения
не обязательны, но они позволяют сделать формулу более читаемой.
Воспроизведение функции Excel ЕСЛИОШИБКА (IFERROR)  375
После применения этой формулы результаты станут такими, как мы и
хотели, что показано на рис. 14.13.
Рис. 14.13. Так-то лучше!
Осталось немного почистить набор данных при помощи инструментов
пользовательского интерфейса:
 щелкните правой кнопкой мыши по заголовку столбца Worker и в выпадающем меню Заполнить (Fill) выберите пункт Вниз (Down);
 установите для столбца Work Date тип данных Дата (Date);
 выделите столбец Work Date и на вкладке Главная (Home) в выпадающей кнопке Удалить строки (Remove Rows) выберите пункт Удалить
ошибки (Remove Errors);
 выделите все столбцы и на вкладке Преобразование (Transform) нажмите на кнопку Определить тип данных (Detect Data Type).
Окончательный результат, показанный на рис. 14.14, абсолютно идентичен выводу, достигнутому в первом примере, при этом количество выполненных шагов снизилось с девяти до пяти.
Рис. 14.14. Другой подход, тот же результат
376  Глава 14. Условная логика в Power Query
Работа с несколькими условиями
Следующую задачу мы также будем выполнять путем добавления настраиваемого столбца, поскольку для условного столбца расчеты будут сложноваты.
Нам придется выстраивать логику на основании значений нескольких столбцов, как показано на рис. 14.15.
Golf Dues
и Curling
Dues
Option 1
или
Option 2
Рис. 14.15. Значения в последних двух столбцах зависят
от содержимого первых колонок
Особенность этой задачи состоит в необходимости анализировать содержимое одного или нескольких столбцов. К примеру, члену клуба выдается
безлимитный абонемент (All Access), если он платит любые взносы за гольф
(Golf dues) и любые взносы за керлинг (Curling dues). Также мы хотели бы
в отдельной колонке видеть, платит ли он какие-нибудь дополнительные
взносы (Option 1 или Option 2).
Начнем, как и всегда, с пустой рабочей книги в Excel или пустого файла в
Power BI:
 создайте запрос с помощью выбора Из текстового/CSV-файла (From
Text/CSV), указав путь к файлу Ch14 Examples\DuesList.txt, и нажмите на
кнопку Преобразовать данные (Transform Data);
 переименуйте запрос в Dues List;
 повысьте первую строку, чтобы использовать ее в качестве заголовков;
 выделите все столбцы, нажмите на вкладке Главная (Home) на кнопку
Замена значений (Replace Values) и замените пустые значения на null.
После этого ваш набор данных должен выглядеть так, как показано на
рис. 14.16.
Рис. 14.16. Данные подготовлены, как теперь создать нужные нам колонки?
Работа с несколькими условиями  377
Первым делом нам необходимо продумать логику, которую мы собираемся
реализовать. Будем размышлять по шагам, и для начала нам нужно сделать
нечто такое:
если [Golf Dues] <> null И [Curling Dues] <> null
Тогда "Полный доступ”
Иначе "Пока не уверен..."
Выражаясь английским языком, получим следующее:
if [Golf Dues] <> null and [Curling Dues] <> null
then "All Access"
else "Not sure yet..."
Как ни удивительно, но если эту формулу ввести для нового настраиваемого столбца с именем Member Type, она сработает, что видно на
рис. 14.17!
Рис. 14.17. Как же это просто!
Опять же, в отличие от Excel и DAX, в которых оператор И (AND), написанный в верхнем регистре, предшествует проверяемым выражениям, в Power
Query используются строчные буквы, а оператор and ставится между выражениями согласно следующему шаблону:
<test 1> and <test 2> (and <test 3>, и т. д.)
Как и в случае с Excel и DAX, количество проверяемых выражений не ограничено, но чтобы в результате формула вернула истинный результат, необходимо, чтобы каждое выражение возвращало истину.
🍌 Примечание. Потенциальная ловушка, связанная с оператором and, заклю-
чается в том, что вам может понадобиться заключать выражения перед и
после него в скобки в случае объединения с условиями or.
Поскольку это уже работает, давайте подумаем, что можно сделать, чтобы
заменить подвыражение else на что-то более осмысленное. Попробуем так:
if [Golf Dues] <> null then "Golf Course"
else if [Curling Dues] <> null then "Curling Club"
else "None"
378  Глава 14. Условная логика в Power Query
🍌 Примечание. Здесь проверка на Curling Dues является не чем иным, как ус-
ловным выражением, вложенным в оператор else предыдущего условия. Вы
можете для простоты восприятия формул делать переносы строк после каждого блока if – then – else, но это совсем не обязательно.
Воспользуемся этой логикой и изменим формулу добавленного столбца
так, как показано на рис. 14.18.
Мы заменили строку
«Not sure yet…»
на новую логику
Рис. 14.18. Обновленная формула настраиваемого столбца
🍌 Примечание. Не уверены, что способны сразу писать длинные работающие
формулы? Не отчаивайтесь! Вы можете создать отдельные настраиваемые
столбцы для каждого элемента логики, после чего объединить их в формуле.
После удаления этих вспомогательных столбцов никто ни о чем не догадается!
Рис. 14.19. Теперь с логикой все в порядке
Сравнение со следующей/предыдущей строкой  379
Так, с этим мы справились, идем дальше. Следующим шагом нам нужно определить, платит ли клиент какие-либо дополнительные взносы. Для
этого достаточно узнать, заполнено ли для него содержимое какого-либо из
столбцов Golf Option 1 и Golf Option 2, а может, и обоих сразу. Сделаем это с
использованием оператора or. Он работает так же, как and, но возвращает
истину в случае, если хотя бы одно из проверяемых выражений истинно:
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 назовите столбец Pays Dues и введите для него следующую формулу:
if [Golf Option 1]<> null or [Golf Option 2] <> null
then "Yes"
else "No"
Результат показан на рис. 14.20 и полностью соответствует нашим ожиданиям.
Рис. 14.20. Использование операторов and, or и else if
помогло нам добиться нужного эффекта
Осталось установить для столбцов правильные типы данных и загрузить
запрос.
Сравнение со следующей/предыдущей строкой
Одной из проблем при работе с Power Query является невозможность напрямую обратиться к предыдущей строке в наборе данных. Как же нам реализовать сценарий, показанный на рис. 14.21?
… в это …
Преобразовать это …
Категория
Предыдущая
строка
Рис. 14.21. Нам нужно извлечь данные на основе предыдущей строки
380  Глава 14. Условная логика в Power Query
В этом решении мы используем действительно очень крутой трюк, и нам
просто не терпится рассказать вам о нем! Приступим:
 создайте запрос с помощью выбора Из текстового/CSV-файла (From
Text/CSV), указав путь к файлу Ch14 Examples\Sales.txt, и нажмите на
кнопку Преобразовать данные (Transform Data);
 повысьте первую строку, чтобы использовать ее в качестве заголовков;
 выделите все столбцы, нажмите на вкладке Главная (Home) на кнопку
Замена значений (Replace Values) и замените пустые значения на null.
Данные теперь будут выглядеть так, как показано на рис. 14.22. Сложность
здесь состоит в том, чтобы извлечь название категории товаров, основываясь
на значении из другой строки.
Рис. 14.22. Нужный нам шаблон находится
в предыдущей строке набора данных
🍌 Примечание. Если внимательно присмотреться к этому набору данных, мож-
но увидеть определенные шаблоны. Каждой категории товаров в столбце
Sales Item предшествует значение null, и такое же значение следует за ней.
Также значение null находится сразу за итогами в столбце Qty. Использование любого из этих шаблонов может нам помочь при определении названий
категорий.
Итак, мы начнем с добавления двух столбцов с индексами:
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую кнопку Столбец индекса (Index Column) и выберите пункт От 1
(From 1);
 повторите эту операцию, но на этот раз выберите пункт От 0 (From 0).
Вот мы и подобрались к нашему крутому шаблону:
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Объединить запросы (Merge Queries) выберите пункт Объединить за-
Сравнение со следующей/предыдущей строкой  381
просы (Merge Queries) (не Объединить запросы в новый (Merge
Queries as New));
 дважды выберите таблицу Sales для объединения ее самой с собой;
 в верхнем экземпляре таблицы выделите столбец Индекс.1 (Index.1), а
в нижней – Индекс (Index), как показано на рис. 14.23.
Рис. 14.23. Самообъединение таблицы для сравнения
с предыдущей строкой
Вы чувствуете, к чему идет?
 нажмите на кнопку OK;
 разверните столбец Qty из созданного столбца Добавлен индекс1 (Added
Index1) без использования префиксов;
 отсортируйте столбец Индекс (Index) по возрастанию.
После выполнения этих действий набор данных будет выглядеть так, как
показано на рис. 14.24.
Рис. 14.24. Мы успешно сместили значения в столбце Qty на одну строчку вниз
382  Глава 14. Условная логика в Power Query
Давайте на минутку остановимся и отметим важные моменты, касающиеся произведенных действий и полученного результата.
1. Этот прием работает как для сравнения значений с другими строками,
так и просто при необходимости сдвинуть значения в одном или нескольких столбцах на определенное количество строк.
2. Для сравнения с предыдущей строкой всегда при объединении выбирайте в верхней таблице столбец Индекс.1 (Index.1), а в нижней – Индекс
(Index). Если же вам нужно сравнить данные со следующей строкой,
сделайте наоборот.
3. Сравнение с предыдущей строкой всегда приводит к пересортировке
данных при разворачивании одного или нескольких значений из объединения. При сравнении со следующей строкой этого не происходит.
🙈 Предупреждение. Если вы используете шаблон сравнения с предыдущей
строкой для реализации условной логики, не забудьте изменить порядок
сортировки после разворачивания объединенных результатов!
Теперь приступим к завершению подготовки данных:
 создайте условный столбец с именем Category и настройте его следующим образом:
if [Qty.1] = "---" then [Sales Item] else null
 щелкните правой кнопкой мыши по заголовку столбца Category и в выпадающем меню Заполнить (Fill) выберите пункт Вверх (Up);
 откройте панель фильтрации столбца Qty.1 и снимите флажок со значения «---»;
 удалите столбцы Index, Index.1 и Qty.1;
 отфильтруйте столбец Sales Item, избавившись от значений null;
 выделите все столбцы, перейдите на вкладку Преобразование
(Transform) и нажмите на кнопку Определить тип данных (Detect
Data Type).
В результате мы получим чистые данные, в которых категория товаров
будет выделена в отдельный столбец, как показано на рис. 14.25.
Рис. 14.25. Вы даже не поверите, что категория
изначально была зашита в столбец с товарами
Столбцы из примеров  383
🍌 Примечание. Файл с окончательным решением содержит версию шаблона
для сравнения данных со следующей строкой. Отличия между шаблонами
заключаются в том, что при объединении таблиц мы указываем столбцы с
индексами в обратном порядке и используем в логике и фильтрах значение
null вместо строки «---».
Столбцы из примеров
Последний инструмент, с которым мы познакомимся в этой главе, называется Столбцы из примеров (Columns From Example). Как и предыдущая
техника, этот инструмент применим не только в области условной логики,
но и представляет из себя полноценное средство построения выражений на
основе логических выводов. Как вы увидите, его можно также использовать
для создания условных правил.
Чтобы продемонстрировать всю мощь описываемого инструмента, представим, что у нас есть слишком сложный исходный набор данных – настолько
сложный, что мы не можем просто взять и импортировать его в Power Query.
К счастью, искать такие наборы данных становится все сложнее, так что мы
намеренно испортим нормальный файл, импортировав его с фиксированной
нулевой длиной столбцов. Для этого сделайте следующее:
 создайте запрос с помощью выбора Из текстового/CSV-файла (From
Text/CSV), указав путь к файлу Ch14 Examples\FireEpisodes.txt;
 в выпадающем списке Разделитель (Delimiter) выберите пункт Фиксированная длина (Fixed Width) и введите в поле ниже 0, как показано
на рис. 14.26.
Этот прием требуется не так часто, но он позволяет переопределить действия Power Query по умолчанию и свести данные в один столбец, с которым
вы сможете работать.
Рис. 14.26. Принудительный импорт данных в виде одной колонки
После нажатия на кнопку Преобразование данных (Transform Data) откроется редактор Power Query со списком эпизодов и статистикой просмот-
384  Глава 14. Условная логика в Power Query
ров первых нескольких сезонов телесериала Пожарные Чикаго (Chicago Fire).
Наша цель – извлечь данные в формате <Название эпизода>, <Номер эпизода>.
Но как это сделать?
Существуют разные способы реализовать эту задумку, начиная от разбиения данных на столбцы до написания пользовательских формул. Однако,
вместо того чтобы тратить уйму времени на поиск точек входа, мы воспользуемся новым инструментом в Power Query:
 перейдите на вкладку Добавление столбца (Add Column) и нажмите
на кнопку Столбец из примеров (Column From Examples).
Вы увидите картину, представленную на рис. 14.27.
Рис. 14.27. Добавление столбца из примеров
Идея состоит в том, что в пустой колонке, появившейся справа, вы просто
вводите значения, которые хотите извлечь из исходного столбца. Давайте
введем первые два значения, которые нам нужно достать:
 введите в первой строке нового столбца текст Pilot, Episode 1;
 во второй строке введите текст Mon Amour, Episode 2.
После окончания ввода текста во вторую строку столбец автоматически
заполнится строками по предполагаемому шаблону. И хотя в большинстве
строк все в порядке, в одном случае, судя по всему, закралась ошибка, что
видно на рис. 14.28.
Рис. 14.28. Почему в десятом эпизоде появилась кавычка?
Столбцы из примеров  385
Давайте исправим это:
 введите поверх ошибочного содержимого следующий текст без кавычки: Merry Christmas, Etc., Episode 10.
Что случилось?! В столбце остались только три записи, которые мы ввели
вручную, а все остальные строки заполнились значениями null, как видно
на рис. 14.29.
Рис. 14.29. Ох! Мы, кажется, сломали столбец из примеров!
Чтобы понять, что случилось, необходимо разобраться в том, как работает
этот инструмент. Когда вы вводите строки в ячейки нового столбца, движок
Power Query за сценой строит формулу, показанную в верхней части диалогового окна, которая используется для извлечения значений по введенному
шаблону. Что произошло в нашем примере? Все просто – наша корректировка строки привела к тому, что результат стал слишком сложным, чтобы
по нему можно было построить формулу. В этом случае Power Query переключается в режим создания обычного условного столбца с использованием
простейшей логики if/then, основанной на введенных нами строках. Как вы
понимаете, этот вариант нельзя масштабировать на всю таблицу.
🍌 Примечание. Логика построения формулы движком Power Query, в частности, зависит от порядка вводимых вами строк. С учетом того, что вы вводите
и в какой последовательности, может меняться и итоговый результат.
Ладно, давайте применим другой подход:
 удалите из нового столбца все введенные вручную строки;
 введите в первой строке слово Pilot;
 во второй строке введите Mon Amour;
386  Глава 14. Условная логика в Power Query
 дважды щелкните мышью по заголовку столбца и назовите его Episode
Name.
Сейчас названия эпизодов в столбце выглядят корректно, даже с эпизодом
«Merry Christmas, Etc.» все в порядке. Кроме того, как вы можете видеть на
рис. 14.30 и в верхней части диалогового окна, формула, созданная Power
Query, более не опирается на примитивную условную логику, а использует
функцию Text.BetweenDelimiters() для извлечения названия эпизодов между
кавычек.
Рис. 14.30. Power Query воспользовался специальной функцией
и корректно извлек названия эпизодов
Давайте на этом остановимся и попробуем извлечь номера эпизодов:
 нажмите на кнопку OK, чтобы сохранить столбец;
 перейдите на вкладку Добавление столбца (Add Column) и снова нажмите на кнопку Столбец из примеров (Column From Examples);
 введите в первой строке нового столбца текст Episode 1;
 во второй строке введите текст Episode 2.
Колонка снова заполнилась по большей части правильно, за исключением
злосчастного рождественского эпизода, который нам придется исправить
вручную:
 замените в десятой строке столбца текст Etc.» (Chicago Fire на Episode 10;
 переименуйте столбец в Episode Nbr.
Теперь результаты выглядят прекрасно, и Power Query показывает,
что при составлении формулы вновь была использована функция Text.
BetweenDelimiters(), но на этот раз текст извлекался между вхождением строки «Fire, » и следующей запятой, что видно на рис. 14.31. Нам это вполне
подходит.
Столбцы из примеров  387
Рис. 14.31. А вы бы додумались использовать текст «Fire, » в качестве разделителя?
🍌 Примечание. Создание столбцов из примеров – великолепный инструмент
из арсенала Power Query, поскольку он даже не требует от вас знания функций, которые используются при построении формул. По сути, для использования этого инструмента вам вообще не нужно знать, что в Power Query есть
какие-то функции.
Теперь давайте подтвердим полученный результат и посмотрим, сможем
ли мы добиться поставленной цели:
 нажмите на кнопку OK;
 снова перейдите на вкладку Добавление столбца (Add Column) и нажмите на кнопку Столбец из примеров (Column From Examples);
 введите в первой строке нового столбца текст Pilot, Episode 1.
В отличие от первой попытки выполнить такой поиск по шаблону, сейчас
Power Query мгновенно вернул нам правильные результаты, причем во всем
столбце. Почему? Потому что он умеет использовать при построении формул
все столбцы в таблице, включая те, которые мы создали ранее. Это видно на
рис. 14.32.
Рис. 14.32. В данном случае Power Query использовал функцию Text.Combine()
388  Глава 14. Условная логика в Power Query
Применительно к тому, что произошло на ваших глазах, важно понимать
следующее:
 вы могли бы выделить столбцы Episode Name и Episode Nbr, на вкладке
Добавление столбца (Add Column) нажать на кнопку Объединить
столбцы (Merge Columns) и использовать в качестве разделителя запятую;
 если бы вы сделали именно так, Power Query создал бы точно такую же
формулу, которую вы видите в верхней части диалогового окна Добавить столбец из примеров (Add Column From Examples);
 если вы хотите исключить результаты столбцов из диалогового окна,
просто снимите флажки в их заголовках.
🍌 Примечание. Ну, правда, классно же? Если вы не можете найти или вспомнить команду для той или иной операции, попробуйте воспользоваться инструментом создания столбцов из примеров. Уверены, он сможет изрядно
облегчить вам жизнь!
Что ж, давайте произведем финальную очистку данных:
 переименуйте столбец Сведено (Merged) в Episode и нажмите на кнопку OK;
 щелкните правой кнопкой мыши по столбцу Episode и выберите пункт
Удалить другие столбцы (Remove Other columns);
 загрузите данные на рабочий лист или в модель данных.
Теперь ваши данные в полном порядке, и никто даже не догадается, что
для достижения цели вам пришлось создавать промежуточные столбцы.
Глава
15
Значения в Power Query
Перед тем как перейти к изучению языка M, давайте посмотрим, как в Power
Query представлены значения, а также данные в целом и функции. Понимание этих моментов поможет вам чувствовать себя более уверенно при
освоении продвинутых концепций программирования.
Обратите внимание, что в этой главе мы не будем говорить о применении
каких-то приемов для достижения результатов. Вместо этого мы посмотрим
на то, как все устроено внутри Power Query.
Если вы будете проверять примеры из этой главы на своем компьютере,
то обнаружите, что все структурированные значения (structured value), к которым относятся таблицы, списки, записи, значения, двоичные данные и
ошибки, располагаясь в столбце, выделяются особым цветом: в Excel – зеленым, в Power BI – желтым. Кроме того, для каждого такого значения будет
работать предварительный просмотр, активирующийся при щелчке мышью
на пустом пространстве ячейки рядом с текстом.
🙈 Предупреждение. В попытках соблюсти баланс между четкостью и доступ-
ностью мы, признаемся, некоторые ресурсы для этой книги создали, основываясь на собственной интерпретации официальной документации по Power
Query. И хотя мы старались максимально точно придерживаться документации, некоторые из применяемых нами терминов нельзя назвать технически
идеальными. Но мы использовали их намеренно, чтобы лучше донести до
вас принятый жаргон языка M.
Типы значений в Power Query
Мы с вами уже видели довольно много примеров работы с Power Query, и вы
наверняка обратили внимание, что в области предварительного просмотра
некоторые данные отображаются в виде коллекции значений. Другие же
данные могут быть выделены цветом – это касается таблиц, списков, записей, двоичных данных и даже ошибок. Чем же они отличаются от остальных
значений в Power Query?
390  Глава 15. Значения в Power Query
🍌 Примечание. Заметьте, что мы не используем принятое во многих языках
программирования, включая VBA, слово объект (object). Вместо этого мы
оперируем более привычным для Power Query термином значение (value).
В Power Query значения могут быть двух типов:
 примитивными (primitive), к которым относятся двоичные данные,
дата, время, длительность, логические значения, null, числа, текст, тип;
 структурированными (structured) – такие значения, к которым относятся таблицы, списки, записи и даже функции, выделяются цветом и
строятся на базе примитивов.
Рис. 15.1. Значения и их типы в Power Query
Если с пониманием примитивных типов у вас проблем не возникнет точно, структурированные типы не так просты, к тому же они уникальны для
Power Query. Причина существования структурированных типов состоит в
возможности выполнять операции на базе строк, столбцов и других аспектов,
доступные только для них.
🍌 Примечание. Если вы знакомы с Python и датафреймами пакета pandas, вам
будет гораздо проще понять то, о чем мы будем говорить в этой главе. Тем не
менее мы постарались выстроить объяснение так, чтобы и без этих знаний
вам все было предельно ясно.
Таблицы  391
Давайте окунемся в мир структурированных значений и узнаем, как все
работает.
Таблицы
Таблица (table) представляет собой структурированное значение в Power
Query, содержащее строки, столбцы и метаданные, такие как имена столбцов
и их типы данных. Табличные значения могут появляться в разных местах,
и вы всегда должны приветствовать их образование, поскольку работать с
ними в Power Query очень легко:
 откройте файл Ch15 Examples\Power Query Values.xlsx;
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
 в строке формул напишите следующий код:
=Excel.CurrentWorkbook()
 как видно на рис. 15.2, в нашем рабочем листе находится одна таблица.
Рис. 15.2. Предварительный просмотр единственной таблицы рабочего листа
Преимущества табличных значений в Power Query можно перечислять
долго. Вот лишь некоторые из них:
 мы можем осуществлять предварительный просмотр данных в таблице;
 данные, содержащиеся в таблице, будут разбиты на строки и столбцы
(хотя ничто не гарантирует наличие в ней заголовков);
 мы можем раскрыть детализацию по конкретной таблице в столбце, а
можем развернуть все имеющиеся таблицы;
 после разворачивания таблицы в нашем распоряжении будет полный
арсенал инструментов для манипулирования табличными данными и
их преобразования.
Разумеется, табличные значения в Power Query не ограничиваются одними
лишь таблицами из рабочих книг Excel. Таблицы могут содержаться в самых
разных источниках данных, включая те, из которых мы осуществляем им-
392  Глава 15. Значения в Power Query
порт при помощи функций вроде Csv.Document() и Excel.CurrentWorkbook(), а
также базы данных и другие источники, как вы видели в предыдущих главах.
Давайте завершим работу с нашим запросом, прежде чем двигаться дальше:
 переименуйте запрос в Table;
 перейдите на вкладку Главная (Home) и нажмите на кнопку Закрыть
и загрузить в… (Close & Load To…), установив переключатель в положение Только создать подключение (Only Create Connection).
Списки
Списки (list) в Power Query являются невероятно мощным и гибким типом,
позволяющим писать и использовать очень полезные формулы.
Основным отличием списков от таблиц в Power Query является то, что в
списках присутствует лишь один столбец с данными. К примеру, если применить типы данных к списку покупок, то при помощи списка вы можете
только перечислить продукты, которые вам необходимо купить (список, по
сути, представляет собой одну колонку из таблицы без заголовка). Если же
вам понадобится сравнить цены на эти продукты в разных магазинах, без
таблицы вам не обойтись.
Синтаксис
В Power Query списки идентифицируются по наличию фигурных скобок,
тогда как сами элементы списка отделяются друг от друга при помощи запятых. В то же время текстовые элементы должны быть заключены в кавычки
подобно тому, как это происходит в формулах Excel:
={1,2,3,4,5,6,7,8,9,10}
={"A","B","C","D"}
Кроме того, списки могут содержать разнородную информацию, включая
другие списки, как показано ниже:
={1,465,"M","Data Monkey",{999,234}}
Итак, самое важное, что нужно знать о списках в Power Query, – это то, что
их содержимое заключается в фигурные скобки, а элементы отделяются друг
от друга запятыми.
Создание списков
Давайте создадим несколько списков и посмотрим, как они работают:
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
Создание списков  393
 в строке формул напишите следующий код:
={1,2,3,4,5,6,7,8,9,10}
 нажмите на клавишу Enter.
Вы увидите созданный список в виде столбца с числами от 1 до 10, как
показано на рис. 15.3.
Рис. 15.3. Создание списка с нуля
Таким образом, мы создали список примитивов, а в качестве бонуса нам
открылась новая вкладка с названием Средства для списков (List Tools) и
вложенная вкладка Преобразование (Transform), как показано на рис. 15.3.
Фактически в этот момент все остальные инструменты на других вкладках
стали неактивными, что, кажется, серьезно ограничивает наш функционал.
В то же время у нас остался доступ к операциям сохранения/удаления строк,
сортировки, удаления дубликатов из списка и даже к некоторым базовым
статистическим функциям.
Здорово, что мы научились создавать списки с нуля, перечисляя все входящие в них элементы. Но что делать, если нам нужно создать список порядковых номеров дней в году от 1 до 365? Перечислять их все через запятую
было бы достаточно утомительно. Гораздо удобнее было бы ввести их с использованием какого-то специального шаблона. И такой шаблон существует.
Замените формулу в строке на следующую:
={1..365}
394  Глава 15. Значения в Power Query
Как видно по рис. 15.4, это позволило нам создать полный список последовательных чисел от 1 до 365.
Рис. 15.4. Использование оператора из двух точек для создания списка
🍌 Примечание. Так же точно вы можете создавать и списки с последователь-
ностями букв, расположенных в алфавитном порядке. При этом вы должны
заключать элементы в кавычки и использовать только одиночные символы.
К примеру, формула ={"A".."Z"} приведет к созданию правильного списка,
а ={"AA".."ZZ"} – нет.
В символьных элементах списков могут содержаться запятые, при условии
что они будут находиться внутри кавычек. Замените формулу на показанную
ниже:
= {"Puls,Ken","Escobar,Miguel"}
В результате будет создан список из двух элементов, содержащий фамилии
и имена авторов этой книги, как показано на рис. 15.5.
Рис. 15.5. В элементах списков могут присутствовать запятые
Преобразование списка в таблицу
Допустим, нам жизненно необходимо представить последний созданный
нами список в виде двух столбцов. В рамках списка это пожелание реализовать будет невозможно, поскольку список предполагает наличие единственного столбца. Придется воспользоваться таблицей.
К счастью, любой список можно легко и просто преобразовать в таблицу.
Для этого достаточно нажать на кнопку В таблицу (To Table), расположенную
в левой части вкладки Средства для списков (List Tools).
Создание списков  395
В результате откроется любопытное диалоговое окно, показанное на
рис. 15.6.
Рис. 15.6. Что тут у нас с разделителями?
Вы можете выбрать в качестве разделителей запятую и нажать на кнопку
OK, после чего список будет успешно преобразован в табличный вид, показанный на рис. 15.7.
Рис. 15.7. Данные, загруженные из списка, разделенного запятыми
🍌 Примечание. Вы увидите это диалоговое окно вне зависимости от того, есть
в ваших данных разделители или нет. В случае их отсутствия просто нажмите
на кнопку OK, и преобразование будет выполнено.
Давайте завершим работу с запросом:
 переименуйте запрос в List_Authors;
 загрузите его в виде подключения.
Создание списка из столбца таблицы
Бывают случаи, когда вам необходимо извлечь информацию из столбца
запроса в виде списка значений. Для демонстрации этого сценария давайте
подключимся к таблице Sales:
396  Глава 15. Значения в Power Query
 перейдите на рабочий лист Sales и выделите любую ячейку в таблице;
 создайте новый запрос, используя кнопку Из таблицы/диапазона
(From Table/Range).
В результате откроется редактор Power Query с загруженной в него исходной таблицей, как показано на рис. 15.8.
Рис. 15.8. Таблица с сырыми данными
Что делать, если нам потребовалось получить список уникальных элементов из столбца Inventory Item? Если бы нам было удобно оставить столбец в
виде таблицы, мы могли бы выделить его, удалить остальные колонки, после
чего перейти на вкладку Преобразование (Transform) и удалить дубликаты.
Проблема в том, что данные останутся в табличном виде, а значит, мы не
сможем при необходимости передать их на вход функции. В качестве альтернативы мы можем получить перечень уникальных элементов из нашей
колонки в виде списка следующим образом:
 удалите шаг Измененный тип (Changed Type) на панели примененных
шагов;
 щелкните правой кнопкой мыши по заголовку столбца Inventory Item и
выберите пункт Детализация (Drill Down).
В результате вы получите список из всех элементов выбранного столбца,
как показано на рис. 15.9.
Рис. 15.9. Столбец, преобразованный в список
Перед тем как двигаться дальше, обратите внимание на строку формул, в
которой написан следующий код:
Создание списков  397
=Источник[Inventory Item]
=Source[Inventory Item]
Здесь мы обращаемся к столбцу Inventory Item, который был вычислен на
шаге Источник (Source). Этот шаблон можно использовать для извлечения
любых столбцов в виде списков без использования инструментов интерфейса пользователя. Позже вы увидите, что это может быть очень полезно.
🍌 Примечание. Еще один способ достижения такого результата состоит в ис-
пользовании функции Table.Column(), которая в качестве первого параметра
принимает таблицу, а в качестве второго – имя извлекаемого столбца. На
выходе функция возвращает список значений из указанного столбца. В нашем случае формула с использованием этой функции выглядела бы Table.
Column(Source, "Inventory Item") и возвращала бы тот же результат, что и выражение Source[Inventory Item].
После извлечения списка значений из столбца таблицы вы можете воспользоваться любыми инструментами, применимыми к спискам. Например,
можно избавиться от дубликатов в списке следующим образом:
 на вкладке Средства для списков (List Tools) откройте раздел Преобразование (Transform) и нажмите на кнопку Удалить дубликаты
(Remove Duplicates).
В результате вы получите список уникальных элементов, который можно
при необходимости передать на вход другой функции.
Завершим работу с запросом:
 переименуйте запрос в List_FromColumn;
 загрузите его в виде подключения.
Создание списка списков
Ранее мы уже упоминали, что в Power Query допустимо создавать списки,
в свою очередь состоящие из списков. Это может звучать довольно странно,
так что проиллюстрируем данную концепцию на примере.
У нас есть четыре уникальных идентификатора сотрудников (от 1 до 4) из
таблицы с продажами. Эти идентификаторы принадлежат последовательно
сотрудникам с именами Fred, John, Jane и Mary. Было бы здорово иметь возможность преобразовать эти данные в список имен сотрудников без необходимости создавать отдельную таблицу. Давайте посмотрим, можно ли для
этого использовать списки:
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
398  Глава 15. Значения в Power Query
 создайте список, написав в строке формул следующий код:
= {{1,"Fred"},{2,"John"},{3,"Jane"},{4,"Mary"}}
Обратите внимание, что в качестве элементов списка мы указали другие
списки, каждый из которых обрамлен фигурными скобками, а друг от друга
они отделены запятыми. Итоговый список также заключен в фигурные скобки. Таким образом, мы создали список, состоящий из четырех подсписков,
что видно на рис. 15.10.
Рис. 15.10. Список списков
Как видите, предварительный просмотр первого элемента списка показал
нам список из двух элементов: 1 и Fred. Это интересно. Но как это можно
использовать?
Преобразование нашего списка в таблицу привело к образованию таблицы, состоящей из одного столбца, в котором также находятся списки. Зато в
заголовке мы видим привычную кнопку для разворачивания содержимого
столбца. Нажмем на нее и получим результат, показанный на рис. 15.11.
Рис. 15.11. Наш список развернулся вертикально, а не горизонтально!
Как видите, агрегирование списков привело к объединению данных по
строкам, а не восприятию каждого элемента списка в качестве отдельной
строки. Конечно, мы можем преобразовать эти данные в требуемый нам вид
путем применения инструментов индексирования, вычисления остатка от
Создание списков  399
деления и сведения, которые мы рассматривали в главе 13, но это потребует
дополнительных действий, а их хотелось бы избежать.
🍌 Примечание. Чтобы это сработало, нам нужно было объявить список, как
в примере с авторами книги, – не в виде списка списков, а в виде списка
отдельных текстовых элементов, разделенных запятыми.
Давайте закроем этот пример:
 переименуйте запрос в List_of_Lists;
 загрузите его в виде подключения.
На данный момент вы должны запомнить две важные вещи относительно
работы со списками:
 списки могут содержать в своем составе другие списки;
 разворачивание списка списков не меняет его ориентацию.
Также показанный выше результат можно получить, используя функцию
List.Combine(). Для этого достаточно нажать на кнопку fx слева от строки
формул для создания нового шага, после чего заключить содержимое строки
в функцию List.Combine(), как показано ниже и на рис. 15.12:
= List.Combine( Источник )
= List.Combine( Source )
Рис. 15.12. Использование функции List.Combine()
для объединения списка списков
Функция List.Combine() преобразовывает список списков в единый список.
По сути, это равносильно выполнению операции добавления запросов, но
применительно к спискам.
Powered by TCPDF (www.tcpdf.org)
400  Глава 15. Значения в Power Query
Но нам нужно, чтобы каждый входящий в список элемент был выведен в
таблице в двух столбцах, т. е. чтобы каждый элемент списка стал отдельной
строкой. С этой целью можно использовать функцию Table.FromRows(),
которой по силам создать полноценную таблицу на основе списка списков.
Все, что нам нужно сделать, – это передать на вход функции Table.FromRows()
наш список списков, как показано на рис. 15.13.
Рис. 15.13. Таблица, созданная на основе списка списков
с использованием функции Table.FromRows()
Записи
Если списочные значения в Power Query можно описать как единичные вертикальные столбцы с данными, то записи (record) являются их горизонтальным многостолбцовым аналогом. Запись может быть отображена как таблица
с единственной строкой, содержащая всю информацию, характеризующую
покупателя или транзакцию.
В Power Query записи могут появляться в столбцах таблиц или списках
при извлечении данных. Также они могут быть созданы вручную при необходимости.
Синтаксис
Записи являются чуть более сложным типом данных по сравнению со
списками, поскольку при их определении нужно указывать не только сами
значения, но и имена столбцов, как показано ниже:
=[Name="Ken Puls", Country="Canada", Languages Spoken=2]
Ключевые моменты, которые необходимо помнить при создании записей:
 каждая запись должна быть заключена в квадратные скобки;
 каждое поле записи (столбец) должно быть определено при помощи
имени со следующим за ним знаком равенства (=);
 после знака равенства должно быть указано значение поля, заключенное в кавычки, если речь идет о текстовых данных;
 все пары, состоящие из имени поля и значения, должны быть отделены
друг от друга запятыми.
Записи  401
🍌 Примечание. Имена столбцов не должны иметь обрамляющих их знаков
препинания вне зависимости от того, содержат они пробелы или нет.
А что, если вам необходимо создать одновременно несколько записей?
В этом случае вы должны прибегнуть к помощи списка следующим образом:
={ [Name="Ken Puls", Country="Canada", Languages Spoken=2],
[Name="Miguel Escobar", Country="Panama", Languages Spoken=2] }
Создание записи
Давайте создадим запись, характеризующую сотрудника, с указанием его
идентификатора и имени:
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
 создайте запись, написав в строке формул следующий код:
=[EmployeeID=1,EmployeeName="Fred»]
После нажатия на клавишу Enter Power Query вернет созданную запись,
как показано на рис. 15.14.
Рис. 15.14. Наша первая запись
Как видно на рисунке, имена полей записи выводятся в левом столбце, а
соответствующие значения – в правом. Любопытно, что данные при этом
организованы по вертикали, а не по горизонтали, как можно было ожидать.
Это не проблема, к такому отображению просто нужно привыкнуть.
Кроме того, после создания записи в меню появится вкладка Средства для
записей  Преобразовать (Record Tools  Convert), а на остальных вкладках
инструменты станут неактивными.
402  Глава 15. Значения в Power Query
Преобразование записи в таблицу
С записями можно производить не так много действий. Давайте преобразуем ее в таблицу и посмотрим, что получится. Для этого на вкладке Средства
для записей  Преобразовать (Record Tools  Convert) нажмите на кнопку
В таблицу (Into Table).
Результат, показанный на рис. 15.15, может вас удивить.
Рис. 15.15. Запись, преобразованная в таблицу
Если вы подумали, что имена полей должны быть указаны в названиях
столбцов, а значения – в первой строке, что ж, вы не одиноки. Но поскольку
перед нами уже таблица, привести данные в желаемый вид не составит труда:
 перейдите на вкладку Преобразование (Transform) и нажмите на
кнопку Транспонировать (Transpose);
 там же на вкладке Преобразование (Transform) нажмите на кнопку
Использовать первую строку в качестве заголовков (Use First Row
as Headers).
Результат выполненного преобразования, показанный на рис. 15.16, должен вас полностью устроить.
Рис. 15.16. Теперь наша запись выглядит как настоящая таблица
Теперь все в порядке. А что, если у нас будет несколько записей, которые
мы захотим преобразовать в таблицу? Давайте сделаем это:
 переименуйте запрос в Record_Single;
 загрузите запрос в виде подключения.
Создание нескольких записей
На этот раз мы хотим объединить в таблице информацию обо всех наших
сотрудниках. Для этого создадим список, состоящий из записей:
Записи  403
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
 в строке формул напишите следующий код:
= {[EmployeeID=1,EmployeeName="Fred"],
[EmployeeID=2,EmployeeName="John"],
[EmployeeID=3,EmployeeName="Jane"],
[EmployeeID=4,EmployeeName="Mary"] }
Обратите внимание, что для каждой отдельной записи мы используем
тот же формат, что и раньше, тогда как в списке, обрамленном фигурными
скобками, записи отделяются друг от друга запятыми.
Запустив на выполнение показанную выше формулу, мы получим список,
состоящий из записей, как показано на рис. 15.17.
Рис. 15.17. Список записей с предварительным просмотром
🍌 Примечание. Стрелка в верхнем правом углу строки формул позволит вам
раскрыть область, чтобы были видны несколько строк.
Преобразование нескольких записей в таблицу
Теперь пришло время преобразовать наш список записей в таблицу. Давайте сделаем это и посмотрим, что же получится:
 на вкладке Средства для записей  Преобразовать (Record Tools 
Convert) нажмите на кнопку В таблицу (Into Table).
Результатом будет столбец, состоящий из записей, который можно развернуть, как показано на рис. 15.18. Интересно, что при нажатии на кнопку
разворачивания мы увидим поля для выбора.
404  Глава 15. Значения в Power Query
Рис. 15.18. Это уже выглядит лучше
Нажав на кнопку OK, вы получите набор столбцов и строк именно в таком
виде, к которому мы стремились при работе с одной записью, что видно на
рис. 15.19!
Рис. 15.19. Мы создали таблицу с нуля!
Это может показаться странным и нелогичным, но преобразование в таблицу нескольких записей действительно приводит к более интересным результатам в сравнении с одной записью. После объединения исходных записей в одном столбце происходит корректное считывание информации о
каждой записи, что приводит к образованию таблицы ожидаемого вида.
Теперь мы можем сохранить полученную таблицу и даже объединить ее
с другими запросами при необходимости.
Также есть еще один способ преобразовать список записей в таблицу, требующий написания всего одной строки кода:
 создайте пустой запрос и введите в строку формул тот же список записей, что и в предыдущем примере;
 нажмите на кнопку fx слева от строки формул для создания нового
пользовательского шага;
 введите следующую формулу:
Table.FromRecords(Источник)
Table.FromRecords(Source)
В результате будет создана полноценная таблица на основе списка записей,
что видно по рис. 15.20. Функция Table.FromRecords() широко используется в
Записи  405
документации для демонстрации создания таблиц при помощи языка M, так
что вам будет полезно узнать, что она из себя представляет и как работает.
Рис. 15.20. Использование функции Table.FromRecords()
для извлечения значений из списка записей
Доступ к записям таблиц по позиции
(индексирование строк)
Когда мы говорили о списках, мы показывали способ преобразования
столбца в список. Также у вас есть возможность представить строку в виде
записи. Для начала создайте новый запрос:
 перейдите на рабочий лист Sales и выделите любую ячейку в таблице
Sales;
 создайте новый запрос, используя кнопку Из таблицы/диапазона
(From Table/Range).
Откроется редактор Power Query со всей загруженной таблицей. Для извлечения первой записи необходимо создать пустой шаг запроса следующим
образом:
 нажмите на кнопку fx слева от строки формул, как показано на
рис. 15.21.
Рис. 15.21. Создание пустого шага запроса
406  Глава 15. Значения в Power Query
В результате будет создан новый пользовательский шаг со следующей формулой:
=Источник
=Source
Модифицируйте эту формулу, добавив к ней {0}:
=Источник{0}
=Source{0}
В результате мы получим первую запись из нашей таблицы, как показано
на рис. 15.22.
Рис. 15.22. {0} = запись 1?
Что же тут произошло?
При таком обращении шаг Источник возвращает запись. И для извлечения
нужной вам записи необходимо указать правильный индекс в фигурных
скобках. Поскольку в Power Query индексация начинается с нуля, указание
индекса {0} приведет к извлечению первой записи таблицы. Если вам нужно
получить информацию о второй записи, используйте индекс {1}.
🍌 Примечание. Этот прием применим не только к таблицам, но и к спискам.
Иными словами, вы можете обратиться к первому элементу списка при помощи синтаксиса List{0}. К записям такой подход неприменим, поскольку
запись, по сути, представляет собой таблицу с единственной строкой. При
этом вы всегда можете обратиться к нужному полю записи, о чем мы будем
говорить далее в этой главе.
Еще интереснее то, что мы можем и дальше углубляться, получив доступ
к конкретному полю записи с помощью указания его имени в квадратных
скобках. Попробуйте изменить формулу следующим образом:
=Источник{0}[Price]
=Source{0}[Price]
Записи  407
Как видно на рис. 15.23, мы еще повысили детализацию данных и извлекли
информацию из столбца Price первой записи таблицы.
Рис. 15.23. Получили цену из первой записи таблицы
Чтобы оценить пользу этого приема, представьте, что вам необходимо
получить доступ к конкретной записи таблицы для управления фильтрами.
В следующей главе мы посмотрим, как это можно сделать. А пока завершим
работу над запросом:
 переименуйте запрос в Record_From_Table;
 загрузите запрос в виде подключения.
Доступ к записям таблиц по критерию
Существует еще один способ осуществления навигации по записям таблицы. Вместо обращения к записи по порядковому номеру вы можете извлекать нужные вам записи, задавая определенные критерии для полей. По сути,
именно это Power Query делает, когда мы щелкаем по структурированным
значениям и генерируем шаг Навигация (Navigation).
Возвращаясь к нашему примеру с набором данных из таблицы Sales, убедитесь, что типы данных для столбцов заданы следующим образом, как показано на рис. 15.24:
 столбец Date – тип Дата (Date);
 столбец Inventory Item – тип Текст (Text);
 столбцы EmployeeID, Quantity и Price – Целое число (Whole Number).
Рис. 15.24. Типы данных в таблице Sales
Нажмите на кнопку fx слева от строки формул для создания нового шага
и введите следующую формулу:
= #"Измененный тип"{[Inventory Item= "Lovable Kitten", EmployeeID = 1,
Quantity = 4]}
= #"Changed Type"{[Inventory Item= "Lovable Kitten", EmployeeID = 1,
Quantity = 4]}
408  Глава 15. Значения в Power Query
По сути, эта формула определяет навигацию к нужной нам записи, отвечающей заданным критериям. Иными словами, в нашем распоряжении есть
записи, организованные в список, которые помогают осуществлять навигацию к определенному значению, отвечающему заданным условиям.
В нашем случае навигация строится таким образом, чтобы можно было
найти конкретную строку в таблице, возвращаемой на шаге Измененный тип,
в соответствии со следующими критериями, как показано на рис. 15.25:
 в столбце Inventory Item содержится строка «Lovable Kitten»;
 в столбце EmployeeID – значение 1;
 в столбце Quantity – значение 4.
Рис. 15.25. Навигация к записи таблицы при помощи
синтаксиса Таблица{[Поле = Условие]}
Самый важный аспект этого шаблона заключается в том, что логика обращения к записям работает так же, как фильтрация таблиц. Однако, чтобы это
работало, вы должны предоставить ключ, который позволит сузить поиск до
одной записи. В нашем случае указанный критерий привел к единственной
записи в таблице.
Если в результате применения критериев сразу несколько записей из таблицы будут соответствовать заданному условию, вы получите ошибку, показанную на рис. 15.26.
Рис. 15.26. Ошибка Expression.Error возникает в случае
совпадения ключа более чем с одной записью в таблице
Ошибка явно демонстрирует, что в нашем наборе данных находится больше одной записи с указанными значениями полей EmployeeID и Inventory Item.
🍌 Примечание. Самый простой способ избавиться от этой ошибки – гарантировать наличие в таблице ключевого столбца с уникальными значениями. Если
у вас его нет, создайте столбец с индексом и используйте значения из него
для навигации по записям в таблице.
Записи  409
После нахождения нужной нам записи в таблице мы можем извлечь значение конкретного поля с помощью уже знакомого вам синтаксиса:
= Пользовательский1[Price]
= Custom1[Price]
В результате мы получим то же значение, что и в предыдущем примере,
показанное на рис. 15.27, но совсем другим способом.
Рис. 15.27. Доступ к полю Price найденной записи
Не существует правильного и неправильного способов выполнения навигации к нужным вам данным, поскольку здесь все зависит от вашего конкретного случая. Но, работая с Power Query, вы заметите, что обычно он
применяет последний прием. К примеру, если вы перейдете к шагу Источник
(Source) и посмотрите на его формулу, то обнаружите этот самый шаблон:
= Excel.CurrentWorkbook(){[Name="Sales"]}[Content]
Если разобрать формулу на составляющие, получится следующее:
 Excel.CurrentWorkbook() – генерирует таблицу со всеми доступными
объектами в рамках активной рабочей книги;
 {[Name = "Sales"]} – здесь заключена фильтрующая логика обращения к
записи, согласно которой в столбце с именем Name должна находиться
строка «Sales»;
 [Content] – после выполнения навигации к нужной строке мы обращаемся к столбцу Content, который в нашем случае содержит табличное
значение. Именно поэтому в результате мы получаем полноразмерный
табличный вывод, показанный на рис. 15.28.
Рис. 15.28. Автоматический доступ к записи
и столбцу в Power Query
410  Глава 15. Значения в Power Query
🍌 Примечание. Понимание концепции доступа к записи и столбцу является
ключевым в освоении языка M, встроенного в Power Query.
Создание записей из каждой строки таблицы
Преобразовать все строки таблицы в записи можно разными способами.
Давайте посмотрим, как это сделать с применением небольшого хитрого
трюка. Для начала сделайте следующее:
 перейдите на рабочий лист Sales и выделите любую ячейку в таблице
Sales;
 создайте новый запрос, используя кнопку Из таблицы/диапазона
(From Table/Range).
Теперь нам необходимо преобразовать каждую строку таблицы в запись.
Проблема в том, что для этого нам понадобится порядковый номер записи.
Давайте обратимся к колонке с индексом:
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую кнопку Столбец индекса (Index Column) и выберите пункт От 0
(From 0).
Далее надо переименовать созданный шаг (не столбец) в области примененных шагов:
 щелкните правой кнопкой мыши на шаге Добавлен индекс (Added Index),
выберите пункт Переименовать (Rename) и введите имя AddedIndex
(без пробелов).
В данный момент наш запрос будет выглядеть так, как показано на
рис. 15.29.
Рис. 15.29. Добавлен столбец индекса, а шаг переименован, чтобы не было пробелов
Обратимся к настраиваемым столбцам, чтобы преобразовать наши строки
в записи. Нам очень важно было создать столбец с индексом – с ним у нас
есть значения, необходимые для извлечения записей. Зачем нам понадо-
Записи  411
бился этот трюк? Мы собираемся работать не с текущей строкой, а с выводом
созданного шага AddedIndex. В этом случае вместо получения конкретного
значения (такого как первая строка) мы можем динамически передавать
индекс запросу для получения каждой строки:
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 назовите столбец Records;
 введите следующую формулу для столбца:
=AddedIndex{[Индекс]}
=AddedIndex{[Index]}
В результате будет создан столбец с записями в качестве значений, как
показано на рис. 15.30.
Рис. 15.30. Столбец с записями
🍌 Примечание. Строго говоря, мы не обязаны были переименовывать шаг, из-
бавляясь от пробелов. Просто это облегчит нам задачу при работе в интерфейсе пользователя.
В данный момент мы можем избавиться от всех колонок, кроме столбца с
записями. Для этого:
 щелкните правой кнопкой мыши по столбцу Records и выберите пункт
Удалить другие столбцы (Remove Other columns);
 переименуйте запрос в Records_From_Table;
 загрузите запрос в виде подключения.
Можно еще проще добиться того же результата, вовсе не создавая колонку
с индексом. Вместо этого добавьте настраиваемый столбец со следующей
странной формулой, состоящей из символа подчеркивания, как показано на
рис. 15.31:
=_
412  Глава 15. Значения в Power Query
Рис. 15.31. Создание записей из строк с использованием символа подчеркивания
🍌 Примечание. Знак подчеркивания является специальным символом в языке
M, который в сочетании с ключевым словом each позволяет ссылаться на
текущий элемент в коллекции, который в нашем случае представляет собой
текущую строку.
🍌 Примечание. Позже в этой книге мы подробнее остановимся на этой концепции и общей концепции функций, но этот небольшой трюк вы можете
начать использовать уже сейчас, не обладая особыми знаниями о языке M.
Значения
Если вы работаете с реляционными источниками данных, такими как OData
или базы данных, вы время от времени будете сталкиваться с тем, что в колонках вместо данных будут стоять ключевые слова Value, как показано на
рис. 15.32.
Это происходит в особенных случаях, а именно когда вы работаете с реляционным источником, в котором между таблицами настроена связь по
первичному и внешнему ключам. Любопытно, что при помощи ключевого
слова Value база данных, по сути, возвращает запись.
Ошибки  413
Рис. 15.32. Неуловимые Value
Когда вы знаете, с какими полями имеете дело, работать с ними вы можете
так же, как и с остальными типами данных, на которые они ссылаются.
🍌 Примечание. Какое именно значение для связанной колонки будет возвращено в запросе, зависит от кратности (cardinality) связи при работе с
реляционным источником. Если вы находитесь в таблице фактов, а связь направлена к измерению, в колонке окажется структурированный тип Value
(запись). Если же наоборот – Table (таблица).
Двоичные данные
Power Query отображает файлы как двоичные данные – при помощи ключевого слова Binary. При этом содержимое файлов может быть извлечено при
помощи различных коннекторов (функций), способных интерпретировать и
отображать подобные данные.
К примеру, двоичный файл может быть интерпретирован как рабочая книга Excel, файл CSV/TXT, JSON, XML, PDF, веб-страница. Существуют и другие
коннекторы для доступа к содержимому файлов, а многие будут написаны,
пока эта книга будет находиться в печати.
Ошибки
В Power Query выделяют два вида ошибок (error): ошибки на уровне шага (step
level error) и ошибки на уровне строки (row level error).
Ошибки на уровне строки
Ошибки этого типа обычно возникают при неудачной попытке преобразовать тип данных или работе с данными, еще не приведенными к корректному
типу. Читая эту книгу, вы уже не раз сталкивались с ошибками на уровне
строки, подобными той, что показана на рис. 15.33.
414  Глава 15. Значения в Power Query
Рис. 15.33. Ошибка, вызванная попыткой привести поле Order #
к типу данных Дата (Date)
Обычно ошибки на уровне строки не препятствуют выводу предварительного просмотра данных и даже могут быть использованы при очистке информации одним из следующих способов:
1) в качестве фильтра для сохранения/удаления строк;
2) для последующей замены при помощи инструмента Заменить ошибки (Replace Errors).
Несмотря на то что в Power Query отсутствует механизм отладки, ошибки
такого типа зачастую бывает легко отследить, и в большинстве случаев (хотя
и не всегда) они связаны с неправильным выбором типа данных.
Ошибки на уровне шага
С ошибками на уровне шага справиться бывает сложнее. Сообщения о
появлении таких ошибок блокируют любой вывод в окне предварительного
просмотра, за исключением информации о самой ошибке, как показано на
рис. 15.34 и 15.35.
Рис. 15.34. Ошибка типа Expression.SyntaxError, вызванная
отсутствием закрывающей скобки в конце выражения
Рис. 15.35. Обобщенная ошибка типа Expression.Error
из-за неправильного написания названия объекта Sql
Функции  415
К сожалению, на данный момент средства отладки в Power Query оставляют
желать лучшего, что хорошо видно по рис. 15.36.
Рис. 15.36. Синтаксическая ошибка вызвана отсутствием закрывающей
фигурной скобки, тогда как анализатор жалуется на пропуск запятой
Первая проблема, которую мы тут наблюдаем, заключается в том, что сообщение об ошибке выводится на одной строке (для рисунка оно было обрезано
и перенесено по словам). В конце строки присутствует символ-помощник ^,
показывающий, в каком именно месте Power Query ожидает ввода запятой.
При этом истинной причиной ошибки является то, что мы не закрыли фигурную скобку в конце списка (на рис. 15.36 это место обозначено вертикальной
красной стрелкой).
Ошибки этого типа действительно доставляют немало хлопот при работе с
Power Query. И хотя сегодня код выделяется при помощи цвета, это не сильно
помогает. Радует то, что Power Query довольно часто обновляется, и мы надеемся, что в одном из обновлений эти проблемы будут исправлены. А пока
нам придется продолжать выполнять процесс отладки путем долгих и мучительных поисков ошибок с открывающими и закрывающими символами.
Функции
Последний тип значений, с которым вы столкнетесь при работе в Power
Query, – это функция (function). Этот тип предназначен для преобразования
набора аргументов в единое значение. Чаще всего вы будете сталкиваться с
этими значениями в одном из трех контекстов:
1) внутри базы данных, работая с функциями на уровне БД;
2) при возвращении списка функций в Power Query;
3) при обращении к функциям вручную.
Далее в этой книге вы научитесь работать с функциями и вызывать их,
сейчас же мы хотим вам показать один трюк, помогающий понять, как определяются функции, а также позволяющий извлечь полный список доступных
функций в Power Query:
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
 введите в строке формул следующий код:
=#shared
416  Глава 15. Значения в Power Query
 на вкладке Средства для записей  Преобразовать (Record Tools 
Convert) нажмите на кнопку В таблицу (Into Table).
В результате будет сгенерирована таблица, содержащая все существующие
запросы в текущей рабочей книге, а также, что более важно, предоставляющая доступ к документации по всем функциям Power Query, как показано на
рис. 15.37.
Рис. 15.37. Таблица функций
🍌 Примечание. Ключевое слово #shared дает доступ к той же документации,
которая располагается в разделе функций Power Query по адресу https://
docs.microsoft.com/en-us/powerquery-m.
Как использовать эту таблицу? Давайте отфильтруем ее по вхождению
слова Max (с заглавной буквой M):
 нажмите на кнопку фильтрации в столбце Name, в выпадающем меню
Текстовые фильтры (Text Filters) выберите пункт Содержит (Contains)
и введите слово Max.
В итоге в таблице останется четыре строки, показанные на рис. 15.38.
Рис. 15.38. Все функции, содержащие в названии слово Max
Функции  417
Если щелкнуть на слове Function напротив функции Table.Max, произойдут
сразу две вещи: на заднем плане появится документация по указанной функции, а на переднем – окно вызова, как представлено на рис. 15.39.
Рис. 15.39. Окно вызова функции и документация по ней на фоне
Цель появления окна вызова функции состоит в возможности протестировать ее, при этом нажатие на кнопку Отмена (Cancel) приведет к его закрытию. На заднем плане будет открыта полная документация по функции,
так что вы сможете быстро понять, та ли это функция, которую вы искали.
Стоит отметить, что вы не обязаны пользоваться документацией и проверять работоспособность функций исключительно из пустых запросов. Вместо этого всякий раз, когда вам во время работы потребуется обратиться к
инструкции, вы можете сделать следующее:




нажмите на кнопку fx слева от строки формул для создания нового шага;
замените формулу по умолчанию на =#shared;
преобразуйте записи в таблицу;
откройте функцию, по которой вам требуется дополнительная информация.
После этого вы сможете вернуться к предыдущим примененным шагам
для использования функции, просто удалив все шаги, связанные с поиском
сведений о ней в документации.
🍌 Примечание. В любом продукте, в который интегрирован инструмент Power
Query, присутствует порядка 600 функций. Мы ни в коем случае не призываем вас запоминать все функции. Мы сами никогда не делали этого и не собираемся, поскольку прекрасно понимаем, что уровень знания любого языка
программирования определяется не количеством функций, лежащих в памяти мертвым грузом, а умением правильно интерпретировать их и применять
в подходящих ситуациях.
418  Глава 15. Значения в Power Query
Впрочем, вам будет очень полезно пробежаться по представленному списку, чтобы узнать, какие функции есть в вашем распоряжении, а также попытаться понять принцип разделения функций на категории по их префиксу или предназначению, которое часто выражается в формате Категория.
Действие. Давайте рассмотрим некоторые категории функций:
 Data source: функции из этой группы, например Excel.Workbook(), используются в основном для подключения к источникам данных;
 Table: функции для работы с таблицами или связанные с таблицами. Обычно они начинаются с префикса Table, как, например, Table.
PromoteHeaders();
 List: функции для оперирования со списками. Обычно начинаются с
префикса List – к примеру, List.Sum();
 Record: функции для работы с полями записей. Начинаются со слова
Record: Record.FieldNames();
 Text: функции для работы с текстом. Привычный префикс для них –
Text, как в случае с Text.Contains().
🍌 Примечание. Есть и другие категории функций, не представленные в этом
перечне. Мы выбрали эти категории, чтобы показать, какие функции существуют, а вы можете найти функции, требующиеся именно вам.
Ключевые слова в Power Query
В языке M есть целый ряд зарезервированных слов, являющихся ключевыми
(keyword), которые могут быть использованы только в определенных контекстах.
Вот примеры ключевых слов:
and as each else error false if in is let meta not null or otherwise section
shared then true try type #binary #date #datetime #datetimezone #duration
#infinity #nan #sections #shared #table #time
Некоторые из этих ключевых слов уже встречались вам в предыдущих
главах книги. Так, в главе, посвященной формулам и условной логике, мы
уже применяли ключевые слова if, else, then, true, false, and, or, not, try и
otherwise.
Назначение некоторых ключевых слов мы подробно разберем в этом разделе – в особенности это касается слов, начинающихся с символа решетки (#).
За исключением #shared и #sections, эти ключевые слова служат для образования специфических значений, соответствующих определенному типу
данных. Посмотрим, как это работает.
Ключевые слова в Power Query  419
🙈 Предупреждение. Помните, что при написании кода на языке M обязательно
необходимо соблюдать пунктуацию и регистры. Это означает, что ключевые
слова нужно писать точно так, как они написаны в книге, – в противном случае окружение Power Query их просто не распознает.
#binary
Тогда как в большинстве случаев вы будете сталкиваться с двоичными
данными при использовании коннекторов, работающих с файловой системой, таких как Из папки, Из SharePoint или Из Azure Data Lake, вы можете
создавать двоичные значения и непосредственно при помощи кода.
Ключевое слово #binary ожидает на вход любое значение, которое в результате будет преобразовано в двоичное значение (binary value). Наиболее
полезное практическое применение этого ключевого слова заключается в
передаче ему текстового значения, зашифрованного при помощи стандарта
кодирования Base64. К примеру, давайте создадим новый запрос и в первом
же шаге напишем следующую формулу, как показано на рис. 15.40:
#binary("TWlndWVsIEVzY29iYXI=")
Рис. 15.40. Двоичное значение, созданное с использованием
ключевого слова #binary
Если на вкладке Средства для двоичных данных (Binary Tools) нажать
на раскрывающуюся кнопку Открыть как (Open As) и выбрать вариант интерпретации двоичных данных в виде текстового файла, Power Query сделает
то, что показано на рис. 15.41.
420  Глава 15. Значения в Power Query
Рис. 15.41. Декодированное текстовое значение
из переданных двоичных данных
🍌 Примечание. Существуют функции для интерпретации значений в виде дво-
ичных данных. Можете посмотреть функции Binary.From(), Binary.FromText()
и Binary.FromList() – они призваны в более явном виде делать то, для чего
предназначено ключевое слово #binary.
#date, #datetime и #datetimezone
Мы объединили эти ключевые слова в одном разделе, поскольку у них
единая основа. Каждое из этих ключевых слов может быть использовано при
необходимости создать определенное значение из входящих параметров,
например из столбцов в вашем запросе.
Шаблон применения этих ключевых слов следующий:
#keyword(год, месяц, день, часы, минуты, секунды, часовой пояс (часы), часовой
пояс (минуты))
В зависимости от того, какое именно значение вы хотите создать, вы можете передавать ключевому слову разное количество аргументов. Например:
 если вам необходимо создать дату (#date), достаточно будет передать
год, месяц и день. Допустим, дата 23 мая 2021 года может быть создана
следующим образом: #date(2021,5,23);
 при создании даты и времени (#datetime) вы должны передать все указанные выше аргументы, а также часы, минуты и секунды. Таким образом, дата и время 23 мая 2021 года 13:23:54 могут быть созданы так:
#datetime(2021,5,23,13,23,54);
 наконец, если вы хотите учитывать при создании временной точки
часовые пояса (#datetimezone), вам придется передать полный список
аргументов из приведенного выше шаблона. Например, создать точку
23 мая 2021 года 13:23:54 для часового пояса UTC-05:00 можно таким
образом: #datetimezone(2021,5,23,13,23,54,–5,0).
Ключевые слова в Power Query  421
Если вручную ввести указанные выше фрагменты кода в строке формул,
Power Query автоматически преобразует переданные аргументы в значение
нужного типа данных. При этом введенный вами код не удалится – вы всегда
можете перейти в расширенный редактор (Advanced Editor) и увидеть/отредактировать формулу, как показано на рис. 15.42.
Рис. 15.42. Значение, созданное при помощи ключевого слова #datetimezone,
отображается как примитив
На практике ключевые слова #date, #datetime и #datetimezone часто применяются для создания нужного значения на основе имеющихся составляющих. Например, у вас могут присутствовать год, месяц и день в качестве
отдельных столбцов в запросе, а вам нужно в настраиваемом столбце объединить их для создания полноценной даты. С этой целью вы можете воспользоваться подходящим ключевым словом следующим образом: #date( [Year
Number], [Month Number], [Day Number]). Очень важно отметить, что описанные
в этом разделе ключевые слова принимают на вход только целочисленные
аргументы – текстовые или десятичные значения неприемлемы и приведут
к возникновению ошибки.
#time
Очень важно помнить, что тип данных и формат данных – это совершенно
разные вещи. Power Query главным образом сконцентрирован на установке
типов данных, но в то же время в интерфейсе пользователя присутствует
возможность отображать информацию в самых разных форматах.
Тип Время (Time) описывает данные так же точно, как вы видите их на
своих электронных часах, – в диапазоне от 00:00:00 до 23:59:59.
К примеру, если вам нужно создать значение для времени 14:36:54, можно использовать ключевое слово #time, требующее передачи аргументов в
24-часовом формате (14:36:54), как показано на рис. 15.43.
422  Глава 15. Значения в Power Query
Рис. 15.43. Использование ключевого слова #time для создания значения времени
🍌 Примечание. Подобно своим собратьям #date, #datetime и #datetimezone,
ключевое слово #time также принимает на вход аргументы исключительно в
виде целых чисел. Передача аргументов других типов приведет к возникновению ошибки.
#duration
Если ключевое слово #time позволяет сослаться на время в рамках конкретной даты (в диапазоне от 00:00:00 до 23:59:59), #duration описывает некий
промежуток между двумя временными точками. Иными словами, полученное в результате значение будет отвечать на вопрос о том, на сколько одна
дата отстоит от другой.
К примеру, если вам необходимо описать промежуток времени продолжительностью 4 дня, 22 часа, 10 минут и 35 секунд, вы можете воспользоваться
следующей формулой: #duration(4,22,10,35), результат работы которой показан на рис. 15.44.
Рис. 15.44. Использование ключевого слова #duration для задания временного интервала
Ключевые слова в Power Query  423
На практике это ключевое слово зачастую используется в совокупности
со значениями типа дата или время. Скажем, если нам нужно к дате 23 мая
2021 года прибавить 12 дней, можно применить следующую формулу:
= #date(2021,5,23) + #duration(12,0,0,0)
Результат выполнения этой формулы продемонстрирован на рис. 15.45.
Рис. 15.45. Если добавить к 23 мая 12 дней,
получится 4 июня – день рождения Мигеля
Разумеется, эту технику можно применять для добавления к значениям и
более мелких интервалов: часов, дней или минут.
🍌 Примечание. Как и в случае с #date и #time, ключевое слово #duration принимает на вход только аргументы целочисленного типа.
type
Типы данных (data type) в Power Query имеют огромное значение. Они
позволяют вам не только воспользоваться всеми преимуществами, предоставляемыми интерфейсом пользователя, но и повлиять на работу движка
языка M при выполнении определенного шага или функции.
Читая эту книгу, вы уже не раз видели, как мы определяли типы данных,
но что из себя представляют эти типы? В табл. 15.1 приведена выдержка из
официальной документации по языку M, призванная помочь разобраться в
этом вопросе.
Таблица 15.1. Значения типов, как в документации по адресу https://docs.microsoft.com/enus/powerquery-m/m-spec-types
Значение типа – это значение, служащее для классификации других значений. Принято
говорить, что значение, классифицируемое определенным типом, соответствует этому
типу. Система типов данных языка M состоит из следующих типов:
Типы [разные]
Классифицируют примитивные значения (binary, date, datetime,
datetimezone, duration, list, logical, null, number, record, text, time,
type), а также некоторые абстрактные (function, table, any и none)
Тип Record
Классифицирует записи на основе имен полей и типов значений
Тип List
Классифицирует списки с использованием базового типа
элементов
Тип Function
Классифицирует значения функций на основе типов аргументов и
возвращаемых значений
424  Глава 15. Значения в Power Query
Тип Table
Классифицирует табличные значения на основе имен и типов
столбцов, а также ключей
Тип Nullable
Классифицирует значения null в дополнение ко всем значениям,
классифицированным при помощи базовых типов
Тип Type
Классифицирует значения, являющиеся типами
В отношении терминологии очень важно заметить, что, в отличие от значений, которые подразделяются на примитивные и структурированные, все
естественные типы, включая Record, List, Function, Table, Nullable и Type, рассматриваются как примитивные. В то же время сложные типы данных, которые также могут присутствовать, должны определяться пользователем.
🍌 Примечание. Естественные таблицы по умолчанию не содержат типы дан-
ных своих столбцов и классифицируются как примитивный тип таблицы.
Если определение таблицы изменено таким образом, чтобы оно содержало
информацию о столбцах, как мы увидим в одном из примеров в главе 16,
она будет классифицироваться как сложный тип. В исходном виде табличное
значение содержит смесь определенных типов данных по столбцам.
Хотя на данный момент вы уже знакомы с большим количеством типов
данных, есть еще один, о котором стоит упомянуть отдельно, – any. Этот тип
данных появляется в основном тогда, когда данные не могут быть отнесены
к одному конкретному типу. Часто этим типом описываются данные в столбцах до явного определения их типа или в случае, если в колонке содержится
разнородная информация.
Как определить, какой тип данных присвоен каждому столбцу?
Самый простой способ – посмотреть на иконку слева от заголовка столбца.
Но для таблиц, содержащих большое количество столбцов, такой метод не
подходит. Еще один простой и надежный способ определения типов данных
в столбцах состоит в использовании функции Table.Schema(). Чтобы продемонстрировать этот подход на примере, давайте используем таблицу, изображенную на рис. 15.46.
Рис. 15.46. Простая таблица с тремя столбцами и двумя строками
В представленной таблице три столбца/поля:
 id – целочисленный тип данных;
 Patient Name – текстовый тип данных;
 First Vaccine Shot Date – тип данных дата.
Ключевые слова в Power Query  425
Создайте шаг при помощи кнопки fx и передайте на вход функции Table.
Schema() название предыдущего шага – Источник (Source). В результате вы
получите полный набор метаданных для нашей таблицы, как показано на
рис. 15.47.
Рис. 15.47. Использование функции Table.Schema() для вывода метаданных таблицы
Обратите внимание на столбцы TypeName и Kind, которые содержат разные
способы задания типов данных. Применительно к нашей таблице можно использовать оба приведенных ниже варианта установки целочисленного типа
данных для столбца id:
= Table.TransformColumnTypes(Источник,{{"id", Int64.Type}})
= Table.TransformColumnTypes(Источник,{{"id", type number}})
= Table.TransformColumnTypes(Source,{{"id", Int64.Type}})
= Table.TransformColumnTypes(Source,{{"id", type number}})
🍌 Примечание. Как вы узнаете далее в этой главе, type number на самом деле
вернет десятичный тип данных, а не целочисленный.
Существует еще один способ определения типа данных для любого значения – при помощи функции Value.Type(), которая вернет тип данных в том
виде, как он указан в столбце Kind на рис. 15.47. Например, следующая формула применительно к предыдущей таблице вернет строку «text»:
= Value.Type(Источник[Name]{0})
= Value.Type(Source[Name]{0})
Обычно удобнее всего смотреть подобную информацию непосредственно в контексте редактора Power Query. Если создать шаг и в строке формул
написать просто = type number, вам будет
показан только этот тип данных и больше
ничего, как видно на рис. 15.48.
Основным предназначением ключевого слова type является его использование
Рис. 15.48. Тип данных number,
совместно с таблицей при определении
полученный в результате
типов данных и столбцов.
использования ключевого слова type
426  Глава 15. Значения в Power Query
🍌 Примечание. При создании пользовательского коннектора Power BI обяза-
тельно нужно задавать схему для конкретных столбцов и значений. В остальных случаях вам вряд ли понадобится часто пользоваться ключевым словом type.
#table
Хотя в Power Query можно создавать таблицы с использованием списков
записей или функции Table.FromRecords(), как было показано ранее в этой
главе, есть еще один вариант – с применением ключевого слова #table. Мы
оставили этот способ напоследок, поскольку это единственное ключевое слово, с помощью которого можно создать структурированное значение. Этот
метод не хуже и не лучше других, просто еще один инструмент в вашем
арсенале.
Ключевое слово #table требует наличия двух следующих параметров:
1) столбцы таблицы: можно передать список с именами столбцов или
табличный тип с метаданными для имен столбцов и их типов данных;
2) данные для строк таблицы: список списков, где каждый вложенный
список характеризует собой отдельную строку в таблице.
Для проверки этого метода вы можете создать пустой запрос и заменить
формулу первого шага на следующую:
= #table( {"id", "Patient Name", “First Vaccine Shot Date" },
{ {1, "Ken", #date(2021,5,20)},
{2, "Miguel", #date(2021,4,4)} }
)
После выполнения этой формулы вы увидите созданную таблицу с не
определенными для столбцов типами данных. Это легко понять по иконке
слева от имен столбцов на рис. 15.49 – такое обозначение используется для
типа данных any.
Рис. 15.49. Таблица, созданная при помощи ключевого слова #table
с переданным ему списком имен столбцов
Ключевые слова в Power Query  427
🙈 Предупреждение. Критически важно, чтобы данные в полях следовали в том
же порядке, что и заголовки соответствующих столбцов, поскольку заполнение таблицы данными будет производиться исходя из порядковых номеров
столбцов, а не их имен.
Разумеется, после создания таблицы вы можете вручную добавить шаг
Измененный тип (Changed Type), но, быть может, вам захочется определить
типы данных для столбцов таблицы прямо во время ее создания. И здесь вам
на помощь придет табличный тип (table type), позволяющий указать при
создании таблицы необходимые метаданные.
А что из себя представляет табличный тип? Ключевое слово type мы уже
использовали ранее для обращения к типам данных. При этом мы уже много
раз работали с примитивными типами, а сейчас впервые попытаемся определить тип данных для структурированного значения.
Давайте изменим предыдущий код на приведенный ниже:
= #table( type table [ id = Int64.Type, Patient Name = Text.Type, First
Vaccine Shot Date = Date.Type],
{ {1, "Ken", #date(2021,5,20)},
{2, "Miguel", #date(2021,4,4)} }
)
Обратите внимание, что изменился лишь первый параметр. Сначала мы
передавали список с именами столбцов, но список не позволяет задать соответствующие типы данных. На этот раз мы определили эти типы при помощи
конструкции type table, при этом имена и типы столбцов задали посредством
записи, как показано на рис. 15.50.
Рис. 15.50. Таблица, созданная при помощи
ключевого слова #table с переданным ему табличным типом
🍌 Примечание. Как и раньше, порядок следования данных в полях таблицы
должен строго соответствовать последовательности создаваемых заголовков.
428  Глава 15. Значения в Power Query
Кроме того, при использовании такой записи вы можете использовать как
явное указание типов данных для столбцов, так и их псевдонимы из столбца
Kind с рис. 15.47. Например, вы можете изменить формулу следующим образом:
= #table( type table [ id = number, Patient Name = text, First Vaccine
Shot Date = date],
{ {1, "Ken”, #date(2021,5,20)},
{2, "Miguel”, #date(2021,4,4)} }
)
При этом результат немного изменится – столбец id получит не целочисленный тип данных, а десятичный. Это легко понять, взглянув на иконку
слева от имени столбца на рис. 15.51.
Рис. 15.51. Новая формула для создания таблицы
с использованием ключевых слов #table и type
🍌 Примечание. Тип number является своеобразным прикрытием для всех типов
данных, относящихся к числовым значениям. С учетом того, что числа могут
быть с десятичными знаками или без них, Power Query старается действовать
максимально безопасно, чтобы данные не утратили точности. Именно поэтому тип number преобразуется в десятичный тип данных.
Зачастую бывает удобно использовать именно такое упрощенное именование типов данных, и вы увидите, что в большинстве случаев мы будем
останавливаться именно на нем. Явную запись мы будем использовать только тогда, когда этого будет требовать ситуация. Иными словами, при определении типов данных для числовых столбцов мы будем применять именно
запись number, а не более точную Int64.Type, если не будет необходимости в
явном указании целочисленного типа.
Глава
16
Изучаем язык M
Теперь, когда вы познакомились с разными значениями, которые можно использовать при работе с Power Query, пришло время окунуться в увлекательный мир языка M, с помощью которого вершится вся магия. И хотя владение
всеми премудростями языка M не является обязательным для выполнения
процесса обработки данных в Power Query, с его помощью вы сумеете добиться гораздо большего и сможете легко решать задачи, которые другим
не по силам.
Структура запроса на языке M
Для начала давайте импортируем таблицу в Power Query, а затем посмотрим,
какой код был сгенерирован:
 откройте пустой файл;
 создайте новый запрос с помощью коннектора Из базы данных SQL
Server (From SQL Server Database). Данные для подключения к базе используйте из главы 12;
🍌 Примечание. Если вы уже подключались к базе данных AdventureWorks при
чтении главы 12, окно навигатора откроется автоматически. В противном
случае вам придется ввести имя пользователя и пароль для соединения с
базой данных, которые приведены в главе 12.
 в открывшемся окне Навигатор (Navigator) выберите таблицу SalesLT.
Customer и нажмите на кнопку Преобразовать данные (Transform);
 отфильтруйте таблицу в редакторе Power Query, задав для столбца
CompanyName текстовый критерий «Friendly Bike Shop»;
 выделите столбцы CustomerID, FirstName и LastName и удалите остальные;
 переименуйте запрос в Sample Query.
В результате в вашем запросе должно остаться четыре строки и три колонки, как показано на рис. 16.1.
430  Глава 16. Изучаем язык M
Рис. 16.1. Вывод простого запроса
На панели примененных шагов в этот момент вы увидите четыре следующих шага:
 Источник (Source) – подключение к базе данных;
 Навигация (Navigation) – переход к таблице SalesLT.Customer;
 Строки с примененным фильтром (Filtered Rows) – фильтрация таблицы, остаются только записи, в которых в столбце CompanyName указано
«Friendly Bike Shop»;
 Другие удаленные столбцы (Remove Other Columns) – остаются только
столбцы CustomerID, FirstName и LastName.
Рис. 16.2. Панель примененных шагов
для нашего простого запроса
Структура запроса
До сих пор почти все, что мы делали в Power Query, мы делали посредством
интерфейса пользователя. При этом вы уже видели, что Power Query, по сути,
работает в режиме записи макросов, которые можно изменять при помощи
панели примененных шагов и строки формул. Чего вы еще не видели, так
это всей мощи языка M, лежащего в основе всех без исключения действий,
выполняемых Power Query. Пришло время изменить это:
 перейдите на вкладку Главная (Home) и нажмите на кнопку Расширенный редактор (Advanced Editor).
Структура запроса на языке M  431
Откроется одноименное диалоговое окно, в котором вы можете писать
свой код на языке M. При этом здесь полноценно работает синтаксический
помощник Intellisense, а ключевые слова в коде подсвечиваются соответствующими цветами. Также вы можете раскрыть выпадающий список Отобразить параметры (Display options) в верхней правой части окна, чтобы
выбрать нужные вам опции. Чтобы облегчить чтение кода, мы установили
следующие флажки, как показано на рис. 16.3:
 Отображать номера строк (Display line numbers);
 Отображать пробелы (Render whitespace);
 Включить перенос по словам (Enable word wrap).
Рис. 16.3. Опции, доступные в расширенном редакторе
В результате окно редактора и код, введенный в нем, будут выглядеть так,
как показано на рис. 16.4.
Рис. 16.4. Расширенный редактор
Теперь давайте присмотримся к самому коду, который можно условно разделить на следующие ключевые компоненты:
 начало запроса: эта секция начинается с ключевого слова let (в нашем
случае это первая строка запроса);
432  Глава 16. Изучаем язык M
 конец запроса: эта секция обозначается при помощи ключевого слова
in (строка 6). Обычно это слово располагается на предпоследней строке
запроса;
 определение запроса: вся область запроса, заключенная между ключевыми словами let и in. Здесь определяется, что именно будет делать
запрос. В нашем случае определение запроса начинается на второй
строке запроса и заканчивается на пятой;
 вывод запроса: после ключевого слова in необходимо указать, что будет включено в вывод запроса. У нас это определение стоит в седьмой
строке и включает в себя значение, полученное на последнем шаге запроса, а именно #"Другие удаленные столбцы" (#"Removed Other Columns").
🍌 Примечание. Важно понимать, что вывод запроса, как правило, ссылается
на результат выполнения последнего шага из области определения, но это
вовсе не обязательно.
В качестве упрощенного примера рассмотрите следующий запрос с теми
же четырьмя компонентами:
let
Source = 1
in
Source
Ключевым словом let по традиции начинается запрос. Затем на новой
строчке введено имя нового шага Source, следом за которым идет знак
равенства и значение 1. Далее – ключевое слово in, которым завершается
секция определения запроса, и в последней строке – имя шага Source, результат выполнения которого и будет возвращен в виде вывода запроса.
В нашем исходном запросе область определения была гораздо сложнее и
многословнее. Давайте присмотримся к ней повнимательнее, в конце концов, именно здесь происходит вся магия.
Область определения запроса и идентификаторы
Вам необходимо понять, как отдельные строки (шаги) в запросе связаны
между собой. В Power Query так же, как в алгебре и функциональном программировании, мы используем определенные слова для обращения к значениям. Это может быть имя шага в запросе или имя всего запроса в целом. Такие
имена в Power Query называются идентификаторами (identifier) и могут быть
записаны одним из следующих способов:
 в виде обычного идентификатора (Regular Identifier): не должен содержать в имени пробелов и других специальных символов. Например,
шаг с именем StepName может быть написан в запросе на языке M как
StepName;
Структура запроса на языке M  433
 в виде идентификатора с кавычками (Quoted Identifier): может содержать в имени пробелы, другие специальные символы и даже зарезервированные ключевые слова. К примеру, шаг с именем Step Name
может быть написан в запросе на языке M как #"Step Name".
🍌 Примечание. В главе 15 мы говорили о зарезервированных ключевых словах в Power Query и приводили их список.
Такой механизм используется в Power Query во избежание появления неоднозначностей в коде и предотвращения конфликтов, связанных с использованием зарезервированных слов. Можно запомнить, что любой идентификатор в коде на языке M, включающий в себя пробел, специальные символы
или ключевые слова, должен быть заключен в кавычки и предварен символом
решетки (#).
Теперь пришло время сравнить, как соотносятся имена шагов из панели
примененных шагов с тем, как они отображаются в запросе на языке M.
Взгляните на рис. 16.5.
Рис. 16.5. Сравнение идентификаторов в коде с именами примененных шагов
Как видите, на панели Примененные шаги (Applied Steps) имена шагов
приведены понятным языком, описывающим выполняемое действие. И если
имя первого шага (Source) полностью соответствует отображаемому идентификатору в коде, то имя Navigation присутствует только на панели шагов.
Причина этого в том, что шаг с навигацией Power Query создал автоматически
и обозначил его в коде как SalesLT_Customer. Именование этого шага можно
считать исключением из правил, тогда как идентификаторы оставшихся двух
шагов в коде на языке M практически полностью соответствуют именам на
панели. Отличие заключается лишь в использовании кавычек и постановке
символа решетки перед идентификаторами из-за наличия в них пробелов.
434  Глава 16. Изучаем язык M
Также стоит отметить некоторое сходство области определения запроса
(между ключевыми словами let и in) с записью. В главе 15 мы говорили,
что при создании записи мы указываем сначала имя поля, после чего
через знак равенства присваиваем ему выбранное значение, а в случае
наличия в записи нескольких полей разделяем образованные пары запятыми. После заключительной пары запятая не ставится. То же самое мы
видим и применительно к шагам запроса – они разделяются запятыми,
а после заключительного шага запятая не ставится. Поэтому содержимое
области определения запроса может показаться вам знакомым, хотя сами
формулы – нет.
🙈 Предупреждение. Вы можете менять имена шагов непосредственно в расширенном редакторе, но проще и правильнее делать это на панели примененных шагов, поскольку в этом случае Power Query сам обновит в запросе
все записи с упоминаниями измененного шага. Если же вы решили внести
изменения вручную, позаботьтесь о том, чтобы заменить все вхождения
с учетом регистра символов. Кроме того, не забудьте обновить идентификатор в выводе запроса, если ваши изменения коснулись последнего шага.
Обобщенные идентификаторы
Существуют и исключения из указанного выше правила именования идентификаторов, позволяющие использовать обычные идентификаторы даже
при наличии в них специальных символов или пробелов. Такие исключительные сценарии характерны для так называемых обобщенных идентификаторов (Generalized Identifier), которые вы можете встретить в коде на языке M лишь в двух случаях:
 при указании имени поля внутри записи: при создании записи
вам нет необходимости использовать идентификаторы с кавычками.
К примеру, для записи с именем поля Base Line вы можете использовать
следующее определение:
[ Data = [Base Line = 100, Rate = 1.8] ]
 в операторах доступа к полям: при обращении к полям в других значениях вам также нет нужды прибегать к помощи идентификаторов с
кавычками. Допустим, в предыдущем примере мы могли бы организовать доступ к Data и перемножить значения полей Base Line и Rate для
получения нового поля Progression следующим образом:
[
Data = [Base Line = 100, Rate = 1.8],
Progression = Data[Base Line] * Data[Rate]
]
Структура запроса на языке M  435
Наличие обобщенных идентификаторов также объясняет, почему при создании настраиваемых столбцов имена колонок, к которым идет обращение,
указываются без использования кавычек, как показано на рис. 16.6.
Рис. 16.6. При обращении к колонкам при создании настраиваемого столбца нет
необходимости использовать идентификаторы с кавычками
🍌 Примечание. По сути, это означает, что в языке M есть два места, где вы можете использовать имена столбцов, включающие пробелы, напрямую – без
необходимости заключать их в обертку из символов #" ".
Комментарии к коду
Добавить комментарии к коду на языке M можно несколькими способами, и самый простой из них – воспользоваться интерфейсом пользователя.
Все, что вам необходимо сделать,– это щелкнуть правой кнопкой мыши на
шаге, требующем пояснений, выбрать пункт Свойства (Properties) и в открывшемся диалоговом окне заполнить поле Описание (Description), как
показано на рис. 16.7.
436  Глава 16. Изучаем язык M
Рис. 16.7. Добавление комментария к шагу при помощи пользовательского интерфейса
В результате в области примененных шагов рядом с именем шага появится
круглая иконка, сообщающая о том, что для этого шага введен комментарий.
Также этот комментарий появится в коде на языке M в расширенном редакторе непосредственно перед строкой с шагом, как видно на рис. 16.8.
Рис. 16.8. Отображение комментария в расширенном редакторе
и в интерфейсе пользователя
Также в коде M можно создавать многострочные комментарии. Тогда как
однострочные комментарии предваряются двумя символами косой черты (//), многострочные заключаются в блок, перед которым следует сочетание косой черты и звездочки (/*), а закрывается он обратным сочетанием
символов (*/), как показано на рис. 16.9.
Структура запроса на языке M  437
Рис. 16.9. Многострочный комментарий в строках с пятой по седьмую
Собираем все воедино
Хотя запрос, который мы написали, полностью функционален, давайте
добавим еще один шаг, чтобы посмотреть, как поведет себя Power Query и
как обновится текст запроса в расширенном редакторе:
 отфильтруйте столбец FirstName, оставив в нем только текстовые вхождения «Scott».
В результате у вас останется таблица всего с двумя строками, но нам интересно, как изменился текст запроса в расширенном редакторе, показанном
на рис. 16.10.
Рис. 16.10. К нашему запросу был добавлен новый шаг с именем Filtered Rows1
438  Глава 16. Изучаем язык M
Если сравнить этот код с предыдущим, можно заметить, что добавлением
одной строки в запрос дело не ограничилось. Вот полный список произошедших изменений:
 в конце шага, начинающегося на строке 8, была добавлена запятая;
 новый шаг с идентификатором #"Filtered Rows1" вставился на строку 9;
 область вывода запроса (после ключевого слова in) теперь ссылается на
шаг #"Filtered Rows1", а не на #"Removed Other Columns".
Стоит также отметить, что, помимо указанных изменений, все остальные
шаги запроса остались неизменными.
Понимание процесса выполнения запроса
Мы пока подробно не затрагивали тему магии, которая творится буквально
на каждом шаге любого запроса в Power Query. Чтобы досконально понимать
все, что происходит на этих шагах, необходимо изучить документацию по
всем использующимся функциям, как мы делали в главе 15. Так вы сможете
узнать, что делает функция, какие параметры принимает и какое значение возвращает. Единственное, что мы видим, – это наличие связей между
шагами, как если бы между ними была явная зависимость, особенно при
рассмотрении запросов, созданных посредством интерфейса пользователя.
В качестве примера давайте рассмотрим код нашего предыдущего запроса,
а именно последние два шага (снизу вверх):
 #"Filtered Rows1" – на этом шаге используется функция Table.
SelectRows(), требующая в качестве первого параметра таблицу. И этим
параметром будет значение, полученное в результате выполнения предыдущего шага: #"Removed Other Columns";
 #"Removed Other Columns" – этот шаг также использует функцию Table.
SelectColumns(), которая, как мы уже знаем, ожидает на вход таблицу.
И снова в качестве этого параметра будет выступать значение, полученное в результате выполнения предшествующего шага – #"Filtered
Rows", как видно на рис. 16.11.
Чтобы лучше понять, как выполняется запрос в целом, бывает полезно
читать его не сверху вниз, а снизу вверх, поскольку фактически именно
так Power Query и работает. Сначала анализируется вывод запроса и постепенно рассчитываются все недостающие для его вычисления составляющие.
Понимание процесса выполнения запроса  439
Рис. 16.11. Цветом отмечены зависимости между шагами и примеры
передачи значений, полученных на одном шаге, в функции на другом шаге
Что такое ленивое вычисление?
В Power Query выполнение запросов может производиться по-разному в
зависимости от того, где это происходит:
 в окне предварительного просмотра: это основная область Power
Query, в которой вы видите свои данные во время работы;
 в выводе запроса: это сценарий, в котором вы выполняете загрузку
данных в место назначения с полным запуском или обновлением запроса.
Основное различие между приведенными методами состоит в том, что в
первом случае Power Query отправит вам лишь часть данных (обычно первую
тысячу строк), не пытаясь выполнить весь запрос целиком на полном наборе данных. В этом, по сути, состоит одно и важнейших преимуществ Power
Query, использующего, подобно функциональным языкам программирования, концепцию ленивых вычислений (lazy evaluation). Она заключается в
том, что если какое-то вычисление выполнять нет необходимости, оно и не
будет выполнено в срок. Иными словами, Power Query произведет только те
вычисления, которые необходимы для заполнения окна предварительного
просмотра.
440  Глава 16. Изучаем язык M
Этот принцип работает совместно с другой концепцией, реализованной в
Power Query и именуемой свертыванием запросов (query folding). Эта концепция состоит в способности Power Query транслировать запрос в машинный
код, выполняемый на стороне источника данных. В главе 12 мы уже затрагивали данную тему и упоминали инструмент просмотра машинных запросов
и индикатор, говорящий о том, что преобразование для шага было успешно
выполнено.
Ленивые вычисления и свертывание запросов существенно помогают при
работе с Power Query, избавляя от необходимости загружать все данные из
базы или всю выбранную таблицу при построении запросов. Вместо этого
Power Query обычно предпринимает попытку загрузить первую тысячу строк
из источника и создать кеш вычисления (зашифрованные данные, размещенные локально). Именно эти данные отображаются в окне предварительного просмотра, что позволяет производить преобразования применительно
к небольшим наборам данных. Представьте, что в вашей таблице несколько
миллиардов записей, и вы по достоинству оцените эту концепцию.
Конечно, когда речь идет о вычислении выходного значения запроса,
Power Query вынужден обрабатывать весь набор данных целиком, а не только
строки для вывода в окне предварительного просмотра. Именно в этом и состоит смысл ленивых вычислений. Запросы выполняются на полном наборе
данных только тогда, когда это действительно необходимо.
🍌 Примечание. При работе с базой данных SQL Server вы можете использовать
инструмент под названием SQL Server Profiler, позволяющий отслеживать и
анализировать запросы, поступающие от Power Query. Это поможет понять,
какие вычисления производятся для заполнения окна предварительного
просмотра. Главное отличие между запросами, поступающими для формирования предварительного просмотра и создания итогового вывода, состоит
в том, что в первом случае запрос обычно будет начинаться с инструкции
SELECT TOP 1000, а во втором выражение TOP 1000 будет отсутствовать.
План выполнения запроса
Погружаясь в концепцию свертывания запросов, стоит заметить, что далеко не все запросы могут быть транслированы в машинный код для вашего
источника данных. В частности, это зависит от используемого коннектора и
настроек источника.
🍌 Примечание. Именно здесь на арене появляется новый инструмент под на-
званием План запроса (Query Plan), который на момент написания книги присутствует в виде предварительного релиза только в Power Query Online.
План запроса представляет собой ровно то, что и должен, исходя из названия, а именно сценарий или предположение о том, как именно будет вы-
Понимание процесса выполнения запроса  441
полнен запрос. Цель проста – перенести как можно большую часть вычислений на сторону источника данных, и за это отвечает механизм свертывания
запросов.
🍌 Примечание. В данном разделе мы покажем пример построения плана вы-
полнения запроса применительно к Power Query Online, как если бы этот механизм уже был реализован в вашем продукте, использующем Power Query.
Давайте вернемся к запросу Sample Query, с которым уже работали ранее
в этой главе. Напомним, с помощью него мы подключались к базе данных и
извлекали все записи по компании Friendly Bike Shop. Итак, вы можете щелкнуть правой кнопкой мыши на последнем шаге в запросе и выбрать пункт
Просмотр плана запроса (View query plan), после чего откроется диаграмма,
показанная на рис. 16.12.
Рис. 16.12. План выполнения и выражение SQL для нашего запроса Sample Query
Представленный план говорит нам о том, что весь запрос может быть выполнен на стороне источника данных, а это означает, что мы просто получим
на выходе таблицу с тремя столбцами и четырьмя строками, вместо того
чтобы загружать все исходные данные и выполнять нужные нам преобразования локально. Более того, мы можем видеть, какой именно запрос будет
отправлен источнику данных и какому именно источнику.
Давайте добавим новый шаг для сохранения двух нижних строк, который гарантированно прервет процесс свертывания запроса, как показано
на рис. 16.13.
442  Глава 16. Изучаем язык M
Рис. 16.13. Новый шаг с сохранением двух нижних строк в таблице
🙈 Предупреждение. Поскольку в SQL не существует оператора для возвра-
щения последних строк в таблице, эта команда гарантированно приведет
к прерыванию процесса свертывания запроса.
Как видно по рис. 16.13, на созданном нами шаге с именем Kept bottom rows
цепочка успешного свертывания запроса оборвалась, о чем говорит соответствующая иконка красного цвета. Щелкните правой кнопкой мыши по этому
шагу и выберите пункт Просмотр плана запроса. Вы увидите обновленный
вид плана, показанный на рис. 16.14.
Рис. 16.14. План выполнения запроса после добавления шага Kept bottom rows
Итераторы (построчное выполнение)  443
Хотя этот план отчасти похож на предыдущий, мы не можем не заметить, что к нему было добавлено новое событие или задача с именем Table.
LastN. Это имя функции, которая используется на созданном нами шаге по
сохранению нижних строк. Таким образом, наш запрос по-прежнему будет
отправлен в источник данных (как и в случае с изначальным планом), но
после получения данных Power Query запустит преобразующий шаг Table.
LastN локально при помощи собственного движка.
🍌 Примечание. План запроса – это очень эффективный инструмент, помогаю-
щий понять, как выполняются запросы, и произвести их тонкую настройку.
Конечно, пока этот механизм находится лишь на этапе разработки, но мы
возлагаем на него большие надежды и будем следить за его развитием!
Итераторы (построчное выполнение)
Существует еще один очень важный навык в арсенале разработчика в среде
Power Query, состоящий в понимании того, как правильно читать и модифицировать код, работающий в таблице построчно.
В языке M есть множество способов осуществления итераций (iteration) по
значениям в наборе. Говоря простым языком, итерация – это процесс многократного перебора значений в циклах или при выполнении повторяющихся
операций. Представьте, что мы добавили в таблицу столбец, в котором построчно должна выполняться некая формула или функция. Примерно так в
Excel осуществляются вычисления в столбцах таблиц. В данном разделе мы
посмотрим, как с итерациями работать в Power Query, как устанавливать
правила и как извлечь максимум из этого знания.
Ремарка по поводу рекурсивных функций в Power Query
В данной книге мы сосредоточимся на описании стандартных функций языка M, но вы должны знать о наличии в Power Query продвинутых
средств для создания более сложных решений, подобных циклам for-loop или
do-while-loop. Вот две основные рекурсивные функции (recursive function), с которыми вы можете столкнуться при работе с Power Query:
 List.Generate() – эта функция часто используется при написании пользовательских коннекторов для Power BI с целью осуществления разбивки на страницы;
 List.Accumulate() – эта функция работает подобно циклу for-loop, когда
у вас есть набор значений и вам необходимо пройти по нему с целью
создания агрегации. Данную функцию можно применять при наличии списка значений, на основании которого необходимо выполнить
какое-то вычисление, например получить факториал.
И хотя мы знали, что это расстроит некоторых наших читателей, мы решили не приводить подробные примеры использования этих двух функций в
444  Глава 16. Изучаем язык M
данной книге. Да, иногда мы прибегаем к их помощи, но реальность такова,
что эти случаи можно пересчитать по пальцам одной руки. Более того, практически всегда в этих ситуациях мы приходили к альтернативному решению,
которое казалось нам более понятным, дружественным и оптимальным с
точки зрения возможности осуществления свертывания запросов.
🍌 Примечание. В языке M также присутствует зарезервированное слово, пред-
ставляющее собой символ @. Этот символ может быть использован для создания рекурсивных функций, но опыт нам подсказывает, что применение
функций List.Accumulate() и List.Generate() может быть более оптимальным
выбором.
Ключевые слова each и _
Давайте продолжим работать с нашим примером и создадим новый столбец, в котором будет выполняться конкатенация значений из столбцов
FirstName и LastName. Для этого сделайте следующее:
 удалите все шаги, следующие в запросе за шагом Другие удаленные
столбцы (Removed Other Columns);
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 назовите столбец FullName и введите следующую формулу:
[FirstName] & " " & [LastName]
По сути, здесь мы просто сцепляем при помощи пробела имена и фамилии
и вставляем полученные значения в новый столбец. Вопрос в том, откуда
Power Query знает, что ему необходимо создать новый столбец и заполнить
его результирующими значениями.
Ответ на подобные вопросы всегда стоит искать в строке формул или
расширенном редакторе. В нашем случае достаточно бросить взгляд на
формулу, чтобы понять, что Power Query с целью выполнения поставленной задачи воспользовался функцией Table.AddColumn(), как показано на
рис. 6.15.
Как видите, полная формула, созданная автоматически, выглядит так:
=Table.AddColumn(#"Removed Other Columns", "FullName",
each [FirstName] & " " & [LastName])
Если взглянуть на подсказку механизма Intellisense, которую можно получить, удалив, а затем снова поставив открывающую скобку после названия
функции Table.AddColumn(), мы увидим список аргументов, который она
ожидает получить на вход. Давайте посмотрим в табл. 16.1, что представляет
каждый из них и что мы фактически передали на вход функции.
Итераторы (построчное выполнение)  445
Рис. 16.15. Создание настраиваемого столбца FullName
Таблица 16.1. Параметры функции Table.AddColumn()
Параметр
Требуемое значение
Переданное значение
table как табличное выражение
Таблица, в которую будет
добавлен новый столбец
Таблица, полученная в результате выполнения шага #"Removed Other Columns"
newColumnName
как текст
Имя новой колонки
Текстовое значение "FullName"
columnGenerator
как функция
Функция для создания
нового столбца
each [FirstName] & " " & [LastName]
🍌 Примечание. Думайте о функции как о шаге или запросе, принимающем на вход аргументы и возвращающем динамический результат. Table.
AddColumn() – встроенная в Power Query функция, однако мы вполне можем
использовать и собственную пользовательскую функцию, о чем будем подробно говорить в главе 17. Но на данный момент вам достаточно понимания
того, что из себя представляет функция и какая ее основная задача.
Наверняка вы обратили внимание на новое для себя ключевое слово each.
Оно стоит перед формулой, определяющей значение будущего столбца. Но
что это за ключевое слово, в чем его предназначение?
Если убрать слово each из формулы, вы тут же получите ошибку. Давайте
попробуем это сделать и посмотрим, какая ошибка на уровне шага возникнет.
446  Глава 16. Изучаем язык M
Рис. 16.16. Ошибка, появившаяся после удаления из формулы ключевого слова each
В сообщении об ошибке говорится о каком-то [field], на который мы ссылаемся извне выражения each. Хотя смысл в этом сообщении есть, он не до
конца понятен новичку в языке M. Проблема в том, что третий параметр
подразумевает использование функции, а мы, удалив ключевое слово each,
передаем наши поля в виде обычного текста.
Давайте попробуем зайти с другой стороны. Вернитесь в строку формул
и внесите еще одну правку, заменив ключевое слово each на комбинацию
символов (_)=>, как показано на рис. 16.17.
Рис. 16.17. Альтернативный вариант записи ключевого слова each
После запуска формулы вы с удивлением обнаружите, что она снова работает, хотя вы заменили слово each на какой-то несуразный набор символов.
Что же это все значит? А лишь то, что для Power Query слово each и (_)=> – это
полноправные синонимы.
🍌 Примечание. Ключевое слово each в языке M представляет собой так назы-
ваемый синтаксический сахар, т. е. понятное человеку слово, которое легче
запоминать и вводить, чем базовую версию синтаксиса.
Ну, хорошо, а что означает исходная конструкция (_)=>? На самом деле это
определение пользовательской функции!
В общем виде определение функции включает в себя передаваемые параметры, заключенные в скобки, после чего следует комбинация из знака равенства и символа >. Например, так выглядит определение функции, принимающей на вход два числовых значения и возвращающей их произведение:
(x, y) => x*y
Таким образом, важно понимать, что в загадочной комбинации символов
(_)=> знак подчеркивания обозначает передаваемый в функцию параметр.
Мы уже использовали этот символ ранее, в главе 15. Давайте кое-что сделаем:
 добавьте новый столбец с именем Custom и формулой: = _.
Итераторы (построчное выполнение)  447
Результат выполнения этой мудреной формулы показан на рис. 16.18.
Рис. 16.18. Создание нового столбца при помощи одиночного
символа подчеркивания
🍌 Примечание. При создании настраиваемого столбца с использованием одного только символа подчеркивания в нем будет отображаться запись с информацией о текущей строке, поскольку формула выполняется в контексте
таблицы.
Возвращаясь к синтаксическому сахару и разным написаниям одного и
того же выражения, стоит отметить, что следующие три записи вернут одинаковые результаты:
(_)=> _[FirstName] & " " & _[LastName]
(_)=> [FirstName] & " “ & [LastName]
each [FirstName] & " " & [LastName]
Первый вариант представляет собой наиболее явный способ объявления
пользовательской функции, где обращение к полям осуществляется посредством переданного в качестве параметра символа подчеркивания. Иными
словами, в переменной _ мы передаем запись с текущей строкой, после чего
извлекаем из нее нужные нам поля, как было показано в главе 15, где мы
впервые использовали квадратные скобки для доступа к конкретному полю
записи.
Второй вариант синтаксиса также является рабочим, но при этом он не
такой явный, поскольку здесь просто подразумевается, что мы обращаемся к
полям записи, переданной при помощи символа подчеркивания, не указывая
его явным образом.
Последний метод используется Power Query автоматически при создании
настраиваемых столбцов и представляет собой наиболее простой и понятный способ работы с функциями в Power Query. В то же время этот подход
не всегда можно назвать оптимальным, когда он применяется за пределами
функции Table.AddColumn().
448  Глава 16. Изучаем язык M
🍌 Примечание. Мы рекомендуем использовать первый или третий вариант, поскольку они являются наиболее явными.
Важно понимать, что все описанное в этом разделе относится не только к функции Table.AddColumn(), а может быть применено в рамках любой
другой функции. Представьте, например, что у вас есть список целых чисел
{1,2,3,4,5} и вам необходимо умножить каждое число из списка на два. Для
этого вы можете написать следующую функцию:
= List.Transform( {1..5}, each _ * 2)
🍌 Примечание. Вы, наверное, заметили, что в приведенной выше формуле мы
не использовали квадратные скобки. Причина в том, что у нас есть список
примитивных значений, по которому мы будем осуществлять итерации. Если
бы наш список содержал структурированные значения, такие как записи или
таблицы, нам бы, возможно, пришлось осуществлять навигацию по ним – например, так: each [value].
Функция List.Transform() принимает на вход список и функцию для его преобразования, а возвращает измененный список – в нашем случае {2,4,6,8,10}.
Заметьте, что даже в функции для работы со списками можно применять
ключевое слово each совместно с символом подчеркивания для осуществления итераций по списку.
Можно думать о символе подчеркивания как о способе извлечения текущего элемента. Это может быть и запись, как в случае с функцией Table.
AddColumn(), и элемент списка, как в нашем последнем примере.
🍌 Предупреждение. Вы не можете оперировать вложенными ключевыми
словами each, поскольку Power Query в этом случае вернет самый верхний
уровень или внешний each в формуле. Если вам необходимо осуществлять
итерации по нескольким уровням, лучше всего для этого использовать пользовательские функции.
В заключение отметим, что следующие два варианта записи формулы
полностью эквивалентны использованной нами в этом примере, как видно
на рис. 16.19:
= List.Transform( {1..5}, (r)=> r * 2)
= List.Transform( {1..5}, (_)=> _ * 2)
🍌 Примечание. По сути, символ подчеркивания был выбран командой разработчиков Power Query в качестве имени передаваемого функции аргумента
с целью стандартизации. При написании определения функции вы можете
использовать любой другой символ или набор символов вместо подчеркивания (хотя мы не рекомендуем так делать).
Другие техники  449
Рис. 16.19. Использование символа подчеркивания в качестве
аргумента пользовательской функции внутри функции List.Transform()
Подводя итог, хочется отметить, что вам совершенно не стоит бояться
непонятного слова each и знака подчеркивания в строке формул. Они
призваны облегчить вам жизнь за счет упрощения кода. Понимание этих
концепций – первый шаг к освоению работы функций в Power Query в целом
и написанию собственных пользовательских функций в частности.
Другие техники
При написании этой книги мы не ставили себе целью рассказать обо всех
функциях и приемах работы в Power Query. Мы даем лишь самые основы
языка M, а также делимся некоторыми наработками и наблюдениями, приобретенными с многолетним опытом.
В следующих нескольких разделах этой главы мы попытаемся обобщить
все, о чем говорили ранее, и поделимся полезными шаблонами, которые
могут пригодиться вам при работе над следующим проектом в Power Query.
Получение первого значения из столбца таблицы
Представьте, что в вашей таблице есть столбец с именем Content, содержащий двоичные данные, и вам необходимо создать динамическое решение, в
котором будет осуществляться доступ к первому значению из этого столбца.
Давайте рассмотрим простой сценарий из запроса First Value, находящегося в файле из папки Ch16 Examples:
let
Source = #table( type table [Content= binary, Value = text], {
{#binary("Rmlyc3Q="), "First"},
{#binary("U2Vjb25k"), "Second"},
{#binary("VGhpcmQ="), "Third"}
}),
Data = Source{[Value="First"]}[Content],
#"Imported Text" = Table.FromColumns(
{Lines.FromBinary(Data,null,null,1252)})
in
#"Imported Text"
Powered by TCPDF (www.tcpdf.org)
450  Глава 16. Изучаем язык M
На шаге Source, как видно по рис. 16.20, создается реплика данных, аналогичных тем, которые вы могли бы получить при подключении к папке или
похожему источнику до момента навигации к содержимому первого файла.
Рис. 16.20. Простой запрос, имитирующий подключение к данным
посредством коннектора Из папки (From Folder)
В шаге Navigation находится следующая формула:
= Source{[Value="First"]}[Content]
Здесь мы указываем Power Query получить запись, в которой в столбце
Value находится строка "First", и открыть содержимое поля Content. Эта формула не похожа на динамическую, поскольку явным образом полагается на
поиск строки "First". А что, если такой записи не найдется? Для ответа на
этот вопрос перейдите на шаг Source и отфильтруйте значения в колонке
Value, сняв флажок со строки First.
После переключения на шаг навигации появится ошибка, показанная на
рис. 16.21.
Рис. 16.21. Ошибка на уровне шага, связанная с отсутствием ключа в таблице
Можно изменить формулу на шаге навигации таким образом, чтобы она не
привязывалась ни к каким конкретным точкам данных, а вместо этого всегда
обращалась к первой строке в таблице. Как мы видели в главе 15, для этого
нам необходимо избавиться от явного условия [Value=”First”], заменив его
на {0}, тем самым указав Power Query обращаться непосредственно к первой
строке (или записи) таблицы:
= Source{0}[Content]
Другие техники  451
После этого изменения вы обнаружите, что запрос заработал и возвращает
содержимое первого файла в таблице вне зависимости от того, отфильтрованы в ней записи или нет.
Сложно переоценить ценность обращения к строкам таблицы по порядковому номеру при написании сложных динамических решений с использованием Power Query.
🍌 Примечание. Оказывается, именно эту технику Power Query использует в за-
просе Пример файла (Sample File) при объединении файлов, обеспечивая,
чтобы запрос Преобразовать пример файла (Transform Sample File) всегда
базировался на первом файле в (отфильтрованной) папке.
🙈 Предупреждение. При щелчке мышью по значению Binary Power Query
интерпретирует действия пользователя как попытку перейти к выбранному
значению, в связи с чем автоматически создает несколько шагов. В некоторых
из этих шагов могут присутствовать ссылки на идентификаторы, а не
обращение к первому элементу в списке, как мы показали в этом разделе.
Поэтому всегда лучше тщательно проверять, что именно делает Power Query,
и при необходимости вносить в формулы изменения.
Замена на null при ошибке навигации
В предыдущем разделе мы рассмотрели способ динамического обращения к строкам таблицы, но чему недоставало динамики, так это обращению
к столбцу Content. Power Query требует, чтобы ссылка на столбцы производилась по имени, а обратиться к колонке по порядковому номеру просто не
представляется возможным. Вы можете сказать, что это вполне нормально,
поскольку у пользователя должно быть четкое понимание того, к какому
именно столбцу он обращается и где конкретно находятся нужные ему данные. С другой стороны, что делать, если имя столбца изменится?
Давайте на какое-то время забудем о динамическом обращении к строкам
и подумаем, что произойдет, если переименовать столбец Content в Data.
Разумеется, это вызовет появление ошибки с указанием на то, что поля
[Content] не существует.
Воспользуемся техникой, изученной в главе 14, чтобы отловить появление
этой ошибки:
try Source{[Value="First"]}[Data] otherwise null
И хотя этот вариант вполне рабочий, существует и более простой способ
безопасно проверить столбец на существование, который прекрасно работает при навигации по значениям в Power Query. Заключается он в добавлении
ключевого слова в виде знака вопроса (?) в конец нашего исходного кода, как
показано ниже:
Source{[Value="First"]}[Data]?
452  Глава 16. Изучаем язык M
На рис. 16.22 видно, что этот метод работает не хуже последнего, более
многословного варианта.
Рис. 16.22. Использование вопросительного знака при доступе к полю
Такое применение вопросительного знака бывает очень полезным, когда
вы хотите сделать свое решение более надежным, поскольку фактически эта
конструкция является синтаксическим сахаром для следующей логической
структуры: try x otherwise null. Кроме того, если поле будет переименовано
обратно в Content, оба наших предыдущих варианта останутся работоспособными.
Еще более ценной показанная здесь конструкция становится при осуществлении доступа или навигации по таблицам, спискам и другим структурированным значениям. К примеру, замените формулу в шаге Navigation на
следующую:
= Source{[Value="1"]}?[Content]?
Здесь мы пытаемся найти в таблице Source запись со значением поля Value, равным текстовому представлению единицы, после чего осуществляем
навигацию к содержимому поля Content найденной записи. Если вы заметили,
мы добавили еще один вопросительный знак непосредственно после навигации
по таблице, поскольку эта операция поиска записи выполняется первой, и в
случае ее отсутствия мы получим ошибку, которую перехватим при помощи
вопросительного знака и вернем значение null. Если запись будет найдена,
вычисление продолжится, и будет осуществлен доступ к полю Content.
Эту технику можно применять совместно с динамическим доступом к
строке таблицы. Таким образом, формула, приведенная ниже, вернет первое
значение из столбца Content или null, если такого столбца не найдется:
= Source{0}?[Content]?
🍌 Примечание. Вы можете дополнить свой запрос проверкой результата вы-
полнения этого шага на null и действовать соответствующе. В результате вы
будете отлавливать все возникающие на этапе навигации ошибки, что позволит сделать ваше решение намного более устойчивым к отказам.
Создание динамического списка заголовков
типизированных столбцов
Следующий сценарий мы будем строить на базе приведенного ниже кода
запроса List of Headers, находящегося в том же файле из папки к этой главе:
Другие техники  453
= #table( type table [Data=record, Title = text], {
{[First="Bill", Last="Jelen”], "First"”},
{[First = "Miguel", Last= "Escobar", Country ="Panama"],
"Second"},
{[First = "Ken", Last= "Puls", Country ="Canada",
#"Tall?" = true], "Third"}
} )
Поскольку наша таблица содержит записи в столбце Data, мы можем развернуть его, нажав на кнопку в правой части заголовка столбца, как показано
на рис. 16.23.
Рис. 16.23. Разворачивание столбца Data
Вы заметите, что в открывшемся диалоговом окне будет отображено
предупреждение Список может быть незавершенным (List may be incomplete)
и ссылка Загрузить еще (Load more). При нажатии на ссылку вы увидите
картину, показанную на рис. 16.24.
Рис. 16.24. Появилось новое поле в списке полей
454  Глава 16. Изучаем язык M
Вам наверняка не терпится узнать, почему Power Query сразу не отобразил
все доступные поля. Чтобы ответить на этот вопрос, для начала необходимо
узнать, как именно Power Query собирает информацию для этого диалогового
окна.
Если говорить кратко, вариантов здесь два:
1) информация уже есть – когда в типе данных столбца уже заложены
метаданные о том, какие поля будут содержаться в каждой записи;
2) информацию нужно вычислять – когда для записи не задан точный
тип данных, Power Query необходимо самостоятельно выполнить анализ значений в окне предварительного просмотра.
🍌 Примечание. Первый сценарий является довольно распространенным.
К примеру, когда вы применяете операцию объединения для создания нового столбца с табличными значениями, в открывшемся диалоговом окне будет
автоматически загружен полный список полей.
Но что делать в нашем случае? Ответ прост – нам необходимо явно задать
типы данных, и мы сделаем это в два шага.
Шаг 1. Создайте новый запрос с указанием типов данных для полей записи:
 создайте пустой запрос и назовите его MyRecordType;
 введите следующую формулу в строку формул:
= type [First= text, Last=text, Country=text, #"Tall?"=logical]
Шаг 2. Обновите исходный запрос, чтобы он использовал определенные
нами типы данных:
 создайте дубликат запроса List of Headers и назовите его Dynamic
Headers – Typed;
 замените слово record на шаге Источник (Source) на MyRecordType,
как показано ниже:
= #table( type table [Data= MyRecordType, Title = text], {
{[First="Bill", Last="Jelen”], “First"},
{[First = "Miguel", Last= "Escobar", Country ="Panama"],
"Second"},
{[First = "Ken", Last= "Puls", Country ="Canada",
#"Tall?" = true], "Third"}
} )
 выделите шаг Развернутый элемент Data (Expanded Data) или разверните данные в столбце Data, если еще этого не сделали.
Другие техники  455
🍌 Примечание. Весь этот процесс фактически представляет собой более точ-
ный метод определения типов данных в вашей таблице, и в результате мы
получаем данные, классифицируемые как сложные типы. Этот прием не
так часто применяется в решениях, за исключением написания собственных коннекторов, где типы данных всегда должны быть определены очень
точно.
Основные преимущества описанного метода:
1) все столбцы сразу отображаются при выполнении разворачивания данных;
2) столбцы сохраняют свои типы данных при разворачивании, что видно
на рис. 16.25.
Рис. 16.25. Все столбцы разворачиваются в таблицу с правильными типами данных
В реальных проектах мы зачастую не знаем заранее, какие поля могут
быть в наших записях или таблицах и как нам сделать наше решение более
динамическим. Здесь Power Query может помочь вам и выполнить анализ
данных на лету.
При этом не стоит забывать, что Power Query, как мы уже упоминали ранее,
всегда пытается производить ленивые вычисления. Именно поэтому при
первом нажатии на кнопку разворачивания данных он проанализировал
поля лишь в нескольких первых записях, но не в последней. Это очень важно,
поскольку в последней записи в таблице есть поле, не содержащееся в других
записях. Мы вынуждены были просить Power Query провести полный анализ
доступных данных путем нажатия на ссылку Загрузить еще (Load more).
🍌 Примечание. Можем ли мы создавать собственный анализ данных записей и полей таблиц? Конечно да, и этот метод можно применять для передачи динамического списка элементов при использовании функций Table.
ExpandTableColumn(), Table.ExpandRecordColumn() и Table.ExpandListColumn().
456  Глава 16. Изучаем язык M
Создание динамического списка заголовков
нетипизированных столбцов
В качестве альтернативы созданию динамического списка заголовков со
строго типизированными столбцами давайте напишем запрос, делающий то
же самое, но применительно к нетипизированным полям:
 создайте запрос путем копирования запроса List of Headers;
 назовите запрос Dynamic Headers – Untyped;
 удалите шаг Развернутый элемент Data (Expanded Data), если добавляли
его ранее в запрос List of Headers;
 щелкните правой кнопкой мыши по столбцу Data и выберите пункт
Детализация (Drill Down).
В результате выбранный столбец будет преобразован в список, как показано на рис. 16.26.
Рис. 16.26. Список записей
Нажмите на кнопку fx слева от строки формул для создания пользовательского шага и введите следующую формулу:
= List.Transform( Data, each Record.FieldNames(_))
Это позволит преобразовать список записей в список списков, в котором
каждый элемент содержит имена полей для каждой записи, что видно по
рис. 16.27.
Рис. 16.27. Списки списков, содержащие имена полей каждой записи
Другие техники  457
Создайте новый пользовательский шаг со следующей формулой:
= List.Combine( Custom1 )
🍌 Примечание. Функция List.Combine() добавляет в единый список все элемен-
ты исходных списков. Таким образом, мы получим на выходе полный список
имен полей с дубликатами.
Теперь на вкладке Средства для списков (List Tools) откройте раздел Преобразование (Transform) и нажмите на кнопку Удалить дубликаты (Remove
Duplicates), как показано на рис. 16.28.
Рис. 16.28. Объединенный список из уникальных заголовков столбцов
🍌 Примечание. Назовите этот шаг Removed Duplicates, мы будем использовать
это имя шага в дальнейшем.
На данный момент у нас есть запрос, эффективно вычисляющий динамический список из (уникальных) заголовков столбцов, который может быть
передан функции Table.ExpandRecordColumn():
 нажмите на кнопку fx слева от строки формул для создания пользовательского шага;
 измените формулу шага на =Источник (=Source), чтобы получить исходные результаты;
 разверните все поля в столбце Data.
В результате вы получите вывод, показанный на рис. 16.29.
458  Глава 16. Изучаем язык M
Рис. 16.29. Записи развернуты со статическими именами столбцов
🍌 Примечание. Функции Table.ExpandRecordColumn() и Table.ExpandTableColumn()
ожидают на вход первый аргумент в виде таблицы, после чего должно следовать имя столбца, содержащего поля для разворачивания, и, наконец,
список полей, которые необходимо развернуть. В качестве необязательного
четвертого аргумента вы можете передать новые имена столбцов, которые
разворачиваете. В нашем случае развернутые поля получили имена с префиксом Data, поскольку мы оставили соответствующий флажок включенным
при разворачивании столбцов.
Ну и на заключительном шаге необходимо просто заменить последние два
аргумента в вызове функции Table.ExpandRecordColumn(), чтобы получилась
следующая формула:
= Table.ExpandRecordColumn(Custom3, "Data", #"Removed Duplicates")
Таким образом, мы получили решение, показанное на рис. 16.30, в котором будет происходить анализ записей в колонке Data. А поскольку список
столбцов динамический, мы никогда не пропустим новую колонку в какойлибо из записей, а все столбцы будут автоматически отображаться во время
обновления.
Рис. 16.30. Итоговый вывод со всеми развернутыми столбцами
Другие техники  459
🙈 Предупреждение. Хотя это очень полезная техника, не стоит забывать, что
если в списке будут присутствовать поля, уже существующие в вашей таблице, возникнет конфликт с выводом ошибки. Используйте этот прием только в
случае уверенности, что не возникнет пересечений между разворачиваемыми столбцами и существующими колонками в таблице.
🍌 Примечание. Мы продемонстрировали эту технику на примере столбца с
записями, но вы можете применять тот же шаблон и для столбца с табличными
значениями. Все, что вам нужно в этом случае, – это использовать функцию
Table.ColumnNames() вместо Record.FieldNames() и Table.ExpandTableColumn()
вместо Table.ExpandRecordColumn(). Все остальное останется неизменным.
Глава
17
Параметры
и пользовательские
функции
В главе 9 мы рассмотрели довольно интересный пример объединения файлов. В процессе реализации Power Query автоматически создал пользовательскую функцию, позволяющую работать с конкретным примером файла
и затем применить все сделанное ко всей таблице с файлами. Но прелесть
в том, что мы не ограничены лишь теми функциями, которые Power Query
создает для нас. Мы и сами можем создавать собственные функции.
В данной главе мы исследуем методы, которыми пользуется Power Query
при создании функций, и досконально разберемся в них. После этого мы
рассмотрим другие сценарии, в которых можно применить полученные
знания.
Воссоздание метода объединения файлов
В этом разделе мы попробуем вручную воссоздать механику, используемую
Power Query при объединении файлов. И хотя мы не будем выполнять преобразование отдельных файлов, мы продолжим следовать шаблону FilesList, с
которым впервые столкнулись в главе 9. Для начала откройте новую рабочую
книгу и создайте запрос FilesList следующим образом:
 создайте новый запрос, выбрав в меню Из файла (From File) пункт Из
папки (From Folder);
 выберите папку Ch17 Examples\Source Data и нажмите на кнопку
Преобразовать данные (Transform Data);
 щелкните правой кнопкой мыши по заголовку столбца Extension и в
меню Преобразование (Transform) выберите пункт нижний регистр
(lowercase);
 нажмите на кнопку фильтрации в заголовке столбца Extension и в меню
Текстовые фильтры (Text Filters) выберите пункт Равно (Equals);
462  Глава 17. Параметры и пользовательские функции
 установите переключатель в положение Подробнее (Advanced) и
настройте значения полей следующим образом:
• для поля Extension выберите оператор равно (equals) и введите
значение .xlsx;
• для поля Name выберите оператор не начинается с (does not
begin with) и введите символ ~ (тильда);
 переименуйте запрос в FilesList и произведите его загрузку в виде подключения.
Теперь давайте создадим запрос Orders – так же, как и в исходном шаблоне:
 щелкните правой кнопкой мыши по запросу FilesList и выберите пункт
Ссылка (Reference);
 переименуйте запрос в Orders.
На данный момент у нас есть перечень всех файлов в папке, как показано
на рис. 17.1.
Рис. 17.1. Можно было бы просто нажать на кнопку
объединения файлов, но что в этом интересного?
🍌 Примечание. Помните о том, что мы разделили запросы перед объединени-
ем файлов, в связи с чем в строке формул вместо сложной формулы на языке
M у нас написано просто =FilesList.
На этот раз мы не пойдем простым путем, а постараемся вручную сотворить
магию, которая происходит по нажатии на кнопку Объединить файлы
(Combine Files). В процессе мы создадим уже знакомые вам по главе 9 объекты Sample File, Sample File Parameter, Transform Sample и Transform Function.
Создание примера файла (Sample File)
Для создания примера файла начнем с таблицы Orders:
 щелкните правой кнопкой мыши по слову Binary в первой строке столбца Content и выберите пункт Добавить как новый запрос (Add as New
Query);
 переименуйте созданный запрос в Sample File.
Воссоздание метода объединения файлов  463
Обратите внимание, что в запросе Sample File уже содержится два примененных шага:
1) Источник (Source), ссылающийся на запрос Orders;
2) Навигация (Navigation) со ссылкой на выбранный файл.
Проблема в том, что, как видно на рис. 17.2, путь к файлу у нас указан
жестко, что далеко от динамического решения.
Рис. 17.2. Статический путь к файлу
Мы же хотим, чтобы запрос автоматически ссылался на первый файл в
списке, и в главе 16 мы уже освоили эту технику:
 замените путь к файлу на 0, чтобы формула приобрела следующий вид:
=Источник{0}[Content]
=Source{0}[Content]
 удалите шаг, автоматически созданный Power Query для детализации
до уровня файла.
Таким образом, наш запрос Sample File должен приобрести вид, показанный на рис. 17.3.
Рис. 17.3. В запросе Sample File автоматически выбирается первая строка из источника
Создание параметра Sample File Parameter
Это несложный шаг, нам всего лишь потребуется вручную создать параметр. Для этого выполните следующие действия:
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Управление параметрами (Manage Parameters) выберите пункт Создать
параметр (New Parameter);
464  Глава 17. Параметры и пользовательские функции
 назовите параметр Sample File Parameter;
 в выпадающем списке Тип (Type) выберите пункт Двоичный (Binary);
 в выпадающих списках Значение по умолчанию (Default Value) и
Текущее значение (Current Value) выберите наш запрос Sample File,
как показано на рис. 17.4.
Рис. 17.4. Настройка параметра Sample File Parameter
🍌 Примечание. Имя созданного параметра не имеет существенного значения,
мы просто решили следовать соглашению об именах объектов, принятому в
главе 9. Вы могли бы оставить имя параметра по умолчанию – Параметр1
(Parameter1), и все нормально работало бы.
После нажатия на кнопку OK откроется простое диалоговое окно, показанное
на рис. 17.5, в котором отображено текущее значение параметра (Sample File).
Рис. 17.5. Мы будем ссылаться на запрос Sample File
Воссоздание метода объединения файлов  465
Создание преобразования файла (Transform Sample)
Следующее, что нам предстоит сделать, – это создать нашу рабочую лошадку – запрос Transform Sample, в котором будет содержаться шаблон преобразования файлов. Как мы уже упоминали ранее, в данном случае мы на
самом деле не будем выполнять никаких преобразований, поскольку это не
тема данной главы, а просто создадим каркас, в котором вы сможете выполнять манипуляции с файлами по своему усмотрению.
Итак, для создания запроса Transform Sample выполните следующие действия:
 щелкните правой кнопкой мыши по созданному параметру Sample File
Parameter и выберите пункт Ссылка (Reference);
 переименуйте созданный запрос в Transform Sample.
На этом этапе вы должны заметить пару вещей. Во-первых, запрос
Transform Sample по-прежнему ссылается в строке формул на параметр
Sample File Parameter. Во-вторых, наш файл отображается просто как иконка. Чтобы открыть содержимое файла, можно щелкнуть по нему правой
кнопкой мыши и выбрать пункт Книга Excel (Excel Workbook), как показано
на рис. 17.6.
Рис. 17.6. Создание запроса Transform Sample
Итак, давайте откроем сам файл:
 щелкните правой кнопкой мыши по файлу East.xlsx и выберите пункт
Книга Excel (Excel Workbook).
Вы увидите, что при выполнении этого действия Power Query не создает
новый шаг, а просто модифицирует шаг Источник (Source), чтобы на нем использовалась функция Excel.Workbook() для создания списка значений, с которыми вы сможете работать;
 щелкните по слову Table в третьей строке таблицы (где в столбце Item
стоит значение Parts).
В результате будет открыто содержимое таблицы Parts из нашего файла
примера (East.xlsx), как показано на рис. 17.7.
466  Глава 17. Параметры и пользовательские функции
Рис. 17.7. Наш запрос Transform Sample создан
Очевидно, что на этом этапе мы могли бы произвести различные преобразования в файле, но, как мы уже договорились, мы не будем этого делать.
Вместо этого мы сразу перейдем к созданию функции Transform Function,
которая впоследствии будет применена ко всем файлам в папке.
Создание функции Transform Function
С учетом того, что в нашем запросе используется параметр для предоставления двоичного файла, этот шаг будет очень простым:
 щелкните правой кнопкой мыши по запросу Transform Sample и выберите пункт Создать функцию (Create Function);
 назовите созданную функцию Transform Function и нажмите на кнопку
OK;
 по желанию вы также можете перенести запрос Sample File в новую
папку.
Хотите – верьте, хотите – нет, но на данный момент мы воссоздали все
действия, выполняемые Power Query автоматически при нажатии на кнопку
объединения файлов, что видно по рис. 17.8. Просто мы пока не воспользовались плодами своего труда.
Рис. 17.8. Все необходимые компоненты успешно созданы
Воссоздание метода объединения файлов  467
Вызов функции Transform Function
Теперь пришло время проверить, что все корректно подцепилось:
 выделите запрос Orders, перейдите на вкладку Главная (Home), нажмите на кнопку Выбор столбцов (Choose Columns) и отметьте только
столбцы Content и Name;
 теперь перейдите на вкладку Добавление столбца (Add Column),
нажмите на кнопку Вызвать настраиваемую функцию (Custom
Function), выберите нашу функцию Transform Function и нажмите на
кнопку OK;
 откройте предварительный просмотр для таблицы во второй строке
(для файла North.xlsx), как показано на рис. 17.9.
Как видите, созданная нами функция работает не только для файла East.
xlsx, но также и для файла North.xlsx.
Рис. 17.9. Наша функция Transform Function извлекает данные из всех файлов в списке
Обновление функции Transform Function
Пока все в порядке. Но будет ли наше решение работать так же волшебно, как механизм от Power Query? Иначе говоря, если мы обновим запрос
Transform Sample, обновится ли функция Transform Function? Давайте проверим:
 выберите запрос Transform Sample;
 щелкните правой кнопкой мыши по заголовку столбца Products и выберите пункт Отменить свертывание других столбцов (Unpivot Other
columns);
 переименуйте столбец Атрибут (Attribute) в Part, а Значение (Value) – в
Units;
 вернитесь к запросу Orders;
 снова проверьте данные для файла North.
468  Глава 17. Параметры и пользовательские функции
Как видно на рис. 17.10, произведенные нами изменения отразились на
всех файлах.
Рис. 17.10. Наши изменения сработали на «отлично»!
Зная это, мы можем развернуть данные для загрузки:
 нажмите на кнопку Развернуть (Expand) в правой части заголовка
столбца Transform Function;
 удалите столбец Content;
 установите типы данных для всех столбцов.
Осталось лишь загрузить полученные данные, чтобы использовать их, но
здесь есть одна потенциальная ловушка.
Мы создали пять новых запросов в текущей сессии, не выбирая место
назначения. В Power BI эту ситуацию разрешить очень просто – достаточно убедиться перед загрузкой, что у всех запросов снят флажок Включить
загрузку (Enable load). А что делать в Excel? При загрузке запросов можно
указать только одно место назначения, и если случайно выбрать импорт на
рабочий лист или в модель данных, вы можете получить ошибку, говорящую
о том, что запрос Sample File не может быть загружен (поскольку является
двоичным значением).
🍌 Примечание. В данном случае мы настоятельно рекомендуем осуществлять
загрузку в Excel при помощи уже известной вам опции Только создать подключение (Only Create Connection), а после того как запросы будут сохранены, изменить место назначения для запроса Orders.
Ключевые выводы
Главное, что вы должны понять из того, что мы проделали в этом разделе, – это то, что кнопка объединения файлов, по сути, осуществляет запуск
макроса, который создает за вас все необходимые компоненты. Вы просто
нажимаете на кнопку, и вершится магия!
Создание настраиваемых функций с помощью параметров  469
Однако опасность этого подхода заключается в том, что вы рискуете неправильно понять, как все это работает изнутри. Вскоре мы перейдем к теме
создания функций вручную, но перед этим необходимо, чтобы вы усвоили
несколько важных моментов.
1. Запрос Transform Sample является изменяемым и обладает свойством
обратной записи в функцию Transform Function. Это означает, что вы
можете добавлять или удалять параметры из запроса Transform Sample,
и это будет тут же отражаться на функции Transform Function.
2. Хотя запрос Transform Sample можно использовать для обновления
функции Transform Function, фактически эта функция не зависит от упомянутого запроса. Вы можете даже удалить запрос Transform Sample,
если хотите, это не повлияет на работоспособность обновления запроса. Конечно, если вы сделаете это, вы лишитесь возможности легко и
быстро обновлять свою функцию с помощью интерфейса пользователя
и области примененных шагов.
3. Не для всех функций требуется динамический пример, как в нашем
случае с запросом Sample File. Фактически его предоставление дает
возможность легко нарушить правила безопасности и может вызвать
ошибки, связанные с Formula.Firewall.
4. Не зацикливайтесь на попытках сделать свои параметры динамическими. Опции Значение по умолчанию (Default Value) и Текущее
значение (Current Value) используются только в окне предварительного просмотра для отладки запроса Transform Sample. Во время выполнения они будут принимать значения, которые вы передадите.
5. Не думайте, что вы обязательно должны использовать параметры для
собственных настраиваемых функций. Логика функций может базироваться как на запросах, так и на параметрах, а может работать и
обособленно.
🍌 Примечание. Настраиваемые пользовательские функции – это очень мощный инструмент, но не думайте, что они обязательно должны использовать
те же методы, что и в примере с объединением файлов!
Создание настраиваемых функций с помощью
параметров
В данном разделе мы рассмотрим достаточно распространенный пример.
Представьте, что кто-то выполнил некие полезные преобразования данных
из текстового файла, полагая, что это будет разовая работа. После этого он
узнает, что ему, оказывается, необходимо применить произведенные изменения ко всем файлам в папке. Вместо того чтобы реализовывать свое
решение с нуля, этот кто-то решает преобразовать написанный запрос в
470  Глава 17. Параметры и пользовательские функции
функцию и использовать ее в дальнейшем для импорта и преобразования
каждого файла.
В идеале мы хотели бы иметь наш привычный запрос Transform Sample и
функцию Transform Function. Но важно то, что запрос Timesheet уже загружен
на рабочий лист, и в нем реализована бизнес-логика на основании этой таблицы. Мы не можем отказаться от проделанной работы, так что именно с
помощью этого запроса мы будем загружать итоговые данные.
Начнем с файла Ch17 Examples\Retrofitting­Begin.xlsx, в котором содержится
два запроса:
 запрос Timesheet преобразовывает файл 2021­03­14.txt, содержащийся
в папке Timesheets;
 запрос FilesList содержит список всех файлов в папке TimeSheets, возвращая пути к файлам и их имена, как показано на рис. 17.11.
Рис. 17.11. Копируем первое значение из запроса FilesList
🙈 Предупреждение. Помните, что в запросах Timesheet и FilesList пути к файлам прописаны статически. Чтобы работать с этим примером, вам необходимо переписать пути так, чтобы они указывали на вашу локальную папку.
В данном решении нам предстоит выполнить четыре следующих шага:
1) создать параметр FilePath;
2) создать новый запрос Timesheet Transform на основе исходного запроса
для работы с параметром;
3) создать новую функцию Timesheet Function;
4) изменить исходный запрос Timesheet таким образом, чтобы вызывалась наша новая функция.
Создание параметра FilePath
Давайте начнем с создания простого параметра, который будет содержать
полный путь к файлу в виде текста:
Создание настраиваемых функций с помощью параметров  471
 выделите запрос FilesList и скопируйте путь к первому файлу, как показано на рис. 17.11;
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Управление параметрами (Manage Parameters) выберите пункт Создать
параметр (New Parameter);
 назовите параметр FilePath;
 в выпадающем списке Тип (Type) выберите пункт Текст (Text);
 в поле Текущее значение (Current Value) вставьте скопированный
путь, как показано на рис. 17.12, и нажмите на кнопку OK.
Рис. 17.12. Настройка текстового параметра
🍌 Примечание. Помните, что текущее значение параметра используется только для отображения результатов в окне предварительного просмотра, и вы
всегда можете изменить его в дальнейшем при помощи диалогового окна
Управление параметрами (Manage Parameters).
Создание запроса Timesheet Transform
Теперь, когда мы создали параметр, нам необходимо написать запрос
Timesheet Transform на базе исходного запроса Timesheet, чтобы он использовал параметр FilePath. На самом деле сделать это даже проще, чем оно звучит:
472  Глава 17. Параметры и пользовательские функции
 щелкните правой кнопкой мыши по запросу Timesheet и выберите
пункт Дублировать (Duplicate);
 переименуйте запрос Timesheet(2) в Timesheet Transform;
 выберите шаг Source запроса Timesheet Transform и нажмите на кнопку
Изменить параметры (Edit Settings);
 в выпадающем списке под словами Путь к файлу (File path) выберите
пункт Параметр (Parameter).
🍌 Примечание. Здесь проявляется истинная мощь параметров. На самом деле
в Power Query очень много где можно вместо примитивного значения указать столбец и/или параметр. К сожалению, запросы очень редко появляются
в этом списке вариантов, даже если они вычисляют примитивное значение.
Если ваш сценарий содержит только один параметр, он будет выбран автоматически. В противном случае вам нужно будет выбрать его вручную, как
показано на рис. 17.13.
Рис. 17.13. Настройка шага Source в запросе Timesheet Transform
Верите вы или нет, но это все, что необходимо, чтобы создать новый запрос
Transform Sample. Теперь, если в вашем параметре FilePath будет установлен
корректный путь к файлу в поле Текущее значение (Current Value), в окне
предварительного просмотра сразу будут показаны данные, что видно по
рис. 17.14.
Создание настраиваемых функций с помощью параметров  473
Рис. 17.14. Статическое имя файла сменилось на параметр,
а вывод по-прежнему работает
🙈 Предупреждение. В области предварительного просмотра показывается
ошибка? Нажмите на вкладке Главная (Home) кнопку Управление параметрами (Manage Parameters) и убедитесь, что для созданного параметра в поле
Текущее значение (Current Value) стоит корректный путь к одному из двух
файлов в папке.
Создание функции Timesheet Function
Поскольку наш запрос Timesheet Transform уже основывается на значении
параметра, создать функцию Transform Function будет проще простого:
 щелкните правой кнопкой мыши по запросу Timesheet Transform и выберите пункт Создать функцию (Create Function), введя имя функции
Timesheet Function.
Вы не поверите, но это все!
🍌 Примечание. Секрет этого способа создания функции состоит в использовании как минимум одного параметра в запросе, на основании которого она
создается. Если параметр используется, вы можете создать функцию на основе запроса, и все будет работать.
Обновление запроса Timesheet
Заключительная часть нашего решения будет самой сложной. Если на этом
этапе сделать что-то не так, можно нарушить всю бизнес-логику, основанную на исходной таблице Timesheet, так что нужно быть очень аккуратными.
К счастью, наш новый запрос Timesheet Transform содержит нужные названия
столбцов из исходной таблицы, так что мы всегда можем производить сверку
на предмет корректности наших действий.
474  Глава 17. Параметры и пользовательские функции
Чтобы обновить запрос Timesheet, необходимо сделать следующее:
 удалить все существующие шаги;
 перенаправить запрос на чтение из запроса FilesList;
 вызвать функцию Timesheet Function и удалить все столбцы, за исключением результатов выполнения функции;
 развернуть оставшиеся столбцы;
 установить типы данных.
В теории, если мы все это сделаем, то получим те же столбцы, что и до
изменений, а исходная бизнес-логика, базирующаяся на таблице Timesheet,
нарушена не будет.
Для начала нам нужно очистить содержимое существующего запроса
Timesheet. Для этого выполните следующие действия:
 выделите запрос Timesheet, после чего перейдите на вкладку Главная (Home) и нажмите на кнопку Расширенный редактор (Advanced
Editor);
 замените текст запроса на приведенный ниже:
let
Source = FilesList
in
Source
🙈 Предупреждение. Не забудьте: если вы назовете ваш запрос Files List, обра-
щаться к нему вы сможете следующим образом: #"Files List". Кроме того, вы
должны строго соблюдать регистры символов при написании имен запросов,
в противном случае Power Query их не обнаружит.
Нажав на кнопку Готово (Done), вы увидите обновленный запрос, вывод
которого совпадает с запросом FilesList и показан на рис. 17.15.
Рис. 17.15. Запрос Timesheet ссылается на FilesList
Создание настраиваемых функций с помощью параметров  475
Продолжим:
 перейдите на вкладку Добавление столбца (Add Column), нажмите на
кнопку Вызвать настраиваемую функцию (Invoke Custom Function)
и выберите в выпадающем списке функцию Timesheet Function;
 в появившемся списке выберите столбец FilePath и нажмите на кнопку OK.
О, нет! Взгляните на рис. 17.16, что получилось!
Рис. 17.16. Ошибка Formula.Firewall не позволяет нам вызвать
нашу настраиваемую функцию
Это одно из самых пугающих сообщений об ошибке в Power Query, и именно его нам хотелось избежать.
🍌 Примечание. С помощью ошибки типа Formula.Firewall Power Query обыч-
но пытается предупредить вас о возможном объединении данных с несовместимыми уровнями конфиденциальности, но также эта ошибка несет и
другие защитные функции. Вам, возможно, захочется отключить настройки
конфиденциальности, но в данном случае это не поможет.
Подробнее об этой ошибке мы поговорим в главе 19, а сейчас нам нужно
что-то сделать, чтобы исключить ее появление. Отключение конфиденциальности нас не спасет, так какой путь выбрать?
Если вчитаться, становится понятно, что в этом сообщении говорится о
ссылке на другой запрос. Так, может, нам пойти в тот запрос, на который мы
ссылаемся, и попробовать устранить проблему там? Иными словами, сработает ли вызов функции в запросе FilesList? Давайте посмотрим:
 удалите шаг Вызвана настраиваемая функция (Invoked Custom
Function) в запросе Timesheet;
 выделите запрос FilesList;
 перейдите на вкладку Добавление столбца (Add Column), нажмите на
кнопку Вызвать настраиваемую функцию (Invoke Custom Function),
выберите в выпадающем списке функцию Timesheet Function, в появившемся списке выберите столбец FilePath и нажмите на кнопку OK.
Ну и как? Как видно на рис. 17.17, сработало!
476  Глава 17. Параметры и пользовательские функции
Рис. 17.17. Успешный вызов настраиваемой функции в запросе FilesList
В конце концов, для нас это не очень большая проблема. Вызвав функцию в
запросе FilesList, нам удалось избежать возникновения неприятной ошибки,
и теперь у нас есть список файлов и их содержимое в виде табличных значений. Ничто не заставляет нас разворачивать полученную колонку в этом
запросе. Но это было бы нам полезно, если бы мы собирались создавать еще
один зависимый запрос с другим представлением этой информации.
А сейчас давайте вернемся к запросу Timesheet и завершим процесс извлечения столбцов:
 выделите запрос Timesheet;
 щелкните правой кнопкой мыши на столбце Timesheet Function и выберите пункт Удалить другие столбцы (Remove Other columns);
 разверните все поля в столбце Timesheet Function с выключенной опцией использования префиксов;
 установите типы данных для всех столбцов.
Последний подводный камень на этом пути может встретиться вам на
этапе загрузки данных в место назначения. Мы снова создали несколько запросов в нашей сессии. Но дело в том, что запрос Timesheet уже был настроен
для загрузки на рабочий лист, так что нам нужно выбрать место назначения
только для новых запросов, ни один из которых не нужен нам на рабочем
листе:
 перейдите на вкладку Главная (Home) и выполните загрузку в виде
подключения.
Как видно на рис. 17.18, данные в таблице изменятся и будут показывать
итоги по обоим файлам из папки Timesheets, и вам не придется менять формулы вручную.
Рис. 17.18. Бизнес-логика (формулы) обновилась без вашего участия
Создание настраиваемых функций вручную  477
Создание настраиваемых функций вручную
До сих пор все вроде было довольно просто. Создаем один или несколько
параметров, используем их в запросе и на его основе создаем функцию.
К сожалению, довольно часто подобный сценарий бывает неприменим.
Откройте файл Ch17 Examples\Pivoting Tables­Begin.xlsx. В нем вы увидите
две таблички на рабочем листе. Наша цель – отменить свертывание обеих
таблиц для получения результата, показанного на рис. 17.19.
Преобразовать это …
… в это …
Рис. 17.19. Нам нужно отменить свертывание таблиц до их объединения
Конечно, мы могли бы подключиться к каждой таблице отдельно, развернуть их, после чего объединить вместе. А что, если преобразования были бы
гораздо более сложными? Нам бы хотелось создать одну функцию, которая
могла бы быть применена ко всем исходным таблицам.
Если отталкиваться от предыдущего примера, можно подумать, что это
будет не слишком сложно. Но есть одна существенная проблема, состоящая
в том, что на данный момент параметры могут хранить только примитивные значения. А поскольку нам пришлось бы передавать в функцию целую
таблицу (структурированное значение), мы не смогли бы воспользоваться
для этого параметрами. Решение одно – писать пользовательскую настраиваемую функцию с нуля.
В целом этот процесс можно условно разделить на три этапа:
1) построить сценарий разового применения;
2) преобразовать построенный сценарий в функцию;
3) вызвать функцию из другого запроса.
Звучит довольно просто. Давайте попробуем реализовать это на практике.
Построение сценария разового применения
Откройте файл Ch17 Examples\Pivoting Tables­Begin.xlsx и сделайте следующее:
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
 в строке формул напишите: =Excel.CurrentWorkbook();
 переименуйте запрос в Sales;
 отфильтруйте столбец Name, выбрав в меню текстовых фильтров критерий Не равно (Does Not Equal) и введя Sales.
478  Глава 17. Параметры и пользовательские функции
🙈 Предупреждение. Не забывайте урок, усвоенный в главе 8, когда мы использовали функцию Excel.CurrentWorkbook() для консолидации таблиц: всегда исключайте при помощи фильтра таблицу, которую собираетесь создавать!
Итак, позаботившись о будущем, мы можем с легкостью реализовать сценарий разового применения для отмены свертывания одной из двух наших
таблиц. Выполните следующие действия:
 щелкните правой кнопкой мыши по любому из двух слов Table в столбце Content и выберите пункт Добавить как новый запрос (Add as New
Query);
 переименуйте созданный запрос в fxUnpivot;
 щелкните правой кнопкой мыши по столбцу Date и выберите пункт
Отменить свертывание других столбцов (Unpivot Other Columns);
 переименуйте столбец Атрибут (Attribute) в Product, а Значение
(Value) – в Units;
 установите типы данных для столбцов: Дата (Date), Текст (Text) и Целое число (Whole Number) соответственно.
При условии что вы начали с таблицы Table2, вывод запроса на данный
момент должен быть таким, как показано на рис. 17.20.
Рис. 17.20. Ну, хорошо, одну таблицу развернули, а как из этого сделать функцию?
Преобразование запроса в функцию
Следующим шагом нам необходимо трансформировать запрос в функцию.
Это действие можно условно разбить на три шага:
1) придумайте имя переменной для хранения данных, которые вы хотите
заменить;
2) отредактируйте запрос и поместите в его начало конструкцию
( variable_name )=>;
3) проверьте ваш запрос на предмет наличия данных, которые вы хотите
заменить, и замените их на имя переменной.
Создание настраиваемых функций вручную  479
🍌 Примечание. Обратите внимание, что пробелы между скобками и именем
переменной являются необязательными, но мы предпочитаем их ставить, поскольку это позволяет сделать код более легким для чтения.
Всегда лучше давать переменным осмысленные имена, говорящие о хранящихся в них данных. Это облегчает процесс самодокументирования кода.
Поскольку наша цель состоит в преобразовании сценария разового применения в функцию, которой можно передать на вход таблицу, мы будем использовать переменную с именем tbl.
Теперь, когда мы определились с именем переменной, давайте отредактируем запрос, чтобы трансформировать его в функцию:
 выделите запрос fxUnpivot, после чего перейдите на вкладку Главная (Home) и нажмите на кнопку Расширенный редактор (Advanced
Editor);
 установите курсор перед ключевым словом let;
 напишите ( tbl )=> и нажмите на клавишу Enter.
Код запроса должен стать таким, как показано на рис. 17.21.
Рис. 17.21. Наша переменная на своем месте
🍌 Примечание. Для выполнения следующего шага вам действительно необхо-
димо понимать, что стоит за кодом запроса на языке M, чтобы точно определить, куда стоит вставить нашу переменную. Наша цель – передать таблицу
на вход запросу, так что мы должны определиться с тем, какой именно шаг
будет принимать нашу таблицу.
Давайте внимательно прочитаем код запроса. Первые два шага явно связаны с рабочей книгой Excel и исключением таблицы с именем Sales, что
оставляет нам две таблицы с рабочего листа. В следующей строке, начинающейся с Table1, происходит извлечение содержимого таблицы Table2. Таким образом, мы могли бы присвоить шагу Table1 значение переменной tbl
как-то так:
Table1 = tbl ,
480  Глава 17. Параметры и пользовательские функции
И хотя это сработало бы, особенной необходимости в этом нет, поскольку
все, что происходит на этом шаге, – это запись значения таблицы для передачи его в следующую строку кода, а именно:
Table.UnpivotOtherColumns(Table1, {"Date"}, "Attribute", "Value"),
Мы знаем, что функция UnpivotOtherColumns() требует в качестве первого
параметра таблицу, которая и хранится в нашей переменной tbl. Таким образом, вместо того чтобы присваивать tbl шагу Table1, а затем передавать
шаг Table1 следующей строке, почему бы просто не передать переменную tbl
напрямую в функцию Table.UnpivotOtherColumns(), как показано на рис. 17.22?
Рис. 17.22. Давайте поместим сюда переменную tbl
Фактически, если мы это сделаем, первые три строки запроса станут нам
не нужны, и мы сможем от них избавиться, как видно на рис. 17.23.
Рис. 17.23. Функция стала гораздо короче. А она вообще работает?
Сохраните запрос, и вы вдруг увидите, что он волшебным образом преобразуется в вид, привычный для функции, как показано на рис. 17.24!
Рис. 17.24. Отлично! Выглядит как функция! А будет ли работать как функция?
Создание настраиваемых функций вручную  481
Вызов функции
Если ваш параметр требует ввода примитивного значения, такого как
текст или число, вы можете просто ввести нужное значение в диалоговом
окне и нажать на кнопку Вызвать (Invoke). Это позволяет легко проверить
работоспособность функции, чтобы убедиться, что с ней все в порядке. К сожалению, при работе со структурированными значениями все несколько
сложнее.
🍌 Примечание. Увы, в данной ситуации не сработает даже трюк со знаком равенства, как в случае с созданием настраиваемого столбца. Формула =Excel.
CurrentWorkbook(){0}[Content] будет воспринята здесь просто как текст.
Простейший способ протестировать функцию – попытаться вызвать ее,
передав на вход таблицу:
 выберите запрос Sales, перейдите на вкладку Добавление столбца
(Add Column) и нажмите на кнопку Вызвать настраиваемую функцию (Invoke Custom Function);
 выберите в выпадающем списке функцию fxUnpivot, убедитесь, что в
списке с именем tbl выбран вариант Content, и нажмите на кнопку OK;
 проверьте область предварительного просмотра для элемента Table1,
как показано на рис. 17.25.
Рис. 17.25. Похоже, что наша функция fxUnpivot работает
Как видите, хотя параметры могут быть очень полезны в работе, при создании настраиваемой функции использовать их совсем не обязательно. Давайте завершим запрос:
 щелкните правой кнопкой мыши на столбце fxUnpivot и выберите пункт
Удалить другие столбцы (Remove Other columns);
482  Глава 17. Параметры и пользовательские функции
 разверните все поля в столбце fxUnpivot с выключенной опцией использования префиксов;
 установите типы данных для всех столбцов.
В результате наши данные будут выглядеть так, как показано на рис. 17.26,
и если в будущем в список будет добавлена еще одна таблица товаров, она
будет включена в операцию отмены свертывания.
Рис. 17.26. Результат выполнения отмены свертывания
Отладка настраиваемых функций
Вы наверняка заметили, что без создания параметра мы не можем сохранить копию запроса Transform Sample. Это один из главных недостатков настраиваемых функций: при работе с ними мы теряем возможность свободно
перемещаться по шагам. Это серьезно затрудняет процесс отладки функций.
И хотя это нельзя назвать идеальным способом, все же существует возможность преобразовать функцию обратно в запрос для проведения тестирования. К сожалению, речь идет только о временной смене состояния, поскольку
перевод функции в пригодный для отладки вид фактически выводит ее из
разряда функций, что ведет к прерыванию всех последующих запросов во
время отладки. Несмотря на это, иного способа отладки не существует, так
что мы опишем этот процесс.
Чтобы вернуть область примененных шагов, а с ней и возможность для отладки функции, необходимо выполнить обратное преобразование функции
в запрос. Для этого нужно сделать следующее:
1) закомментировать строку, переводящую запрос в статус функции;
2) продублировать закомментированную переменную и инициализировать ее нужным значением.
Если не выполнить одно из перечисленных действий, функция или запрос
будет возвращать в лучшем случае неправильный результат, а в худшем –
ошибку.
Закомментировать код в языке M можно при помощи двух символов косой черты (//) в начале строки. Это говорит движку Power Query о том, что
оставшаяся часть строки не должна выполняться.
Создание настраиваемых функций вручную  483
Чтобы продублировать переменную, необходимо создать новый шаг после
строки с ключевым словом let. Синтаксис этой строки может быть таким, как
показано ниже:
Variable_name = assign_value_here ,
В качестве имени переменной нужно выбрать то же слово, которое стояло в
скобках в начале функции, а строку необходимо завершить запятой. Давайте
попробуем:
 выделите запрос fxUnpivot, после чего перейдите на вкладку Главная (Home) и нажмите на кнопку Расширенный редактор (Advanced
Editor);
 измените текст запроса так, чтобы первые три строки были следующими:
//( tbl )=>
let
tbl = Excel.CurrentWorkbook(){0}[Content] ,
🍌 Примечание. Не забудьте завершающую запятую в конце строки, иначе ваш
код не будет работать!
🙈 Предупреждение. Имейте в виду, что при вызове настраиваемой функции
она будет заключена в новую структуру let/in. В этом случае вам необходимо
закомментировать первые и последние две строки функции, чтобы превратить ее обратно в запрос.
В результате ваш код должен выглядеть так, как показано на рис. 17.27.
Рис. 17.27. Модифицированный код для преобразования функции обратно в запрос
После нажатия на кнопку OK вы снова сможете перемещаться по запросу привычным образом и смотреть, что в нем происходит, как показано на
рис. 17.28.
484  Глава 17. Параметры и пользовательские функции
Рис. 17.28. Примененные шаги вернулись, но что-то не так с запросом Sales
Приятно, что мы снова можем видеть примененные шаги, включая шаг с
инициализацией переменной tbl. Но есть и плохие новости…
🙈 Предупреждение. Пока ваша функция находится в режиме отладки, все ссылающиеся на нее запросы работать не будут.
Восстановление функциональности
Чтобы преобразовать запрос обратно в функцию, вам снова потребуется
править код на языке M, на этот раз следующим образом:
 удалите символы // из первой строки;
 добавьте символы // перед строкой с инициализацией временной переменной.
После этого ваша функция восстановит свою работу, и все запросы, ссылающиеся на нее, также смогут функционировать в полном объеме.
Последнее, что хотелось бы отметить по поводу настраиваемых функций, –
это то, что хорошей практикой считается указание типов данных для всех
переменных, хотя это и не обязательное требование. Для этого достаточно
добавить к объявлению переменной инструкцию as <type>. В нашем случае
код функции с указанием типа данных для переменной tbl мог выглядеть так,
как показано на рис. 17.29.
Рис. 17.29. Определение типа данных для переменной
Таблицы динамических параметров  485
🙈 Предупреждение. Если вы забудете закомментировать строку с инициализацией временной переменной tbl, во время запуска функции содержимое
переданного в нее параметра будет перезаписано. Так что лучше не забывать этого делать!
Таблицы динамических параметров
Размышляя о параметрах в Power Query, можно придумать массу способов для
их применения, помимо динамического изменения пути к файлу или таблице. К примеру, было бы неплохо иметь возможность при помощи параметров
фильтровать ваши данные по конкретному филиалу или подразделению.
Хотя параметры – это очень здорово, в работе с ними существуют определенные недостатки. Первое, что приходит на ум, – это то, что параметры
работают только со статическими значениями. Нам бы очень хотелось управлять параметрами Power Query посредством формул Excel, передавая текущие
значения из рабочего листа прямо во время выполнения. Кроме того, для
обновления значения параметра вам обязательно требуется воспользоваться
кнопкой Управление параметрами (Manage Parameters), которая присутствует только в редакторе Power Query. А это приводит к дополнительным щелчкам мыши и ожиданию каждый раз, когда вам необходимо изменить параметр. Помимо того что это долго, это еще и не очень удобно для пользователя.
В данном разделе мы посмотрим, как можно создать таблицу и функцию
fnGetParameter для решения этих проблем. Эту технику особенно удобно реализовывать в Excel, но и в Power BI она также применима, если создать там
таблицу с параметрами и значениями. При этом в Power BI вас ждет несколько связанных с этим приемом неудобств:
1) вам по-прежнему придется открывать редактор Power Query для изменения значений параметров;
2) пользователи не смогут легко менять значения параметров после публикации модели данных Power BI, поскольку у них не будет доступа к
изменению кода на языке M в опубликованной модели.
Из преимуществ можно отметить то, что при такой реализации все параметры будут собраны в одной табличке, что очень удобно для разработчика
модели.
🍌 Примечание. Как вы увидите, мы не будем создавать сами параметры, а
обойдемся извлечением из таблицы примитивных значений и передачей их
в запросы.
Проблема с динамическими путями к файлам
При работе с данными, размещенными в интернете, совместно использовать файлы очень легко. Вы можете воспользоваться любым из множества
486  Глава 17. Параметры и пользовательские функции
доступных методов, для того чтобы поделиться файлом. При открытии файла получившим его пользователем ему может потребоваться подключиться
к данным, настроить уровень конфиденциальности или пройти аутентификацию, но это вполне ожидаемо. Поскольку данные размещаются в интернете, доступ к ним может передаваться без необходимости обновления
коннекторов источника данных в файле.
А что, если вы реализовали свое решение наподобие Timesheet средствами
Excel? Исходные данные в этом случае будут храниться в папках на локальном компьютере или в сетевом окружении. Итак, вы архивируете проект
в виде целой папки и посылаете своему коллеге по работе – примерно так,
как мы поступили с сопроводительными файлами к этой книге.
Получив архив, коллега распаковывает его в папку на своем диске, открывает файл и пытается обновить данные. Что произойдет? Ответ зависит
от того, разархивировал ли он папку в то же расположение, что и автор, или
нет. В первом случае обновление сработает нормально, а во втором, как и
ожидалось, – нет. В результате пользователю придется переписывать все
пути к файлам в проекте на локальные папки.
🍌 Примечание. Приведенная выше проблема грозит разработчикам решений
в Power BI, основывающих их на локальных источниках данных, но чаще она
возникает в сценариях с использованием Excel, поскольку в этой среде исходные данные обычно хранятся локально.
Давайте попробуем перенести наш пример Timesheet в контекст реального
бизнеса. Вы создали основной файл консолидации данных, сохранив его в
папке H:\Payroll, и на протяжении многих месяцев сохраняли файлы с расписаниями в подпапке с названием H:\Payroll\Timesheets. После года упорного
труда вы, наконец, получили недельку отдыха и хотите передать свои функции по работе с этими данными коллеге. Но здесь есть проблема. Дело в том,
что на его компьютере путь к вашей сетевой папке звучит так: J:\HR\Payroll.
Вместо того чтобы переписывать все пути к файлам в проекте, а потом возвращать все обратно, вам бы хотелось, чтобы пути к исходным файлам собирались динамически относительно папки с рабочей книгой. В этом случае
будет совершенно не важно, располагается исходная папка на компьютере
коллеги по адресу J:\HR\Payroll или H:\Payroll.
Проблема в том, что на данный момент язык M не располагает средствами
обращения к папке, в которой находится рабочая книга, тогда как в Excel
такие средства есть.
🍌 Примечание. В Power BI нет функции для определения местоположения ис-
ходного файла, как в Excel. Если бы мы реализовывали это решение в Power
BI, мы бы сохраняли наши файлы в папке SharePoint и подключались к ней,
поскольку в этом случае данные размещались бы в интернете и путь к ним
не менялся бы.
Таблицы динамических параметров  487
Реализация таблицы динамических параметров
Давайте вернемся к нашему примеру Timesheet и посмотрим, можно ли
сделать так, чтобы пути к файлам в нем были полностью динамическими и
он работал у всех пользователей.
🍌 Примечание. Вы можете следить за нашими действиями в файле Ch17
Examples\Retrofitting-Complete.xlsx.
Разделим процесс создания таблицы параметров условно на три шага.
1. Создание таблицы в Excel.
2. Создание функции для извлечения значений из таблицы.
3. Изменение существующих запросов для вызова функции.
Создание таблицы параметров
Первое, что нам необходимо сделать, – это создать таблицу, в которой
будут располагаться наши параметры. Эта таблица должна отвечать определенным требованиям, чтобы в дальнейшем не возникало проблем с использованием нашей функции.
Создайте таблицу, показанную на рис. 17.30, в диапазоне ячеек F9:G10 на
рабочем листе Timesheet.
Рис. 17.30. Таблица Parameters
Обратите внимание на ключевые моменты, касающиеся созданной таблицы:
 заголовок первого столбца должен быть Parameter;
 заголовок второго столбца – Value;
 имя таблицы – Parameters.
488  Глава 17. Параметры и пользовательские функции
🙈 Предупреждение. Это «умная» таблица в Excel, созданная при помощи соче-
тания клавиш CTRL+T, и очень важно, чтобы все упомянутые характеристики
были заполнены правильно. Если хотя бы один заголовок будет написан с
неточностями, функция работать не будет.
Итак, таблица подготовлена для хранения динамических параметров в
нашем решении. При этом имена параметров будут располагаться в первом
столбце, а их значения – во втором.
🍌 Примечание. В столбце Values могут находиться как статические значения,
так и значения на основе выпадающих списков с проверкой данных или
формулы. Как именно значения будут попадать в эти ячейки – целиком и
полностью зависит от разработчика.
Теперь нам необходимо определить путь к текущей рабочей книге. Для
этого введите следующую формулу в ячейку G10:
=ЕСЛИОШИБКА(ЛЕВСИМВ(ЯЧЕЙКА("filename";A1);НАЙТИ("[";ЯЧЕЙКА
("filename";A1);1)-1); "Необходимо сохранить рабочую книгу!")
=IFERROR(LEFT(CELL("filename",A1),FIND("[",CELL("filename",A1),1)-1),
"Workbook needs to be saved!")
🍌 Примечание. Если ваш файл не сохранен на диске, эта формула не вернет
путь к нему, поскольку он просто неизвестен. В этом случае вам на помощь
придет последний аргумент функции ЕСЛИОШИБКА (IFERROR) с указанием к
действию.
Если вы все сделали правильно, то увидите в таблице параметр с именем
File Path и значением, указывающим путь к папке с текущим рабочим листом. Нам же нужно, чтобы путь указывал на подпапку TimeSheets, поскольку
именно в ней находятся нужные нам файлы. В связи с этим давайте немного
изменим формулу, добавив к ней путь к нужной директории, как показано
на рис. 17.31:
=ЕСЛИОШИБКА(ЛЕВСИМВ(ЯЧЕЙКА("filename";A1);НАЙТИ("[";ЯЧЕЙКА
("filename";A1);1)-1)&"TimeSheets\"; "Необходимо сохранить рабочую книгу!")
=IFERROR(LEFT(CELL("filename",A1),FIND("[",CELL
("filename",A1),1)-1)&"TimeSheets\", "Workbook needs to be saved!”)
Рис. 17.31. Динамический путь к папке средствами Excel
Таблицы динамических параметров  489
🙈 Предупреждение. Применительно к пакету Microsoft 365 есть одно неудоб-
ство, связанное с тем, что пути к файлам, находящимся в папках, синхронизированных со службами OneDrive или SharePoint, будут начинаться с https://,
а не с буквы локального или сетевого диска. Для подключения к таким файлам необходимо использовать другой коннектор. Если же вы хотите, чтобы
в вашем решении использовались локальные пути, вы можете сделать это,
временно отключив синхронизацию с OneDrive и открыв файл локально.
Реализация функции fnGetParameter
Теперь, когда у нас есть таблица параметров, необходимо реализовать метод доступа к ней из Power Query. Это можно сделать при помощи следующей
настраиваемой функции:
( getValue as text ) =>
let
ParamTable = Excel.CurrentWorkbook(){[Name="Parameters"]}[Content],
Result = ParamTable{[Parameter=getValue]}?[Value]?
in
Result
🍌 Примечание. Исходный код этой функции находится в файле fnGetParameter.
txt в папке Ch17 Examples. В дополнение к коду в файле находятся и инструкции по использованию функции, а также формула, возвращающая путь
к файлу в ячейке Excel. Вы можете сохранить содержимое файла на будущее
и пользоваться им как шаблоном при необходимости.
В этой функции выполняется подключение к таблице Parameters, после
чего выбирается из нее строка с нужным параметром. Затем из этой строки
возвращается значение из столбца Value. Именно по причине того, что в
этой функции имена таблицы и полей прописаны статически, такое важное
значение имеет правильность составления таблицы параметров в Excel.
Вместо того чтобы вручную вводить текст функции, откройте файл Ch17
Examples\fnGetParameter.txt и скопируйте его содержимое. Так будет гораздо
проще. Далее выполните следующие действия:
 нажмите на кнопку Получить данные (Get Data) на вкладке Данные
(Data) и в выпадающем меню Из других источников (From Other
Sources) выберите пункт Пустой запрос (Blank Query);
 перейдите на вкладку Главная (Home), нажмите на кнопку Расширенный редактор (Advanced Editor) и выделите все строки кода, написанного автоматически;
 нажмите сочетание клавиш CTRL+V, чтобы вставить содержимое из
буфера обмена в запрос;
490  Глава 17. Параметры и пользовательские функции
 нажмите на кнопку Готово (Done);
 измените имя функции на fnGetParameter.
Все, готово.
Вызов функции
Теперь, когда у нас есть таблица параметров и функция для доступа к ним,
осталось внести изменения в существующий запрос, чтобы он использовал
этот инструментарий. Это позволит нам извлекать путь к файлам из ячейки и использовать его в запросе. А поскольку путь будет обновляться при
каждом пересчете рабочей книги, он всегда будет указывать на актуальное
местоположение файлов.
Для изменения исходного запроса вам даже не придется покидать редактор Power Query:
 щелкните правой кнопкой мыши по запросу FilesList и выберите пункт
Расширенный редактор (Advanced Editor);
 непосредственно за строкой с ключевым словом let вставьте следующую строку:
fullfilepath = fnGetParameter("File Path"),
На этом этапе запрос должен выглядеть так, как показано на рис. 17.32.
Рис. 17.32. Вызов функции fnGetParameter
Обратите внимание, что мы здесь создали новую переменную с именем
fullfilepath, в которой будем хранить значение параметра File Path из таблицы Excel.
🙈 Предупреждение. Хотя вы можете пропустить этот шаг и просто встроить
вызов функции fnGetParameter в следующей строке, мы советуем этого не делать. Создание отдельного шага для каждого вызова функции fnGetParameter
в начале кода позволит избежать ошибки Formula Firewall, с которой мы
встречались в предыдущих разделах, когда нам был запрещен доступ к источнику данных на поздних шагах запроса.
Таблицы динамических параметров  491
К тому же, как вы увидите совсем скоро, вызов функции на отдельном шаге
облегчит процесс отладки запроса.
Выполните следующие действия:
 нажмите на кнопку Готово (Done);
 выделите шаг fullfilepath в окне примененных шагов.
Как показано на рис. 17.33, полный путь к папке с файлами отображается
верно, что позволяет думать, что с этим шагом мы справились нормально.
Рис. 17.33. В переменной fullfilepath путь к папке отображается корректно
Теперь, когда мы знаем, что написанная нами функция возвращает правильный путь к папке, обращаясь при этом к ячейке Excel с формулой, можно
заменить статический путь в шаге Source на переменную:
 откройте расширенный редактор и найдите путь к папке в шаге Source;
 замените статический путь, включая кавычки, на переменную
fullfilepath.
Теперь три первые строки функции должны выглядеть так:
let
fullfilepath = fnGetParameter("File Path"),
Source = Folder.Files(fullfilepath),
🍌 Примечание. Эти изменения в запросе вы должны внести вручную посред-
ством расширенного редактора или строки формул. Сделать это при помощи
кнопки с шестеренкой справа от имени шага Source не удастся, поскольку
fullfilepath не является ни параметром, ни папкой в операционной системе
Windows.
Выполнив все изменения, нажмите на кнопку Готово (Done), и вы увидите,
что все шаги запроса по-прежнему будут прекрасно работать, как показано
на рис. 17.34.
492  Глава 17. Параметры и пользовательские функции
Рис. 17.34. Измененный запрос по-прежнему работает
Применение таблиц параметров
Работая с Power Query в Excel, вы можете максимально эффективно и гибко
использовать таблицы параметров в своих сценариях. Если ваше решение
предназначено для работы внутри компании и должно функционировать
в разных подразделениях, вы можете настроить таблицы параметров для
динамического извлечения путей к папкам относительно базового пути
вашего проекта. Если же вы работаете в качестве консультанта с разными
клиентами, переоценить пользу от этой техники будет просто невозможно,
поскольку структура папок у ваших заказчиков практически всегда будет
коренным образом отличаться от вашей файловой иерархии. Последнее, что
хочется делать в обеих ситуациях, – это требовать от конечного пользователя
научиться разбираться в коде на языке M, чтобы он мог вносить изменения
самостоятельно.
Откройте файл Dynamic FilePath­Complete.xlsx и обновите данные, как показано на рис. 17.35. Если папка TimeSheets и файлы в ней располагаются на
вашем компьютере по тому же пути, который прописан в ячейке Excel, и не
синхронизированы со службами OneDrive или SharePoint, обновление сработает нормально.
Рис. 17.35. Совершенно другой (локальный) путь в ячейке
не сказался на работоспособности решения!
Применение таблиц параметров  493
Но мощь применения таблиц параметров не ограничивается подобными
сценариями. Вот лишь несколько примеров использования этой техники:
 построение таблицы с календарем на основе дат из ячеек в Excel;
 использование в качестве фильтра для таблицы на основе значений в
ячейках Excel;
 определение того, какую из четырех таблиц Excel загружать в решение.
С использованием настраиваемых функций для чтения данных из таблиц
Excel мы можем легко реализовать все перечисленные задачи. Это позволит
нам не только динамически управлять содержимым в наших сценариях, но
и даст возможность генерировать данные в более знакомом нам контексте.
А иногда использование показанного здесь приема может стать единственным возможным вариантом добиться поставленной цели с применением
Power Query.
Глава
18
Техники работы с датой
и временем
При выполнении любого вида анализа или формировании отчетов, в которых присутствуют даты, вам просто необходимо, чтобы в вашем решении
присутствовала таблица с календарем (calendar). Многие, кто работает с
Excel, организуют подобные календарные сведения в виде статических табличек на рабочем листе, связывая их со своими данными при помощи формул или размещая в модели данных. Неудобство состоит в том, что такие
таблички зачастую нуждаются в ручном обновлении в конце финансового
года. Неужели не хочется раз и навсегда избавиться от этих вынужденных
действий?
В данной главе мы рассмотрим различные способы создания таблиц с календарями, а также узнаем, как можно сгенерировать таблицы с отдельными
записями на базе определенного расписания.
Давайте будем честными и скажем, что создавать календари в Power Query
на лету не так-то просто, к тому же это требует немалых ресурсов. Вы могли
бы спросить, не будет ли в таком случае лучше просто загрузить календарь из
корпоративной базы данных. Ответ здесь однозначен – будет! Если у вас есть
нужный вам календарь в базе данных, используйте его. А что делать, если его
нет? Что, если на вас со всех сторон сыплются файлы Excel, а у вас даже нет
доступа к нормальному календарю? Вот здесь вам и понадобится эта глава.
При создании календаря важно помнить о трех ключевых моментах:
о дате начала календаря, дате его окончания и необходимой гранулярности
(granularity) данных. Иными словами, нужна ли нам аналитика по дням, неделям, месяцам и т. д. В этой главе мы посмотрим, как можно создать отдельные поля для каждого из этих компонентов и использовать их в рамках
сценариев, связанных с датами.
Определение границ календаря
Каждый календарь характеризуется своими определенными границами, а
именно датой начала отсчета календаря и датой окончания. Для создания
этих границ можно использовать различные инструменты, в числе которых:
Определение границ календаря  495
 параметры;
 таблицы динамических параметров (которые мы изучали в главе 17);
 данные, динамически сгенерированные на основании набора данных.
Проблема с использованием параметров состоит в том, что их значения могут
быть заданы только статически, и для их изменения потребуется воспользоваться редактором Power Query. Таблицы динамических параметров – отличное
решение для Excel, но мы отдаем предпочтение варианту создания календарей
на основе имеющихся данных. Этот способ обеспечивает гарантию того, что при
обновлении данных границы календаря будут установлены правильно.
🍌 Примечание. В разделе с календарями из этой главы используются таблицы
с самыми разными календарными форматами. Чтобы не увеличивать размер
главы до невероятных размеров, мы не будем приводить пошаговые сценарии для создания всех этих календарей. Зато в сопроводительной папке присутствует файл Ch18 Examples\Calendar Tables.xlsx с разными календарями.
Динамическое создание границ календаря
Определение границ календаря при помощи Power Query – совсем простая
задача, если вы будете следовать приведенным в этом разделе инструкциям.
Но перед тем как их вам открыть, мы проговорим несколько важных моментов.
1. Мы настоятельно рекомендуем вам создавать календари, охватывающие весь финансовый год целиком, основываясь на ваших данных.
2. Начальную дату для календаря необходимо извлекать из таблицы, которая будет гарантированно содержать самую раннюю дату для ваших
данных. Обычно лучше всего для этой цели подходит таблица с продажами.
3. Конечную дату для календаря берем из таблицы с самой поздней датой.
Здесь можно использовать, например, таблицу с планированием – при
условии что она всегда заполняется раньше фактических продаж за
этот период.
С учетом сказанного выше, а также предполагая, что столбцы с датами в
ваших таблицах называются Date, инструкции для определения границ календаря будут такими, как показано в табл. 18.1.
Таблица 18.1. Шаги для заполнения начальной и конечной дат календаря
Шаг
Начальная дата
Конечная дата
1
Создайте ссылку на таблицу с самой
ранней датой
Создайте ссылку на таблицу с самой
поздней датой
2
Удалите все столбцы, за исключением
[Date]
Удалите все столбцы, за исключением
[Date]
496  Глава 18. Техники работы с датой и временем
Шаг
Начальная дата
Конечная дата
3
Установите фильтр на столбец по дате,
выбрав вариант Является самой ранней
(Is Earliest)
Установите фильтр на столбец по дате,
выбрав вариант Является последней (Is
Latest)
4
Удалите дубликаты
Удалите дубликаты
5
На вкладке Преобразование (Transform)
нажмите на кнопку Дата (Date) и выберите в меню Год (Year) пункт Начало года
(Start of Year)
На вкладке Преобразование (Transform)
нажмите на кнопку Дата (Date) и выберите в меню Год (Year) пункт Конец года
(End of Year)
6
Необязательно: осуществите сдвиг дат для нестандартных периодов
Смотрите раздел о корректировке начальной и конечной дат для нестандартных
финансовых периодов далее в этой главе
7
Измените тип данных столбца на Дата
(Date)
Измените тип данных столбца на Дата
(Date)
8
Щелкните правой кнопкой мыши по
ячейке с датой и выберите пункт Детализация (Drill Down)
Щелкните правой кнопкой мыши по
ячейке с датой и выберите пункт Детализация (Drill Down)
9
Назовите запрос StartDate
Назовите запрос EndDate
10
Загрузите запрос в виде подключения
Загрузите запрос в виде подключения
🙈 Предупреждение. Имейте в виду, что эта инструкция предполагает наруше-
ние процесса свертывания запросов. И снова повторим: если ваш отдел ИТ
предоставит вам доступ к корпоративной таблице с календарем, лучше воспользоваться им. Эти инструкции для тех, кто не располагает таким благом,
а работу выполнить нужно.
Большинство из этих шагов достаточно простые, но по поводу трех из них
мы хотели бы дать пояснения.
Шаг 6: для обычного 12-месячного календаря, заканчивающегося 31 декабря, вы можете пропустить этот шаг. Далее в этой главе мы поговорим
о том, как поступать с календарями для нестандартных финансовых
периодов.
Шаг 7: причина, по которой мы переопределяем тип данных на седьмом шаге, состоит в гарантии того, чтобы на следующем шаге была
корректно выполнена детализация данных с использованием формата
{0}. Иногда этого не происходит, если пропустить шаг 7.
Шаг 8: при выполнении детализации очень важно, чтобы вы щелкнули
правой кнопкой мыши по самой дате, а не по заголовку столбца, как
показано на рис. 18.1.
Определение границ календаря  497
Рис. 18.1. Детализация по начальной дате
Если корректно выполнить восьмой шаг, дата окажется представлена в
виде примитивного значения, что видно на рис. 18.2.
Рис. 18.2. Начальная дата должна основываться на формате {0}
и быть представлена в виде примитивного типа Дата (Date)
🍌 Примечание. Дата будет отображаться в соответствии с вашим форматом дат
по умолчанию, так что вы можете видеть ее иначе.
🙈 Предупреждение. Если вместо ячейки щелкнуть правой кнопкой мыши по
заголовку столбца и выбрать пункт Детализация (Drill Down), вы получите
список, что для нашей задачи совсем не подходит.
Корректировка начальной и конечной дат
для нестандартных финансовых периодов
Наиболее распространенным форматом календаря в мире является 12-месячный, но, разумеется, далеко не у всех финансовый год заканчивается
31 декабря. К счастью, в Power Query можно довольно легко сдвинуть начальную и конечную даты календаря в соответствии с характеристиками вашего
финансового периода.
С этой целью мы рекомендуем вам создать отдельный запрос YEMonth
следующим образом:
 создайте пустой запрос;
 переименуйте его в YEMonth;
498  Глава 18. Техники работы с датой и временем
 в строке формул введите порядковый номер последнего месяца в вашем отчетном периоде;
 загрузите запрос в виде подключения.
Если представить, что в вашей компании финансовый год заканчивается
30 сентября, вывод вашего запроса должен выглядеть так, как показано на
рис. 18.3.
Рис. 18.3. Настройка для финансового года, длящегося по сентябрь
После создания запроса YEMonth вы можете следовать инструкции по установке начальной и конечной дат для календаря, представленной выше, но с
расширенным шестым шагом, как показано в табл. 18.2.
Таблица 18.2. Расширение шестого шага для нестандартных финансовых периодов
Шаг
Начальная дата
Конечная дата
6A
На вкладке Добавление столбца (Add
Column) нажмите на кнопку Настраиваемый столбец (Custom Column)
На вкладке Добавление столбца (Add
Column) нажмите на кнопку Настраиваемый столбец (Custom Column)
6B
Назовите столбец Custom и используйте
следующую формулу: =Date.AddMonths(
[Date], YEMonth – 12)
Назовите столбец Custom и используйте
следующую формулу: =Date.AddMonths(
[Date], YEMonth )
6C
Щелкните правой кнопкой мыши по
столбцу [Custom] и выберите пункт
Удалить другие столбцы (Remove Other
columns)
Щелкните правой кнопкой мыши по
столбцу [Custom] и выберите пункт
Удалить другие столбцы (Remove Other
columns)
6D
Переименуйте столбец [Custom] в Date
Переименуйте столбец [Custom] в Date
🍌 Примечание. Если вы уже создали запросы StartDate и EndDate и вам необ-
ходимо расширить шаг 6, убедитесь, что начнете вносить изменения начиная
с шага Calculated Start (End) of Year.
На рис. 18.4 показана разница в выводе запросов StartDate и FiscalStartDate
с расширенным шестым шагом. Здесь очень важно отметить, что первая
продажа в таблице Sales зафиксирована 1 января 2018 года, так что шаблон
Определение границ календаря  499
сдвигает даты так, чтобы был охвачен весь финансовый год вне зависимости
от того, длится он с 1 января по 31 декабря или с 1 октября по 30 сентября.
Рис. 18.4. Сравнение результатов двух запросов
для определения начальной даты календаря
🍌 Примечание. Запросы FiscalStartDate и FiscalEndDate содержатся в одном и
том же файле, чтобы можно было демонстрировать на нем все примеры.
Корректировка начальной и конечной дат
для 364-дневного календаря
Хотя видов рабочих календарей существует бесчисленное множество,
следующим по популярности после стандартного 12-месячного календаря
является 364­дневный календарь (364 day calendar), состоящий из четырех
кварталов по 13 недель, а месяцы в котором могут состоять из четырех или
пяти недель в формате 4-4-5, 4-5-4 и 5-4-4. Такой календарь определяется на
основе недель, из которых состоят кварталы и месяцы, при этом год всегда
будет насчитывать 364 дня, а конец года может выпадать на разные даты.
Сейчас мы хотим внести изменения в определение начальной и конечной
дат для этого специфического календаря. Опять же, чтобы все работало нормально, мы рекомендуем создать с этой целью отдельные запросы. На этот
раз запрос для выявления первого дня года будет называться Start364, и с его
помощью можно будет вычислить начальную дату любого финансового года
компании. Итак, сделайте следующее:




создайте пустой запрос;
переименуйте его в Start364;
в строке формул введите начальную дату любого финансового года;
загрузите запрос в виде подключения.
Учитывая, что финансовые годы начинались 1 января 2017 года, 31 декабря
2017 года и 30 декабря 2018 года (все они приходились на воскресенье), вы
можете ввести любую из этих дат в запрос Start364, как показано на рис. 18.51.
1
Powered by TCPDF (www.tcpdf.org)
Для недель, начинающихся с понедельника, даты будут другими. – Прим. перев.
500  Глава 18. Техники работы с датой и временем
Рис. 18.5. 1 января 2017 года (воскресенье) – подходящая дата
начала финансового года для компании
🍌 Примечание. Если у вас на панели Запросы (Queries) не отображаются соответствующие иконки для дат, попробуйте вводить их в формате
=#date(2017,1,1).
Теперь, когда у нас есть отдельный запрос Start364, мы можем использовать исходную инструкцию для заполнения начальной и конечной дат календаря из табл. 18.1 с изменениями в шестом шаге, показанными в табл. 18.3.
Таблица 18.3. Расширение шестого шага для 364-дневного финансового года
Шаг
Начальная дата
Конечная дата
6A
На вкладке Добавление столбца (Add
Column) нажмите на кнопку Настраиваемый столбец (Custom Column)
На вкладке Добавление столбца (Add
Column) нажмите на кнопку Настраиваемый столбец (Custom Column)
6B
Назовите столбец Custom и используйте
следующую формулу: =Date.AddDays(
Start364, 364 * Number.Round(
Duration.Days( [Date] – Start364 )
/364 , 0 ) )
Назовите столбец Custom и используйте
следующую формулу: =Date.AddDays(
Start364, 364 * Number.RoundUp(
Duration.Days([Date] – Start364 ) /
364 , 0 ) –1 )
6C
Щелкните правой кнопкой мыши по
столбцу [Custom] и выберите пункт
Удалить другие столбцы (Remove Other
columns)
Щелкните правой кнопкой мыши по
столбцу [Custom] и выберите пункт
Удалить другие столбцы (Remove Other
columns)
6D
Переименуйте столбец [Custom] в Date
Переименуйте столбец [Custom] в Date
В нашем примере самой ранней точкой данных является дата 1 января
2018 года. Это означает, что наш 364-дневный календарь должен начинаться
с 31 декабря 2017 года, поскольку это первая дата финансового года, включающего самую раннюю нашу транзакцию. И как видно на рис. 18.6, все так
и оказалось.
Календари с последовательными датами  501
Рис. 18.6. Запрос StartDate364 вернул правильный результат, несмотря на то что
в запросе Start364 указана первая дата предыдущего финансового года
🍌 Примечание. Опять же, чтобы все примеры могли быть представлены в одном файле, мы сохранили наши запросы в нем под именами StartDate364
и EndDate364.
Календари с последовательными датами
Теперь, когда мы знаем, как устанавливать начальную и конечную даты для
различных календарей, давайте приступим к созданию самой таблицы с
календарем. Наша таблица будет содержать даты от StartDate до EndDate с
гранулярностью до дня – по одной записи для каждого дня без пропусков.
Создание календаря
После определения запросов StartDate и EndDate вы обнаружите, что создание таблицы с календарем будет сведено к простейшей последовательности
следующих действий:
 создайте пустой запрос;
 в строке формул введите следующую формулу:
= { Number.From( StartDate ) .. Number.From( EndDate ) }
 нажмите на кнопку В таблицу (To Table), расположенную в левой части вкладки Средства для списков (List Tools), а затем нажмите на
кнопку OK;
 переименуйте столбец Column1 в Date;
 измените тип данных столбца Date на Дата (Date);
 переименуйте запрос в Calendar (выбор имени остается на ваше усмотрение).
502  Глава 18. Техники работы с датой и временем
🍌 Примечание. К сожалению, мы не можем создать список дат при помощи
синтаксиса { .. }, зато можно сделать список аналогичных числовых
значений. Именно с этой целью мы предварительно перевели даты в
последовательные числа при помощи функции Number.From(). Хотя мы могли
преобразовать в числовой формат наши исходные запросы, но предпочли
этого не делать, чтобы они отображались в окне предварительного просмотра как даты, что облегчит работу с ними в будущем.
В результате мы получим полностью динамическую таблицу дат с гранулярностью до дня, охватывающую все финансовые годы, за которые в нашей
модели данных присутствуют транзакции, как показано на рис. 18.7.
Рис. 18.7. Полностью динамическое произведение искусства
На данном этапе нам необходимо убедиться в том, что вы уловили суть.
Хотя на рис. 18.7 показан стандартный календарь, начинающийся 1 января и
заканчивающийся 31 декабря, вы можете легко изменить формат календаря,
подставив другие значения во вспомогательные запросы StartDate и EndDate,
на основе которых и строится календарь.
🙈 Предупреждение. Если в запрос EndDate поместить более раннюю дату по
сравнению со StartDate, будет сгенерирован пустой список, а в результате
вы получите ошибку на уровне шага, когда попытаетесь переименовать
несуществующий столбец Column1. В связи с этим вам следует быть очень
осторожными, если запросы StartDate и EndDate извлекают информацию из
других запросов. Следите за тем, чтобы подобная ситуация возникнуть не
могла.
Кроме того, вам важно понять, что в данном разделе мы продемонстрировали простой и универсальный способ заполнения колонки датами, находящимися в интервале между начальной и конечной датами. Это можно с
успехом использовать и в других областях, не касающихся календарей, как
вы увидите позже в этой главе.
Календари с последовательными датами  503
Обогащение календаря за счет дополнительных
столбцов
Если вы собираетесь производить разного рода аналитику с применением
созданного календаря, вам очень пригодятся дополнительные столбцы, отражающие год, месяц, название месяца и т. д. К счастью, в Power Query с его
богатейшим арсеналом инструментов для работы с датами такие столбцы
создаются крайне просто. Делается это всего в три шага:
 выделите столбец Date и на вкладке Добавление столбца (Add Column)
нажмите на выпадающую кнопку Дата (Date);
 выберите нужную вам составляющую периода;
 проделайте первые два шага для всех колонок, которые хотите добавить.
На рис. 18.8 показан результат добавления к нашему запросу Calendar
столбцов Year, Month и Month Name.
Рис. 18.8. Добавление в календарь полезных столбцов
🙈 Предупреждение. Не забывайте возвращаться на первый шаг и выделять
исходный столбец Date после добавления таких, например, столбцов, как Конец месяца (End of Month). Иначе следующий столбец может быть создан на
основании дат в только что добавленном столбце, а не в исходном.
Столбцы для финансовых периодов в 12-месячном
календаре
Хотя в стандартном меню добавления колонок для составляющих дат достаточно богатый выбор, многие из предлагаемых вариантов могут оказаться бесполезными применительно к финансовым годам, не оканчивающимся
31 декабря. К счастью, расчет финансовых периодов (таких как финансовый
месяц) можно легко произвести в настраиваемых столбцах.
504  Глава 18. Техники работы с датой и временем
В табл. 18.4 приведены несколько формул для показателей, которые могут показаться вам полезными применительно к 12-месячным календарям,
не заканчивающимся 31 декабря.
Таблица 18.4. Финансовые периоды для 12-месячных календарей
Имя столбца
Требуемые столбцы
Формула
Fiscal Year
[Date]
Date.Year(Date.AddMonths([Date],
12–YEMonth))
Fiscal Month
[Date]
Date.Month(Date.AddMonths([Date],
–YEMonth))
Fiscal Quarter
[Fiscal Month]
Number.RoundUp([Fiscal Month]/3)
Fiscal Month of Quarter
[Fiscal Month]
if Number.Mod([Fiscal Month],3) = 0
then 3 else Number.Mod([Fiscal Month],3)
End of Fiscal Year
[Date],
[Fiscal Month]
Date.EndOfMonth(Date.AddMonths([Date],
12–[Fiscal Month]))
End of Fiscal Quarter
[Date],
[Fiscal Month of
Quarter]
Date.EndOfMonth(Date.AddMonths([Date],
3–[Fiscal Month of Quarter] ) )
На рис. 18.9 показаны колонки Fiscal Year и Fiscal Month, созданные с применением этих формул, тогда как при создании столбца Month Name был
использован стандартный вариант Название месяца (Name of Month) из
выпадающей кнопки Дата (Date).
Рис. 18.9. Значения в столбцах Fiscal Year и Fiscal Month изменились после 30 сентября
Столбцы-идентификаторы периодов для 364-дневного
календаря
Самая большая сложность при работе с 364-дневным календарем состоит
в невозможности использовать стандартные инструменты преобразования
дат, которые прекрасно работают в случае с 12-месячным календарем. Вмес-
Календари с последовательными датами  505
то этого нам придется добавлять особые столбцы, которые позволят нам
составлять финансовую отчетность в зависимости от вида используемого
364-дневного календаря. Вне зависимости от того, используем ли мы календарь формата 4-4-5 или строго базируемся на 13 месяцах по четыре недели,
все начинается со столбца DayID с идентификатором дня.
Столбец DayID, по сути, представляет собой сквозную последовательность
номеров строк для календаря с ежедневным увеличением на единицу, который не обнуляется на протяжении всего календаря. Это поле впоследствии
будет использоваться в формулах для создания всех остальных дополнительных столбцов. К счастью, создать и заполнить такой столбец довольно просто.
После генерирования столбца с последовательными датами в календаре, что
мы сделали ранее, можно выполнить следующие простые шаги для создания
колонки с именем DayID:
 на вкладке Добавить столбец (Add Column) нажмите на выпадающую кнопку Столбец индекса (Index Column) и выберите пункт От 1
(From 1);
 переименуйте новый столбец в DayID.
Теперь, когда у нас есть такой важный столбец, являющийся превосходным строительным материалом для других, давайте на его основе добавим остальные нужные нам колонки с идентификаторами периодов. Все
эти новые поля мы создадим при помощи настраиваемых столбцов, главное – знать, какую формулу использовать. В табл. 18.5 содержатся формулы
столбцов для всех разновидностей календарей. Внимательно следите за тем,
какой именно вариант вам нужен, поскольку формулы в столбце MonthID для
разных календарей отличаются.
Таблица 18.5. Колонки-идентификаторы периодов для 364-дневных календарей
Имя столбца
Требуемые столбцы
Формула
WeekID
[DayID]
Number.RoundUp([DayID]/7)
MonthID
[DayID]
Number.RoundDown([DayID]/91)*3+ ( if
Number.Mod([DayID],91)=0 then 0 else if
Number.Mod([DayID],91)<= 28 then 1 else if
Number.Mod([DayID],91)<= 56 then 2 else 3 )
[DayID]
Number.RoundDown([DayID]/91)*3+ ( if
Number.Mod([DayID],91)=0 then 0 else if
Number.Mod([DayID],91)<= 28 then 1 else if
Number.Mod([DayID],91)<= 63 then 2 else 3 )
[DayID]
Number.RoundDown([DayID]/91)*3+ ( if
Number.Mod([DayID],91)=0 then 0 else if
Number.Mod([DayID],91)<= 35 then 1 else if
Number.Mod([DayID],91)<= 63 then 2 else 3 )
[DayID]
Number.RoundUp ([DayID]/28)
(for 4-4-5 Calendars)
MonthID
(for 4-5-4 Calendars)
MonthID
(for 5-4-4 Calendars)
MonthID
(for 13x4 Calendars)
506  Глава 18. Техники работы с датой и временем
Имя столбца
Требуемые столбцы
Формула
QuarterID
[DayID]
Number.RoundUp([DayID]/91)
YearID
[DayID]
Number.RoundUp([DayID]/364)
🍌 Примечание. Если вы знакомы с шаблоном DAX от Роба Колли (Rob Collie)
под шуточным названием GFITW (Greatest Formula In The World, Величайшая
формула в мире), вы поймете, что именно эти колонки легли в основу мер
логики операций со временем, связанных с разными периодами в DAX для
календарей типа 4-4-5.
Рис. 18.10. Колонки-идентификаторы периодов
на смене финансовых годов для календаря типа 4-4-5
Об этих вспомогательных столбцах важно знать то, что они используются
не для построения отчетов, а для реализации дополнительной логики.
🙈 Предупреждение. Представленные выше шаблоны не принимают во внима-
ние варианты стандартных шаблонов 364-дневного календаря. Если в вашей
компании применяется практика «догоняющего» года (catch-up year), когда
каждые несколько лет добавляется дополнительная неделя, вам нужно будет
скорректировать используемую логику, чтобы отразить это.
Столбцы финансовых периодов
для календарей 4-4-5 (и их разновидностей)
В отличие от 12-месячных календарей, которые могут использовать стандартную логику для преобразования дат, пользовательские версии календарей требуют применения дополнительных формул для корректного заполнения столбцов с финансовыми периодами. К счастью, при наличии созданных
на предыдущем шаге колонок-идентификаторов обогатить таблицу новыми
колонками будет не так сложно.
Мы знаем, как сложно бывает прописывать подобную логику, поэтому в
следующих нескольких таблицах постарались привести все формулы, которые позволят вам создать необходимые столбцы для обозначения финан-
Календари с последовательными датами  507
совых периодов для календаря типа 4-4-5 и его разновидностей (4-5-4 и
5-4-4). Особое внимание обратите на колонку Требуемые столбцы, поскольку
некоторые из создаваемых здесь столбцов предполагают наличие в таблице
других колонок, которые и перечислены в этой области таблицы.
🍌 Примечание. Вам в вашей таблице не нужна одна или несколько колонок из
списка требуемых столбцов? Не беда – просто удалите их в конце работы,
Power Query отнесется к этому нормально.
Таблица 18.6. Формула для столбца с финансовым годом
Имя столбца
Требуемые столбцы
Формула
Fiscal Year
StartDate445, [YearID]
Date.Year(Date.From(StartDate))+[YearID]
Следует иметь в виду, что в зависимости от первой используемой даты и
финансового года, который вы хотите, чтобы она представляла, вам может
потребоваться прибавить или вычесть единицу из результата.
Таблица 18.7. Формулы для столбцов, представляющих периоды года
Имя столбца
Требуемые столбцы
Формула
Quarter of Year
[QuarterID]
Number.Mod([QuarterID]-1,4)+1
Month of Year
[MonthID]
Number.Mod([MonthID]-1,12)+1
Week of Year
[WeekID]
Number.Mod([WeekID]-1,52)+1
Day of Year
[DayID]
Number.Mod([DayID]-1,364)+1
Помните о том, что Power Query является регистрозависимым инструментом, а значит, имя поля Day Of Year будет отличаться от Day of Year. Если
при создании столбца вы получите ошибку, говорящую о том, что какие-то
колонки не существуют в таблице, хотя вы знаете, что создавали их, внимательно проверьте написание их имен.
Таблица 18.8. Формулы для столбцов, представляющих периоды квартала, месяца и недели
Имя столбца
Требуемые столбцы
Формула
Month of Quarter
[Month of Year]
Number.Mod([Month of Year]–1,3)+1
Week of Quarter
[Week of Year]
Number.Mod([Week of Year]–1,13)+1
Day of Quarter
[Day of Year]
Number.Mod([Day of Year]–1,91)+1
Day of Month
[Day of Quarter],
[Month of Quarter]
if [Month of Quarter] = 1
then [Day of Quarter]
else if [Month of Quarter] = 2
then [Day of Quarter] – 28
else [Day of Quarter] – 35
(for 4-4-5 Calendars)
508  Глава 18. Техники работы с датой и временем
Имя столбца
Требуемые столбцы
Формула
Day of Month
(for 4-5-4 Calendars)
[Day of Quarter],
[Month of Quarter]
if [Month of Quarter] = 1
then [Day of Quarter]
else if [Month of Quarter] = 2
then [Day of Quarter] – 28
else [Day of Quarter] – 63
Day of Month
(for 5-4-4 Calendars)
[Day of Quarter],
[Month of Quarter]
if [Month of Quarter] = 1
then [Day of Quarter]
else if [Month of Quarter] = 2
then [Day of Quarter] – 35
else [Day of Quarter] – 63
Week of Month
[Day of Month]
Number.RoundUp([Day of Month]/7)
Day of Week
[Day of Year]
Number.Mod([Day of Year]–1,7)+1
Таблица 18.9. Формулы для столбцов, представляющих количество дней в периодах
Имя столбца
Требуемые столбцы
Формула
Days in Year
–
364
Days in Quarter
–
91
Days in Month
(for 4-4-5 Calendars)
[Week of Quarter]
if [Week of Quarter] > 8
then 35
else 28
Days in Month
(for 4-5-4 Calendars)
[Week of Quarter]
if [Week of Quarter]>4 and
[Week of Quarter]<10
then 35
else 28
Days in Month
(for 5-4-4 Calendars)
[Week of Quarter]
if [Week of Quarter] < 5
then 35
else 28
Days in Week
–
7
Таблица 18.10. Формулы для столбцов, представляющих начало и конец периода
Имя столбца
Требуемые столбцы
Формула
Start of Week
[Date], [Day of Week]
Date.AddDays([Date],–([Day of Week]–1))
End of Week
[Start of Week]
Date.AddDays([Start of Week],6)
Start of Month
[Date], [Day of Month]
Date.AddDays([Date],–([Day of Month]–1))
End of Month
[Start of Month],
[Days in Month]
Date.AddDays([Start of Month],[Days in
Month]–1)
Start of Quarter
[Date], [Day of Quarter]
Date.AddDays([Date],–([Day of Quarter]–1))
Календари с последовательными датами  509
Имя столбца
Требуемые столбцы
Формула
End of Quarter
[Start of Quarter]
Date.AddDays([Start of Quarter],91–1)
Start of Year
[Date], [Day of Year]
Date.AddDays([Date],–([Day of Year]–1))
End of Year
[Start of Year]
Date.AddDays([Start of Year],364–1)
Что находится в файле с примерами?
В файле Ch18 Examples\Calendar Tables.xlsx вы найдете все перечисленные
ниже версии календарей, построенные с использованием техник, описанных
в этой главе:
 Calendar: стандартный 12-месячный календарь, заканчивающийся
31 декабря;
 Calendar-Sep30: 12-месячный календарь с финансовым годом, заканчивающимся 30 сентября;
 Calendar-445: 364-дневный календарь с использованием шаблона недель 4-4-5;
 Calendar-454: 364-дневный календарь с использованием шаблона недель 4-5-4;
 Calendar-544: 364-дневный календарь с использованием шаблона недель 5-4-4.
Все таблицы загружены в модель данных и объединены связями с таблицами Sales и Budgets, как показано на рис. 18.11.
Рис. 18.11. Пять различных календарей связаны
с таблицами Sales и Budgets посредством поля Date
Кроме того, в файле созданы меры Sales $ и Budget $, а также несколько
примеров на листе Comparisons, на которых можно видеть сходства и отличия
между тем, как могут быть представлены данные с использованием разных
календарей.
510  Глава 18. Техники работы с датой и временем
Помимо этого, для всех календарей приведены понятно названные шаги
в редакторе Power Query, что позволит вам легко понять, какие именно формулы были использованы в том или ином случае.
Заполнение особых диапазонов даты и времени
Хотя показанные выше шаблоны для календарей очень полезны, их предназначение ограничено заполнением последовательными датами полных
финансовых календарей в заданном интервале. В данном разделе мы рассмотрим альтернативные способы заполнения таблиц датами исходя из требований бизнес-логики.
Заполнение определенного количества дат
В наших предыдущих решениях мы заполняли последовательными датами
таблицы в заранее заданном интервале. А что, если у вас есть только начальная дата и количество последовательных дат, начиная от нее, которыми
нужно заполнить столбец? Рассмотрите пример, приведенный на рис. 18.12,
базирующийся на данных из таблицы Visitors из файла Ch18 Examples\Fill
Dates­Begin.xlsx. Реализовав этот сценарий, мы должны иметь возможность
узнать, какие посетители будут присутствовать в определенную дату.
Преобразовать это …
… в это …
Рис. 18.12. Нам необходимо сгенерировать список посетителей по датам
Вывод, к которому мы стремимся, сложным не назовешь. Мы знаем дату
прибытия посетителя и сколько дней он пробудет в месте пребывания.
Для реализации нашего решения мы будем использовать очень полезную функцию List.Dates(). Если открыть документацию по этой функции,
показанную на рис. 18.13, можно увидеть, что в ней представлены не только
входящие аргументы функции, но и описание ожидаемого на выходе значения. В этом описании сказано, что «функция генерирует список дат с учетом
начальной даты, количества значений и шага приращения». Отлично!
Заполнение особых диапазонов даты и времени  511
Рис. 18.13. Документация по функции List.Dates()
Единственную сложность для нас может составлять последний параметр
функции, указывающий на шаг приращения. Простейший способ задать длительность в днях – это объявить ее при помощи следующего нехитрого кода:
#duration(1,0,0,0)
🍌 Примечание. Четыре входных параметра значения #duration представляют
дни, часы, минуты и секунды.
Что ж, давайте попробуем:
 создайте новый запрос на основе таблицы Visitors;
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 назовите столбец Pass Date и введите следующую формулу:
=List.Dates( [Arrival], [Days on Site], #duration(1,0,0,0) )
 выделите столбцы Pass Date и Visitor, щелкните правой кнопкой мыши
по любому из них и выберите пункт Удалить другие столбцы (Remove
Other columns);
 разверните столбец Pass Date в строки;
 установите типы данных.
В результате мы получим то, что и требовалось, как показано на рис. 18.14.
🍌 Примечание. Причина, по которой мы не со-
ветуем использовать функцию List.Dates() для
создания календарей, заключается в том, что
последним параметром в нее передается длительность. К сожалению, для месяцев длительность не предусмотрена. А с учетом того, что
от месяца к месяцу количество дней меняется
(а в случае с февралем еще и от года к году),
гораздо легче для создания календарей будет
использовать показанные ранее приемы.
Рис. 18.14. Получилось два
дня для Мигеля, пять для Кена
и четыре для Мэтта
512  Глава 18. Техники работы с датой и временем
Заполнение определенного количества часов
по каждой дате
Предыдущий пример работает отлично, но
есть один нюанс, связанный с использованием функции List.Dates(), который необходимо
понимать. Дело в том, что подсчет длительностей в нем происходит, начиная с нуля часов –
с начала суток. Это видно по тому, что первая
запись для каждого посетителя указывает на
ту же дату, которая стоит для него в таблице
в поле Arrival.
Это может иметь значение, если вы используете в работе длительности менее одного
дня. К примеру, обратите внимание, как изменится результат, если изменить длительность
Рис. 18.15. Количество
в предыдущей формуле на часовой интервал –
интервалов правильное, но все
#duration(0,1,0,0). Вывод показан на рис. 18.15.
даты одинаковые. А где время?
В данном случае Power Query создает список
дат с повторением часов для заданного количества часов, начиная с полуночи начальной даты. К сожалению, это трудно увидеть, поскольку функция
List.Dates() возвращает только даты, обрезая время.
А что, если нам необходимо взять наши даты, как мы делали в предыдущем
примере, и добавить 8-часовые интервалы, начиная с 9 часов утра? Очевидно, что мы не можем использовать для этого функцию List.Dates(), так что нам
придется задействовать другую полезную функцию List.Times() с отправной
точкой в виде #time(9,0,0).
🍌 Примечание. Три передаваемых параметра в функцию представляют часы,
минуты и секунды. Помните, что эта функция оперирует 24-часовым форматом времени, так что для передачи значения, эквивалентного часу дня,
необходимо использовать запись #time(13,0,0).
Давайте соберем все воедино:
 создайте дубликат предыдущего запроса и назовите его Pass Times;
 на вкладке Добавление столбца (Add Column) нажмите на кнопку Настраиваемый столбец (Custom Column);
 назовите столбец Hour и введите следующую формулу:
=List.Times( #time(9,0,0), 8, #duration(0,1,0,0) )
На данном этапе мы можем при помощи окна предварительного просмотра убедиться, что использовали правильные временные интервалы для
каждой даты, как показано на рис. 18.16. А поскольку списки были созданы
Заполнение особых диапазонов даты и времени  513
на уровне дня, разворачивание столбца Hour приведет к образованию новых
строк с корректными часовыми интервалами для каждой даты, представленной в столбце Pass Date.
Рис. 18.16. Мы добавили 8-часовые интервалы
для каждой даты в исходном наборе данных
🍌 Примечание. Также есть функция List.DateTimes(), которая позволит вам передать полное значение с датой и временем в виде #datetime в качестве начальной даты.
Одной из главных сложностей при работе с датами является непостоянство
количества дней от месяца к месяцу и даже от года к году. У составляющей
времени такого недостатка нет, поскольку каждый день состоит из 24 часов,
каждый час – из 60 минут, а минута – из 60 секунд. Именно поэтому при построении таблиц, включающих временные интервалы, лучше пользоваться
функцией List.Times().
Заполнение определенного количества дат
с заданными интервалами
В следующем примере мы рассмотрим вариант преобразования дат, показанный на рис. 18.17.
Как это ни удивительно, но у нас уже есть ответ на этот вопрос. Мы можем
использовать ту же функцию List.Dates(), что и раньше. Нам лишь придется изменить последний аргумент функции, чтобы можно было передавать
нужные нам интервалы. При этом функция List.Dates() требует, чтобы этот
аргумент имел тип Продолжительность (Duration), так что мы создадим
его при помощи функции Duration.From(), которой передадим значение из
столбца Frequency.
514  Глава 18. Техники работы с датой и временем
Преобразовать это …
… в это …
2 записи
14-дневные
интервалы
5 записей
7-дневные
интервалы
4 записи
5-дневные
интервалы
Рис. 18.17. Как создать таблицу с повторением определенного
количества дат с заданными интервалами?
Вы можете создать запрос на основании таблицы Contracts из файла Ch18
Examples\Fill Every x Dates­Begin.xlsx и выполнить следующие действия:
 добавьте настраиваемый столбец с именем Follow Up и формулой, показанной ниже:
=List.Dates( [Contract Start], [Check Ins], Duration.From([Frequency]) )
 разверните полученное содержимое в столбце Follow Up;
 выделите столбцы Customer и Follow Up, щелкните правой кнопкой
мыши по любому из них и выберите пункт Удалить другие столбцы
(Remove Other columns);
 установите типы данных.
В результате вы получите таблицу, показанную на рис. 18.18. Именно к
такому представлению данных мы и стремились.
Рис. 18.18. Мы получили X записей, повторяющихся каждые Y дней
Разнесение данных на основе таблиц с датами  515
🍌 Примечание. Эта техника вовсе не ограничена использованием функции
List.Dates(). Здесь также могут быть применены функции List.DateTimes() или
List.Times(), если вам необходимо работать со временем.
Разнесение данных на основе таблиц с датами
Еще одна задача, с которой мы сталкиваемся достаточно часто, заключается в необходимости применить описанные выше техники для составления
определенного графика, в особенности для разнесения доходов и расходов
по месяцам.
Честно говоря, подобные задачи обычно связаны с большим количеством
нюансов, зависящих от бизнес-логики, но в данной главе мы будем рассматривать два варианта решения этого сценария. В файле Ch18 Examples\
Allocations­Begin.xlsx находится исходная таблица с именем Sales со всеми
необходимыми столбцами для решения примеров из этой главы. Столбцы,
которые нам будут не нужны для демонстрации того или иного приема, мы
будем удалять.
Для начала создадим подготовительный запрос, к которому сможем подключаться при рассмотрении конкретных примеров:




создайте новый запрос на основе таблицы Sales;
измените тип данных для столбцов Start Date и End Date на Дата (Date);
переименуйте запрос в Raw Data;
загрузите запрос в виде подключения.
Разнесение данных по дням
В первом сценарии мы воспользуемся концепцией генерации списков,
которую применяли при создании календарей ранее в этой главе. Оказывается, этот прием вполне уместен для разбивки транзакций на определенное
количество дней, как показано на рис. 18.19.
Преобразовать это …
… в это …
78 дней
122 дня
Рис. 18.19. Распределение продаж по месяцам, исходя из количества дней в них
516  Глава 18. Техники работы с датой и временем
🍌 Примечание. Какое-то странное распределение продаж по клиенту с име-
нем Никлас (Niklas), вам не кажется? Сумма в $200 должна быть разбита
ровно на четыре месяца, но почему в итоге у нас не получилось четыре записи по $50 каждая? Причина в том, что мы разбиваем средства по месяцам
в зависимости от количества дней в них, которое варьируется от месяца к
месяцу.
Основные проблемы в этом сценарии связаны с определением правильного списка месяцев для каждого клиента и разнесением по ним нужных сумм
исходя из количества дней.
Начнем с вычисления суммы, приходящейся на каждый день. Для этого
нам нужно знать точное количество дней от начальной даты до конечной.
И хотя Power Query не позволяет просто вычесть одну дату из другой, мы уже
знаем, как легко обойти это ограничение при помощи преобразования дат
в последовательные числа:
 создайте ссылку на запрос Raw Data;
 удалите столбец Months, который не понадобится нам для этого сценария;
 добавьте настраиваемый столбец с именем Amount и формулой, показанной ниже:
= [Sale] /
( Number.From( [End Date] ) – Number.From( [Start Date] ) + 1 )
🙈 Предупреждение. Не забывайте добавлять единицу к разности между двумя
датами!
Результат добавления столбца показан на рис. 18.20.
Рис. 18.20. Мы получили сумму в расчете на день для каждого клиента
Теперь можно двигаться дальше и развернуть таблицу по дням для клиентов. Для этого выполните следующие действия:
 добавьте настраиваемый столбец с именем Date и формулой, показанной ниже:
= { Number.From( [Start Date] ) .. Number.From( [End Date] ) }
Разнесение данных на основе таблиц с датами  517
 разверните полученный столбец Date;
 измените тип данных для столбца Date на Дата (Date).
Воспользовавшись этой техникой создания списков, мы смогли получить
расширенную таблицу транзакций, показанную на рис. 18.21.
Рис. 18.21. Распределение по дням
Теперь у нас есть два пути. Если вы хотите оставить данные на этом уровне
гранулярности, просто удалите столбцы Sale, Start Date и End Date и установите правильные типы данных. После этого можете загружать данные в место
назначения. Но мы хотим объединить суммы по месяцам, так что придется
еще немного поработать:
 выделите столбец Date, на вкладке Преобразование (Transform) нажмите на выпадающую кнопку Дата (Date) и в подменю Месяц (Month)
выберите пункт Конец месяца (End of Month);
 выделите столбцы Client, Sale, Start Date и Date и на вкладке Преобразование (Transform) нажмите на кнопку Группировать по (Group By);
 добавьте агрегирование с именем Amount, операцией суммирования и
исходным столбцом Amount;
 нажмите на кнопку OK;
 удалите колонки Sale и Start Date.
После этого ваши данные будут выглядеть так, как показано на рис. 18.22.
Рис. 18.22. Ура! Суммы распределились по месяцам в соответствии с количеством дней
518  Глава 18. Техники работы с датой и временем
🍌 Примечание. Причина того, почему мы выполнили группировку по такому
большому количеству полей, заключается в стремлении снизить шансы
агрегирования в месте несоответствующих данных. Если в вашей таблице
присутствует уникальный идентификатор, например номер контракта, вы
можете осуществить группировку только по нему (если не хотите оставить
остальные столбцы в таблице).
Стоит заметить, что мы никак не округляли расчетные данные по продажам за день, поскольку это увеличило бы накопительную ошибку в итоговых значениях. Если вам необходимо видеть округленные числа, мы рекомендуем сделать это на заключительном этапе запроса, чтобы снизить
риск того, что суммы по дням не будут в сумме давать итоговые значения
по месяцам.
Разнесение данных по целым месяцам
В следующем сценарии мы будем разносить сумму продаж по месяцам
поровну, вне зависимости от того, сколько дней пришлось на тот или иной
месяц. Даже если в учетном периоде присутствует всего один день из целого
месяца, мы принимаем его в полноценный расчет. На рис. 18.23 показано,
как все это должно работать.
Преобразовать это …
… в это …
3 месяца
1 месяц
5 месяцев
Рис. 18.23. Равное распределение суммы по месяцам
Было бы здорово, если бы в Power Query была функция, позволяющая создать список из последних чисел месяцев, входящих в интервал. Но мы можем
реализовать такое поведение при помощи настраиваемой функции. Для начала давайте создадим преобразование на базе двух параметров:
 откройте редактор Power Query;
 перейдите на вкладку Главная (Home) и в выпадающей кнопке Управление параметрами (Manage Parameters) выберите пункт Создать
параметр (New Parameter);
Разнесение данных на основе таблиц с датами  519
 создайте два следующих параметра:
• FromDate с типом Дата (Date) и текущим значением 2021-06-01;
• ToDate с типом Дата (Date) и текущим значением 2021-08-31, как
показано на рис. 18.24.
Рис. 18.24. Создание параметров для нашей функции
Теперь, когда у нас есть параметры, мы можем написать запрос getMonthEnds
следующим образом:
 создайте пустой запрос и назовите его getMonthEnds;
 введите следующую формулу в строку формул:
= { Number.From( FromDate ) .. Number.From( ToDate ) }
 нажмите на кнопку В таблицу (To Table), расположенную в левой части
вкладки Средства для списков (List Tools), а затем – на кнопку OK;
 измените тип данных столбца Column1 на Дата (Date);
 выделите столбец Column1, на вкладке Преобразование (Transform)
нажмите на выпадающую кнопку Дата (Date) и в подменю Месяц
(Month) выберите пункт Конец месяца (End of Month);
 щелкните правой кнопкой мыши по столбцу Column1 и выберите пункт
Удалить дубликаты (Remove Duplicates);
 переименуйте столбец Column1 в Month End.
Результатом будет небольшая табличка с датами окончания месяцев в
интервале между текущими значениями параметров FromDate и ToDate, показанная на рис. 18.25.
520  Глава 18. Техники работы с датой и временем
Рис. 18.25. Таблица с последними датами месяцев из интервала
Как мы уже знаем из главы 17, шаги, которые мы выполнили, позволят
сохранить объект getMonthEnds в виде запроса, хотя мы легко можем преобразовать его в функцию, что сейчас и сделаем:
 щелкните правой кнопкой мыши по запросу GetMonthEnds, выберите пункт Создать функцию (Create Function), назовите функцию
fxGetMonthEnds и нажмите на кнопку OK.
В результате будет создана функция, как показано на рис. 18.26.
Рис. 18.26. Функция fxGetMonthEnds, принимающая два параметра
🍌 Примечание. Сейчас самое время сохранить проект и загрузить созданные
запросы в виде подключения, поскольку нам не требуется импортировать их
на лист или в модель данных.
Разнесение данных на основе таблиц с датами  521
Теперь, когда мы создали рабочую функцию, можно воспользоваться ей
для распределения продаж по месяцам:
 создайте ссылку на запрос Raw Data;
 удалите столбец Months, который не понадобится нам для этого сценария;
 перейдите на вкладку Добавление столбца (Add Column), нажмите на
кнопку Вызвать настраиваемую функцию (Invoke Custom Function)
и выберите в выпадающем списке функцию fxGetMonthEnds;
 выберите в качестве значения параметра FromDate столбец Start Date,
а в качестве ToDate – End Date.
После создания запроса мы можем обратиться к предварительному просмотру, как показано на рис. 18.27, и увидеть, как функция применяется к
нашему набору данных.
Рис. 18.27. Наша пользовательская функция работает превосходно
Итак, осталось распределить суммы поровну по всем месяцам. А как это
сделать? Если сейчас развернуть столбец fxGetMonthEnds, мы лишимся возможности быстро подсчитать количество месяцев в каждой из вложенных
таблиц. Конечно, можно использовать для этого группировку, но не кажется
ли вам странным взять таблицу, развернуть ее, провести группировку данных и снова ее развернуть? Определенно, должен быть способ получше…
И он есть! Можно воспользоваться функцией Table.RowCount() внутри настраиваемого столбца следующим образом:
 создайте настраиваемый столбец с именем Amount и следующей формулой:
= [Sale] / Table.RowCount( [fxGetMonthEnds] )
 выделите столбцы Client, fxGetMonthEnds и Amount, щелкните правой
кнопкой мыши по любому из них и выберите пункт Удалить другие
столбцы (Remove Other columns);
 разверните столбец fxGetMonthEnds без использования префиксов;
 установите типы данных для всех столбцов.
522  Глава 18. Техники работы с датой и временем
Результат точно вас порадует. Как вы догадались, функция Table.RowCount()
подсчитывает количество строк в выводе функции fxGetMonthEnds для каждого клиента, и именно на столько частей делится значение из столбца Sale.
После разворачивания данных вы обнаружите, что суммы продаж по каждому клиенту действительно были аккуратно поделены на количество месяцев
по ним, как показано на рис. 18.28.
Рис. 18.28. Суммы распределены в соответствии с условием задачи
🍌 Примечание. Это один из тех примеров, когда быстрый поиск по докумен-
тации языка M может быть очень полезен. Главное – знать, где искать. Ранее
мы уже работали с объектом Table, так что поиск в этой секции документации
быстро дал свои результаты и привел к нужной функции.
Помните, что настраиваемые функции могут сэкономить вам уйму времени в ситуациях, для которых не подходят стандартные средства Power Query,
или в сценариях, где вам необходимо создать повторно используемую логику
для сложных шаблонов. Если при разработке своего алгоритма разнесения
данных вам понадобится использовать более сложные методы, не забывайте,
что в вашем арсенале есть такой полезный инструмент!
Разнесение данных по заданному количеству месяцев
от начальной даты
В заключительном примере из этой главы мы добавим к нашему предыдущему сценарию пару важных нюансов. Финансовый отдел потребовал, чтобы
доходы во время разбивки данных относились к первому месяцу в интервале
только в случае, если первая транзакция была совершена до 15-го числа месяца включительно. Иначе этот месяц не учитывается, а расчеты начинаются
со следующего. Кроме того, исходными данными в этой задаче являются дата
первой операции и количество месяцев, без указания конечной даты, как
показано на рис. 18.29.
Разнесение данных на основе таблиц с датами  523
Преобразовать это …
… в это …
Начало
в июне
Начало
в июле
Рис. 18.29. Как распределить суммы по заданному количеству месяцев?
Для решения этого сценария нам придется объединить технику создания
списков, которую мы использовали при определении календарей, с парой
дополнительных формул и условной логикой.
Давайте начнем с вычисления сумм на месяц:
 создайте ссылку на запрос Raw Data;
 удалите столбец EndDate, который для этого сценария нам не понадобится;
 выделите столбцы Sale и Months, перейдите на вкладку Добавить столбец (Add Column) и в выпадающей кнопке Стандартный (Standard)
выберите пункт Разделить (Divide);
 переименуйте новый столбец Деление (Division) в Amount.
На этом этапе ваш набор данных должен выглядеть так, как показано на
рис. 18.30.
Рис. 18.30. Мы вычислили суммы для месячного распределения
Теперь, когда суммы по месяцам нам известны, пришло время развернуть нашу таблицу, чтобы добавить строки по месяцам. У нас есть количество месяцев для каждого клиента – оно прописано в колонке Months, – но
есть и пара важных нюансов. Мы не можем использовать здесь функцию
List.Dates(), поскольку нельзя указать продолжительность длиной в месяц,
но и вариант {1 .. [Months] } нам не подходит из-за необходимости учитывать смещения в зависимости от значения в столбце Start Date. Применим
следующий метод:
524  Глава 18. Техники работы с датой и временем
 создайте настраиваемый столбец с именем Custom и формулой, приведенной ниже:
=if Date.Day([Start Date]) <= 15
then { 0 .. [Months] - 1 }
else { 1 .. [Months] }
 разверните столбец Custom в строки.
Вы увидите вывод, показанный на рис. 18.31.
Рис. 18.31. Результат разворачивания условного столбца
Давайте сделаем пару важных замечаний по поводу полученного результата.
1. Для каждого клиента количество строк совпадает с количеством месяцев, на которые должна разбиваться сумма.
2. Для первых двух клиентов значения в столбце Custom начинаются с
нуля, а для третьего – с единицы.
Давайте воспользуемся нашим новым столбцом для создания даты окончания распределения для каждого клиента:
 создайте еще один настраиваемый столбец с именем Date и следующей
формулой:
= Date.EndOfMonth( Date.AddMonths( [Start Date], [Custom] ) )
 выделите столбцы Date, Client и Amount, щелкните правой кнопкой
мыши по любому из них и выберите пункт Удалить другие столбцы
(Remove Other columns);
 установите типы данных для всех столбцов.
Как видите, трюк здесь состоял в создании списка требуемых месяцев для
распределения (с корректными смещениями для каждого месяца) и использовании функции Date.AddMonths().
На рис. 18.32 представлен окончательный вывод сценария.
Разнесение данных на основе таблиц с датами  525
Рис. 18.32. Наши суммы по клиентам корректно разбиты
на нужное количество месяцев
🍌 Примечание. Не хотите, чтобы в таблице отображались последние дни ме-
сяцев? Не проблема. Уберите из формулы вызов функции Date.EndOfMonth(),
и в итоговом наборе данных у вас окажутся даты с тем же днем, что и в исходном столбце Start Date.
Заключительные штрихи к разнесению данных
Как мы уже упоминали ранее, существует великое множество способов
распределить данные в таблице. Мы лишь показали вам наиболее часто
встречающиеся примеры на нашей практике. Надеемся, представленные
здесь идеи поспособствуют рождению у вас новых творческих мыслей, и вы
сможете реализовать свои методы разбиения данных, полностью отвечающие вашим бизнес-требованиям.
Глава
19
Оптимизация запросов
Power Query – невероятно полезный инструмент, способный значительно
ускорить процессы преобразования данных. В то же время ни для кого не является секретом, что с его помощью легко можно написать довольно тяжелые
и медленные запросы. Кроме того, при разработке решений вы также часто
можете испытывать трудности, связанные с задержкой ответа. Эту главу мы
решили посвятить вопросам того, как можно выжать максимум возможного
из Power Query и писать эффективные запросы, не затрачивая на это много
времени.
Оптимизация настроек Power Query
Первое, с чего всегда стоит начинать процесс оптимизации (optimizing) работы с Power Query, – это проверка настроек, установленных в вашем окружении по умолчанию. Посмотреть их можно в диалоговом окне Параметры
запроса (Query Options), доступ к которому можно получить следующим
образом:
 Excel: перейдите на вкладку Данные (Data), раскройте выпадающую
кнопку Получить данные (Get Data) и выберите пункт Параметры
запроса (Query Options);
 Power BI: на вкладке Файл (File) откройте раздел Параметры и настройки (Options & settings) и выберите пункт Параметры (Options).
Рассмотрим некоторые важные разделы и вкладки этого диалогового окна.
Глобальные параметры загрузки данных
В разделе Загрузка данных (Data Load) группы Глобальные (Global) первые две секции посвящены определению типов и фоновым данным. Хотя
это очень полезные области настроек, мы рекомендуем оставить в обеих
секциях переключатель, установленный в среднюю позицию. Это оставит
опции активными и позволит менять их на уровне файлов, что обеспечит вам
оптимальный баланс между функциональностью и возможностью изменить
текущее положение дел для конкретного сценария.
Следующие два параметра доступны только в Excel, и мы изменим установки по умолчанию для них обоих:
528  Глава 19. Оптимизация запросов
 Стандартные параметры загрузки запроса (Default Load Settings).
Мы рекомендуем установить этот переключатель в положение Указать
пользовательские параметры загрузки по умолчанию (Custom
default load setting) и оставить оба флажка Загрузить в лист (Load to
Worksheet) и Загрузить в модель данных (Load to Data Model) неустановленными. Причина проста: при создании нескольких запросов в одном экземпляре Power Query вы можете выбрать только одно
место назначения для загрузки. Сколько бы запросов мы ни создавали
в одной сессии, их загрузка в виде подключений редко занимала у нас
больше пары секунд. Сравните это с настройкой по умолчанию, в которой все запросы загружаются в свои таблицы на отдельных рабочих
листах. В этом случае вам не только придется ждать, пока все запросы
загрузятся, но и тратить время на удаление тех из них, которые вам на
самом деле не нужны. Кроме того, придется еще и рабочие листы за
ними удалять. Гораздо быстрее бывает загрузить все запросы в виде
подключений, после чего для нужных из них включить загрузку на
лист;
 Быстрая загрузка данных (Fast Data Load). Убедитесь, что этот флажок установлен. А кому хочется, чтобы данные загружались медленно?
В реальности включение этой опции может блокировать окно Excel в
момент обновления данных, но обычно мы не обращаем на это внимания, поскольку и так всегда переходим к следующей задаче только
после полной загрузки данных.
Глобальные параметры редактора Power Query
В разделе Редактор Power Query (Power Query Editor) группы Глобальные
(Global) все очень просто – все флажки здесь должны быть включены.
Глобальные параметры безопасности
Если вы следуете нашему совету из главы 12 и никогда не заполняете поле
Инструкция SQL (SQL statement) при подключении к базе данных, раздел
Машинные запросы к базе данных (Native Database Queries) не должен вас
особо интересовать, поскольку вы не будете их посылать.
Если же вы игнорируете нашу рекомендацию и отправляете при подключении к серверу инструкции SQL, вы можете отключить флажок с требованиями утверждения пользователя, чтобы избежать необходимости отвечать
на назойливые вопросы. Очень жаль, что эта опция доступна только на глобальном уровне настроек, ведь отключать ее для всех проектов нелогично.
В большинстве из них вам будет полезно, чтобы этот флажок был активен.
Причина, по которой важно оставить эту опцию включенной, состоит
в том, что Power Query не ограничивает вас отправкой только инструкций
SELECT посредством коннектора к базе данных. Таким образом, это предупреждение может быть единственным, которое вы получите, когда в канун
1 апреля кому-то вздумается послать базе данных инструкцию DROP TABLE
вместо SELECT.
Оптимизация настроек Power Query  529
🍌 Примечание. Честно говоря, обеспечением доступа к базе данных со сторо-
ны разных пользователей в вашей компании должен заниматься отдел ИТ.
Но мы посмотрим, как вы будете все отрицать, когда инструкция к базе данных будет отправлена именно под вашей учетной записью!
Последуйте нашему совету и оставьте этот флажок включенным. Позвольте
Power Query строить запросы SQL за вас.
Глобальные параметры конфиденциальности
Как мы уже видели в главе 12, настройки конфиденциальности могут оказывать влияние как на скорость обновления запросов, так и на возможность
объединять разные данные. Многие пользователи бездумно устанавливают
переключатель в этом разделе в состояние Всегда игнорировать параметры уровней конфиденциальности (Always ignore Privacy Level settings).
Никогда так не делайте!
Мы понимаем, что вопросы проверки конфиденциальности могут раздражать, но отключение этой опции на глобальном уровне не позволит вам
получать уведомления и обеспечивать защиту даже тогда, когда вам это необходимо. Переключать режимы конфиденциальности – это допустимо, но
делайте это строго в соответствии с требованиями конкретного решения,
хорошо зная, какие источники данных вы используете. Оставьте переключатель в этом разделе в положении по умолчанию – Объединение данных
в соответствии с настройками уровня конфиденциальности каждого
файла (Combine data according to each file’s Privacy Level Settings).
Настройки текущей книги (файла) – фоновые данные
Хотя в разделе Загрузка данных (Data Load) из группы Текущая книга/
файл (Current Workbook/File) есть достаточно много настроек, большинство
из них понятно без дополнительных описаний. Единственная опция, о которой хочется поговорить отдельно, – это возможность Разрешить скачивание в фоновом режиме для предварительного просмотра данных (Allow
data previews to download in the background).
Этот флажок установлен по умолчанию и отвечает за то, будет ли Excel
или Power BI пытаться автоматически загружать данные, требуемые для
корректного отображения значков и предварительного просмотра на панели Запросы и подключения (Queries & Connections) и в редакторе Power
Query.
Хотя эти опции могут быть весьма полезными, в случае загрузки большого
объема данных они могут стать причиной расходования дополнительных
ресурсов. При обнаружении серьезных задержек во время загрузки рабочей
книги с большим количеством сложных запросов вы можете рассмотреть
вариант отключения этого флажка.
530  Глава 19. Оптимизация запросов
🍌 Примечание. Помните, что отключение этой опции не ведет к более быстрой
загрузке ваших запросов, а просто запрещает Power Query загружать данные
в фоновом режиме. Хотя в обычном режиме работы приложения это может
помочь снизить утечку ресурсов, в процессе редактирования запросов вы,
возможно, почувствуете определенные задержки по причине того, что данные из предварительного просмотра будут пересчитываться при доступе к
ним.
Перед тем как отключать фоновую загрузку, вы должны понимать, что это
может привести к некоторым побочным визуальным эффектам. На рис. 19.1
показан фрагмент очень сложного решения, в котором была отключена опция фонового обновления. Тогда как это позволило сделать рабочую книгу
более отзывчивой, взамен некоторые запросы начали отображаться с вопросительным знаком на иконке (поскольку предварительный просмотр для
них не генерировался), а в самом окне предпросмотра появились пугающие
сообщения.
Рис. 19.1. Скачивание в фоновом режиме было отключено
в этой рабочей книге в глобальных настройках
В сообщении, показанном на рисунке, говорится о том, что с вашими данными ничего страшного не случилось. Операция обновления данных продолжит выполняться корректно, но в редакторе Power Query вам придется
принудительно обновлять предварительный просмотр путем нажатия на
кнопку Обновить предварительный просмотр (Refresh Preview) на вкладке
Главная (Home).
Использование функций буферизации  531
🍌 Примечание. Обычно мы оставляем эту опцию включенной, если только у
нас не возникают проблемы с производительностью или длительные задержки, когда мы не редактируем запросы.
Настройки текущей книги (файла) – другие
Многие из опций, которые встречались вам в глобальном разделе, присутствуют и в разделе с настройкой текущей книги или файла. И именно здесь
лучше всего вносить все изменения, поскольку это позволяет выполнить
настройку в рамках конкретного проекта. Опции, которые вам может потребоваться изменить, включают в себя следующие:
 Региональные настройки (Regional Settings)  Языковой стандарт
(Locale). Здесь при необходимости вы можете переопределить настройки локализации по умолчанию для проекта, чтобы можно было поделиться им с другими;
 Конфиденциальность (Privacy). Подробно мы говорили о настройках
уровней конфиденциальности в главе 12. Если вы надумаете отключить
эту опцию, лучшего места вам не найти. По крайней мере, так вы не
затронете другие проекты.
Использование функций буферизации
При попытке рассчитать значение Power Query пытается совместно использовать принципы ленивых вычислений и свертывания запросов, которые
мы обсуждали в главе 16. По сути, именно так Power Query транслирует ваш
код на языке M в план выполнения запроса, решая, какие операции будут
переданы для вычисления в источник данных, а какие будут произведены
собственными силами.
По умолчанию во время создания запроса все шаги, для которых может
быть выполнено свертывание, выгружаются в источник данных, а оставшиеся проходят обработку в движке Power Query. А что, если вы захотите, чтобы
запрос целиком выполнялся при помощи локального движка Power Query,
или вам будет необходимо оптимизировать запрос, в основе которого лежит
значение, к которому доступ будет осуществлен многократно?
Здесь вам придут на помощь функции буферизации (buffer function), которые преследуют две цели:
 форсируют вычисление значения;
 буферизуют вычисление значения.
В Power Query буферизация перекрывает действие движка ленивых вычислений, форсируя расчет значений на конкретном шаге и только на нем (предыдущие шаги не будут буферизованы и продолжат вычисляться в обычном
режиме при выполнении ссылки на них в других шагах). Результат буферизованного шага сохраняется в памяти – в изоляции от внешних изменений
во время вычисления. Это может оказывать как положительное, так и от-
532  Глава 19. Оптимизация запросов
рицательное влияние в зависимости от запроса и объема данных, которые
необходимо разместить в памяти.
🍌 Примечание. На момент написания книги в Power Query насчитывалось три
функции буферизации: Table.Buffer(), List.Buffer() и Binary.Buffer(), – которые
используются для сохранения в буфер переданного значения.
Давайте рассмотрим основные области применения функций буферизации и несколько сопутствующих примеров реализации подобного кода.
Форсирование вычисления значения
Первая область применения функций буферизации, как мы уже сказали,
связана с принудительным вычислением значения.
Давайте попробуем при помощи Power Query сгенерировать случайные
числа (random number) в каждой строке набора данных. Для начала создадим
пустой запрос и пропишем следующий код в окне расширенного редактора:
let
Source = Table.FromList( {"A" .. "E"}, null, {"Column1"} ),
#"Added Custom" = Table.AddColumn(Source, "Random Value",
each Number.RandomBetween(1,10))
in
#"Added Custom"
Результат показан на рис. 19.2.
Рис. 19.2. Не ожидали?
🍌 Примечание. Если у вас одна из ранних версий Excel, вы можете увидеть,
что в окне предварительного просмотра числа на всех строках окажутся
случайными. Несмотря на это, при загрузке данных на рабочий лист или в
модель данных вы получите результат в виде столбца, показанного выше. Мы
рекомендуем вам проделать все описанные в этом разделе действия, чтобы
обезопасить свои решения при переходе на более новые версии Excel или
Power BI.
Это известная проблема Power Query, связанная с генерацией случайных
чисел. Дело в том, что когда в действие вступает движок ленивых вычис-
Использование функций буферизации  533
лений, он генерирует лишь одно случайное число, а затем использует это
значение во всех строках. Чтобы исправить ситуацию, давайте исправим код
настраиваемого столбца таким образом, чтобы в каждой строке генерировался отдельный список с единственным случайным числом. Итак, замените код
настраиваемого столбца на следующий:
= { Number.RandomBetween(1,10) }
На первый взгляд, все в порядке. В каждом списке находится уникальное
случайное число, как видно на рис. 19.3.
Рис. 19.3. Теперь вроде получше – в каждой строке
располагается список с единственным случайным числом
После разворачивания столбца Random Value мы вернемся к исходной ситуации – в каждой строке будет находиться одно и то же число.
Это одна из тех ситуаций, когда нам необходимо форсировать вычисление
значений в списках, чтобы «зафиксировать» значения, которые мы видим в
окне предварительного просмотра. Для этого выполните следующие действия:
 вернитесь к шагу с именем Added Custom;
 заключите формулу в функцию Table.Buffer(), чтобы получилась следующая запись:
= Table.Buffer( Table.AddColumn(Source, "Random Value",
each { Number.RandomBetween(1, 10) } ) )
Вернувшись к последнему шагу запроса, вы обнаружите, что в каждой
строке будет стоять случайное число, как показано на рис. 19.4.
Рис. 19.4. Это то, что нам и нужно было!
534  Глава 19. Оптимизация запросов
🍌 Примечание. Хотя мы продемонстрировали это применение функций буферизации на примере генерации случайных чисел, на практике часто можно
столкнуться, например, с изменением порядка сортировки таблицы при добавлении нового столбца, особенно при наличии группировки данных. Если
вы столкнетесь с такой ситуацией, попробуйте буферизовать таблицу перед
добавлением нового шага, и в большинстве случаев это поможет предотвратить пересортировку набора данных.
Буферизация вычисления значения
Для следующего сценария представьте ситуацию, в которой для ваших
запросов не может выполняться свертывание. К примеру, вы подключаетесь
к папке с файлами CSV, TXT или Excel, ни один из которых не поддерживает
технологию свертывания запросов. С точки зрения производительности это
будет означать, что в процессе обновления данных к запросу со списком ваших файлов будет происходить многократное обращение, а значит, и многократное чтение.
При реализации цепочек запросов Power Query всегда пытается кешировать общие узлы, будь то запросы или шаги, на которые ссылаются сразу
несколько других запросов. В случае успеха это позволяет запросу (или шагу)
вычисляться лишь раз, после чего сохраненное значение используется при
последующих обращениях к нему. Однако иногда этого недостаточно. В таких случаях можно оптимизировать наши запросы путем буферизации всего
запроса в целом или значений из него.
🍌 Примечание. Вы всегда можете представлять, что с каждым вашим запро-
сом хранится счетчик его операций чтения и преобразования. И чем меньше значение этого счетчика, тем лучше. С увеличением количества шагов и
связанных с ними преобразований вы будете наблюдать снижение производительности вашего решения.
Представьте, что в вашей папке на диске хранятся порядка 240 файлов
Excel, и из каждого из них нам необходимо извлечь по две таблицы. Мы могли
бы спроектировать свои запросы так, как показано на рис. 19.5.
Рис. 19.5. Запросы для представленного примера
Использование функций буферизации  535
На первый взгляд может показаться, что у нас тут есть четыре запроса, но
на самом деле здесь представлено пять следующих компонентов:
 Source Files – запрос указывает на исходную папку с двоичными файлами для обработки. Каждый из них является файлом Excel с несколькими листами и объектами, которые нам нужно извлечь;
 Use Buffering – параметр, позволяющий нам быстро переключаться
между буферизованным и небуферизованным списками файлов в следующих трех запросах;
 Files * – этот запрос фактически ссылается на запрос Source Files, превращая его в список двоичных файлов из исходной папки (* для сравнения файл примера содержит две версии этого запроса: Buffered Files
и Un­Buffered Files);
 Forecast – динамически ссылается на нужный список двоичных файлов (исходя из значения параметра Use Buffering), извлекая из каждого
файла данные из таблицы Forecast;
 Parts – то же самое, что и в случае с Forecast, но данные извлекаются
из таблицы Parts.
Здесь очень важно понимать, что между запросами Buffered Files и UnBuffered Files существует единственное различие, и кроется оно в последнем
шаге. Если в запросе Buffered Files мы видим вызов функции Binary.Buffer()
на шаге Content (он показан ниже), то в запросе Un­Buffered Files этот вызов
отсутствует:
= List.Transform( #”Removed Other Columns”[Content],
each Excel.Workbook ( Binary.Buffer( _ ) ) )
🍌 Примечание. Несмотря на использование здесь функции буферизации,
движок ленивых вычислений продолжает работать, проверяя в запросах
Forecast и Parts значение параметра Use Buffering. Если значение истинно,
будет производиться работа над списком Buffered, в противном случае – над
списком Un-Buffered.
Посмотрим, что будет, если запустить десять обновлений нашего решения
с буферизованными файлами и десять – с небуферизованными. Сравнение
показано на рис. 19.6.
В среднем на обновление буферизованного списка у нас уходило порядка
9,6 секунды (со стандартным отклонением, равным 0,16 секунды), тогда как
с небуферизованным списком это время составляет 16,6 секунды (со стандартным отклонением 0,33 секунды). Получается, что буферизация данных
позволяет сэкономить процентов 30 времени с вдвое меньшим показателем
изменчивости.
536  Глава 19. Оптимизация запросов
Рис. 19.6. Сравнение времени обновления буферизованных
и небуферизованных файлов в папке
🍌 Примечание. Показанные здесь тесты проводились на 64-битной сборке
Excel версии 2107 из бета-канала Microsoft 365. Технические данные о компьютере: двухъядерный i7-7600U CPU @2.8 ГГц, с памятью 16 Гб. Также учитывайте, что ваши тесты могут давать различные результаты в разные дни и
на разных компьютерах, поскольку у Power Query нет эксклюзивного доступа
к памяти и процессору. Иными словами, чем больше программ запущено на
компьютере, тем медленнее будут обновляться ваши запросы.
Тогда как такой прирост производительности мог вас вдохновить, обычно
бывает трудно сказать, получите ли вы подобные результаты при использовании буферизации в вашем конкретном случае. На момент написания
книги в среде Power Query не было реализовано ни одного инструмента для
отладки, который помог бы нам повысить эффективность наших сценариев.
Таким образом, все замеры пока приходится делать вручную.
Стоит отметить, что в рабочих сценариях мы бы никогда не стали оставлять запросы с возможностью динамического переключения между буферизованными и небуферизованными файлами. Вместо этого мы бы сравнили
время обновления в обоих случаях и сделали свой выбор.
Ищете инструменты для замера времени обновления запросов? У вас есть
три варианта.
1. Ручное измерение. Наименее точный и наиболее трудозатратный метод.
2. Инструмент диагностики запросов в Power BI Desktop. Позволяет фиксировать времена обновления запроса с детализацией до шагов, но
интерпретировать полученные данные придется вам самостоятельно.
Инструмент можно найти на панели редактора Power Query: Инструменты (Tools)  Начать диагностику (Start Diagnostics).
Снижение временных лагов во время разработки  537
В надстройке Monkey Tools от Excelguru. Этот инструмент позволяет провести оценку и построить график по конкретному запросу или полной операции обновления в Excel. Подробности по адресу https://xlguru.ca/monkeytools.
🙈 Предупреждение. Выполнять буферизацию значений рекомендуется только
в том случае, если вы знаете, что не сможете воспользоваться всеми преимуществами механизмов свертывания запросов и ленивых вычислений.
Использование функций буферизации без необходимости может привести к
снижению производительности вашего решения.
🍌 Примечание. Не стоит пытаться буферизовать уже буферизованное значе-
ние с использованием комбинации соответствующих функций. Всегда
выбирайте правильную функцию буферизации, исходя из нужд вашего сценария и с учетом особенностей ваших запросов.
Снижение временных лагов во время разработки
Одним из существенных недостатков в работе с Power Query можно назвать
временные лаги (задержки), то и дело возникающие при добавлении новых
шагов в запросы. И чем объемнее ваши запросы, тем больше вы ощущаете
дискомфорт. Это еще одна проблема, напрямую связанная с механизмом
ленивых вычислений, но на этот раз она относится исключительно к области
воспроизведения блоков предварительного просмотра в Power Query.
Чтобы продемонстрировать то, о чем мы говорим, представьте следующие
рабочие обстоятельства:
 ваш источник данных насчитывает 70 млн строк;
 область предварительного просмотра в Power Query заполняется тысячей строк.
Теперь давайте пройдемся по привычному процессу разработки запросов:
 пользователь подключается к источнику данных;
 Power Query извлекает первую тысячу строк и загружает их в область
предварительного просмотра;
 пользователь фильтрует запрос, оставляя в нем только данные по департаменту 105, тем самым удаляя половину записей из набора.
Что происходит в этот момент? Мы знаем, что Power Query не оставит
в окне предварительного просмотра всего 500 записей, отвечающих установленному критерию. Вместо этого он попробует выполнить свертывание
нового шага в единый запрос и извлечь обновленный набор данных для
предпросмотра.
После этого пользователь удаляет 20 столбцов и… Power Query снова выполняет те же действия. Новое свертывание, новая попытка извлечь данные
538  Глава 19. Оптимизация запросов
для предварительного просмотра на основании обновленного критерия, и
заполнение области на экране.
Таким образом, фактически каждое действие по добавлению или редактированию шага на панели примененных шагов будет приводить к форсированному обновлению данных. А поскольку в нашем источнике насчитывается 70 млн строк, получение набора данных для предварительного
просмотра может занимать немало времени. И часто это вызывает раздражение.
🍌 Примечание. Прежде чем вы успели спросить «А почему бы не использовать
здесь функцию Table.Buffer()?», мы ответим, что в данном случае это не поможет. Когда вы находитесь внутри редактора запросов, функции буферизации
будут в лучшем случае игнорироваться, а в худшем – вызываться повторно,
что приведет к увеличению общего времени обновления, поскольку данные
будут загружаться в память. Иными словами, хотя эти функции могут помочь
вам на этапе выполнения, они не придут вам на помощь при разработке
запросов, поскольку область предварительного просмотра нуждается в обновлении, чтобы отразить все произведенные вами изменения.
Что нам очень хотелось бы иметь в Power Query, так это возможность эффективно буферизовать шаги только в окне предварительного просмотра
при помощи закрепления шага и принудительной буферизации в области
предпросмотра. Далее можно представить, что все последующие шаги считывали бы данные из этого закрепленного шага, пока пользователь не нажмет на кнопку Обновить предварительный просмотр (Refresh Preview),
что приведет к полному пересчету всех шагов в окне запроса. Это обеспечило
бы разработчику более детальный контроль за тем, как должно обновляться
окно предварительного просмотра при работе с большими объемами данных. К сожалению, пока это только мечты, так что нужно искать способы
решения данной проблемы в текущих реалиях.
Стратегия уменьшения временных лагов
Один из методов борьбы с подобного рода задержками состоит в создании промежуточного контейнера для ваших данных в отрыве от источника.
В целом эту задачу можно разбить на следующие шесть шагов.
1. Подключение к источнику данных (запрос Data Source).
2. Создание ссылки на запрос к источнику (запрос Data Staging) и загрузка
его в таблицу Excel.
3. Загрузка таблицы Excel в Power Query с созданием запроса на подключение (Temp Data).
4. Ссылка на запрос Temp Data и создание запроса Output.
5. Перенаправление запроса Output на запрос Data Source.
6. Удаление запросов Data Staging и Temp Data, а также таблицы Excel.
Снижение временных лагов во время разработки  539
Диаграмма цепочек запросов Разработка (Development) и Внедрение
(Release) показана на рис. 19.7.
Разработка
Внедрение
Рис. 19.7. Визуальное сравнение архитектуры запросов
на этапе разработки и внедрения
Если внимательно изучить рис. 19.7, вы увидите, что цепочка Внедрение
(Release) соответствует тому, как мы традиционно создаем запросы в Power
Query. И откровенно говоря, этой процедуры вполне достаточно в большинстве ситуаций – исключение составляют лишь случаи, когда вы действительно начинаете чувствовать ощутимые задержки при разработке запросов.
Здесь-то вам и пригодится альтернативный путь.
Смысл создания новой цепочки запросов состоит во временной загрузке
ограниченного набора данных в таблицу Excel и обращении к ней при разработке нашего запроса. Представьте, что ваш источник данных насчитывает
70 млн записей, и 2000 строк мы временно помещаем на рабочий лист Excel.
При создании своего запроса мы ссылаемся на эти временные данные, что
позволяет заполнять окно предварительного просмотра на основании всего
2000 строк, без обращения к исходной базе данных. И хотя это не избавляет
нас от необходимости постоянно обновлять видимые данные, исходный набор в этом случае существенно сокращается.
🍌 Примечание. Поскольку таблицы Excel не поддерживают механизм сверты-
вания запросов, мы не сможем воспользоваться этой технологией при написании запроса Output. Но по окончании отладки мы сможем перенаправить
наше решение на базовый запрос Raw Data, и механизм свертывания запросов вновь будет активирован, если он поддерживается источником.
Пример борьбы с временными лагами при разработке
На словах описанный выше процесс звучит довольно просто и эффективно, но правда в том, что при реальной разработке запросов вы редко будете
540  Глава 19. Оптимизация запросов
задумываться о том, чтобы применить такой подход. А на тот момент, когда
решите пойти этим путем по причине возникновения все больших задержек
в работе с запросами, у вас уже будет написано довольно много кода. Что
делать в этой ситуации? Как адаптировать существующее решение под эту
методологию?
Допустим, нам необходимо рассчитать итоговую сумму продаж по товарам
и годам. В файле Ch19 Examples\Development Lag­Begin.xlsx представлен запрос
в виде подключения с именем Output, который на данный момент выполняет
следующие действия:
 подключается к базе данных AdventureWorks с использованием личных
сведений из главы 12;
 переходит к таблице Sales Order Detail;
 удаляет все столбцы, за исключением четырех.
В результате у нас получился набор данных, показанный на рис. 19.8.
Рис. 19.8. Текущее состояние запроса
Перед тем как продолжить, мы должны рассказать вам про еще один шаг
в этом запросе. Мы не стали размещать в интернете объемную базу данных,
которая помогла бы вам воспроизвести описываемую проблему, а вместо
этого добавили шаг, искусственно замедляющий работу запроса. Этот шаг
называется Custom1 и содержит следующую формулу:
= Table.Repeat(#"Removed Other Columns»,1000)
Здесь происходит извлечение 542 строк из источника и их дублирование
в количестве 1000 раз. В результате мы получаем набор данных, состоящий
из 542 000 строк, что должно существенно замедлить процесс работы с запросом.
🍌 Примечание. Функция Table.Repeat() просто добавляет один и тот же набор
данных x раз. Это может быть очень полезно для искусственного увеличения
объема исходных данных с целью проведения тестирования.
Снижение временных лагов во время разработки  541
🙈 Предупреждение. Если в процессе обработки вы получите ошибку Expression.
Error, говорящую о нехватке памяти, уменьшите аргумент функции Table.
Repeat() на шаге Custom1 с 1000 до более приемлемого значения.
Сейчас мы сделаем еще два шага к нашей цели и почувствуем на себе действие пресловутого лага:
 разверните в столбце SalesLT.Product только поле с именем Name;
 задайте типы данных для всех столбцов.
Хотя данные, как показано на рис. 19.9, выглядят нормально, каждая операция теперь требует минимум 5-секундного ожидания, которое кажется
вечностью.
Рис. 19.9. Ожидание при изменении типа данных столбца ModifiedDate на Дата (Date)
Хотя нам еще предстоит выполнить несколько действий по преобразованию данных в желаемый формат, сейчас самое время остановиться и попытаться устранить возникшие трудности.
Адаптация решения для снижения временных лагов
Первым делом необходимо обеспечить, чтобы наш существующий запрос
Output по-прежнему загружался в место назначения, поскольку на его выводе
может базироваться какая-то бизнес-логика. По этой причине мы не будем
строить новый запрос на его основании, а вместо этого просто выделим
предыдущие шаги в отдельный запрос, как показано ниже:
 щелкните правой кнопкой мыши на шаге Измененный тип (Changed
Type), выберите пункт Извлечь предыдущий (Extract Previous) и назовите новый запрос Raw Data;
 создайте ссылку на запрос Raw Data и назовите новый запрос Staging
Data;
 выделите запрос Staging Data, на вкладке Главная (Home) нажмите на
выпадающую кнопку Сохранить строки (Keep Rows) и выберите пункт
Сохранить верхние строки (Keep Top Rows), указав в поле количества
сохраняемых строк цифру 1000;
542  Глава 19. Оптимизация запросов
 загрузите все запросы в виде подключения;
 задайте место назначения для запроса Staging Data в виде нового листа
в Excel.
В целом этот процесс может занять у вас какое-то время, поскольку Power
Query будет пытаться извлекать данные для предварительного просмотра
запросов Raw Data и Staging Data. Вы также можете обнаружить, что перед
фильтрацией первой тысячи строк в запросе Staging Data окно предварительного просмотра полностью обновится.
🙈 Предупреждение. Будьте внимательны при загрузке этих запросов. Вам и
так придется ждать полной загрузки запроса Output, а если вы забудете
изменить место назначения запросов при их загрузке, то запрос Raw Data
утроит время вашего ожидания из-за необходимости загружать такое же
количество строк в модель данных, как в случае с запросом Output, да и
запрос Staging Data должен будет загрузиться полностью. Помимо этого, затем вам придется менять тип загрузки для импортированных запросов, что
также займет время.
По готовности мы получим в Excel таблицу из 1000 строк, показанную на
рис. 19.10, с теми же данными, которые отображались бы в окне предварительного просмотра редактора Power Query.
Рис. 19.10. Тысяча строк с данными из «предварительного просмотра»
🍌 Примечание. Не забудьте перед загрузкой данных развернуть все примитивы в столбцах, содержащих значения Value или Table, поскольку Excel не
справится с интерпретацией структурированных типов.
Теперь нам нужно создать запрос на основе этой таблицы и перенаправить
на него запрос Output на время разработки решения:
 щелкните по любой ячейке в таблице и создайте новый запрос, используя кнопку Из таблицы/диапазона (From Table/Range) или Из
листа (From Sheet);
Снижение временных лагов во время разработки  543
 назовите запрос Temp Data;
 выделите запрос Output и измените формулу шага Source на следующую: =#"Temp Data";
 выделите шаг Измененный тип (Changed Type) в запросе Output.
Вы не сможете не заметить, что мы оказались в том же месте, где были
до разделения запросов, но при этом окно предварительного просмотра заполнилось очень быстро.
Теперь давайте завершим разработку нашего запроса, не тратя времени
на временные лаги:
 выделите столбцы OrderQty и UnitPrice и на вкладке Добавление
столбца (Add Column) нажмите на выпадающую кнопку Стандартный
(Standard) и выберите вариант Умножить (Multiply);
 выделите столбец ModifiedDate, на вкладке Преобразование (Transform)
нажмите на выпадающую кнопку Дата (Date) и в подменю Год (Year)
выберите пункт Год (Year);
 щелкните правой кнопкой мыши на заголовке столбца ModifiedDate,
выберите пункт Переименовать (Rename) и введите новое имя Year;
 выделите столбцы Year и Name, после чего на вкладке Преобразование
(Transform) нажмите на кнопку Группировать по (Group By);
 в открывшемся диалоговом окне назовите новый столбец Revenue и
установите в качестве операции суммирование по полю Умножение
(Multiplication).
После этого вывод вашего запроса будет таким, как показано на рис. 19.11.
Рис. 19.11. Теперь наши данные отражают
суммарные доходы по годам и товарам
Если вы вместе с нами выполняли последние шаги, то наверняка заметили,
как быстро производились все действия по сравнению с тем, что было раньше. Осталось сделать завершающие шаги:
 выделите шаг Source в запросе Output;
 верните прежнюю формулу для этого шага: =#"Raw Data";
 закройте и загрузите запрос.
544  Глава 19. Оптимизация запросов
🍌 Примечание. Вы не обязаны ждать окончания обновления окна предварительного просмотра, чтобы начать загрузку запроса. Также стоит упомянуть,
что после нажатия на кнопку загрузки данных Power Query принудительно
произведет обновление только запроса Output, поскольку запрос Staging
Data мы не меняли.
Теперь, когда запрос Output вновь указывает на исходную базу данных,
вам потребуется какое-то время для его загрузки в модель данных. После
этого вы можете удалить рабочий лист, служивший хранилищем для запроса
Staging Data, а также сами запросы Staging Data и Temp Data.
🍌 Примечание. В законченном файле мы перенаправили запрос Output на Raw
Data. Запросы Staging Data и Temp Data мы оставили, так же, как и рабочий
лист Staging Data.
Изменение данных в предпросмотре
Причина ускорения работы с использованием описанного здесь приема
состоит в своеобразном замораживании исходных данных на определенном
шаге. А что, если вам потребуется расширить или изменить эти данные во
время разработки?
Ответ прост – вы можете вносить все необходимые изменения в запрос
Data Staging, служащий источником для нашего рабочего листа в Excel.
Чтобы изменить данные, добавьте новый шаг Удаление верхних строк
(Remove Top Rows) перед шагом сохранения строк. Это фактически позволит
вам перейти к следующему блоку строк в вашем наборе данных.
Если же вам необходимо загрузить больше данных, просто измените шаг
для сохранения верхних строк, увеличив входной аргумент.
Помните о том, что запрос Data Staging по-прежнему указывает на исходную базу данных, так что при его изменении вы будете испытывать те же
временные задержки. Зато после окончания редактирования запроса предварительный просмотр в запросе Output будет извлекать данные уже из обновленного набора.
Ошибка Formula Firewall
Ошибка Formula.Firewall – страшный сон для всех пользователей Power
Query – обычно возникает при попытке комбинировать данные из различных источников. Ее смысл понимают далеко не все, к тому же она выглядит
очень устрашающе и всегда заканчивается загадочной фразой «Please rebuild
this data combination» («Пожалуйста, перестройте ваше сочетание данных»).
Одной из самых больших сложностей, связанных с этим сообщением об
ошибке, является то, что оно может возникать в абсолютно разных ситуациях
и по совершенно разным причинам.
Ошибка Formula Firewall  545
Ошибка Formula.Firewall № 1: несовместимость
уровней конфиденциальности
Первый тип ошибки Formula.Firewall, показанный на рис. 19.12, возникает,
когда вы внутри одного запроса пытаетесь получить доступ к нескольким
источникам данных с несовместимыми уровнями конфиденциальности.
Рис. 19.12. Причина ошибки Formula.Firewall – несовместимость
уровней конфиденциальности
Мы детально обсудили эту проблему в главе 12 в разделе, посвященном
уровням конфиденциальности данных. При появлении этого типа ошибки
мы советуем вам обратиться к этой главе и следовать приведенным там советам по ее устранению.
Ошибка Formula.Firewall № 2: доступ
к источнику данных
Сравните ошибки Formula.Firewall, показанные на рис. 19.12 и 19.13.
Рис. 19.13. Ошибка Formula.Firewall, связанная с доступом к источнику данных
Вполне понятно, почему некоторым эти ошибки в процессе работы кажутся совершенно идентичными. Сообщения о них начинаются одинаково и
заканчиваются одними и теми же словами. И давайте быть честными – неужели кто-то когда-то читает полный текст ошибки? Вот и нам так кажется.
Максимум, что вы делаете, – это цепляете мышью последние несколько слов
из сообщения об ошибке и кидаете их в гугл.
Но в данном случае суть проблемы содержится именно в центральной части текста, и именно там кроется подсказка о том, что необходимо сделать,
чтобы исправить ситуацию. И хотя отключение конфиденциальности в настройках порой помогает избавиться от этой доставучей ошибки, это работает не всегда. В ситуациях, когда вы либо не можете отключить конфиденциальность, либо это не помогает, у вас остается один выход – последовать
совету Power Query и перестроить сочетание данных. Но как?
546  Глава 19. Оптимизация запросов
Вызов ошибки перестроения сочетания данных
Эта ошибка часто возникает при попытке использовать значения из одного источника данных для динамического извлечения/объединения и/или
фильтрации данных из другого источника. Такая ситуация характерна для
работы с таблицами параметров в Excel, а также с источниками или базами
данных, хранящимися в интернете.
Суть этой ошибки кроется в том, что перед вычислением результатов запроса Power Query сканирует весь запрос целиком на предмет того, какие
источники данных в нем используются и как обстоит дело с совместимостью
их уровней конфиденциальности. Эти действия называются статическим
анализом, и в процессе их выполнения Power Query определяет функции в
источниках данных и аргументы, передаваемые этим функциям.
Проблема с «динамическими источниками данных», в которых ключевой
компонент функции представлен не статическим значением, а динамическим, заключается в необходимости предварительно вычислить аргумент
функции источника, чтобы Power Query знал, куда ему нужно подключиться
и как это повлияет на конфиденциальность данных. Но это в корне нарушает основные принципы и структуру механизма ленивых вычислений, что и
приводит к возникновению ошибки Formula.Firewall.
🍌 Примечание. Говоря коротко, попытка передать динамическое значение
в любую функцию языка M, относящуюся к функциям доступа к данным, с
большой степенью вероятности приведет к возникновению ошибки. С полным списком функций этого типа можно ознакомиться по адресу https://
docs.microsoft.com/en-us/powerquery-m/accessing-data-functions.
Для демонстрации этой проблемы и способов обхода ошибок, связанных
с доступом к данным, давайте исследуем запросы из файла Ch19 Examples\
Firewall­Begin.xlsx. Этот файл содержит четыре следующих ключевых компонента:
 функцию fnGetParameter (которую мы рассматривали в главе 17);
 таблицу параметров, показанную на рис. 19.14;
Рис. 19.14. В таблице параметров применяется проверка данных
для заполнения полей Date и Department
Ошибка Formula Firewall  547
 запрос Timesheet, извлекающий и преобразующий данные из текстового файла. Полный путь к файлу генерируется динамически на основании значений File Path, Timesheet и Date из таблицы параметров и
передается на вход запросу Timesheet на шаге FilePath;
 запрос EmployeeDepts, извлекающий данные из рабочей книги Excel с
названием Departments.xlsx. Путь к этому файлу также динамически
генерируется на шаге FilePath в запросе EmployeeDepts и, как и в случае
с запросом Timesheet, использует для этого функцию fnGetParameter.
В данный момент запросы Timesheet и EmployeeDepts загружены только в
виде подключений, при этом первый из них динамически подгружает нужное
расписание на основании значений, выбранных в таблице параметров. Наша
цель сейчас – присоединить таблицу с департаментами к расписанию, чтобы
мы могли видеть, к какому из отделов прикреплен конкретный сотрудник, и
добавить возможность динамически фильтровать запрос из рабочего листа:
 перейдите в режим редактирования запроса TimeSheet и на вкладке
Главная (Home) нажмите на кнопку Объединить запросы (Merge
Queries);
 выделите в верхней таблице столбец Worker, выберите в выпадающем
списке запрос EmployeeDepts и отметьте в нем колонку Employee.
В этот момент вы получите предупреждение о том, что Power Query не
удалось определить, сколько результатов возвращается при поиске, как показано на рис. 19.15.
Рис. 19.15. Что все это значит?
548  Глава 19. Оптимизация запросов
Мы отчетливо видим, что упоминание о сотруднике Thompson, John присутствует в обеих таблицах, но при этом Power Query сообщает нам о проблеме. Давайте не будем обращать на это внимания и нажмем на кнопку OK.
В результате мы получим ошибку, показанную на рис. 19.16.
Рис. 19.16. Power Query явно не очень рад
Если говорить предельно точно, шаг Объединенные запросы (Merged Queries)
ссылается на другой запрос, который напрямую подключается к источнику
данных. Именно это мы видим во второй строке кода на языке M, как показано на рис. 19.17.
Рис. 19.17. Запрос EmployeeDepts ссылается на источник
посредством функции File.Contents()
Как бы то ни было, это не работает так, как мы предполагали, так что давайте удалим этот шаг. Остается вопрос – как же нам достичь нашей цели?
Перестроение сочетания данных против создания
цепочек запросов
Если бы вы следовали принципам архитектуры со множеством запросов,
которую мы обсуждали в главе 2, вполне вероятно, что в такую ловушку вы
бы не угодили. Почему? Причина проста – в этом случае, вместо того чтобы
объединять данные непосредственно в запросе Timesheet, мы бы сделали
иначе. Попробуйте:
 щелкните правой кнопкой мыши по запросу Timesheet, выберите пункт
Ссылка (Reference) и задайте имя запроса Output;
 выполните объединение в запросе Output;
 разверните столбец EmployeeDepts и извлеките из него поле Department.
Ошибка Formula Firewall  549
Как видно на рис. 19.18, все прошло гладко, без всяких ошибок Formula.
Firewall.
Рис. 19.18. Именно это мы и планировали увидеть сразу
Это одна из причин, почему мы разделяем запросы на отдельные компоненты.
Теперь давайте пойдем дальше. Мы хотим добавить фильтр, чтобы иметь
возможность динамически выбирать, какой департамент показывать. Попробуем:
 отфильтруйте столбец Department, оставив в нем только вариант
Accounting;
 замените в строке формул "Accounting" на fnGetParameter("Department").
Отлично, мы получили еще одну ошибку, показанную на рис. 19.19.
Рис. 19.19. Еще одна ошибка доступа к источнику данных
О чем нам говорит эта ошибка? Этот запрос не обращается к источнику
данных, хотя ссылается на два запроса, которые это делают. Но в данном случае проблема не в них, а в шаге запроса. Причина? Функция fnGetParameter
по своей природе обращается к источнику данных (таблице параметров на
листе Excel), чтобы вернуть значение.
Как с этим справиться? Выделить извлечение параметра в отдельный шаг.
Это можно сделать, вызвав функцию fnGetParameter для создания отдельного
запроса:
 выделите функцию fnGetParameter;
 в параметр getValue введите слово Department и нажмите на кнопку
Вызвать (Invoke);
 назовите созданный запрос Department.
Powered by TCPDF (www.tcpdf.org)
550  Глава 19. Оптимизация запросов
В результате мы получим простейший запрос, извлекающий параметр
Department из таблицы Excel и возвращающий его значение в виде примитива, как показано на рис. 19.20.
Рис. 19.20. Запрос Department был создан путем вызова функции fnGetParameter
Теперь давайте посмотрим, как нам это поможет с нашей проблемой:
 перейдите к запросу Output и выделите шаг Строки с примененным
фильтром (Filtered Rows);
 измените формулу так, чтобы она заканчивалась на each ([Department]
= Department)), как показано на рис. 19.21.
Рис. 19.21. Результаты запроса оказались динамически отфильтрованы
по имени файла (дата) и департаменту
После этого запрос не только вернул нам результаты вместо ошибки
Formula.Firewall, но и правильно отфильтровал их по отделу Forming, как
указано в нашей таблице параметров в Excel.
Также мы хотим сделать еще одно замечание по поводу этого решения, и
касается оно заполнения фильтра по отделам. В таблице параметров в Excel
пользователь может выбрать один департамент, но может и оставить поле
пустым, чтобы посмотреть информацию по всем отделам. Однако если он
просто очистит значение в ячейке, наш запрос Department вернет значение null. Давайте добавим динамики шагу Строки с примененным фильтром
(Filtered Rows), чтобы он выполнялся только в случае, если запрос Department
вернул непустое значение. В противном случае мы не будем ничего делать, а
значит, просто вернем результаты предыдущего шага Развернутый элемент
EmployeeDepts (Expanded EmployeeDepts). Таким образом, давайте заменим
эту формулу шага с фильтром:
Ошибка Formula Firewall  551
= Table.SelectRows(#"Expanded EmployeeDepts",
each ([Department] = Department))
на эту:
= if Department <> null
then Table.SelectRows(#"Expanded EmployeeDepts",
each ([Department] = Department))
else #"Expanded EmployeeDepts"
Теперь вы можете загрузить запрос Output на рабочий лист Excel и сделать
следующее:
 выберите, какой файл вы хотите извлечь, при помощи выпадающего
списка в ячейке C7 (параметр Date);
 выберите, информацию по какому отделу вы хотите видеть, в ячейке
C8 (параметр Department). Также вы можете оставить это поле пустым.
Выбор должен работать нормально, при условии что ваш путь к файлам
не начинается с https://.
🍌 Примечание. Параметр с датой не влияет на фильтр, он помогает при фор-
мировании пути к файлу для извлечения. Поэтому попытка оставить пустым
это поле приведет к возникновению ошибки. Также стоит отметить, что это
относится только к нашей реализации решения. Вы могли бы извлекать данные из папки и использовать параметр по дате в качестве динамического
фильтра.
Преимущество этого подхода (если не считать мелких доработок фильтра)
заключается в возможности реализовать все только при помощи интерфейса пользователя. Кроме того, использование этой методики поможет вам в
большинстве случаев обойти ошибку Formula.Firewall. Однако, как бы нам ни
хотелось утверждать, что способ с созданием цепочек запросов является на
100 % надежным, к сожалению, бывают случаи, когда необходимо применять
иные подходы.
Перестроение сочетания данных против
выравнивания запросов
Еще один вариант – произвести выравнивание (flattening) всех ваших обращений к данным в рамках одного запроса. Хотя это можно сделать при
помощи интерфейса пользователя и кнопки fx, в реальности гораздо удобнее
будет реализовать задуманное посредством кода на языке M в расширенном
редакторе.
Полный текст запроса содержится в файле Ch19 Examples\Firewall­Complete.
xlsx в виде запроса с именем All_In_One. Если судить по названию, этот запрос
вполне может функционировать обособленно, и при этом в нем реализова-
552  Глава 19. Оптимизация запросов
на вся логика из предыдущего раздела. Фактически вы можете удалить все
остальные запросы из рабочей книги, и запрос All_In_One загрузит результаты в полной идентичности с запросом Output, который мы писали ранее.
Основной принцип, лежащий в основе этого подхода, заключается в настройке шагов для подключения ко всем необходимым источникам данных
в рамках одного запроса. Фокус состоит в том, чтобы выполнить все эти подключения в самом начале запроса, еще до работы с ними. Запрос All_In_One
с комментариями приведен на рис. 19.22.
Рис. 19.22. Выровненное решение с реализацией логики в рамках одного запроса
Давайте отметим несколько важных моментов касательно этого запроса
(номера соответствуют номерам на рис. 19.22).
1. Мы вложили функцию fnGetParameter (переименованную в
fxGetParameter, чтобы избежать конфликтов с исходной функцией) прямо в наш запрос. В этом не было особой необходимости, поскольку мы
могли и сослаться на оригинальную функцию fnGetParameter, но мы
решили сделать это решение полностью автономным. Если вы будете
делать так же, мы рекомендуем вам включать объявление всех функций
в самое начало запроса.
2. Далее мы объявляем все переменные для обращения к нужным нам
источникам данных: FilePath, TimesheetPath и Dept.
Ошибка Formula Firewall  553
3. Эта секция повторяет оригинальный запрос EmployeeDepts, измененный для явного определения имен шагов.
4. Здесь мы используем те же шаги, что и в запросе Timesheet, но с измененными именами во избежание конфликтов.
5. Заключительная секция, ранее реализованная в запросе Output, вложена в общий запрос.
Очевидным преимуществом такого подхода по сравнению с предыдущим
является то, что единый запрос гораздо проще переносить из одного решения в другое.
Перестроение сочетания данных при передаче
значений в SQL
Бывают ситуации, когда вы не можете использовать выравнивание запросов или разделять их на цепочки. В этом случае вы можете передать фильтры
из таблицы Excel непосредственно на вход запроса SQL. Представьте, что
нужно дать пользователю возможность выбирать транзакции с суммами,
входящими в заданный диапазон. Он создает запрос SQL и пытается передать в него параметры, полученные при помощи функции fnGetParameter,
как показано на рис. 19.23.
Рис. 19.23. Ошибка Formula.Firewall при передаче переменных в выражение SQL
По причине динамического доступа к источнику шаги MinValue и MaxValue
не могут быть переданы в функцию для доступа к данным вроде SQL.
Database(). И хотя мы здесь имеем дело с выровненным запросом, в котором
все источники данных содержатся в рамках одного запроса, очень важно понимать, что в целом итог будет такой же, как в случае с отдельными запросами MinValue и MaxValue. Ошибка Formula.Firewall будет возникать всякий раз
при попытке передачи динамически полученных компонентов в функцию,
осуществляющую доступ к источнику данных.
554  Глава 19. Оптимизация запросов
🍌 Примечание. Мы по-прежнему настоятельно рекомендуем вам использо-
вать Power Query для подключения к источникам данных и осуществления
фильтрации посредством интерфейса пользователя – это позволит выполнять свертывание запросов и избежать лишних проблем. Но это ваш выбор,
к тому же бывают случаи, когда вам просто необходимо передать заранее
подготовленный запрос базе данных SQL.
К счастью, существует функция Value.NativeQuery(), служащая как раз для
этих целей. Она позволяет безопасно объявлять и передавать динамические
значения в запрос SQL. Но для того чтобы ее использовать, нам придется
выполнить кое-какую предварительную работу.
В файле Ch19 Examples\Dynamic SQL.xlsx вы найдете таблицу параметров в виде, представленном
на рис. 19.24.
Первое, что нужно сделать, – это создать два заРис. 19.24. Таблица
проса для извлечения значений требуемых параметпараметров для
ров. Названия запросов и их формулы приведены
указания минимального
ниже:
и максимального
 valMin =Text.From(fnGetParameter("Minimum"))
 valMax =Text.From(fnGetParameter("Maximum"))
значений
🍌 Примечание. Файл с примером содержит запрос с именем NativeQuery-Flat,
в котором мы попытались реализовать все это в одном запросе. Увы, это привело к возникновению нашей любимой ошибки Formula.Firewall.
Теперь, когда мы извлекли значения наших параметров из таблицы в Excel,
можно воспользоваться функцией Value.NativeQuery() для создания нового
запроса. Код на языке M для запроса показан ниже:
let
Source = Sql.Database(
"xlgdemos.database.windows.net", "AdventureWorks"),
Return = Value.NativeQuery(
Source,
"SELECT SalesOrderID, OrderQty,ProductID, UnitPrice, LineTotal
FROM [SalesLT].[SalesOrderDetail]
WHERE LineTotal >= @Minimum AND LineTotal <= @Maximum",
[Minimum=valMin, Maximum=valMax] )
in
Return
Если вы знаете язык запросов SQL, то без труда поймете, что здесь происходит. Последний аргумент функции Value.NativeQuery() выступает в роли
неявной инструкции DECLARE, позволяющей определить все переменные,
которые мы будем использовать в запросе SQL, и инициализировать их
Ошибка Formula Firewall  555
нужными значениями. Присвоенные переменным значения (в нашем случае это запросы valMin и valMax) передаются запросу SQL в виде переменных @Minimum и @Maximum. В результате мы получим полноценный запрос SELECT, который отправим базе данных, определенной на шаге Source.
🍌 Примечание. При попытке загрузки запроса, использующего функцию Value.
NativeQuery(), вы будете получать предупреждения для каждого отправляемого в базу данных запроса. И хотя эти предупреждения можно отключить,
мы делать этого не рекомендуем, а причины были описаны ранее в этой
главе.
Результат приведенного выше решения показан на рис. 19.25.
Рис. 19.25. Запрос с динамическим выражением SQL
🍌 Примечание. В файле с примерами содержится как правильный вариант
запроса, так и попытки, приведшие к появлению ошибки Formula.Firewall.
На самом деле область применения функции Value.NativeQuery() гораздо
шире, чем составление динамических запросов SELECT. В частности, ее можно использовать для запуска хранимых процедур (stored procedure).
Заключительные мысли об ошибках Formula.Firewall
Если с ошибками, связанными с несовместимостью уровней конфиденциальности данных, справиться бывает довольно просто, проблемы с доступом
к данным могут доставлять разработчику куда больше хлопот. При создании
решений необходимо думать о том, чтобы источники данных в запросах
были изолированы друг от друга. Зачастую этого можно добиться, ограничив
запросы отдельными источниками данных или загружая их на ранних стадиях запроса. Использование настраиваемых функций и параметров также
может помочь отделить разные источники данных друг от друга, особенно
если вам необходимо вернуть значение для каждой строки в таблице.
Глава
20
Автоматизация
обновлений
Все больше и больше работая с Power Query и осознавая, сколько времени
позволяет экономить этот потрясающий инструмент, вы невольно задумываетесь о еще большей автоматизации процессов. Да, можно просто нажимать на кнопку Обновить все (Refresh All), но со временем и это действие
начинает казаться каким-то слишком уж… ручным. Не лучше ли как-то запланировать обновления или даже взять под контроль порядок выполнения
обновлений?
Варианты автоматического обновления в Excel
Power Query предлагает сразу несколько опций для автоматического обновления:





обновление при открытии рабочей книги;
обновление каждые x минут;
обновление соединения по требованию посредством кода VBA;
обновление всех соединений посредством кода VBA;
настройка расписания обновлений при помощи сторонних средств.
Каждый из этих методов имеет свои достоинства и недостатки, о которых
мы и поговорим в этой главе.
Обновления в Excel без VBA
Первые два способа настройки обновлений не предусматривают программирования на языке VBA. Они могут быть реализованы на уровне подключения,
а автоматизация при желании может затрагивать и Power Pivot. Всеми подключениями можно управлять на панели запросов и подключений:
 перейдите на вкладку Данные (Data), нажмите на кнопку Запросы
и подключения (Queries & Connections), щелкните правой кнопкой
мыши по нужному запросу и выберите пункт Свойства (Properties).
558  Глава 20. Автоматизация обновлений
Это приведет к открытию диалогового окна, показанного на рис. 20.1.
Рис. 20.1. Диалоговое окно Свойства запроса
Фоновое обновление
С концепцией фонового обновления мы познакомились в главе 19. Эта
опция может быть включена или отключена на трех уровнях:
 на уровне запроса: в свойствах конкретного запроса, как показано
на рис. 20.1;
 на уровне рабочей книги: в разделе Загрузка данных (Data Load) в
настройках текущей книги в окне Параметры запроса (Query Options);
 на уровне приложения: в разделе Загрузка данных (Data Load) в
глобальных настройках в окне Параметры запроса (Query Options).
🍌 Примечание. Для доступа к этому диалоговому окну нажмите на выпадаю-
щую кнопку Получить данные (Get Data) и выберите пункт Параметры запроса (Query Options).
Маловероятно, что вы будете пользоваться этими настройками, поскольку
пользователи обычно предпочитают отключать фоновую загрузку для всего
решения в целом, а не для конкретного подключения. Но если вам вдруг
понадобится переопределить установки для выбранного подключения, вы
можете сделать это именно здесь.
Обновление каждые X минут
Следующая настройка касается обновления данных с определенной периодичностью. Устанавливая соответствующий флажок в диалоговом окне,
вы также можете задать интервал обновлений. Эта настройка может вам
пригодиться, если вы извлекаете данные из обновляющегося источника в ин-
Обновления в Excel без VBA  559
тернете или из базы данных, также подвергающейся периодическим обновлениям. В подобном случае вы можете постоянно быть уверены, что ваши
данные актуальны, пока вы работаете с файлом.
Помните, что рабочая книга должна быть открыта, чтобы эти обновления
выполнялись. И если вы хотите, чтобы ваша рабочая книга во время работы
с ней обновлялась довольно часто, вам нужно убедиться, что параметр фонового обновления включен.
🍌 Примечание. В поле с минутами можно ввести значение от 1 до 32,767, что
позволяет задать периодичность автоматических обновлений в диапазоне
от 1 минуты до 22,75 дня.
Обновление при открытии рабочей книги
В этой области диалогового окна присутствуют две настройки:
 обновление при открытии файла;
 удаление данных из внешнего диапазона перед сохранением книги.
Первый пункт в дополнительных пояснениях не нуждается. При установке
этого флажка данные будут обновляться всякий раз, когда файл открывается. Это позволит вам гарантировать актуальность информации при начале
работы с файлом.
Если вы работаете с большим количеством источников данных или обновление информации требует достаточно продолжительного времени, вероятно, вам лучше будет установить флажок для фоновых обновлений, чтобы вы
могли использовать рабочую книгу в это время.
Вторая опция в этой области касается того, будут ли в рабочей книге сохраняться данные или только определения запросов. Фактически эта настройка
связана с безопасностью, поскольку позволяет обеспечить пользователям
доступ к источнику данных при открытии рабочей книги. Если доступа не
будет, перед ними предстанет пустая таблица из-за невозможности обновить
данные. В противном случае запрос будет запущен и данные отобразятся.
Быстрая загрузка данных
Флажок Включить быструю загрузку данных (Enable Fast Data Load)
позволяет определить, хотите ли вы продолжать работать в Excel в моменты
обновления данных. Если установить его, это может существенно снизить
количество времени, требуемого для обновления данных, но при этом интерфейс Excel будет заблокирован, что не позволит вам работать с программой.
Если вы хотите, чтобы пользователи не могли взаимодействовать с данными до момента их полного обновления, эта опция – ваш выбор. Но если
вы желаете продолжать работать во время обновлений, мы советуем не устанавливать этот флажок.
560  Глава 20. Автоматизация обновлений
🍌 Примечание. Эта опция может быть установлена глобально в диалоговом
окне Параметры запроса (Query Options).
Автоматизация обновлений запросов
в Excel с помощью VBA
Варианты, перечисленные выше, позволят вам настроить обновление запросов без всяких предупреждений о безопасности макросов. Кроме того,
рабочие книги, в которых используется такое обновление, легче перенести
в Power BI, поскольку их использование не приводит ни к каким проблемам
с блокировками.
Но если вы работаете исключительно в Excel, у вас время от времени будет
возникать желание дать пользователям возможность легко и удобно обновлять свои решения, использующие Power Query. Это можно реализовать при
помощи макросов VBA.
Обновление одного подключения
Давайте посмотрим, как при помощи макроса можно обновить одно подключение Power Query. Откройте файл Ch20 Examples\Automating Refresh.xlsx
и перейдите на рабочий лист Transactions.
Здесь вы видите исходную таблицу с именем Transactions и сводную таблицу. Предположим, нам необходимо создать макрос для обновления таблицы
Transactions, а следом за ней и сводной таблицы.
Для этого мы запишем простой макрос следующим образом:
 перейдите на вкладку Разработчик (Developer);
🍌 Примечание. Если у вас не отображается вкладка Разработчик (Developer),
щелкните правой кнопкой мыши по ленте и выберите пункт Настройка ленты (Customize Ribbon). В правом окне установите флажок напротив пункта
Разработчик (Developer) и нажмите на кнопку OK.
 в левом верхнем углу ленты нажмите на кнопку Запись макроса
(Record Macro), как показано на рис. 20.2;
Рис. 20.2. Запись макроса
Автоматизация обновлений запросов в Excel с помощью VBA  561
🙈 Предупреждение. После начала записи макроса Excel будет фиксировать
все ваши действия, включая щелчки мышью, даже ошибочные. Следуйте приведенным ниже шагам в точности, чтобы получить чистый макрос!
 назовите макрос Refresh, укажите вариант сохранения Эта книга (This
Workbook) и нажмите на кнопку OK;
 перейдите на вкладку Данные (Data) и нажмите на кнопку Обновить
все (Refresh All);
 вернитесь на вкладку Разработчик (Developer) и нажмите на кнопку
Остановить запись (Stop Recording).
🍌 Примечание. Кнопка Обновить все (Refresh All) служит для обновления всех
подключений в рабочей книге, а также сводных таблиц, подключенных к
таблицам, созданным при помощи Power Query.
Макрос записан и готов к использованию. Давайте его проверим:
 перейдите на вкладку Разработчик (Developer) и нажмите на кнопку
Макросы (Macros).
Откроется диалоговое окно со всеми макросами в нашей рабочей книге,
показанное на рис. 20.3. Поскольку у нас есть только один макрос с именем
Refresh, давайте выберем его и нажмем на кнопку Выполнить (Run).
Рис. 20.3. Запуск макроса
При запуске макроса вы увидите, что обновится таблица Transactions, а
следом и сводная таблица. Конечно, это было бы еще более заметно, если
бы исходные данные изменились, но мы используем статический источник
данных.
562  Глава 20. Автоматизация обновлений
Как бы это все здорово ни было, отправлять пользователей на вкладку
Разработчик как-то не хочется. Почему бы не сделать для них отдельную
кнопку для обновления макроса?
 Перейдите на вкладку Разработчик, нажмите на кнопку Вставить
(Insert) и выберите левую верхнюю иконку из списка, обозначающую
кнопку;
 выберите свободное место на рабочем листе;
 зажмите левую кнопку мыши и переместите курсор вправо и вниз,
создавая кнопку.
Появится диалоговое окно Назначить макрос объекту (Assign Macro) с
нашим макросом в списке:
 выделите макрос Refresh;
 нажмите на кнопку OK;
 щелкните правой кнопкой мыши по созданной кнопке и выберите
пункт Изменить текст (Edit Text);
 введите текст Refresh;
 выделите любую свободную ячейку на листе.
Теперь у вас есть на рабочем листе кнопка для обновления таблиц, как
показано на рис. 20.4.
Рис. 20.4. Кнопка запуска макроса
Нажмите на кнопку. Теперь любой пользователь сможет легко и просто
обновлять ваши запросы.
🍌 Примечание. При необходимости изменить свойства кнопки просто щелкните по ней правой кнопкой мыши. Это переведет ее в режим разработки, о
чем будут свидетельствовать белые кружки по периметру кнопки. Выделите
любую ячейку на рабочем листе для перевода кнопки обратно в режим работы.
Автоматизация обновлений запросов в Excel с помощью VBA  563
Обновление в определенном порядке
Следующая наша задача – получить контроль над порядком, в котором будут обновляться запросы. По умолчанию запросы обновляются по алфавиту,
если какой-либо из них не обновляется заранее из другого (родительского)
запроса. И хотя можно задать порядок обновления запросов путем их переименования, это нежелательный способ.
Мы попробуем задать порядок обновления запросов вручную следующим
образом:
 перейдите на вкладку Разработчик и нажмите на кнопку Запись макроса (Record Macro);
 назовите макрос Refresh_Explicit, укажите вариант сохранения Эта книга (This Workbook) и нажмите на кнопку OK;
 перейдите на вкладку Данные (Data) и нажмите на кнопку Обновить
все (Refresh All);
 вернитесь на вкладку Разработчик и нажмите на кнопку Остановить
запись (Stop Recording).
 перейдите на панель Запросы и подключения (Queries & Connections),
щелкните правой кнопкой мыши по запросу Transactions и выберите
пункт Обновить (Refresh);
 щелкните правой кнопкой мыши по ячейке в сводной таблице (мы выбрали ячейку G6) и также выберите пункт Обновить (Refresh);
 перейдите на вкладку Разработчик и нажмите на кнопку Остановить
запись (Stop Recording);
 перейдите на вкладку Разработчик, нажмите на кнопку Макросы
(Macros), выделите созданный запрос и нажмите на кнопку Изменить
(Edit).
Откроется окно редактора Visual Basic (Visual Basic Editor), в котором вы
увидите приведенный ниже код:
Sub Refresh_Explicit()
'
' Refresh_Explicit Macro
'
'
ActiveWorkbook.Connections("Query - Transactions").Refresh
Range("G6").Select
ActiveSheet.PivotTables("PivotTable1").PivotCache.Refresh
End Sub
🍌 Примечание. Слово Query может быть локализовано в зависимости от уста-
новки Excel, в которой создавался запрос. Каждый из существующих запросов в этой рабочей книге будет иметь префикс Query, поскольку запросы
создавались в английской версии Excel. (В русской версии программы слово
Query будет изменено на Запрос. – Прим. перев.)
564  Глава 20. Автоматизация обновлений
Разберем записанный макрос построчно:
 в первых четырех строках после указания имени процедуры Sub Refresh_
Explicit() находятся комментарии к макросу, которые можно удалить;
 за обновление подключения отвечает строка, начинающаяся с
ActiveWorkbook;
 в следующей строке происходит выбор диапазона на листе;
 в последней строке макроса выполняется обновление сводной таблицы.
Теперь мы можем внести изменения в макрос, чтобы не только можно
было управлять порядком обновления запросов, но и в целом сделать код
более надежным, поскольку сейчас мы получим ошибку, если запустим макрос на листе, на котором нет сводной таблицы.
Измененный код макроса может выглядеть так:
Sub Refresh()
ActiveWorkbook.Connections("Query – Jan2008").Refresh
ActiveWorkbook.Connections("Query – Feb2008").Refresh
ActiveWorkbook.Connections("Query – Mar2008").Refresh
ActiveWorkbook.Connections("Query – Transactions”).Refresh
Worksheets("Transactions").PivotTables("PivotTable1") _
.PivotCache.Refresh
End Sub
Заметьте, что мы избавились от необязательных комментариев в начале
макроса. После этого мы добавили строки для задания определенного порядка обновления запросов.
Вдобавок в последней строке запроса мы заменили объект ActiveSheet на
Worksheets("Transactions"), указав на то, что сводная таблица, которую следует обновить, находится на рабочем листе с именем Transactions.
Теперь по нажатии на кнопку обновления все запросы будут обновляться
в заданном порядке, после чего будет обновлена сводная таблица.
🍌 Примечание. Этот пример мы привели исключительно в качестве иллюстра-
ции, поскольку здесь наши данные обновляются дважды: сначала в месячных запросах, а затем в запросе Transactions, являющемся родительским для
них всех. В обычных условиях мы бы использовали такую технику, если бы
обновляли запрос, который должен быть загружен на рабочий лист перед
загрузкой в другой запрос.
🙈 Предупреждение. Вам стоит знать, что рабочую книгу, содержащую макросы,
нельзя сохранять с расширением .xlsx. Вместо этого необходимо использовать расширение .xlsm. Таким образом, пользователи, у которых установлена
защита в Excel, при открытии книги будут получать предупреждение о том,
что в ней присутствуют макросы.
Автоматизация обновлений запросов в Excel с помощью VBA  565
Обновление всех запросов
Чтобы обновить только запросы в рабочей книге, созданные в Power Query,
необходимо использовать несколько иную технику. В представленном ниже
макросе мы проходим по всем подключениям в рабочей книге и проверяем,
были ли они созданы в Power Query:
Public Sub RefreshPowerQueriesOnly()
Dim lTest As Long, cn As WorkbookConnection
On Error Resume Next
For Each cn In ThisWorkbook.Connections
lTest = InStr(1, cn.OLEDBConnection.Connection, _
"Provider=Microsoft.Mashup.OleDb.1")
If Err.Number <> 0 Then
Err.Clear
Exit For
End If
If lTest > 0 Then cn.Refresh
Next cn
End Sub
Этот макрос можно сохранить в той же рабочей книге, в которой мы создавали предыдущие макросы, а можно и заменить им написанный ранее
код, не забыв при этом перенаправить нашу кнопку обновления на новый
макрос.
🙈 Предупреждение. Представленный выше код не будет соблюдать нужный
вам порядок обновления запросов, поскольку Excel обрабатывает запросы в
алфавитном порядке. Чтобы задать нужную вам последовательность обновления запросов, используйте описанную ранее технику.
Проблемы с синхронным обновлением
В написанном нами макросе предполагается, что единственной нашей
целью является обновление запросов. В более сложных сценариях, когда вам
необходимо, чтобы Power Query завершал загрузку запросов на рабочий лист
или в модель данных перед переходом к следующему шагу, приведенного
выше подхода может оказаться недостаточно.
Однако, поскольку столь высокие требования не слишком распространены
в среде разработчиков, мы не будем уделять время этой теме. Также стоит
знать, что Power Query выполняет обработку данных в асинхронной манере,
после чего переходит к следующей инструкции VBA еще до того, как процесс
загрузки на рабочий лист или в модель данных завершится. Если это вам не
подходит, вы можете рассмотреть вариант запуска обновления в таблице
566  Глава 20. Автоматизация обновлений
назначения вместо автоматизации обновлений запросов Power Query, объединяющих данные в таблице.
Расписание обновлений в Power BI
Хотя в Power BI не поддерживается макроязык для автоматизации обновления данных, вы можете настроить расписание обновлений при помощи
службы Power BI (Power BI service). В идеальном случае все ваши источники
данных должны быть размещены в сети, чтобы вы могли опубликовать свой
файл Power BI и затем настроить расписание обновлений на портале Power
BI. Но если вы располагаете локальными файлами, которые выступают в качестве источников, ничего не потеряно – в этом случае вы можете установить
шлюз данных (data gateway), выступающий в качестве туннеля между службой
Power BI и вашим локальным решением.
Чтобы запланировать обновление в службе Power BI, нужно выполнить
следующие действия:
 опубликовать решение в Power BI;
 подключиться к службе Power BI, выбрав нужную рабочую область
(Workspace) для своего набора данных;
 нажать на ссылку Наборы данных + потоки данных (Datasets +
Dataflows), выбрать набор данных и нажать на кнопку Запланировать
обновление (Schedule Refresh), как показано на рис. 20.5.
Рис. 20.5. Расписание обновлений в службе Power BI
Откроется страница, на которой вы сможете выполнить настройку обновлений для набора данных. Для этого необходимо настроить учетные данные
для доступа к источнику (для источников, размещенных в сети) или подключить шлюз (для локальных источников), как показано на рис. 20.6.
После настройки одного или обоих пунктов вы сможете приступить к созданию расписания обновлений для вашего набора данных.
🍌 Примечание. Пункт с подключением шлюза содержит ссылку на документацию и установочные файлы для соответствующего программного обеспечения. Мы настоятельно рекомендуем вам ознакомиться с этой документацией
перед установкой шлюза, поскольку процесс его инсталляции и настройки
выходит за рамки данной книги.
Расписание обновлений в Power BI  567
Сначала вам нужно
выполнить эти настройки
Рис. 20.6. Настройка расписания обновлений в службе Power BI
Предметный указатель
Нумерованный
364-дневный календарь, 499
Символы
@, 444
&, 374
(_)=>, 446
#binary, 419
#date, 420
#datetime, 420
#datetimezone, 420
#duration, 422, 511
#shared, 416
#table, 426
#time, 421
A
and, 377
B
Base64, 419
Binary, 413
Binary.From(), 420
Binary.FromList(), 420
Binary.FromText(), 420
C
Csv.Document(), 392
D
Date.AddMonths(), 524
Date.EndOfMonth(), 525
Date.From(), 374
E
each, 445
ETL, 28, 41
Excel версии ниже 2016, 35
Excel.CurrentWorkbook(), 392
Excel.Workbook(), 465
I
if, 371
in, 432
Intellisense, 371, 431
J
Join, 253
L
let, 431
List.Combine(), 399, 457
List.Dates(), 510
List.Times(), 512
List.Transform(), 448
M
Microsoft 365, 35
Microsoft Access, 298
Microsoft Azure, 298
Microsoft Store, 35
Monkey Tools, 70, 537
N
null, 349
number, 428
Number.From(), 374, 502
O
ODBC, 29
OLEDB, 29
OneDrive для бизнеса, 231
or, 379
otherwise, 373
P
Power Automate, 30
Power BI Desktop, 35
Power Query, 32
Power Query Desktop, 33
Power Query Online, 33
Q
Query Sleuth, 70
S
SharePoint, 229
SQL, 25
SQL.Database(), 553
T
Table.AddColumn(), 444
Table.Column(), 397
Table.ColumnNames(), 459
Table.ExpandRecordColumn(), 457
Table.ExpandTableColumn(), 459
Table.FromRecords(), 404, 426
Table.FromRows(), 400
Table.Repeat(), 540
Table.RowCount(), 521
Table.Schema(), 424
Table.SelectRows(), 438
Text.BetweenDelimiters(), 386
Предметный указатель  569
Time.From(), 374
try, 373
type, 425
V
Value, 412
Value.NativeQuery(), 554
Value.Type(), 425
VBA, 25
А
Алгоритм определения подобности
Жаккара, 279
Аутентификация, 42
Б
Базы данных, 298
Быстрая загрузка данных, 40
В
Вертикально сгруппированные данные, 330
ВПР, 253
Временные лаги, 537
Все строки, 352
Вспомогательные запросы, 226, 237
Выравнивание запросов, 551
Выражения SQL, 25
Г
Горизонтально сгруппированные
данные, 332
Гранулярность данных, 199, 494
Группировка данных, 199
Д
Данные с подкатегориями, 337
Движок M, 32
Двоичное значение, 419
Двоичные данные, 413
Декартово произведение, 268
Дерево зависимостей запросов, 69
Динамические источники данных, 546
Динамический именованный диапазон, 163
Добавление данных, 203
Драйвер ODBC, 298
Е
ЕСЛИОШИБКА, 373
З
Загрузка данных, 30
Загрузка запроса, 71
Загрузка запроса в Excel, 52
Загрузка запроса в Power BI, 53
Запись, 400
Заполнитель, 349
Запрос с ошибками, 105
Запросы M, 32
Значение, 390
примитивное, 390
структурированное, 390
Значение N/A, 102
Значения кластера, 284
И
Идентификаторы, 432
обобщенный, 434
обычный, 432
с кавычками, 433
Извлечение данных, 29
Изменение названий шагов, 51
Изменение порядка групп и запросов, 80
Изменение региональных настроек, 141
Измененный тип, 47
Именование шагов в Power Query, 210
Именованный диапазон, 161
Импорт данных в Power BI, 119
Импорт запросов, 115
Импорт из активной книги, 155
Импорт содержимого рабочего листа, 170
Импорт файлов с разделителями, 135
ИНДЕКС, 253
Инструмент извлечения данных
из веб-таблиц, 287
Интеграция данных, 29
Интерфейс пользователя Power Query, 33
Исключение дублирующихся пробелов, 151
Используемый диапазон, 171
Источник, 46
Источник файла, 43
Итерации, 443
К
Календарь, 494
Канал обновления, 35
Качество столбца, 100
Кеширование узлов, 64
Кеш сводной таблицы, 74
Ключевые слова, 418
Кнопка с шестеренкой, 58
Копирование запросов в Excel , 110
Копирование запросов в Power BI, 115
Копирование запросов из Power BI
в Excel, 114
Кратность связи, 413
Л
Ленивые вычисления, 439
Лента, 45
Локаль, 138
М
Мастер создания условной логики, 368
570  Предметный указатель
Машинные запросы, 308
Меры, 90
Модель данных, 62
Н
Настраиваемый столбец, 369
Настройка Power Query, 40
Нечеткие совпадения, 272
О
Область печати, 165, 218
Обнаружение типов данных, 43
Обновить предварительный просмотр, 57
Обновление запроса, 54
Обновления Power Query, 34
Обогащение данных, 29
Объединение данных, 253
Объединение столбцов, 150
Объединение файлов, 225
Объект, 390
Окно свойств, 46
Окно текущего представления, 45
Операция усечения, 144
Оптимизация, 527
Организация запросов, 78
Особые именованные диапазоны, 218
Отдельные значения, 100, 272
Отмена сведения, 178
Отмена свертывания данных, 337
Очистка данных, 29
Очистка файлов без разделителей, 143
Ошибки, 93, 147, 413
ошибки значений, 94, 99
ошибки на уровне шага, 93
П
Панель Запросы и подключения, 53
Панель навигатора запросов, 45
Панель примененных шагов, 46
Перевод строки, 189
Переименование запроса, 52
Переименованные столбцы, 48
Перекрестное соединение, 268
Перенос запросов, 109
Перенос запросов между Excel
и Power BI, 113
Переопределение типов данных, 50
План запроса, 440
Плоские файлы, 131
Повышенные заголовки, 47
Подготовительный запрос, 71
Подготовка запроса, 61
Подключение к веб-странице, 288
Подключение к внешнему файлу Excel, 166
Подключение к данным, 41
Подключение к именованному
диапазону, 169
Подключение к таблице, 168
Подключение к файлам
без разделителей, 142
Подключение к файлам в интернете, 285
ПОИСКПОЗ, 253
Поле Date Created, 251
Поле Date Modified, 251
Порог подобия, 282
Порядок шагов в запросе, 90
Потоки данных, 30
Предварительный просмотр, 42
Предлагаемые таблицы, 288
Представление схемы, 69
Преобразование данных, 29
Преобразование записи в таблицу, 402
Преобразования по умолчанию, 46
Приблизительные совпадения, 272
Примененные шаги, 46
Принудительный возврат каретки, 189
Профиль столбца, 100
Р
Рабочая область, 566
Разворачивание столбца, 214
Разделение запросов, 63, 82
Разделение столбца на строки, 189
Разделение столбцов, 186
Разделение столбцов по позиции, 145
Разделение столбцов по разделителю, 150
Разделитель, 43
Разнесение запросов по группам, 79
Ранжирование данных, 355
плотное ранжирование, 358
порядковое ранжирование, 355
стандартное конкурентное
ранжирование, 356
Распределение столбцов, 100
Рассведение данных, 179
Расчет доли значений, 352
Расширенный редактор, 430
Редактор Power Query, 33, 45, 56
Редактор Visual Basic, 563
Рекурсивные функции, 443
List.Accumulate(), 443
List.Generate(), 443
С
Сведение данных, 323
Сведение сгруппированных данных, 323
Сведение столбца, 184
Свертывание запросов, 307, 440
Сводная диаграмма, 74
Связанные сущности, 65
Связь многие ко многим, 268
Связь один ко многим, 255
Система интеллектуального ввода, 371
Системные настройки, 132
Предметный указатель  571
Служба Power BI, 317, 566
Случайные перекрестные соединения, 271
Случайные числа, 532
Совмещение запросов, 62
Создание группы запросов, 78
Создание записи, 401
Создание таблицы с календарем, 501
Сортировка данных, 192, 197
Составной ключ, 258
Списки, 392
Сравнение с соседними строками, 379
Ссылочные запросы, 66
Столбцы из примеров, 383
Строка состояния, 45
Строка формул, 45
Структурированные значения, 389
Сырые данные, 61
Т
Таблица, 391
Таблица поиска, 273
Таблица преобразования, 280
Таблицы HTML, 288
Табличный тип, 427
Типы данных, 47, 86, 423
дата и время, 47
десятичное число, 47
текст, 47
целое число, 47
any, 87, 424
Типы ошибок, 95
DataFormat.Error, 102
DataSource.Error, 95
Expression.Error, 98, 541
Formula.Firewall, 544
Типы соединений, 257
антисоединение справа, 266
антисоединения слева, 265
внешнее соединение слева, 260
внешнее соединение справа, 262
внутреннее соединение, 265
полное антисоединение, 267
полное внешнее соединение, 264
Только создать подключение, 74
Точные совпадения, 272
У
Удаление столбца, 48
Удаленные столбцы, 48
Указание локали, 135
Уникальные значения, 100, 272
Уровни конфиденциальности, 313
общий, 314
организационный, 314
частный, 314
Условная логика, 364
Условный столбец, 368
Учетные данные, 299
Ф
Фильтрация данных, 191, 192
Форматирование данных, 86
Формулы Excel, 24
Функции буферизации, 531
Binary.Buffer(), 532
List.Buffer(), 532
Table.Buffer(), 532
Функция, 415
Х
Хранимые процедуры, 555
Ш
Шлюз данных, 566
Я
Язык M, 429
Книги издательства «ДМК ПРЕСС»
можно купить оптом и в розницу в книготорговой компании «Галактика»
(представляет интересы издательств «ДМК ПРЕСС», «СОЛОН ПРЕСС», «КТК Галактика»).
Адрес: г. Москва, пр. Андропова, 38;
тел.: (499) 782-38-89, электронная почта: books@alians-kniga.ru.
При оформлении заказа следует указать адрес (полностью),
по которому должны быть высланы книги; фамилию, имя и отчество получателя.
Желательно также указать свой телефон и электронный адрес.
Эти книги вы можете заказать и в интернет-магазине: www.a-planeta.ru.
Кен Пульс, Мигель Эскобар
Приручи данные с помощью Power Query в Excel и Power BI
Использование Power Query для получения
и преобразования исходных данных
Главный редактор
Мовчан Д. А.
dmkpress@gmail.com
Зам. главного редактора
Перевод
Корректор
Верстка
Дизайн обложки
Сенченкова Е. А.
Гинько А. Ю.
Абросимова Л. А.
Паранская Н. В.
Мовчан А. Г.
Гарнитура PT Serif. Печать цифровая.
Усл. печ. л. 46,48. Тираж 200 экз.
Веб-сайт издательства: www.dmkpress.com
Powered by TCPDF (www.tcpdf.org)
Related documents
Download