SQL-Ex blog
Как думать подобно SQL Server: повторяющиеся запуски запросов
Добавил smois on Среда, 26 февраля. 2020
Ранее в этой серии мы запускали запрос с ORDER BY, и обнаружили, что это интенсивно нагружает процессор, что утраивает стоимость запроса:

Теперь давайте запустим этот запрос многократно. В SSMS вы можете добавить число после GO, тогда SSMS выполнит ваш запрос указанное число раз. Я выполню его 50 раз:
SET STATISTICS IO, TIME ON;
GO
SELECT Id
FROM dbo.Users
WHERE LastAccessDate > '2014/07/01'
ORDER BY LastAccessDate;
GO 50
В первой статье я объяснял инструкцию SET STATISTICS IO ON. Теперь я добавлю новую опцию: TIME. Это добавит больше сообщений, которые покажут, сколько времени процессора и всего потрачено на выполнение запроса:

SQL Server выполняет запрос снова и снова, читая всякий раз 7405 страниц и выполняя сортировку.
Когда я был разработчиком, то у меня никогда не было проблем с получением данных с SQL Server. В конце концов, я бы просто запустил такой запрос раньше, верно? Данные в кэше, так? Конечно, SQL Server кэширует отсортированные данные, чтобы не пришлось повторять всю работу, особенно когда мои запросы выполняют множество соединений, группировку, фильтрацию и сортировку.
SQL Serwer кэширует страницы необработанных данных, а не результат запроса.
Не важно, что данные не изменились. Это не имеет значения, даже если вы единственный пользователь базы данных, и даже если база данных установлена в режим «только чтение».
SQL Server повторно выполняется запрос с нуля.
Аналогично, если 500 человек запускают в точности один и тот же запрос в одно и то же время, SQL Server не выполняет его один раз, распределяя результаты по всем сессиям. Каждый запрос получает свою собственную выделенную память и собственную долю работы процессора.
Это одна из тех областей, где Oracle побеждает. Иногда меня спрашивают о том, какая моя любимая СУБД; и я должен признаться, что если бы деньги не имели значения, я, вероятно, действительно увлекся бы Oracle. Посмотрите их функцию Result Cache: вы можете сконфигурировать процент памяти для кэширования результатов запроса на случай, когда приложения продолжают повторять один и тот же запрос. Однако $47500 на одно ядро процессора для лицензирования Enterprise Edition, боюсь, что в ближайшее время я не сподоблюсь попробовать эту икру.
- Самый быстрый запрос — это тот, который вы никогда не напишете
- Какие запросы следует кэшировать в приложении?
- Как кэшировать результаты хранимой процедуры
SQL-Ex blog

Как думать подобно SQL Server: что означает поиск ключа?
Добавил smois on Суббота, 7 марта. 2020
В паре наших последних статей мы использовали простой запрос для нахождения ИД тех, кто входил в систему с середины 2014 года:
SELECT Id
FROM dbo.Users
WHERE LastAccessDate > '2014-07-01'
ORDER BY LastAccessDate;
Но один лишь ИД не очень полезен. Поэтому давайте добавим еще несколько столбцов в наш запрос:
SELECT LastAccessDate, Id, DisplayName, Age
FROM dbo.Users
WHERE LastAccessDate > '2014-07-01'
ORDER BY LastAccessDate;
Теперь подумайте о том, как вы собираетесь выполнить этот план запроса на естественном языке. У вас есть две копии таблицы: некластеризованный индекс (черные страницы), содержащий LastAccessDate, Id:

и кластеризованный индекс (белые страницы), содержащий все столбцы таблицы:

Один способ — это использовать сначала некластеризованный индекс.
- Мы могли бы взять черные страницы, найти 2014-07-01 и начать составлять список нужных нам LastAccessDates и Id.
- Взять белые страницы, и для каждого Id, который мы нашли на черных страницах, найти эти id на белых страницах для получения дополнительных столбцов (DisplayName, Age), которых нет в черном индексе.

