рельсы с использованием переменных sql в find_by_sql - PullRequest
3 голосов
/ 20 июня 2011

У меня есть этот запрос:

SET @current_group = NULL; 
SET @current_count = 0; 
SELECT user_id, MIN( created_at ) as created_at, CASE WHEN @current_group = user_id THEN @current_count WHEN @current_group := user_id THEN @current_count := @current_count + 1 END AS c 
FROM notifies 
G    ROUP BY user_id, c 
ORDER BY id desc LIMIT 0 , 10

Если я запускаю его, он работает

но если я добавлю его в метод find_by_sql, например:

Notify.find_by_sql("SET @current_group = NULL; SET @current_count = 0; SELECT user_id, MIN( created_at ) as created_at, CASE WHEN @current_group = user_id THEN @current_count WHEN @current_group := user_id THEN @current_count := @current_count + 1 END AS c FROM notifies GROUP BY user_id, c ORDER BY id desc LIMIT 0 , 10")

Возвращает эту ошибку:

Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SET @current_count = 0; SELECT user_id, MIN( created_at ) as created_at, CASE WH' at line 1:

Как я могу это сделать?

спасибо

Ответы [ 2 ]

9 голосов
/ 02 марта 2012

Это потому, что find_by_sql работает только с одним оператором .

Установка переменных происходит в отдельных инструкциях. set специально находится в разделе Администрирование базы данных , номер 12.4.4, а select находится в разделе Управление данными , номер 12.2.7. Консоли (обычно) допускают несколько операторов и поддерживают переменные, но запросы ActiveRecord - нет.

Чтобы разрешить несколько операторов, я думаю вы должны поддерживать постоянное соединение с базой данных, чего не делает Rails (правка: обычно). Но я не уверен в этом - если бы кто-то еще знал, я бы хотел более определенную причину.

Редактировать: на самом деле, у меня есть решение для вас. Попробуйте это:

items = YourModel.transaction do
  YourModel.connection.execute("SET @current_group = NULL;")
  YourModel.connection.execute("SET @current_count = 0;")
  # this is returned, because it's the last line in the block
  YourModel.find_by_sql(%Q|
    SELECT user_id, MIN( created_at ) as created_at, CASE WHEN @current_group = user_id THEN @current_count WHEN @current_group := user_id THEN @current_count := @current_count + 1 END AS c 
    FROM notifies 
    GROUP BY user_id, c 
    ORDER BY id desc LIMIT 0 , 10
  |)
end

Все они выполняются в одной транзакции, и любые переменные / настройки внутри блока транзакции будут сохраняться между запросами. Вы по-прежнему связаны с одним утверждением на запрос. Возможно, есть способ сделать это без фактической транзакции, охватывающей весь набор, но я ее не искал - скорее всего, вы захотите ее, или у вас теперь есть очень специфическая вещь, которую нужно искать, если вы знаете, что нет .

Наслаждайтесь!

0 голосов
/ 20 июня 2011

В соответствии с API это синтаксис:

Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id,  start_date]

Так что вы можете попробовать поместить его в массив вместо использования скобок.

Notify.find_by_sql ["SET @current_group = NULL; SET @current_count = 0; SELECT user_id, MIN( created_at ) as created_at, CASE WHEN @current_group = user_id THEN @current_count WHEN @current_group := user_id THEN @current_count := @current_count + 1 END AS c FROM notifies GROUP BY user_id, c ORDER BY id desc LIMIT 0 , 10"]
...