Проблемы Active Record в CodeIgniter — Вложенные запросы, Внутренние функции БД
Ожидает приглашения
Ошибка в результирующем запросе при использовании встроенных функций БД
Есть код который генерирует не правильный SQL-запрос.
$p = $this->db->dbprefix('table');
$sub = $this->db->dbprefix('sec_table');
$this->db->select($p.'.id', false);
$this->db->select($p.'.main_name', false);
$this->db->select('(COUNT('.$sub.'.id) + 1) AS pages_count', false);
$this->db->from($sub);
$this->db->join($p, $sub.'.profile_id = '.$p.'.id', 'RIGHT');
$this->db->where($p.'.is_vip', 1, false);
$this->db->where($sub.'.is_enable', 1, false);
$res = $this->db->get();
генерируемый SQL имеет добавочный префикс таблиц — pr_(COUNT(pr_sec_table.id) + 1) AS pages_count
К сожалению, расширение классов базы данных не возможно стандартными средствами CI. Как избавиться от такого спецэффекта без правки кода самого фреймверка? только ручным формированием кода запроса?
при этом в UG черным по белому:
$this->db->select() accepts an optional second parameter. If you set it to FALSE, CodeIgniter will not try to protect your field or table names with backticks. This is useful if you need a compound select statement.
$this->db->select('(SELECT SUM(payments.amount) FROM payments WHERE payments.invoice_id=4') AS amount_paid', FALSE);
$query = $this->db->get('mytable');
Решение нашел в процессе эксперимента. Когда выяснилось, что хак найденный на оф.форуме не подействовал решил пойти в абанк… и получилось… вот решение:
следует перед вызовом get() сбросить переменную префикса, а после вызова восстановить.
$pref = $this->db->dbprefix;
$this->db->dbprefix = '';
$res = $this->db->get();
$this->db->dbprefix = $pref;
Вложенные запросы
Вся соль проблемы была в том что нет явного способа описать вложенный запрос средствами ActivRecord в CI.
Не будем спорить по поводу качества запроса, о том, возможно ли его преобразовать в запрос без вложений…
Будем считать, что это не возможно.
В исходном коде DB_active_rec.php, который как раз и реализует механизм ActiveRecord,
есть 2 функции:
_compile_select и _reset_select
они помечены как access private, но… это же синтаксис php4 т.е. без хаков можно задействовать эти функции с целью формировать нужные по синтаксису запросы используя только ActiveRecord…
Алгоритм прост. Первым делом нужно описать методами ActiveRecord все сложенные запросы. В конце каждого из них, вместо $this->db->get() нужно вызывать $s = $this->db->_compile_select() — этот вызов сгенерирует нужный код запроса в переменную $s. Важно — после этого нужно обязательно очистить очередь вызовов методом $this->db->_reset_select(). После этого можно формировать новый вложенный или внешний запрос. Таким образом можно сформировать запросы любой глубины вложенности.
Применение полученных строк запросов простое — при формировании основного запроса нужно сделать вполне логичный вызов $this->db->from('('.$s.') as table1')
Главное не забыть обернуть строку вложенного запроса в скобки, иначе библиотека добавит префикс таблицы.
Статьи взяты с моего ЖЖ: tovit.livejournal.com