Мы читаем планы справа налево, но также сверху вниз.
Первое, что сделал SQL Server, это Index Seek (поиск по индексу) вверху справа — это поиск на черных страницах. SQL Server нашел конкретную дату-время, прочитал LastAccessDate и Id из каждой строки, и на этом закончилась работа Index Seek. (Это, в целом, отдельная автономная программа.)
Затем SQL Server берет этот список ИД и ищет каждый из них на белых страницах — это операция Key Lookup (поиск ключа). SQL Server использует свой кластеризованный ключ — в данном случае id, поскольку именно на id мы строили наш кластеризованный индекс. (Если вы не строите кластеризованный индекс, все равно тот же базовый процесс будет иметь место — но об этом в другой раз.)
Вот почему каждый некластеризованный индекс включает кластеризованные ключи.
Когда я впервые сказал вам, что создал черный индекс, я имел в виду это:
CREATE INDEX IX_LastAccessDate_Id
ON dbo.Users(LastAccessDate, Id);
Но это не обязательно, я мог бы просто сделать так:
CREATE INDEX IX_LastAccessDate
ON dbo.Users(LastAccessDate);
И мы получили бы те же самые черные страницы. SQL Server добавляет кластеризованные ключи в каждый некластеризованный индекс, поскольку он должен иметь возможность выполнить поиск этих ключей. Для каждой строки, которую он находит в некластеризованном индексе, он должен суметь перейти к соответствующей уникальной строке в кластеризованном индексе.
Я сначала сказал вам, что создал индекс на обоих столбцах, просто для того, чтобы вам легче было это понять.
Операторы Key Lookup скрывают множество деталей.
Я хочу, чтобы планы выполнения были трехмерными: Я бы хотел, чтобы операторы выдвигались со страницы столько раз, сколько раз они были выполнены. Вы видите этот «Key Lookup» и думаете, что он случился только раз, но это совсем не так. Наведите мышь на этот оператор, и вы увидите число выполнений (Number of Executions) — т.е. сколько раз он фактически выполнялся:

- Estimated Number of Executions основано на предположении SQL Server о том, сколько строк выйдет из Index Seek. Для каждой найденной строки, мы собираемся выполнять одну операцию Key Lookup.
- Estimated Number of Rows — как много строк вернет КАЖДЫЙ поиск ключа.
- Number of Executions — сколько раз мы фактически сделали это, основано на количестве строк, которые фактически вернул поиск по индексу.
- Actual Number of Rows — общее число строк, которые вернули ВСЕ поиски ключа (не каждая).
Стоимость поиска ключа — это логические чтения.
Всякий раз, когда мы выполняем поиск ключа — в данном случае 1576 раз — мы открываем белые страницы и выполняем несколько логических чтений. Чтобы увидеть это, давайте выполним запрос без поиска (который получает только Id), и многостолбцовый запрос (который получает также DisplayName и Age), и сравним число логических чтений:

Верхний запрос дает только 7 чтений, а нижний — 4942! Эти 1576 поиска ключа должны выполнить около 3 логических чтений каждый. (Почему не просто 1 чтение каждый? Потому что им требуется навигация по древовидной структуре страниц, чтобы точно найти нужную страницу, которая содержит требуемые данные — это лишние пара или более страниц при всяком поиске в индексе. Мы еще поговорим об альтернативных решениях позже.)
Чем больше строк возвращает ваш поиск по индексу, тем больше вероятность того, что вы вообще не получите такой план выполнения. Обратите внимание, что в этой статье я не использовал 2014-07-01 в качестве даты фильтрации — я использовал более свежие данные. Почему? Об этом как раз в следующей публикации.
Обратные ссылки
Нет обратных ссылок
Комментарии
Показывать комментарии Как список | Древовидной структурой
Как думать на sql

