Приручи данные с помощью Power Query в Excel и Power BI 9785937001054, 9781615470587

Иногда нас называют мартышками, работающими с данными, но на самом деле мы чаще походим на волшебников. Наши данные редк

461 119 19MB

Russian Pages 572 [573] Year 2022

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Приручи данные с помощью Power Query в Excel и Power BI
 9785937001054, 9781615470587

Table of contents :
Оглавление
Предисловие от издательства
Отзывы и пожелания
Список опечаток
Нарушение авторских прав
Предисловие
Как Power Query изменил НАШИ жизни
История Кена: «Кофе и Power Query»
История Мигеля: новый старт
Благодарности от авторов
Благодарности от Кена
Благодарности от Мигеля
Наши преданные читатели
И наконец…
Глава 0. Революция данных
Общий сценарий для аналитиков данных
Преимущества и опасности черной магии
Будущее изменилось
Почему Power Query – это магия?
Извлечение
Преобразование
Загрузка
Возможности Power Query и интеграция с другими продуктами
Компоненты Power Query
Цикл обновлений Power Query
Power Query Online
Microsoft 365
Excel 2016/2019/2021
Excel 2010 & 2013
Power BI Desktop
Как использовать эту книгу
Где найти Power Query?
Excel 365
Power BI Desktop
Предыдущие версии Excel
Подключение к данным
Особые пометки
Сопроводительные файлы
Глава 1. Основы Power Query
Перед началом
Изменение настроек Power Query по умолчанию в Excel
Изменение настроек Power Query по умолчанию в Power BI
Извлечение
Настройки подключения (выбор данных)
Аутентификация
Предварительный просмотр
Выбор назначения запроса
Преобразование
Редактор Power Query
Преобразования по умолчанию
Источник (Source)
Повышенные заголовки (Promoted Headers)
Измененный тип (Changed Type)
Создание и изменение преобразований
Загрузка
Установка типов данных
Переименование запроса
Загрузка запроса в Excel
Загрузка запроса в Power BI
Обновление запросов
Редактирование запросов
Запуск редактора Power Query в Power BI
Запуск редактора Power Query в Excel
Просмотр шагов
Настройка шагов
Влияние Power Query
Глава 2. Управление запросами
Использование архитектуры со множеством запросов
Разделение запросов на E, T и L
Преимущества совмещения запросов
Преимущества разделения запросов
Влияние разделения запросов на производительность
Ссылки на запросы
Создание базового запроса
Ссылочные запросы
Визуализация дерева зависимостей запросов
Просмотр зависимостей при помощи Monkey Tools
Выбор места загрузки запроса
Выбор места загрузки запроса в Power BI
Выбор места загрузки запроса в Excel
Изменение места назначения
Организация запросов
Создание папок в Power Query
Перенос запросов в группы
Изменение порядка следования запросов и групп
Создание подпапок запросов
Разделение существующих запросов
Заключительные мысли об архитектуре запросов
Глава 3. Типы данных и ошибки
Типы и форматы данных
Форматы
Типы данных
Как устанавливать формат данных в Power Query?
Порядок шагов имеет значение
Важность определения типов данных
Распространенные ошибки в Power Query
Ошибки на уровне шага
Ошибки источников данных
Ошибки вида «столбец X не найден»
Ошибки значений
Обнаружение ошибок
Ошибки из-за неправильного приведения типов
Ошибки по причине несовместимости типов данных
Проверка запросов на ошибки
Обнаружение источника ошибок
Исправление исходного запроса
Удаление запроса с ошибками
Заключительные мысли о типах данных и ошибках
Глава 4. Перенос запросов между Excel и Power BI
Перенос запросов между решениями
Перенос запросов Excel в новую рабочую книгу
Перенос запросов из Excel в Power BI
Перенос запросов из Power BI в Excel
Перенос запросов из Power BI в новый проект Power BI
Импорт запросов из Excel в Power BI
Только внешние источники данных
Импорт модели данных Excel в Power BI
Импорт данных на основе таблиц Excel – копирование
Таблицы Excel – сохранение подключения
Заключительные мысли о переносе запросов между решениями
Глава 5. Импортирование из плоских файлов
Понимание процесса импорта данных
Определение системных настроек
Как программа интерпретирует плоские данные
Импортирование файлов с разделителями
Источник данных
Извлечение данных
Задача
Использование локали для установки корректных типов данных
Импортирование файлов без разделителей
Подключение к файлу
Очистка файлов без разделителей
Разделение столбцов по позиции
Прелесть ошибок в Power Query
Удаление лишних столбцов
Объединение столбцов
Разделение столбцов по разделителю
Исключение дублирующихся пробелов
Минута славы Power Query
Глава 6. Импортирование из файлов Excel
Данные в активной рабочей книге
Подключение к таблицам Excel
Подключение к табличным диапазонам
Подключение к именованным диапазонам
Динамические именованные диапазоны
Подключение к рабочим листам Excel из той же книги
Данные из других рабочих книг
Подключение к файлу Excel
Подключение к таблицам
Подключение к именованным диапазонам
Подключение к рабочим листам
Заключительные мысли о подключении к данным Excel
Глава 7. Простые техники преобразования данных
Снимаем проклятие сводных данных
Подготовка данных
Отмена свертывания других столбцов
Повторное сведение данных при помощи сводной таблицы
Есть ли жизнь после обновления данных?
Разница между различными типами отмены свертывания
Сведение столбца
Разделение столбцов
Разделение столбца на несколько столбцов
Разделение столбца на строки
Разделение на столбцы с отменой свертывания против разделения на строки
Фильтрация и сортировка
Фильтрация значений
Применение контекстных фильтров
Сортировка данных
Группирование данных
Глава 8. Добавление данных
Базовые операции по добавлению данных
Добавление двух таблиц
Добавление дополнительных таблиц
Объединение запросов с разными заголовками
Добавление таблиц и диапазонов в текущем файле
Консолидация таблиц
Консолидация диапазонов и рабочих листов
Используйте =Excel.CurrentWorkbook() с осторожностью
Заключительные мысли о добавлении запросов
Глава 9. Объединение файлов
Практический пример
Описание процесса
Методология объединения файлов
Архитектура запросов при объединении файлов
Шаг 0: подключение к папке
Подключение к локальной/сетевой папке
Подключение к папке SharePoint
Подключение к OneDrive для бизнеса
Подключение к другим файловым системам
Шаг 1: фильтрация и страховка на будущее
Методология шага 1
Применение шага 1 к нашему примеру
Шаг 2: объединение файлов
Методология шага 2
Применение шага 2 к нашему примеру
Шаг 3: преобразование данных в запросе примера
Почему нужно использовать запрос «Преобразовать пример файла»?
Использование запроса «Преобразовать пример файла»
Шаг 4: преобразование данных в мастер-запросе
Исправление ошибки на уровне шага в мастер-запросе
Сохранение свойств файлов
Добавление дополнительных шагов
Обновление
Использование данных
Добавление новых файлов
Повышение эффективности с помощью сохранения верхних строк
Глава 10. Объединение данных
Основы объединения данных
Создание подготовительных запросов
Выполнение объединения запросов
Типы соединений
Внешнее соединение слева
Внешнее соединение справа
Полное внешнее соединение
Внутреннее соединение
Антисоединение слева
Антисоединение справа
Полное антисоединение
Декартовы произведения
Методология
Пример
Случайные декартовы произведения
Объединения с приблизительными совпадениями
Методология
Пример
Поиск нечетких соответствий
Основы нечеткого поиска
Таблицы преобразования
Управление порогом подобия
Стратегии поддержки решений с нечетким поиском
Глава 11. Источники данных в интернете
Подключение к файлам данных в интернете
Подключение к веб-страницам
Подключение к данным на веб-странице
Естественные и предлагаемые таблицы
Добавление таблиц с использованием примеров
Подключение к страницам без таблиц
Предостережения при работе с данными из интернета
Сбор данных
Целостность данных
Надежность решения
Глава 12. Реляционные источники данных
Подключение к базам данных
Соединение с БД
Управление учетными данными
Не можете подключиться к нашей базе данных?
Использование навигатора
Исследование данных
Свертывание запросов
Что такое свертывание запросов?
Какие технологии поддерживает механизм свертывания запросов?
Распространенные мифы относительно свертывания запросов
Уровни конфиденциальности
Объявление уровней конфиденциальности данных
Управление уровнями конфиденциальности данных
Конфиденциальность и производительность
Отключение движка конфиденциальности
Оптимизация
Глава 13. Преобразование табличных данных
Сложные шаблоны сведения данных
Сведение сгруппированных данных
Сведение вертикально сгруппированных данных
Сведение горизонтально сгруппированных данных
Сложные шаблоны отмены свертывания данных
Отмена свертывания данных с подкатегориями
Эффективная отмена свертывания данных с подкатегориями
Изменение запроса отмены свертывания данных с подкатегориями
Сохранение значений null при отмене свертывания данных
Продвинутые техники группирования данных
Процент от целого
Ранжирование данных
Нумерация сгруппированных строк (номера строк по секциям)
Глава 14. Условная логика в Power Query
Основы условной логики
Описание набора данных
Подключение к данным
Создание условной логики при помощи интерфейса пользователя
Условная проверка в ручном режиме
Воспроизведение функции Excel ЕСЛИОШИБКА (IFERROR)
Работа с несколькими условиями
Сравнение со следующей/предыдущей строкой
Столбцы из примеров
Глава 15. Значения в Power Query
Типы значений в Power Query
Таблицы
Списки
Синтаксис
Создание списков
Преобразование списка в таблицу
Создание списка из столбца таблицы
Создание списка списков
Записи
Синтаксис
Создание записи
Преобразование записи в таблицу
Создание нескольких записей
Преобразование нескольких записей в таблицу
Доступ к записям таблиц по позиции (индексирование строк)
Доступ к записям таблиц по критерию
Создание записей из каждой строки таблицы
Значения
Двоичные данные
Ошибки
Ошибки на уровне строки
Ошибки на уровне шага
Функции
Ключевые слова в Power Query
#binary
#date, #datetime и #datetimezone
#time
#duration
type
#table
Глава 16. Изучаем язык M
Структура запроса на языке M
Структура запроса
Область определения запроса и идентификаторы
Обобщенные идентификаторы
Комментарии к коду
Собираем все воедино
Понимание процесса выполнения запроса
Что такое ленивое вычисление?
План выполнения запроса
Итераторы (построчное выполнение)
Ремарка по поводу рекурсивных функций в Power Query
Ключевые слова each и _
Другие техники
Получение первого значения из столбца таблицы
Замена на null при ошибке навигации
Создание динамического списка заголовков типизированных столбцов
Создание динамического списка заголовков нетипизированных столбцов
Глава 17. Параметры и пользовательские функции
Воссоздание метода объединения файлов
Создание примера файла (Sample File)
Создание параметра Sample File Parameter
Создание преобразования файла (Transform Sample)
Создание функции Transform Function
Вызов функции Transform Function
Обновление функции Transform Function
Ключевые выводы
Создание настраиваемых функций с помощью параметров
Создание параметра FilePath
Создание запроса Timesheet Transform
Создание функции Timesheet Functio
Обновление запроса Timesheet
Создание настраиваемых функций вручную
Построение сценария разового применения
Преобразование запроса в функцию
Вызов функции
Отладка настраиваемых функций
Восстановление функциональности
Таблицы динамических параметров
Проблема с динамическими путями к файлам
Реализация таблицы динамических параметров
Создание таблицы параметров
Реализация функции fnGetParameter
Вызов функции
Применение таблиц параметров
Глава 18. Техники работы с датой и временем
Определение границ календаря
Динамическое создание границ календаря
Корректировка начальной и конечной дат для нестандартных финансовых периодов
Корректировка начальной и конечной дат для 364-дневного календаря
Календари с последовательными датами
Создание календаря
Обогащение календаря за счет дополнительных столбцов
Столбцы для финансовых периодов в 12-месячном календаре
Столбцы-идентификаторы периодов для 364-дневного календаря
Столбцы финансовых периодов для календарей 4-4-5 (и их разновидностей)
Что находится в файле с примерами?
Заполнение особых диапазонов даты и времени
Заполнение определенного количества дат
Заполнение определенного количества часов по каждой дате
Заполнение определенного количества дат с заданными интервалами
Разнесение данных на основе таблиц с датами
Разнесение данных по дням
Разнесение данных по целым месяцам
Разнесение данных по заданному количеству месяцев от начальной даты
Заключительные штрихи к разнесению данных
Глава 19. Оптимизация запросов
Оптимизация настроек Power Query
Глобальные параметры загрузки данных
Глобальные параметры редактора Power Query
Глобальные параметры безопасности
Глобальные параметры конфиденциальности
Настройки текущей книги (файла) – фоновые данные
Настройки текущей книги (файла) – другие
Использование функций буферизации
Форсирование вычисления значения
Буферизация вычисления значения
Снижение временных лагов во время разработки
Стратегия уменьшения временных лагов
Пример борьбы с временными лагами при разработке
Адаптация решения для снижения временных лагов
Изменение данных в предпросмотре
Ошибка Formula Firewall
Ошибка Formula.Firewall № 1: несовместимость уровней конфиденциальности
Ошибка Formula.Firewall № 2: доступ к источнику данных
Вызов ошибки перестроения сочетания данных
Перестроение сочетания данных против создания цепочек запросов
Перестроение сочетания данных против выравнивания запросов
Перестроение сочетания данных при передаче значений в SQL
Заключительные мысли об ошибках Formula.Firewall
Глава 20. Автоматизация обновлений
Варианты автоматического обновления в Excel
Обновления в Excel без VBA
Фоновое обновление
Обновление каждые X минут
Обновление при открытии рабочей книги
Быстрая загрузка данных
Автоматизация обновлений запросов в Excel с помощью VBA
Обновление одного подключения
Обновление в определенном порядке
Обновление всех запросов
Проблемы с синхронным обновлением
Расписание обновлений в Power BI
Предметный указатель

