- Часть первая. SQL и программный код - как, имея очень простую задачу, получить очень плохое решение.
- Антракт. Почему нам неудобно писать SQL
- Часть вторая. Почему существующие решения - отстой.
- Антракт. Мечты об идеальном инструменте разработки SQL
- Часть третья. История велосипеда, или свой инструмент самый лучший
21. Недостатки inline подхода
• Невозможность ограничить текст запроса
• Дублирование логики в запросах и в
параметрах
• Часть свойств в тексте запроса, часть как
явные параметры
• Сложность разработки и отладки SQL
22. Как происходит разработка SQL
• Получить SQL из кода
• Заменить «?» на значения
• Внести изменения в SQL редакторе
• Внедрить изменения в код или «оживить»
написанный SQL целиком
29. Что дает шаблонизация?
• Возможность ограничить текст запроса
• Текст первичен
• Многострочные запросы легко копировать
30. Какой должна быть разработка SQL
• Получить SQL из кода
• Заменить «?» на значения
• Внести изменения в SQL редакторе
• Внедрить изменения в код или «оживить»
написанный SQL целиком
32. Требования к шаблонизатору
• Шаблон должен быть максимально
валидным SQL
• Возможность «выключить» ненужный join
• Поддержка типизированных параметров
• Автоматическое включение joinов
47. Пример с join
select distinct c.id, c.name
from company c
inner join comp_office co on co.comp_id = c.id
where c.name ilike '2 gis%’
and co.country ilike ‘russia%’
48. Пример с join
select distinct c.id, c.name
from company c
inner join comp_office co on co.comp_id = c.id
where c.name ilike /*name(*/'2 gis%’/*)*/
and co.country ilike /*country(*/ ‘russia%’/*)*/
49. Пример с join
select distinct c.id, c.name
from company c
inner join comp_office co on co.comp_id = c.id
where c.name ilike /*name(*/'2 gis%’/*)*/
/*office(*/and co.country ilike /*country(*/ ‘russia%’/*))*/
50. Пример с join
select distinct c.id, c.name
from company c
/*office(*/inner join comp_office co on co.comp_id = c.id/*)*/
where c.name ilike /*name(*/'2 gis%’/*)*/
/*office(*/and co.country ilike /*country(*/ ‘russia%’/*))*/
51. Пример с join
• Шаблон
– office (join)
– name
– office (where)
• country
53. Пример с join
select distinct c.id, c.name
from company c
where c.name ilike ‘Sbertech%’
54. Пример с join
Template t = new Template(“…”);
t.assignValue(“name”, “Sbertech%”);
t.assignValue(“country”, “Rus%”);
55. Пример с join
select distinct c.id, c.name
from company c
inner join comp_office co on co.comp_id = c.id
where c.name ilike ‘Sbertech%’
and co.country ilike ‘Rus%’
56. Реальный пример
select distinct c.id, c.name
from company c
inner join comp_office co on co.comp_id = c.id
inner join orders o on o.comp_id = c.id
where c.name ilike '2 gis%'
and co.country ilike 'russia%'
and co.city ilike 'novosibirsk%'
and co.street ilike 'marks%'
and o.date > currenttime - '6 month'::interval
limit 10 offset 5
57. Реальный пример
select distinct c.id, c.name
from company c
inner join comp_office co on co.comp_id = c.id
inner join orders o on o.comp_id = c.id
where c.name ilike /*name(*/'2 gis%’/*)*/
and co.country ilike /*country(*/'russia%' /*)*/
and co.city ilike /*city(*/'novosibirsk%’/*)*/
and co.street ilike /*street(*/'marks%'/*)*/
and o.date > currenttime - '6 month'::interval
limit /*limit(int*/10/*)*/ offset /*offset(int*/5/*)*/
58. Реальный пример
select distinct c.id, c.name
from company c
inner join comp_office co on co.comp_id = c.id
inner join orders o on o.comp_id = c.id
where c.name ilike /*name(*/'2 gis%’/*)*/
and co.country ilike /*country(*/'russia%' /*)*/
and co.city ilike /*city(*/'novosibirsk%’/*)*/
and co.street ilike /*street(*/'marks%'/*)*/
/*active(*/and o.date > currenttime - '6 month'::interval/*)*/
limit /*limit(int*/10/*)*/ offset /*offset(int*/5/*)*/
59. Реальный пример
select distinct c.id, c.name
from company c
inner join comp_office co on co.comp_id = c.id
/*active(*/inner join orders o on o.comp_id = c.id/*)*/
where c.name ilike /*name(*/'2 gis%’/*)*/
and co.country ilike /*country(*/'russia%' /*)*/
and co.city ilike /*city(*/'novosibirsk%’/*)*/
and co.street ilike /*street(*/'marks%'/*)*/
/*active(*/and o.date > currenttime - '6 month'::interval/*)*/
limit /*limit(int*/10/*)*/ offset /*offset(int*/5/*)*/
60. Реальный пример
select distinct c.id, c.name
from company c
/*office(*/inner join comp_office co on co.comp_id = c.id/*)*/
/*active(*/inner join orders o on o.comp_id = c.id/*)*/
where c.name ilike /*name(*/'2 gis%’/*)*/
/*office(*/and co.country ilike /*country(*/'russia%' /*)*/
and co.city ilike /*city(*/'novosibirsk%’/*)*/
and co.street ilike /*street(*/'marks%'/*))*/
/*active(*/and o.date > currenttime - '6 month'::interval/*)*/
limit /*limit(int*/10/*)*/ offset /*offset(int*/5/*)*/
61. Реальный пример
• Шаблон
– office (join)
– active (join)
– name
– office (where)
• country
• city
• street
– active (where)
– limit и offset
62. Реальный пример
Template t = new Template(“…”);
t.assignValue(“name”, “2 gis”);
t.assignValue(“country”, “russia”);
t.assignValue(“city”, “novosibirsk”);
t.assignValue(“street”, “marksa”);
t.assignValue(“limit”, 10);
t.assignValue(“offset”, 5);
t.enable(“active”);
63. Что дает нам велосипед?
• Ограничение текста запроса
• Позволяет контролировать тип параметров
• Позволяет не удалять значения параметров
• Позволяет разрабатывать и использовать в
программе один и тот же шаблон
64. Что дальше?
• POJO как конфигурация запроса
• Как получить PreparedStatement, а не текст?
• “Reflection” API и автотесты
• IDE plugins
65. Вместо заключения
• Заимствуйте в смежных областях
• Сфокусируйтесь на узкой задаче
• Придумывайте простое решение
• DSL FTW