События
- Тестирование
- Основы
- Откуда берутся ошибки в ПО?
- Почему тестирование необходимо?
- Мифы о тестировании
- Психология тестирования
- Когда начинать и заканчивать тестирование?
- Фундаментальный процесс тестирования
- Принципы тестирования
- Верификация и валидация
- QA, QC и тестирование
- Кто занимается тестированием?
- Цели тестирования
- Что такое тестирование программного обеспечения?
- Роль тестирования в процессе разработки ПО
- Сколько стоят дефекты?
- Качество программного обеспечения (ISO/IEC 25010)
- Матрица соответствия требований (Requirements Traceability Matrix)
- Матрица покрытия и Матрица отслеживания
- Тестирование веб-проектов: основные этапы и советы.
- Мобильное и веб-приложение. В чем разница?
- Тест дизайн (Test Design)
- Agile
- Словарь тестировщика
- 75 популярных вопросов на собеседовании QA (+ примеры и ответы)
- HTML и CSS для тестировщиков
- Итеративная модель (Iterative model)
- Спиральная модель (Spiral model)
- V-модель (V-model)
- Каскадная модель (Waterfall model)
- Стадии цикла разработки ПО
- Жизненный цикл ПО
- Приемочное тестирование
- Системное тестирование
- Интеграционное тестирование
- Модульное тестирование
- White/Black/Grey Box-тестирование
- Статическое и динамическое тестирование
- Ручное и автоматизированное
- Тестирование документации
- Интернационализация и локализация
- Стресс тестирование
- Тестирование установки
- Конфигурационное тестирование
- Тестирование на отказ и восстановление
- Юзабилити
- Тестирование сборки
- Тестирование взаимодействия
- Тестирование безопасности
- Дымное тестирование
- Регрессионное тестирование
- Тестирование производительности
- Функциональное тестирование
- Нефункциональное тестирование
- Спецификация требований
- Test Plan
- Checklists для тестировщика
- Test Case
- Bug report
- Жизненный цикл дефектов
- Классификация дефектов
- Тестирование мобильных приложений
- Протоколы
- Протокол TCP/IP или как работает Интернет (для новичков)
- HTTP-запрос (HTTP request)
- Автоматизация
- Автоматизированное тестирование
- Теория по X-Path локаторам
- Как написать X-Path локатор.
- Использование tagname
- Вложенность родительского элемента.
- Как выбрать инструмент автоматизации?
- Базы данных в тестировании
- Зачем нужен SQL для тестирования?
- Общее
- Интерфейс в коде ПО
- Фреймворк в программировании
- Парадигмы программирования
- Что такое микросервисная архитектура ПО?
- Микросервисная архитектура
- Что такое монолитная архитектура?
- Монолитная архитектура
- Что такое API?
- Процесс коммуникации с помощью API
- Что такое JSON
- Что не так с Android?
- Android Studio 2.0
- RxJava
- Основы
- Внутренний мир компьютера: что там внутри
Зачем нужен SQL для тестирования?
Каждая система должна иметь базу данных. Информация (сведения о пользователе, состояние транзакции) обычно поддерживается в традиционных реляционных базах данных, таких как MySQL и Oracle.
SQL — это стандартный компьютерный язык для управления реляционными базами данных и обработки данных. SQL используется для запроса, вставки, обновления и изменения данных. Вы можете думать о SQL как о средстве связи между пользователем и СУБД (система управления БД).
Проще говоря, SQL — это язык программирования, с помощью которого мы обращаемся к нашей базе данных.

