- Java SQL
- QueryDSL. Каскадный стиль синтаксиса
- Сортировка (ORDER BY)
- Группировка (GROUP BY)
- Условие WHERE
- Использование оператора WHERE в запросе выборки SELECT
- Задание сложных условий
- Вставка (INSERT)
- Запрос (UPDATE)
- Как редактировать несколько значений
- Удаление (DELETE)
- Пакетные запросы к базе данных
В AnyLogic вы обычно создаете запросы на выборку, используя удобный графический конструктов запросов.
Однако вы можете создавать и специализированные запросы, используя один из двух альтернативных синтаксисов: Java SQL или QueryDSL.
Вы можете написать запрос, используя обычный SQL. Чтобы выполнить SQL-утверждение, используйте функцию AnyLogic selectUniqueValue() или selectFirstValue(). Обе функции содержат два аргумента: возвращаемое значение и текстовый SQL-запрос (типа String).
selectUniqueValue() возвращает единственное значение. Если будет несколько значений, удовлетворяющих выбранному условию, вы увидите сообщение об ошибке.
selectFirstValue() не выдаст ошибку в случае нескольких допустимых значений, просто вернет первое значение из результата запроса.
Пример:
selectUniqueValue(double.class, "SELECT processing_time FROM processing_times WHERE part = agent.name;");
Как мы видим, используется обычный SQL запрос.
Обратите внимание, что если вы хотите разбить запрос на несколько строк (как показано ниже), то чтобы продолжить писать запрос с новой строки, следует закончить текущую строку пробелом, поставить кавычки ", затем поставить символ сложения +, и после этого начать новую строку символом ". То есть, допустимый многострочный запрос в AnyLogic должен выглядеть следующим образом:
selectUniqueValue(double.class, "SELECT processing_time " +
"FROM processing_times WHERE part = agent.name;");
При вызове функции selectFrom() в QueryDSL можно использовать каскадные функции: where, groupBy, having, orderBy, join, и т.д.
Пример:
(double)selectFrom( courses ).
where( courses.course.eq( courseName ) ).
uniqueResult( courses.duration_days )
Если нужен дополнительный оператор в запрос на выборку, необходимо поставить точку и поместить вызов соответствующей каскадной функции наподобие нашей, где where() определяет предмет выборки, а uniqueResult() позволяет возвращать единственный результат, а не несколько допустимых.
Чтобы писать запросы на QueryDSL, ознакомьтесь со статьей с примерами использования оператора SELECT.
Также есть отдельные разделы о следующих SQL-операторах и их аналогах в QueryDSL: ORDER BY, GROUP BY, WHERE, INSERT, UPDATE, DELETE.
Ниже краткое описание каскадных функций:
innerJoin, join, leftJoin, fullJoin, on | Используйте эти операторы, чтобы определить элементы объединения. Для функции JOIN первый аргумент является источником сложения, а второй целью (псевдонимом). |
where | Определяет фильтры запроса либо в функции с переменным количеством аргументов (varargs) с разделением запятыми, либо каскадно через оператор and. |
groupBy | Определяет аргументы оператора группировки GROUP BY в функции с переменным количеством аргументов. |
having | HAVING аналогичен WHERE за исключением того, что строки отбираются не по значениям столбцов, а строятся из значений столбцов, указанных в GROUP BY, и значений агрегатных функций, вычисленных для каждой группы, образованной GROUP BY. |
orderBy | Используйте orderBy для сортировки данных, возвращаемых запросом. |
limit, offset, restrict | Задать постраничную обработку результата. Используйте limit для задания максимального количества результатов, offset для пропуска строк и restrict для определения обоих параметров в одном вызове. |
list | Определяет перечень значений для столбцов таблицы, которые указаны как аргументы функции. |
all | Выводит значения всех столбцов опрашиваемой таблицы БД. |
uniqueResult | Возвращает единственный результат. |
firstResult | Возвращает первый результат по определенному запросу на выборку, или null если ничего не найдено. |
Вы можете отсортировать результаты запроса выборки SELECT в порядке возрастания или убывания значений в определенном столбце (или поочередно в нескольких столбцах) при помощи SQL-оператора ORDER BY.
Вам необходимо указать названия столбца (или столбцов), по которому будет производиться сортировка. Для каждого столбца вы указываете порядок сортировки записей, добавляя ASC, если вы будете сортировать записи по возрастанию, или DESC — в случае сортировки по убыванию. В SQL, если иное не указано, по умолчанию применяется сортировка по возрастанию.
В данном примере мы осуществляем выборку из базы данных сотрудников employees. Нам нужно отобразить имя сотрудника, его оклад и возраст. Мы сортируем записи по имени (в порядке возрастания), а затем по окладу (в порядке убывания).
SELECT e.name, e.salary, e.age FROM employees e ORDER BY e.name ASC, c.salary DESC;
Так этот запрос выглядит в QueryDSL:
selectFrom(employees) .orderBy(employees.name.asc(), employees.salary.desc()) .list(employees.name, employees.salary, employees.age);
В QueryDSL, вы указываете порядок сортировки, вызывая сортировщик asc() или desc() для каждого столбца в списке сортировки orderBy().
Вы можете группировать результаты запроса SELECT на основе одного или нескольких столбцов, используя SQL-оператор GROUP BY. После оператора GROUP BY нужно указать имя столбца, который, возможно, содержит повторяющиеся имена. В результате группировки у вас будет только одна запись для каждого значения указанного в столбце. Как правило, вы можете использовать определенные агрегирующие функции SQL, чтобы отобразить в других столбцах сумму, максимум, минимум или количество сгруппированных записей.
В утверждении SELECT выражение GROUP BY следует за условием WHERE и предшествует выражению ORDER BY.
Предположим, у нас есть таблица awards, перечисляющая победителей по версии FIFA Golden Ball, и мы хотим посчитать количество наград у каждого игрока:
year | player |
2010 | Lionel Messi |
2011 | Lionel Messi |
2012 | Lionel Messi |
2013 | Cristiano Ronaldo |
2014 | Cristiano Ronaldo |
Мы хотим посчитать количество наград для каждого игрока и с этой целью будем использовать группировку. В SQL группировку можно выполнить следующим образом:
SELECT player, COUNT(player) FROM awards GROUP BY player;
Это эквивалентно следующему запросу QueryDSL:
selectFrom(awards)
.groupBy(awards.player)
.list(awards.player, awards.player.count());
Получим результат:
Lionel Messi | 3 |
Cristiano Ronaldo | 2 |
Оператор WHERE используется в выражениях запросов вставки, обновления и удаления SELECT, UPDATE и DELETE. С его помощью вы можете задать условие выбора определенных записей для их последующего отбора, обновления или удаления.
Вы задаете условие с помощью следующих операторов сравнения:
Операция сравнения | SQL-оператор | QueryDSL-оператор |
---|---|---|
Равно | = | eq() |
Не равно | NOT | ne() |
Больше, чем | > | gt() |
Больше или равно | >= | goe() |
Меньше, чем | < | lt() |
Меньше или равно | <= | loe() |
В следующем примере мы осуществляем выборку из таблицы factories тех предприятий, прибыль которых составляет более 100000 у.е.:
SQL | SELECT name, country, profit FROM factories f WHERE f.profit > 100000; |
QueryDSL |
|
Вы можете задавать сложные условия, комбинируя несколько условий с помощью операторов AND и OR.
- Оператор AND осуществляет выборку записи, если для нее выполняется как первое, так И второе условие;
- Оператор OR осуществляет выборку записи, если выполняется первое ИЛИ второе условие.
В следующем примере мы добавили еще одно условие. Мы осуществляем выборку прибыльных предприятий, расположенных во Франции:
SQL | SELECT name, country, profit FROM factories f WHERE f.profit > 100000 AND country = 'France'; |
QueryDSL |
|
Вы можете формировать сложные условия путем комбинирования операторов AND и OR. Чтобы комбинировать несколько операторов, используйте скобки. В следующем примере отражено применение обоих операторов AND и OR. Здесь мы осуществляем выборку всех прибыльных предприятий в Нидерландах, Бельгии и Люксембурге.
Необходимо выбрать данные из всех колонок таблицы. Для этого мы применяем SELECT * в SQL и list() в QueryDSL.
SQL | SELECT * FROM factories f WHERE f.profit > 100000 AND (country = 'Netherlands' OR country = 'Belgium' OR country = 'Luxembourg'); |
QueryDSL |
|
Аналогично вы можете использовать оператор WHERE и в запросах UPDATE и DELETE.
Добавлять новые записи в таблицу базы данных можно с помощью SQL-запроса вставки — INSERT INTO.
Ниже приведен пример запроса с использованием альтернативных синтаксисов, поддерживаемых AnyLogic:
SQL | executeStatement("INSERT INTO eu (country, capital) VALUES ('Croatia', 'Zagreb')"); |
QueryDSL |
|
Запрос SQL UPDATE используется для редактирования существующих записей в таблице базы данных.
Представим, что мы меняем имя определенного человека в таблице базы данных actors.
Синтаксис UPDATE в SQL выглядит следующим образом:
executeStatement("UPDATE actors SET name = 'Kaley Cuoco-Sweeting' WHERE name = 'Kaley Cuoco'");
В данном случае мы выделяем определенные записи с помощью оператора WHERE и устанавливаем новое значение 'Kaley Cuoco-Sweeting' в столбце name для всех полученных записей. В операторе WHERE можно сочетать несколько условий, используя операторы AND и OR.
Эквивалент функции в QueryDSL:
update(actors)
.where(actors.name.eq("Kaley Cuoco"))
.set(actors.name, "Kaley Cuoco-Sweeting")
.execute();
Прошлый пример был простым. Сейчас рассмотрим, как редактировать несколько значений сразу.
Предположим, мы хотим также отредактировать семейное положение. Решение очевидно, если данные представлены в виде строковой функции String, поэтому сейчас мы рассмотрим возможность отредактировать значение, которое представлено в виде элемента списка вариантов. Предположим, что статус в модели представлен в виде списка вариантов MaritalStatus с элементами SINGLE и MARRIED.
Запросы должны выглядеть:
update(actors)
.where(actors.name.eq("Kaley Cuoco"))
.set(actors.name, "Kaley Cuoco-Sweeting")
.set(actors.status, MARRIED)
.execute();
executeStatement("UPDATE actors SET name = ?, status = ? WHERE name = ?",
"Kaley Cuoco-Sweeting", MARRIED, "Kaley Cuoco");
С помощью запроса SQL DELETE производится удаление существующих записей из таблицы базы данных.
Можно указать, какие именно записи нужно удалить, задав соответствующее условие с помощью оператора WHERE. Вы можете задавать сложные условия, объединяя несколько простых условий с помощью операторов AND и/или OR. Более подробную информацию об операторе WHERE и составлении сложных условий вы можете найти выше.
SQL | executeStatement("DELETE FROM employees e WHERE e.age >= 60 AND e.gender = 'male'"); |
QueryDSL |
|
Чтобы удалить все записи из таблицы, не добавляйте никаких условий:
SQL | executeStatement("DELETE FROM customers c"); |
QueryDSL |
|
API QueryDSL, используемый в базе данных AnyLogic, предоставляет удобный способ обработки большого количества запросов к базе данных в виде пакета запросов. Пакетная обработка объединяет несколько запросов в один. Затем этот запрос выполняется, одновременно перемещая все необходимые данные, что, в свою очередь, значительно повышает производительность модели.
Для пакетной обработки запросов используются подклассы класса QueryDSL AbstractSQLClause. Каждый из этих подклассов группирует определенные типы запросов: есть подкласс для запросов на вставку, подкласс для запросов на удаление и т.д.
В следующем примере мы используем класс SQLInsertClause для создания пакета запросов на вставку.
Для создания экземпляра этого класса используйте следующий конструктор:
SQLInsertClause batch = new SQLInsertClause(Connection connection, SQLTemplates template, RelationalPath path);
Рассмотрим аргументы подробнее:
- connection — Указывается соединение с базой данных, к которой мы обращаемся. В случае внутренней базы данных модели AnyLogic оно может быть получено с помощью функции getDatabaseConnection.
- template — Указывает шаблон базы данных. Во внутренней базе данных используется SQLTemplates.DEFAULT.
- path — Указывает путь к целевой сущности в базе данных, т.е. имя таблицы или столбца.
После создания пакета необходимо заполнить его запросами. Наиболее простой способ сделать это — использовать комбинацию функций set(Path path, T value) и addBatch():
batch.set(my_table.first_column, "key").set(my_table.second_column, "value").addBatch()
Как видите, все очень просто: достаточно задать необходимые привязки в качестве аргументов функции set() и добавить их в пакет.
Рассмотрим следующий пример:
for ( int i = 0; i < 100; i++ ) {
SQLInsertClause batch = new SQLInsertClause( getDatabaseConnection(), SQLTemplates.DEFAULT, my_table ); // Создание пакета для таблицы с именем "table_name"
for ( int j = 0; j < 10000; j++ ) {
insert.set(my_table.first_column, "key").set(my_table.second_column, "value").addBatch(); // Заполнение пакета идентичными запросами с помощью простого цикла for
// Запись "key" добавляется в первый столбец таблицы, а запись "value" — во второй столбец
}
insert.execute(); // Выполнение пакета запросов
}
Аналогичным образом можно создать пакеты запросов обновления, слияния и удаления, используя соответствующие подклассы AbstractSQLClause.
-
Как мы можем улучшить эту статью?
-