![Page 1: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/1.jpg)
Сложные SQL запросы в Ruby On RailsМанылов Павел aka [r-k]SFD 2012 / Екатеринбург
![Page 2: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/2.jpg)
Сложные запросы?
● Не описаны в туториалах и документации по Rails
● Чаще всего затрагивают больше одной таблицы
● Вызывают затруднения при написании
![Page 3: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/3.jpg)
Короткий обзор
● Rails - MVC фреймворк
● ActiveRecord - ORM библиотека
● ARel - менеджер синтаксических
деревьев для составления sql-запросов
Rails использует ActiveRecord использует ARel
![Page 4: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/4.jpg)
Требования к коду
● Красивость
● Читабельность
● Без вставок SQL-кода
● Гибкость, DRY
● Rails Way
![Page 5: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/5.jpg)
Группировка и агрегирование
Используем следующую структуры БД
![Page 6: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/6.jpg)
Группировка и агрегирование
Необходимо получить население по областям (штатам) в виде массива объектов со следующими данными:
[{:country=>"Страна", :state=>"Область", :population=>20000
}, ...]
![Page 7: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/7.jpg)
Группировка и агрегирование
На чистом SQL:
City.find_by_sql(" SELECT `country`, `state`, sum(`population`) as `population` FROM `cities` GROUP BY `country`, `state`")
![Page 8: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/8.jpg)
Группировка и агрегирование
На чистом SQL:
City.find_by_sql(" SELECT `country`, `state`, sum(`population`) as `population` FROM `cities` GROUP BY `country`, `state`")
![Page 9: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/9.jpg)
Группировка и агрегирование
На чистом SQL:
City.find_by_sql(" SELECT `country`, `state`, sum(`population`) as `population` FROM `cities` GROUP BY `country`, `state`")
![Page 10: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/10.jpg)
Группировка и агрегирование
ActiveRecord:
City.group(:country,:state) \ .sum(:population)
![Page 11: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/11.jpg)
Группировка и агрегирование
ActiveRecord:
City.group(:country,:state) \ .sum(:population) # => { ["Страна", "Область"] => 10000}
![Page 12: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/12.jpg)
Группировка и агрегирование
ActiveRecord:
City.group(:country,:state) \ .sum(:population) \ .map{|k,v| { :country=>k[0], :state=>k[1], :population=>v } } # => Array<Hash>
![Page 13: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/13.jpg)
Группировка и агрегирование
ActiveRecord:
City.group(:country,:state) \ .sum(:population) \ .map{|k,v| { :country=>k[0], :state=>k[1], :population=>v } } # => Array<Hash>
![Page 14: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/14.jpg)
Группировка и агрегирование
ActiveRecord:
City.select( [ :country, :state, "sum(`population`) as `population`" ])\ .group(:country, :state)
![Page 15: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/15.jpg)
Группировка и агрегирование
ActiveRecord:
City.select( [ :country, :state, "sum(`population`) as `population`" ])\ .group(:country, :state)
![Page 16: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/16.jpg)
Группировка и агрегирование
ActiveRecord:
City.select( [ :country, :state, "sum(`population`) as `population`" ])\ .group(:country, :state)
![Page 17: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/17.jpg)
Группировка и агрегирование
ActiveRecord:
City.select( [ :country, :state, "sum(`population`) as `population`" ])\ .group(:country, :state)# => ActiveRecord::Relation
![Page 18: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/18.jpg)
Группировка и агрегирование
ActiveRecord:
City.select( [ :country, :state, "sum(`population`) as `population`" ])\ .group(:country, :state)
![Page 19: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/19.jpg)
Группировка и агрегирование
SQL by ARel:
at = City.arel_tableCity.find_by_sql(
at.project(at[:country], at[:state], at[:population].sum.as("population")
).group(at[:country],at[:state]))
![Page 20: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/20.jpg)
Группировка и агрегирование
SQL by ARel:
at = City.arel_tableCity.find_by_sql(
at.project(at[:country], at[:state], at[:population].sum.as("population")
).group(at[:country],at[:state]))
![Page 21: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/21.jpg)
Группировка и агрегирование
SQL by ARel:
at = City.arel_tableCity.find_by_sql(
at.project( # Arel::SelectManager.new(…).from(…).project(…)
at[:country], at[:state], at[:population].sum.as("population")
).group(at[:country],at[:state]))
![Page 22: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/22.jpg)
Группировка и агрегирование
SQL by ARel:
at = City.arel_tableCity.find_by_sql(
at.project(at[:country], at[:state], at[:population].sum.as("population")
).group(at[:country],at[:state]))
![Page 23: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/23.jpg)
Группировка и агрегирование
SQL by ARel:
at = City.arel_tableCity.find_by_sql(
at.project(at[:country], at[:state], at[:population].sum.as("population")
).group(at[:country],at[:state]))
![Page 24: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/24.jpg)
Группировка и агрегирование
SQL by ARel:
at = City.arel_tableCity.find_by_sql(
at.project(at[:country], at[:state], at[:population].sum.as("population")
).group(at[:country],at[:state]))
![Page 25: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/25.jpg)
Группировка и агрегирование
ActiveRecord + ARel:
at = City.arel_tableCity.select(
[:country, :state, at[:population].sum.as("population")
]).group(:country, :state)
![Page 26: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/26.jpg)
Группировка и агрегирование
ActiveRecord + ARel:
at = City.arel_tableCity.select(
[:country, :state, at[:population].sum.as("population")
]).group(:country, :state)
![Page 27: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/27.jpg)
Вложенные запросы
Необходимо получить список городов, которые посещали люди, посещавшие так же город Х, в виде массива объектов модели City:
[<City>, ...]
![Page 28: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/28.jpg)
Вложенные запросы
На чистом SQL:
City.find_by_sql("SELECT * FROM `cities`WHERE `cities`.`id` IN (
SELECT `v1`.`city_id` FROM `visits` as `v1` WHERE `v1`.`person_id` IN(
SELECT `v2`.`person_id` FROM `visits` as `v2` WHERE `city_id` = #{city_id}
))")
ARel
![Page 29: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/29.jpg)
Вложенные запросы
На чистом SQL:
City.find_by_sql("SELECT * FROM `cities`WHERE `cities`.`id` IN (
SELECT `v1`.`city_id` FROM `visits` as `v1` WHERE `v1`.`person_id` IN(
SELECT `v2`.`person_id` FROM `visits` as `v2` WHERE `city_id` = #{city_id}
))")
![Page 30: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/30.jpg)
Вложенные запросы
На чистом SQL:
City.find_by_sql("SELECT * FROM `cities`WHERE `cities`.`id` IN (
SELECT `v1`.`city_id` FROM `visits` as `v1` WHERE `v1`.`person_id` IN(
SELECT `v2`.`person_id` FROM `visits` as `v2` WHERE `city_id` = #{city_id}
))")
![Page 31: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/31.jpg)
Вложенные запросы
На чистом SQL:
City.find_by_sql("SELECT * FROM `cities`WHERE `cities`.`id` IN (
SELECT `v1`.`city_id` FROM `visits` as `v1` WHERE `v1`.`person_id` IN(
SELECT `v2`.`person_id` FROM `visits` as `v2` WHERE `city_id` = #{city_id}
))")
![Page 32: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/32.jpg)
Вложенные запросы
ARel:
at = City.arel_table
v1_alias = Visit.arel_table.alias("v1")v1 = Arel::SelectManager.new(ActiveRecord::Base) \ .from(v1_alias)
v2_alias = Visit.arel_table.alias("v2")v2 = Arel::SelectManager.new(ActiveRecord::Base) \ .from(v2_alias)
![Page 33: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/33.jpg)
Вложенные запросы
ARel:
at = City.arel_table
v1_alias = Visit.arel_table.alias("v1")v1 = Arel::SelectManager.new(ActiveRecord::Base) \ .from(v1_alias)
v2_alias = Visit.arel_table.alias("v2")v2 = Arel::SelectManager.new(ActiveRecord::Base) \ .from(v2_alias)
![Page 34: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/34.jpg)
Вложенные запросы
ARel:
at = City.arel_table
v1_alias = Visit.arel_table.alias("v1")v1 = Arel::SelectManager.new(ActiveRecord::Base) \ .from(v1_alias)
v2_alias = Visit.arel_table.alias("v2")v2 = Arel::SelectManager.new(ActiveRecord::Base) \ .from(v2_alias)
![Page 35: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/35.jpg)
Вложенные запросы
ARel:
at = City.arel_table
v1_alias = Visit.arel_table.alias("v1")v1 = Arel::SelectManager.new(ActiveRecord::Base) \ .from(v1_alias)
v2_alias = Visit.arel_table.alias("v2")v2 = Arel::SelectManager.new(ActiveRecord::Base) \ .from(v2_alias)
![Page 36: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/36.jpg)
Вложенные запросы
ARel:City.find_by_sql(
at.project(Arel.star).where(at[:id].in(
v1.project(v1_alias[:city_id]).where(v1_alias[:person_id].in(
v2.project(v2_alias[:person_id]).where(v2_alias[:city_id].eq(city_id)
))
))
))
SQL Arel
![Page 37: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/37.jpg)
Вложенные запросы
ARel:City.find_by_sql(
at.project(Arel.star).where(at[:id].in(
v1.project(v1_alias[:city_id]).where(v1_alias[:person_id].in(
v2.project(v2_alias[:person_id]).where(v2_alias[:city_id].eq(city_id)
))
))
))
at.project("*") at.project(Arel::SqlLiteral.new("*"))# .to_sql => "SELECT * FROM `cities`"
at.project(at["*"])at.project(at[Arel.star])# .to_sql => "SELECT `cities`.* FROM `cities`"
![Page 38: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/38.jpg)
Вложенные запросы
ARel:City.find_by_sql(
at.project(Arel.star).where(at[:id].in(
v1.project(v1_alias[:city_id]).where(v1_alias[:person_id].in(
v2.project(v2_alias[:person_id]).where(v2_alias[:city_id].eq(city_id)
))
))
))
Arel::Nodes::Equality.new(v2_alias[:city_id], cities[1].id)# .to_sql => "`v2`.`city_id` = X"
![Page 39: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/39.jpg)
Вложенные запросы
ARel:City.find_by_sql(
at.project(Arel.star).where(at[:id].in(
v1.project(v1_alias[:city_id]).where(v1_alias[:person_id].in(
v2.project(v2_alias[:person_id]).where(v2_alias[:city_id].eq(city_id)
))
))
))
Arel::Nodes::In.new(at[:id], v1.…)# .to_sql => "`cities`.`id` IN (SELECT …)"
SQL
![Page 40: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/40.jpg)
Вложенные запросы
ARel:
НЕ ОЧЕНЬЯ думал, намного будет… Намного
лучше будет это всеСколько раз сюда ходи-и-и-л — было
намного лучше, но на этот раз как-то не удало-о-ось.
![Page 41: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/41.jpg)
Вложенные запросы
ActiveRecord only:
City.where(:id => Visit.select(:city_id).where(
:person_id => Visit.select(:person_id) \ .where(:city_id=>city_id)
))
![Page 42: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/42.jpg)
Вложенные запросы
ActiveRecord only:
City.where(:id => Visit.select(:city_id).where(
:person_id => Visit.select(:person_id) \ .where(:city_id=>city_id)
))
![Page 43: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/43.jpg)
Вложенные запросы
ActiveRecord only:
City.where(:id => Visit.select(:city_id).where(
:person_id => Visit.select(:person_id) \ .where(:city_id=>city_id)
))
![Page 44: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/44.jpg)
Вложенные запросы
ActiveRecord only:
SO GOOD!
![Page 45: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/45.jpg)
Вложенные запросы с агрегацией
Достаточно часто используемый пример: статистика скачиваний файлов.
![Page 46: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/46.jpg)
Вложенные запросы с агрегацией
Необходимо получить статистику уникальных загрузок файлов с группировкой по дням в виде:[
{ :file_id=>5, :year_in_tz=>2012, :month_in_tz=>3, :day_in_tz=>1, :hosts_count=>2}, …
]
![Page 47: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/47.jpg)
Вложенные запросы с агрегацией
ActiveRecord + ARel
DownloadStatistic.select([:file_id, :year_in_tz,
:month_in_tz, :day_in_tz,
Arel.star.count.as("hosts_count")]) \
.from( DownloadStatistic.select(
[:file_id,:year_in_tz, :month_in_tz, :day_in_tz]
).group(:file_id, :ip,
:year_in_tz,:month_in_tz, :day_in_tz) \
.arel.as("t1")
).group(:file_id, :year_in_tz, :month_in_tz, :day_in_tz)
![Page 48: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/48.jpg)
Вложенные запросы с агрегацией
ActiveRecord + ARel
DownloadStatistic.select([:file_id, :year_in_tz,
:month_in_tz, :day_in_tz,
Arel.star.count.as("hosts_count")]) \
.from( DownloadStatistic.select( [:file_id,:year_in_tz, :month_in_tz, :day_in_tz] ).group(:file_id, :ip, :year_in_tz,:month_in_tz, :day_in_tz) \ .arel.as("t1") ).group(:file_id, :year_in_tz, :month_in_tz, :day_in_tz)
![Page 49: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/49.jpg)
Вложенные запросы с агрегацией
ActiveRecord + ARel
DownloadStatistic.select([:file_id, :year_in_tz,
:month_in_tz, :day_in_tz,
Arel.star.count.as("hosts_count")]) \
.from( DownloadStatistic.select(
[:file_id,:year_in_tz, :month_in_tz, :day_in_tz]
).group(:file_id, :ip,
:year_in_tz,:month_in_tz, :day_in_tz) \
. arel.as("t1") ).group(:file_id, :year_in_tz, :month_in_tz, :day_in_tz)
<Arel::SelectManager>
![Page 50: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/50.jpg)
Вложенные запросы с агрегацией
ActiveRecord + ARel
DownloadStatistic.select([:file_id, :year_in_tz,
:month_in_tz, :day_in_tz,
Arel.star.count.as("hosts_count")]) \
.from( DownloadStatistic.select(
[:file_id,:year_in_tz, :month_in_tz, :day_in_tz]
).group(:file_id, :ip,
:year_in_tz,:month_in_tz, :day_in_tz) \
.arel. as("t1") ).group(:file_id, :year_in_tz, :month_in_tz, :day_in_tz)
<Arel::Nodes::TableAlias># .to_sql => "(SELECT …) t1"
![Page 51: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/51.jpg)
Вложенные запросы с агрегацией
ActiveRecord + ARel
DownloadStatistic.select([:file_id, :year_in_tz,
:month_in_tz, :day_in_tz,
Arel.star.count.as("hosts_count")]) \ .from( DownloadStatistic.select(
[:file_id,:year_in_tz, :month_in_tz, :day_in_tz]
).group(:file_id, :ip,
:year_in_tz,:month_in_tz, :day_in_tz) \
.arel.as("t1")
).group(:file_id, :year_in_tz, :month_in_tz, :day_in_tz)
# .to_sql => COUNT(*) as `hosts_count`
![Page 52: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/52.jpg)
JOIN-ы таблиц
Возьмём в качестве примера интернет-магазин. В данный момент нас интересуют следующие таблицы и связь между ними:
![Page 53: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/53.jpg)
JOIN-ы таблиц
Необходимо получить массив объектов моделей Client с дополнительными полями, отражающими общее количество покупок и сумму потраченных в магазине средств в виде:
[ <Client … spent_money=2000 purchases_count=3>, …]
![Page 54: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/54.jpg)
JOIN-ы таблиц: add_select
Иногда необходимо динамически добавлять к запросу поля выборки:class ActiveRecord::Relation def add_select(selects) t=self.scoped selects=[selects] unless selects.kind_of?(Array) t.select_values = [self.arel_table[Arel.star]] if t.select_values.blank? t.select_values+=selects t endend
![Page 55: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/55.jpg)
JOIN-ы таблиц: add_select
Иногда необходимо динамически добавлять к запросу поля выборки:class ActiveRecord::Relation def add_select(selects) t=self.scoped selects=[selects] unless selects.kind_of?(Array) t.select_values = [self.arel_table[Arel.star]] if t.select_values.blank? t.select_values+=selects t endend
![Page 56: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/56.jpg)
JOIN-ы таблиц: add_select
Примеры использования:
p = Purchase.select(Purchase.arel_table[:sum])# .to_sql => SELECT `purchases`.`sum` FROM `purchases`
x = p.add_select(Purchase.arel_table[:client_id])# . to_sql => SELECT `purchases`.`sum`, `purchases`.`client_id` FROM `purchases`
![Page 57: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/57.jpg)
JOIN-ы таблиц: add_select
Примеры использования:
p = Purchase.select(Purchase.arel_table[:sum])# .to_sql => SELECT `purchases`.`sum` FROM `purchases`
x = p.add_select(Purchase.arel_table[:client_id])# . to_sql => SELECT `purchases`.`sum`, `purchases`.`client_id` FROM `purchases`
![Page 58: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/58.jpg)
JOIN-ы таблиц: add_select
Примеры использования:
p = Purchase.select(Purchase.arel_table[:sum])# .to_sql => SELECT `purchases`.`sum` FROM `purchases`
x = p.add_select(Purchase.arel_table[:client_id])# . to_sql => SELECT `purchases`.`sum`, `purchases`.`client_id` FROM `purchases`
![Page 59: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/59.jpg)
JOIN-ы таблиц: LEFT OUTER JOINp_at = Purchase.arel_tablec_at = Client.arel_table
purchases_join = Arel::OuterJoin.new( p_at, Arel::Nodes::On.new( c_at[:id].eq(p_at[:client_id]) ))#.to_sql => "LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id`"
![Page 60: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/60.jpg)
JOIN-ы таблиц: LEFT OUTER JOINp_at = Purchase.arel_tablec_at = Client.arel_table
purchases_join = Arel::OuterJoin.new( p_at, Arel::Nodes::On.new( c_at[:id].eq(p_at[:client_id]) ))#.to_sql => "LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id`"
![Page 61: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/61.jpg)
JOIN-ы таблиц: LEFT OUTER JOINp_at = Purchase.arel_tablec_at = Client.arel_table
purchases_join = Arel::OuterJoin.new( p_at, Arel::Nodes::On.new( c_at[:id].eq(p_at[:client_id]) ))#.to_sql => "LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id`"
![Page 62: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/62.jpg)
JOIN-ы таблиц: LEFT OUTER JOINp_at = Purchase.arel_tablec_at = Client.arel_table
purchases_join = Arel::OuterJoin.new( p_at, Arel::Nodes::On.new( c_at[:id].eq(p_at[:client_id]) ))#.to_sql => "LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id`"
![Page 63: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/63.jpg)
JOIN-ы таблиц: Полные запросы#p_at, c_at, purchases_join определили ранее
Client.joins(purchases_join) \ .add_select( p_at[:id].count \ .as("purchases_count") ).group(p_at[:client_id])
# .to_sql => "SELECT `clients`.*, COUNT(`purchases`.`id`) AS purchases_count FROM `clients` LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id` GROUP BY `purchases`.`client_id`"
![Page 64: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/64.jpg)
JOIN-ы таблиц: Полные запросы#p_at, c_at, purchases_join определили ранее
Client.joins(purchases_join) \ .add_select( p_at[:id].count \ .as("purchases_count") ).group(p_at[:client_id])
# .to_sql => "SELECT `clients`.*, COUNT(`purchases`.`id`) AS purchases_count FROM `clients` LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id` GROUP BY `purchases`.`client_id`"
![Page 65: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/65.jpg)
JOIN-ы таблиц: Полные запросы#p_at, c_at, purchases_join определили ранее
Client.joins(purchases_join) \ .add_select( p_at[:id].count \ .as("purchases_count") ).group(p_at[:client_id])
# .to_sql => "SELECT `clients`.*, COUNT(`purchases`.`id`) AS purchases_count FROM `clients` LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id` GROUP BY `purchases`.`client_id`"
![Page 66: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/66.jpg)
JOIN-ы таблиц: Полные запросы#p_at, c_at, purchases_join определили ранее
Client.joins(purchases_join) \ .add_select( p_at[:id].count \ .as("purchases_count") ).group(p_at[:client_id])
# .to_sql => "SELECT `clients`.*, COUNT(`purchases`.`id`) AS purchases_count FROM `clients` LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id` GROUP BY `purchases`.`client_id`"
![Page 67: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/67.jpg)
JOIN-ы таблиц: Полные запросы
Аналогично для spent_money:
Client.joins(purchases_join) \ .add_select( p_at[:sum].sum.as("spent_money") ).group(p_at[:client_id])
# .to_sql => "SELECT `clients`.*, SUM(`purchases`.`sum`) AS spent_money FROM `clients` LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id` GROUP BY `purchases`.`client_id`"
![Page 68: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/68.jpg)
JOIN-ы таблиц: Полные запросы
Аналогично для spent_money:
Client.joins(purchases_join) \ .add_select( p_at[:sum].sum.as("spent_money") ).group(p_at[:client_id])
# .to_sql => "SELECT `clients`.*, SUM(`purchases`.`sum`) AS spent_money FROM `clients` LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id` GROUP BY `purchases`.`client_id`"
![Page 69: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/69.jpg)
JOIN-ы таблиц: Scopes
joins_purchase в виде named scope с предотвращением повторных join-ов:class Client < ActiveRecord::Base… scope :joins_purchase, lambda{ unless defined?(@joins_purchase) p = Purchase.arel_table @joins_purchase = joins(Arel::OuterJoin.new(p, Arel::Nodes::On.new(arel_table[:id].eq(p[:client_id])))).group(p[:client_id]) end @joins_purchase }…
![Page 70: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/70.jpg)
JOIN-ы таблиц: Scopesclass Client < ActiveRecord::Base… scope :with_purchases_count, lambda{ joins_purchase.add_select( Purchase.arel_table[:id].count.as("purchases_count") ) }
scope :with_spent_money, lambda{ joins_purchase.add_select( Purchase.arel_table[:sum].sum.as("spent_money") ) }…
![Page 71: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/71.jpg)
JOIN-ы таблиц: Scopesclass Client < ActiveRecord::Base… scope :with_purchases_count, lambda{ joins_purchase.add_select( Purchase.arel_table[:id].count.as("purchases_count") ) }
scope :with_spent_money, lambda{ joins_purchase.add_select( Purchase.arel_table[:sum].sum.as("spent_money") ) }…
![Page 72: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/72.jpg)
JOIN-ы таблиц: Scopesclass Client < ActiveRecord::Base… scope :with_purchases_count, lambda{ joins_purchase.add_select( Purchase.arel_table[:id].count.as("purchases_count") ) }
scope :with_spent_money, lambda{ joins_purchase.add_select( Purchase.arel_table[:sum].sum.as("spent_money") ) }…
![Page 73: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/73.jpg)
JOIN-ы таблиц: Scopesclass Client < ActiveRecord::Base… scope :with_purchases_information, lambda{ with_purchases_count.with_spent_money }…endClient.with_purchases_information# .to_sql => "
#SELECT `clients`.*, COUNT(`purchases`.`id`) AS purchases_count,# SUM(`purchases`.`sum`) AS spent_money #FROM `clients`
#LEFT OUTER JOIN `purchases` ON `clients`.`id` = `purchases`.`client_id`
#GROUP BY `purchases`.`client_id`
#"
![Page 74: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/74.jpg)
JOIN-ы таблиц: ПроблемаClient.with_purchases_information.count
# => { group_item=>count, … }
group(…)
![Page 75: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/75.jpg)
JOIN-ы таблиц: ПроблемаClient.with_purchases_information.count
# => { group_item=>count, … }
Решения:● Переписать со вложенными запросами● Считать количество не COUNT(*) запросом, а на
стороне Rails: Client.with_purchases_information.all.count
group(…)
![Page 76: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/76.jpg)
Polymorphic Associations
Используем тот же самый магазин, добавим к нему систему тикетов (общение менеджеров с клиентами)
![Page 77: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/77.jpg)
Polymorphic Associationsclass Ticket < ActiveRecord::Base belongs_to :client belongs_to :initiator, :polymorphic => true has_many :ticket_messagesend
class TicketMessage < ActiveRecord::Base belongs_to :sender, :polymorphic => true belongs_to :ticketend
class Manager < ActiveRecord::Base has_many :ticket_messages, :as=>:senderend
![Page 78: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/78.jpg)
Polymorphic Associations
Необходимо получить массив сообщений для данного тикета с указанием имени отправителя в виде:
[ <TicketMessage … sender_name="Василий">, …]
![Page 79: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/79.jpg)
Polymorphic Associations: JOINSc_at = Client.arel_tabletm_at = TicketMessage.arel_table
sender_client_join = Arel::Nodes::OuterJoin.new( c_at, Arel::Nodes::On.new( c_at[:id].eq(tm_at[:sender_id]). \ and(tm_at[:sender_type].eq("Client")) ))
![Page 80: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/80.jpg)
Polymorphic Associations: JOINSc_at = Client.arel_tabletm_at = TicketMessage.arel_table
sender_client_join = Arel::Nodes::OuterJoin.new( c_at, Arel::Nodes::On.new( c_at[:id].eq(tm_at[:sender_id]). \ and(tm_at[:sender_type].eq("Client")) ))
![Page 81: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/81.jpg)
Polymorphic Associations: JOINSm_at = Manager.arel_tabletm_at = TicketMessage.arel_table
sender_manager_join = Arel::Nodes::OuterJoin.new( m_at, Arel::Nodes::On.new( m_at[:id].eq(tm_at[:sender_id]). \ and(tm_at[:sender_type].eq("Manager")) ))
![Page 82: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/82.jpg)
Polymorphic Associations: JOINSm_at = Manager.arel_tabletm_at = TicketMessage.arel_table
sender_manager_join = Arel::Nodes::OuterJoin.new( m_at, Arel::Nodes::On.new( m_at[:id].eq(tm_at[:sender_id]). \ and(tm_at[:sender_type].eq("Manager")) ))
![Page 83: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/83.jpg)
Polymorphic Associations: Запрос
Итоговый запрос:
ticket = Ticket.find(some_id)ticket.ticket_messages \ .joins(sender_client_join).joins(sender_manager_join) \ .add_select( Arel::Nodes::NamedFunction.new("IFNULL", [ c_at[:name], m_at[:name] ]).as("sender_name") )
![Page 84: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/84.jpg)
Polymorphic Associations: Запрос
Итоговый запрос:
ticket = Ticket.find(some_id)ticket.ticket_messages \ .joins(sender_client_join).joins(sender_manager_join)\ .add_select( Arel::Nodes::NamedFunction.new("IFNULL", [ c_at[:name], m_at[:name] ]).as("sender_name") )
# .to_sql => "IFNULL(`clients`.`name`, `managers`.`name`) AS sender_name"
![Page 85: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/85.jpg)
Ну и хватит с запросами
![Page 86: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/86.jpg)
Полезные ruby gems
● Squeel - sql запросы в ruby стиле https://github.com/ernie/squeel
● Advanjo - сложные join-ы в одну строку https://github.com/rap-kasta/advanjo.git
● Chooseme - подбор индекса по используемым столбцам https://github.com/rap-kasta/chooseme.git
![Page 87: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/87.jpg)
ВОПРОСЫ?
![Page 88: в Ruby On Rails Сложные SQL запросыkomar.in/files/1.Manylov_P.-ROR-SQL.pdf · Короткий обзор Rails - MVC фреймворк ActiveRecord - ORM библиотека](https://reader034.vdocuments.mx/reader034/viewer/2022042407/5f2148297bdc8469091360f8/html5/thumbnails/88.jpg)
Контакты
Манылов Павел Сергеевич
email: [email protected]: [email protected]: rapkastatwitter: rap_kasta
Нет, я не фанат, ну ... не на столько.