Citation preview

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/ в разделе «Отзывы и рецензии». Также можно послать письмо главному редактору по адресу [email protected]; при этом укажите название книги в теме письма. Если вы являетесь экспертом в какой-либо области и заинтересованы в написании новой книги, заполните форму на нашем сайте по адресу http://dmkpress.com/ authors/publish_book/ или напишите в издательство по адресу [email protected].

Список опечаток

Просканируйте код камерой смартфона и пройдите по ссылке

Хотя мы приняли все возможные меры для того, чтобы обеспечить высокое качество наших текстов, ошибки все равно случаются. Если вы найдете ошибку в одной из наших книг – возможно, ошибку в основном тексте или программном коде, – мы будем очень благодарны, если вы сообщите нам о ней. Сделав это, вы избавите других читателей от недопонимания и поможете нам улучшить последующие издания этой книги. Если вы найдете какие-либо ошибки в коде, пожалуйста, сообщите о них главному редактору по адресу [email protected], и мы исправим это в следующих тиражах.

Нарушение авторских прав Пиратство в интернете по-прежнему остается насущной проблемой. Издательства «ДМК Пресс» и Tickling Keys очень серьезно относятся к вопросам защиты авторских прав и лицензирования. Если вы столкнетесь в интернете с незаконной публикацией какой-либо из наших книг, пожалуйста, пришлите нам ссылку на интернет-ресурс, чтобы мы могли применить санкции. Ссылку на подозрительные материалы можно прислать по адресу электронной почты [email protected]. Мы высоко ценим любую помощь по защите наших авторов, благодаря которой мы можем предоставлять вам качественные материалы.