Чтобы определить SQL-запрос, нам сначала нужно понять, что такое запрос? Запрос может быть определен как запрос данных из базы данных через СУБД. Запрос может рассматриваться как инструкция, отправляемая в СУБД для получения набора данных на основе критериев. Такой запрос может быть разработан с использованием SQL и называется запросом SQL.
Простым примером SQL-запроса будет: Select * from Table.
Посмотрев на этот запрос, вы легко сможете понять, что он пытается сделать — выбрать все данные (представленные *) из таблицы.
Когда вы проводите функциональное тестирование системы через frontend (веб-сайт, мобильные приложения и т.д.), вам также необходимо проверить, правильно ли обновляются отправляемые вами данные в базе данных.
Спрос на универсальных тестировщиков растет. Это означает, что тестировщики должны иметь навыки тестирования функциональности системы с помощью традиционных методов тестирования «наведи, щелкни и проверь», и уметь использовать технические знания для проверки всех аспектов системы. Эти технические знания включают навыки проверки операционной системы, интерфейса и базы данных. В данном случае мы подчеркнем важность хороших навыков языка структурированных запросов (SQL).
Насколько важны навыки SQL для тестировщика программного обеспечения?
Некоторые приложения требуют сильных навыков проверки SQL, некоторые из них требуют средних навыков, а для некоторых приложений знания SQL вообще не требуются.
Возьмем в пример веб-сайты, на которых размещаются документы, которые пользователи могут распечатать на принтере. Печать этих документов требует, чтобы пользователи сначала установили специальный контроллер печати на свой ПК. В данном случае работа тестировщика заключается в том, чтобы печатать документы из различных комбинаций операционных систем, браузеров и принтеров и проверять качество печати документов. Для этого теста не нужно применять какие-либо навыки SQL. Опыт SQL требуется для проверки тестовых данных, вставки, обновления и удаления значений тестовых данных в базе данных.
Рассмотрим работу над другим проектом, участие в бэкэнд-тестировании, где требуются сильные знания SQL-запросов. Внутренний инструмент пользовательского интерфейса для получения данных из базы данных Oracle на основе входных значений. В рамках тестирования сравниваются выходные данные инструмента пользовательского интерфейса и выходные данные базы данных, вводятся одинаковые значения в инструмент и базу данных, чтобы убедиться, что инструмент функционировал должным образом. Каждый раз, когда входные значения меняются, администратор базы данных дает группе тестирования очень большие запросы с использованием оператора select. Для начала нужно понять связь между таблицами, столбцами и запросом, прежде чем его использовать. Кроме того, нужно использовать различные типы операторов SQL для проверки тестовых данных.
Следующие знания базы данных и SQL должны быть у тестировщика:
- Он должен уметь распознать различные типы баз данных;
- Подключаться к базе данных с использованием разных клиентов SQL-соединений;
- Понимать отношения между таблицами базы данных, ключами и индексами;
- Умение написать простой оператор выбора или SQL вместе с более сложными запросами на соединение;
- Интерпретировать более сложные запросы.
Наиболее используемые операторы SQL в тестировании:
- Data Manipulation Language (DML): используется для извлечения, хранения, изменения, удаления, вставки и обновления данных в базе данных. Примеры: операторы SELECT, UPDATE и INSERT.
- Data Definition Language (DDL): используется для создания и изменения структуры объектов базы данных в базе данных. Примеры: операторы CREATE, ALTER и DROP.
- Transactional Control Language (TCL): Управляет различными транзакциями, происходящими в базе данных. Примеры: операторы COMMIT, ROLLBACK.
- Inner Join: извлекает сопоставленные записи из обеих таблиц.
- Distinct: извлекает различные значения из одного или нескольких полей.
- In: этот оператор используется, чтобы найти значение в списке или нет.
- Between: этот оператор используется для получения значений в диапазоне.
- WHERE: указывает, какие строки получить.
- Like: этот оператор используется для выполнения сопоставления с шаблоном; он используется с оператором WHERE.
- Order By Clause: указывает порядок возврата строк, сортирует записи таблицы в порядке возрастания или убывания. По умолчанию порядок возрастает.
- GROUP BY: группирует строки, имеющие общее свойство, так что агрегатная функция может быть применена к каждой группе.
- HAVING: выбирает из групп, определенных оператором GROUP BY.
- Aggregate Functions: выполняет вычисление для набора значений и возвращает одно значение. Пример: Avg, Min, Max, Sum, count и т. д.
SQL очень важен в тестировании программного обеспечения, потому что:
- Проверка поможет понять, что данные, которые добавляются в форму (на frontend), добавляются на бэкэнд или нет. Например, при регистрации пользователя на сайте, некоторые поля пропущены, следовательно, мы видим какое-то сообщение об ошибке относительно регистрации пользователя. Также, если мы выполним SQL-запрос, то сможем сказать, что следующие поля пропущены, и есть некоторая ошибка в функциональном модуле регистрации пользователя.
- SQL помогает нам в получении тестовых данных. Например, если нужно проверить некоторые исправления для товаров, которые видны на работающем сайте. С помощью SQL-запроса, можно получить продукты с определенным условием (фильтрацией), и изменить описание товара одновременно всем записям.
- SQL помогает нам в автоматизации тестирования. Например, если нам нужно убедиться, что для платного зарегистрированного пользователя будет отображен флаг VIP после входа в систему. SQL поможет в том, что мы напрямую получим пользователя с этими определенными условиями из базы данных, а затем авторизуемся, используя данные, и просто проверим наличие или отсутствие флага VIP, вместо того чтобы создать нового пользователя и затем произвести оплату от его имени.
Учитывая преимущества работы с SQL и полезность навыков SQL в общем, наш совет тестировщикам -> приобрести минимальные знания SQL, чтобы стать универсальным тестером, который ценится клиентами и компаниями. Изучить SQL вы сможете с помощью нашего курса Практический SQL.
- Выбери курс для обучения
- Тестирование
- Базовый модуль тестирования
- Тестирование ПО
- Тестирование WEB-сервисов
- Тестирование мобильных приложений
- Тестирование нагрузки с JMeter
- Расширенный модуль автоматизации тестирования
- Автоматизация тестирования с Selenium WebDriver (Python)
- Автоматизация тестирования с Selenium WebDriver (Java)
- Автоматизация тестирования с Selenium WebDriver (C#)
- Автоматизация тестирования на JavaScript
- Java для автоматизаторов
- Fullstack Web Developer
- Java
- Python
- JavaScript
- HTML5 И CSS3
- Полный стек разработки на фреймворке Laravel
- Разработка CMS на основе PHP
- Git для автоматизаторов
- Практический SQL
- Основы Unix и сети
- WEB-серверы и WEB-сервисы
- Создание проекта автоматизации и написания UI тестов
- Составление комбинированных тестов UI и API. Написание BDD тестов
- IT Project Manager
- HR-менеджер в ИТ-компании
- Как правильно составить резюме и пройти собеседование
- Подготовка к сертификации ISTQB Foundation Level на основе Syllabus Version 2018
- Тестирование
- Базовый модуль тестирования
Как думать на SQL?
Если вы похожи на меня, то согласитесь: SQL — это одна из тех штук, которые на первый взгляд кажутся легкими (читается как будто по-английски!), но почему-то приходится гуглить каждый простой запрос, чтобы найти правильный синтаксис.
А потом начинаются джойны, агрегирование, подзапросы, и получается совсем белиберда. Вроде такой:
SELECT members.firstname || ' ' || members.lastname AS "Full Name" FROM borrowings INNER JOIN members ON members.memberid=borrowings.memberid INNER JOIN books ON books.bookid=borrowings.bookid WHERE borrowings.bookid IN (SELECT bookid FROM books WHERE stock>(SELECT avg(stock) FROM books)) GROUP BY members.firstname, members.lastname;Буэ! Такое спугнет любого новичка, или даже разработчика среднего уровня, если он видит SQL впервые. Но не все так плохо.
Легко запомнить то, что интуитивно понятно, и с помощью этого руководства я надеюсь снизить порог входа в SQL для новичков, а уже опытным предложить по-новому взглянуть на SQL.
Не смотря на то, что синтаксис SQL почти не отличается в разных базах данных, в этой статье для запросов используется PostgreSQL. Некоторые примеры будут работать в MySQL и других базах.
1. Три волшебных слова
В SQL много ключевых слов, но SELECT , FROM и WHERE присутствуют практически в каждом запросе. Чуть позже вы поймете, что эти три слова представляют собой самые фундаментальные аспекты построения запросов к базе, а другие, более сложные запросы, являются всего лишь надстройками над ними.
2. Наша база
Давайте взглянем на базу данных, которую мы будем использовать в качестве примера в этой статье:

У нас есть книжная библиотека и люди. Также есть специальная таблица для учета выданных книг.
- В таблице «books» хранится информация о заголовке, авторе, дате публикации и наличии книги. Все просто.
- В таблице “members” — имена и фамилии всех записавшихся в библиотеку людей.
- В таблице “borrowings” хранится информация о взятых из библиотеки книгах. Колонка bookid относится к идентификатору взятой книги в таблице “books”, а колонка memberid относится к соответствующему человеку из таблицы “members”. У нас также есть дата выдачи и дата, когда книгу нужно вернуть.
3. Простой запрос
Давайте начнем с простого запроса: нам нужны имена и идентификаторы (id) всех книг, написанных автором “Dan Brown”
Запрос будет таким:
SELECT bookid AS "id", title FROM books WHERE author='Dan Brown';А результат таким:
id title 2 The Lost Symbol 4 Inferno Довольно просто. Давайте разберем запрос чтобы понять, что происходит.
3.1 FROM — откуда берем данные
Сейчас это может показаться очевидным, но FROM будет очень важен позже, когда мы перейдем к соединениям и подзапросам.
FROM указывает на таблицу, по которой нужно делать запрос. Это может быть уже существующая таблица (как в примере выше), или таблица, создаваемая на лету через соединения или подзапросы.
3.2 WHERE — какие данные показываем
WHERE просто-напросто ведет себя как фильтр строк, которые мы хотим вывести. В нашем случае мы хотим видеть только те строки, где значение в колонке author — это “Dan Brown”.
3.3 SELECT — как показываем данные
Теперь, когда у нас есть все нужные нам колонки из нужной нам таблицы, нужно решить, как именно показывать эти данные. В нашем случае нужны только названия и идентификаторы книг, так что именно это мы и выберем с помощью SELECT . Заодно можно переименовать колонку используя AS .
Весь запрос можно визуализировать с помощью простой диаграммы:

4. Соединения (джойны)
Теперь мы хотим увидеть названия (не обязательно уникальные) всех книг Дэна Брауна, которые были взяты из библиотеки, и когда эти книги нужно вернуть:
SELECT books.title AS "Title", borrowings.returndate AS "Return Date" FROM borrowings JOIN books ON borrowings.bookid=books.bookid WHERE books.author='Dan Brown';Title Return Date The Lost Symbol 2016-03-23 00:00:00 Inferno 2016-04-13 00:00:00 The Lost Symbol 2016-04-19 00:00:00 По большей части запрос похож на предыдущий за исключением секции FROM . Это означает, что мы запрашиваем данные из другой таблицы. Мы не обращаемся ни к таблице “books”, ни к таблице “borrowings”. Вместо этого мы обращаемся к новой таблице, которая создалась соединением этих двух таблиц.
borrowings JOIN books ON borrowings.bookid=books.bookid — это, считай, новая таблица, которая была сформирована комбинированием всех записей из таблиц «books» и «borrowings», в которых значения bookid совпадают. Результатом такого слияния будет:

А потом мы делаем запрос к этой таблице так же, как в примере выше. Это значит, что при соединении таблиц нужно заботиться только о том, как провести это соединение. А потом запрос становится таким же понятным, как в случае с «простым запросом» из пункта 3.
Давайте попробуем чуть более сложное соединение с двумя таблицами.
Теперь мы хотим получить имена и фамилии людей, которые взяли из библиотеки книги автора “Dan Brown”.
На этот раз давайте пойдем снизу вверх:
Шаг Step 1 — откуда берем данные? Чтобы получить нужный нам результат, нужно соединить таблицы “member” и “books” с таблицей “borrowings”. Секция JOIN будет выглядеть так:
borrowings JOIN books ON borrowings.bookid=books.bookid JOIN members ON members.memberid=borrowings.memberidРезультат соединения можно увидеть по ссылке.
Шаг 2 — какие данные показываем? Нас интересуют только те данные, где автор книги — “Dan Brown”
WHERE books.author='Dan Brown'Шаг 3 — как показываем данные? Теперь, когда данные получены, нужно просто вывести имя и фамилию тех, кто взял книги:
SELECT members.firstname AS "First Name", members.lastname AS "Last Name"Супер! Осталось лишь объединить три составные части и сделать нужный нам запрос:
SELECT members.firstname AS "First Name", members.lastname AS "Last Name" FROM borrowings JOIN books ON borrowings.bookid=books.bookid JOIN members ON members.memberid=borrowings.memberid WHERE books.author='Dan Brown';First Name Last Name Mike Willis Ellen Horton Ellen Horton Отлично! Но имена повторяются (они не уникальны). Мы скоро это исправим.
5. Агрегирование
Грубо говоря, агрегирования нужны для конвертации нескольких строк в одну. При этом, во время агрегирования для разных колонок используется разная логика.
Давайте продолжим наш пример, в котором появляются повторяющиеся имена. Видно, что Ellen Horton взяла больше одной книги, но это не самый лучший способ показать эту информацию. Можно сделать другой запрос:
SELECT members.firstname AS "First Name", members.lastname AS "Last Name", count(*) AS "Number of books borrowed" FROM borrowings JOIN books ON borrowings.bookid=books.bookid JOIN members ON members.memberid=borrowings.memberid WHERE books.author='Dan Brown' GROUP BY members.firstname, members.lastname;Что даст нам нужный результат:
First Name Last Name Number of books borrowed Mike Willis 1 Ellen Horton 2 Почти все агрегации идут вместе с выражением GROUP BY . Эта штука превращает таблицу, которую можно было бы получить запросом, в группы таблиц. Каждая группа соответствует уникальному значению (или группе значений) колонки, которую мы указали в GROUP BY . В нашем примере мы конвертируем результат из прошлого упражнения в группу строк. Мы также проводим агрегирование с count , которая конвертирует несколько строк в целое значение (в нашем случае это количество строк). Потом это значение приписывается каждой группе.
Каждая строка в результате представляет собой результат агрегирования каждой группы.
Можно прийти к логическому выводу, что все поля в результате должны быть или указаны в GROUP BY , или по ним должно производиться агрегирование. Потому что все другие поля могут отличаться друг от друга в разных строках, и если выбирать их SELECT ‘ом, то непонятно, какие из возможных значений нужно брать.
В примере выше функция count обрабатывала все строки (так как мы считали количество строк). Другие функции вроде sum или max обрабатывают только указанные строки. Например, если мы хотим узнать количество книг, написанных каждым автором, то нужен такой запрос:
SELECT author, sum(stock) FROM books GROUP BY author;author sum Robin Sharma 4 Dan Brown 6 John Green 3 Amish Tripathi 2 Здесь функция sum обрабатывает только колонку stock и считает сумму всех значений в каждой группе.
6. Подзапросы

Подзапросы это обычные SQL-запросы, встроенные в более крупные запросы. Они делятся на три вида по типу возвращаемого результата.
6.1 Двумерная таблица
Есть запросы, которые возвращают несколько колонок. Хороший пример это запрос из прошлого упражнения по агрегированию. Будучи подзапросом, он просто вернет еще одну таблицу, по которой можно делать новые запросы. Продолжая предыдущее упражнение, если мы хотим узнать количество книг, написанных автором “Robin Sharma”, то один из возможных способов — использовать подзапросы:
SELECT * FROM ( SELECT author, sum(stock) FROM books GROUP BY author ) AS results WHERE author='Robin Sharma';author sum Robin Sharma 4 6.2 Одномерный массив
Запросы, которые возвращают несколько строк одной колонки, можно использовать не только как двумерные таблицы, но и как массивы.
Допустим, мы хотим узнать названия и идентификаторы всех книг, написанных определенным автором, но только если в библиотеке таких книг больше трех. Разобьем это на два шага:
1. Получаем список авторов с количеством книг больше 3. Дополняя наш прошлый пример:
SELECT author FROM ( SELECT author, sum(stock) FROM books GROUP BY author ) AS results WHERE sum > 3;author Robin Sharma Dan Brown Можно записать как: [‘Robin Sharma’, ‘Dan Brown’]
2. Теперь используем этот результат в новом запросе:
SELECT title, bookid FROM books WHERE author IN ( SELECT author FROM ( SELECT author, sum(stock) FROM books GROUP BY author ) AS results WHERE sum > 3);title bookid The Lost Symbol 2 Who Will Cry When You Die? 3 Inferno 4 Это то же самое, что:
SELECT title, bookid FROM books WHERE author IN ('Robin Sharma', 'Dan Brown');6.3 Отдельные значения
Бывают запросы, результатом которых являются всего одна строка и одна колонка. К ним можно относиться как к константным значениям, и их можно использовать везде, где используются значения, например, в операторах сравнения. Их также можно использовать в качестве двумерных таблиц или массивов, состоящих из одного элемента.
Давайте, к примеру, получим информацию о всех книгах, количество которых в библиотеке превышает среднее значение в данный момент.
Среднее количество можно получить таким образом:
select avg(stock) from books;avg 3.000 И это можно использовать в качестве скалярной величины 3 .
Теперь, наконец, можно написать весь запрос:
SELECT * FROM books WHERE stock>(SELECT avg(stock) FROM books);Это то же самое, что:
SELECT * FROM books WHERE stock>3.000bookid title author published stock 3 Who Will Cry When You Die? Robin Sharma 2006-06-15 00:00:00 4 7. Операции записи
Большинство операций записи в базе данных довольно просты, если сравнивать с более сложными операциями чтения.
7.1 Update
Синтаксис запроса UPDATE семантически совпадает с запросом на чтение. Единственное отличие в том, что вместо выбора колонок SELECT ‘ом, мы задаем знаения SET ‘ом.
Если все книги Дэна Брауна потерялись, то нужно обнулить значение количества. Запрос для этого будет таким:
UPDATE books SET stock=0 WHERE author='Dan Brown';WHERE делает то же самое, что раньше: выбирает строки. Вместо SELECT , который использовался при чтении, мы теперь используем SET . Однако, теперь нужно указать не только имя колонки, но и новое значение для этой колонки в выбранных строках.
7.2 Delete
Запрос DELETE это просто запрос SELECT или UPDATE без названий колонок. Серьезно. Как и в случае с SELECT и UPDATE , блок WHERE остается таким же: он выбирает строки, которые нужно удалить. Операция удаления уничтожает всю строку, так что не имеет смысла указывать отдельные колонки. Так что, если мы решим не обнулять количество книг Дэна Брауна, а вообще удалить все записи, то можно сделать такой запрос:
DELETE FROM books WHERE author='Dan Brown';7.3 Insert
Пожалуй, единственное, что отличается от других типов запросов, это INSERT . Формат такой:
INSERT INTO x (a,b,c) VALUES (x, y, z);Где a , b , c это названия колонок, а x , y и z это значения, которые нужно вставить в эти колонки, в том же порядке. Вот, в принципе, и все.
Взглянем на конкретный пример. Вот запрос с INSERT , который заполняет всю таблицу «books»:
INSERT INTO books (bookid,title,author,published,stock) VALUES (1,'Scion of Ikshvaku','Amish Tripathi','06-22-2015',2), (2,'The Lost Symbol','Dan Brown','07-22-2010',3), (3,'Who Will Cry When You Die?','Robin Sharma','06-15-2006',4), (4,'Inferno','Dan Brown','05-05-2014',3), (5,'The Fault in our Stars','John Green','01-03-2015',3);8. Проверка
Мы подошли к концу, предлагаю небольшой тест. Посмотрите на тот запрос в самом начале статьи. Можете разобраться в нем? Попробуйте разбить его на секции SELECT , FROM , WHERE , GROUP BY , и рассмотреть отдельные компоненты подзапросов.
Вот он в более удобном для чтения виде:
SELECT members.firstname || ' ' || members.lastname AS "Full Name" FROM borrowings INNER JOIN members ON members.memberid=borrowings.memberid INNER JOIN books ON books.bookid=borrowings.bookid WHERE borrowings.bookid IN (SELECT bookid FROM books WHERE stock> (SELECT avg(stock) FROM books) ) GROUP BY members.firstname, members.lastname;Этот запрос выводит список людей, которые взяли из библиотеки книгу, у которой общее количество выше среднего значения.
Full Name Lida Tyler Надеюсь, вам удалось разобраться без проблем. Но если нет, то буду рад вашим комментариям и отзывам, чтобы я мог улучшить этот пост.
- Тестирование
- Основы
