#mysql #ruby_on_rails #procedure
Всем привет! Как создать хранимые процедуры в миграциях? Спасибо. Рабочий код: DELIMITER | DROP PROCEDURE IF EXISTS search_result | CREATE PROCEDURE search_result(IN search_data VARCHAR(255)) BEGIN DROP TABLE IF EXISTS searchTableRes; CREATE TABLE IF NOT EXISTS searchTableRes ( `id` INT NOT NULL, `title` VARCHAR(255), `article` TEXT, `articleable_id` INT, `articleable_type` VARCHAR(255) )ENGINE=MYISAM SET utf8 COLLATE utf8_general_ci; INSERT INTO searchTableRes ( `id`, `title`, `article`, `articleable_id`, `articleable_type` ) SELECT `a`.`id` as `id`, `a`.`title` as `title`, `a`.`article` as `article`, `a`.`articleable_id` as `articleable_id`, `a`.`articleable_type` as `articleable_type` FROM `articles` `a`; CREATE FULLTEXT INDEX ixFull ON searchTableRes (`title`, `article`); SELECT *,MATCH(`title`, `article`) AGAINST (CONCAT('*',search_data,'*') IN NATURAL LANGUAGE MODE) AS coefficient FROM searchTableRes WHERE MATCH(`title`, `article`) AGAINST (CONCAT('*',search_data,'*') IN BOOLEAN MODE) ORDER BY coefficient DESC; ALTER table searchTableRes ENGINE = BLACKHOLE; END | DELIMITER ;
Ответы
Ответ 1
Вы можете воспользоваться ActiveRecord::Base.connection.execute() для выполнения чистого SQL-запроса. Можно поступить примерно так class CreateProcedure < ActiveRecord::Migration def change sql = 'DROP PROCEDURE IF EXISTS search_result'; ActiveRecord::Base.connection.execute sql sql << 'CREATE PROCEDURE search_result(IN search_data VARCHAR(255)) BEGIN DROP TABLE IF EXISTS searchTableRes; CREATE TABLE IF NOT EXISTS searchTableRes ( `id` INT NOT NULL, `title` VARCHAR(255), `article` TEXT, `articleable_id` INT, `articleable_type` VARCHAR(255) )ENGINE=MYISAM SET utf8 COLLATE utf8_general_ci; INSERT INTO searchTableRes ( `id`, `title`, `article`, `articleable_id`, `articleable_type` ) SELECT `a`.`id` as `id`, `a`.`title` as `title`, `a`.`article` as `article`, `a`.`articleable_id` as `articleable_id`, `a`.`articleable_type` as `articleable_type` FROM `articles` `a`; CREATE FULLTEXT INDEX ixFull ON searchTableRes (`title`, `article`); SELECT *,MATCH(`title`, `article`) AGAINST (CONCAT('*',search_data,'*') IN NATURAL LANGUAGE MODE) AS coefficient FROM searchTableRes WHERE MATCH(`title`, `article`) AGAINST (CONCAT('*',search_data,'*') IN BOOLEAN MODE) ORDER BY coefficient DESC; ALTER table searchTableRes ENGINE = BLACKHOLE; END'; ActiveRecord::Base.connection.execute sql end endОтвет 2
Ну, когда язык запросов и миграций ActiveRecord не может предложить необходимых удобств БД из доступных, всегда есть execute у соединения, который позволяет выполнить произвольный SQL. Например, можно сделать: ActiveRecord::Base.connection.execute(запрос, пояснение_для_логов) Хорошо сочетается с heredoc-синтаксисом строк: запрос = <<-SQL SELECT * FROM table SQL Некоторые редакторы могут даже опознавать по маркеру окончания (здесь SQL) язык строки и подсвечивать её соответствующим образом, что облегчает редактирование. Или, как вариант, можно вынести SQL в отдельный *.sql-файл и редактировать его в режиме SQL. Это косметика, но жить с ней немножко легче. Для использования продвинутых возможностей реляционных баз может иметь смысл заменить ActiveRecord на Sequel.Ответ 3
Учитывая ответы cheops и D-side, получился следующее: Это готовый пример реализации умного и быстрого поиска с помощью 'хранимых процедур', что и запускается из миграции бес проблем. # /db/migrate/20160806225544_create_searches.rb: class CreateSearches < ActiveRecord::Migration def change ActiveRecord::Base.connection.execute('DROP PROCEDURE IF EXISTS search') ActiveRecord::Base.clear_active_connections! sql = <<-SQL CREATE PROCEDURE search(IN search_data VARCHAR(255)) BEGIN DROP TABLE IF EXISTS searches; CREATE TABLE IF NOT EXISTS searches ( `article_id` INT(11), `article_title` VARCHAR(255), `article` TEXT, `article_index` VARCHAR(255), `articleable_id` INT, `articleable_type` VARCHAR(255), `article_position` INT, `article_published` INT, `texture_title` VARCHAR(255), `texture_position` INT, `texture_published` INT, `message_index` VARCHAR(255), `message_name` VARCHAR(255), `message_contact` VARCHAR(255), `message_product_id` INT, `message_date` DATETIME, `message_position` INT, `message_published` INT, `page_title` VARCHAR(255), `page_slug` VARCHAR(255), `page_menu_id` INT, `page_parent_id` INT, `page_action_template` VARCHAR(255), `page_position` INT, `page_published` INT, `product_title` VARCHAR(255), `product_price` VARCHAR(255), `product_menu_id` INT, `product_texture_id` INT, `product_view_id` INT, `product_filling_id` INT, `product_seat_count_id` INT, `product_position` INT(11), `product_published` INT(11) )ENGINE=MYISAM DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; INSERT INTO searches ( `article_id` , `article_title` , `article` , `article_index` , `articleable_id` , `articleable_type` , `article_position` , `article_published` , `texture_title` , `texture_position` , `texture_published` , `message_index` , `message_name` , `message_contact` , `message_product_id` , `message_date` , `message_position` , `message_published` , `page_title` , `page_slug` , `page_menu_id` , `page_parent_id` , `page_action_template` , `page_position` , `page_published` , `product_title` , `product_price` , `product_menu_id` , `product_texture_id` , `product_view_id` , `product_filling_id` , `product_seat_count_id`, `product_position` , `product_published` ) SELECT DISTINCT `a`.`id` as `article_id` , `a`.`title` as `article_title` , `a`.`article` as `article` , `a`.`index` as `article_index` , `a`.`articleable_id` as `articleable_id` , `a`.`articleable_type` as `articleable_type` , `a`.`position` as `article_position` , `a`.`published` as `article_published` , `t`.`title` as `texture_title` , `t`.`position` as `texture_position` , `t`.`published` as `texture_published` , `m`.`index` as `message_index` , `m`.`name` as `message_name` , `m`.`contact` as `message_contact` , `m`.`product_id` as `message_product_id` , `m`.`date` as `message_date` , `m`.`position` as `message_position` , `m`.`published` as `message_published` , `p`.`title` as `page_title` , `p`.`slug` as `page_slug` , `p`.`menu_id` as `page_menu_id` , `p`.`parent_id` as `page_parent_id` , `p`.`action_template` as `page_action_template` , `p`.`position` as `page_position` , `p`.`published` as `page_published` , `pc`.`title` as `product_title` , `pc`.`price` as `product_price` , `pc`.`menu_id` as `product_menu_id` , `pc`.`texture_id` as `product_texture_id` , `pc`.`product_view_id` as `product_view_id` , `pc`.`product_filling_id` as `product_filling_id` , `pc`.`product_seat_count_id` as `product_seat_count_id`, `pc`.`position` as `product_position` , `pc`.`published` as `product_published` FROM `articles` `a` LEFT OUTER JOIN `textures` `t` ON `a`.`articleable_id` = `t`.`id` LEFT OUTER JOIN `messages` `m` ON `a`.`articleable_id` = `m`.`id` LEFT OUTER JOIN `pages` `p` ON `a`.`articleable_id` = `p`.`id` LEFT OUTER JOIN `products` `pc` ON `a`.`articleable_id` = `pc`.`id` UNION SELECT DISTINCT `a`.`id` as `article_id` , `a`.`title` as `article_title` , `a`.`article` as `article` , `a`.`index` as `article_index` , `a`.`articleable_id` as `articleable_id` , `a`.`articleable_type` as `articleable_type` , `a`.`position` as `article_position` , `a`.`published` as `article_published` , `t`.`title` as `texture_title` , `t`.`position` as `texture_position` , `t`.`published` as `texture_published` , `m`.`index` as `message_index` , `m`.`name` as `message_name` , `m`.`contact` as `message_contact` , `m`.`product_id` as `message_product_id` , `m`.`date` as `message_date` , `m`.`position` as `message_position` , `m`.`published` as `message_published` , `p`.`title` as `page_title` , `p`.`slug` as `page_slug` , `p`.`menu_id` as `page_menu_id` , `p`.`parent_id` as `page_parent_id` , `p`.`action_template` as `page_action_template` , `p`.`position` as `page_position` , `p`.`published` as `page_published` , `pc`.`title` as `product_title` , `pc`.`price` as `product_price` , `pc`.`menu_id` as `product_menu_id` , `pc`.`texture_id` as `product_texture_id` , `pc`.`product_view_id` as `product_view_id` , `pc`.`product_filling_id` as `product_filling_id` , `pc`.`product_seat_count_id` as `product_seat_count_id`, `pc`.`position` as `product_position` , `pc`.`published` as `product_published` FROM `articles` `a` RIGHT OUTER JOIN `textures` `t` ON `a`.`articleable_id` = `t`.`id` RIGHT OUTER JOIN `messages` `m` ON `a`.`articleable_id` = `m`.`id` RIGHT OUTER JOIN `pages` `p` ON `a`.`articleable_id` = `p`.`id` RIGHT OUTER JOIN `products` `pc` ON `a`.`articleable_id` = `pc`.`id`; CREATE FULLTEXT INDEX ixFull ON searches ( `article_title`, `article` , `texture_title`, `page_title` , `product_title` ); SELECT *,MATCH( `article_title`, `article` , `texture_title`, `page_title` , `product_title` ) AGAINST (CONCAT('*',search_data,'*') IN NATURAL LANGUAGE MODE) AS coefficient FROM searches WHERE MATCH( `article_title`, `article` , `texture_title`, `page_title` , `product_title` ) AGAINST (CONCAT('*',search_data,'*') IN BOOLEAN MODE) ORDER BY coefficient DESC; ALTER table searches ENGINE = BLACKHOLE; END SQL ActiveRecord::Base.connection.execute(sql) ActiveRecord::Base.clear_active_connections! end end # /app/controllers/searches_controller.rb: class SearchesController < InheritedResources::Base def show @result = ActiveRecord::Base.connection.execute("call search('#{params[:search]}')") ActiveRecord::Base.clear_active_connections! end end
Комментариев нет:
Отправить комментарий