Предисловие Как 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.

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). Казалось бы, разносить запросы по группам было бы очень удобно путем простого перетаскивания их мышью, но, к сожалению, такой функционал

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 ). Опуская подробную механику создания этого вспомогательного запроса, скажем лишь, что он берет ваш исходный запрос, добавляет к нему порядковые номера строк, после чего фильтрует его таким образом, чтобы остались только строки с ошибками. На рис. 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, даже нет упоминания этого продукта.

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, если вас устраивает голубая схема, принятая по умолчанию);

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 тысяч записей в таблице. Продолжим:

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 будет иметь вид .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:// (без последующих папок).

Подключение к OneDrive для бизнеса Самый большой секрет OneDrive для бизнеса (OneDrive for Business) состоит в том, что он, по сути, представляет собой личный сайт, размещенный на SharePoint. Из этого следует, что вы можете подключаться к папкам этой службы так же точно, как к сайту SharePoint: либо посредством коннектора Из папки (если данные синхронизированы с вашим локальным компьютером), либо с помощью коннектора Из папки SharePoint. Здесь важно понимать, к какому адресу следует подключаться, поскольку он будет отличаться от вашей привычной ссылки на хранилище SharePoint. При подключении с помощью коннектора Из папки SharePoint формат адреса будет выглядеть так: https:///personal/. Вы также должны быть в курсе, что все символы «.» и «@» в вашем электронном адресе будут заменены на символы подчеркивания.

🍌 Примечание. Если в вашей компании используется Microsoft 365, адрес ва-

шего домена в SharePoint будет иметь формат -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). Затем эта функция вызывается для всех файлов в списке перед их объединением, и это происходит автомагически!

🍌 Примечание. Используйте для очистки данных запрос Преобразовать пример файла всегда, когда это возможно.

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 и

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, и в браузере мы видели тег 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 ставится между выражениями согласно следующему шаблону: and (and , и т. д.) Как и в случае с 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() преобразовывает список списков в единый список. По сути, это равносильно выполнению операции добавления запросов, но применительно к спискам.

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"

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 . В нашем случае код функции с указанием типа данных для переменной 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

Для недель, начинающихся с понедельника, даты будут другими. – Прим. перев.

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)