Как получить sql выражение, которое выполняет findAll()

Привет, коллеги,

Есть модель, есть связанная с ней модель. Есть CDbCriteria с with и condition.

Как мне получить sql выражение, которое будет выполнено при $model->findAll($criteria);?

Ну или хотя бы CDbCommand с этим выражением.

Это нужно для построения запроса вида SELCT WHERE IN (SELECT…)

Можно посмотреть каким-нибудь логгером, например этим

Нет, вы не поняли, мне нужно выражение программно, для дальнейшего использования в запросах :)

ну так вы же пишете, что вам sql выражение нужно =)

Никак :) Ибо этот метод возвращает список объектов.

Можно всё делать ручками, используя методы CDbCommandBuilder, которые возвращают объект CDbCommand, у которого есть нужное вам поле text.

Не видел, чтоб такие задачи решались таким странным способом. Если вам нужно построить сложный запрос со вложенными SELECT’ами, то есть и другие способы. Напишите запрос, который вы хотите выполнить - вам помогут :)

CDbcommandBuilder в чистом виде не может помочь ибо он ничего не знает про with и не умеет с ним обращаться.

За with отвечают CActiveFinder, CJoinElement и CJoinQuery. Но CActiveFinder написан без оглядки на то, что кому-то взбредет в голову его расширять — все свойства private. Видимо тупик.

Это нужно для построения фильтров по связанным таблицам. Сначала фильтруется связанная таблица по критерию, затем основная фильтруется по id’шкам полученным из предыдущего запроса. Но сделать все просто: выполнить первый запрос и сделать addInCondition(результаты первого запроса) ко второму не получается — получается запрос с тысячами параметров в IN.

Запрос то отрабатывает, но предположительно из-за него php слетает с катушек, читай, падает. Помогает только рестарт апача. Итого, я пытаюсь спрятать эти тысячи параметров в подзапрос прямо в SQL.

Какие есть способы построения такого запроса?

Если я правильно понимаю: есть таблицы T1 и T2. Вы хотите выбрать записи из T2 по некоторому критерию. Каждая запись в T2 имеет свой id. Затем в таблице T1 нужно оставить те записи, у которых T1.id = T2.id. Почему в данном случае не воспользоваться таким запросом: SELECT T1.* FROM T1 INNER JOIN T2 ON T1.id = T2.id WHERE T2.field = :value ?

В случае двух таблиц — конечно. Но у меня универсальная фильтрация довольно большого набора данных (можно отсортировать и отфильтровать по любому столбцу)и таких таблиц может джойниться с десяток. Так что все фильтры вынесены в отдельные запросы, от которых получаем список айдишек. На мой взгляд десяток простых запросов лучше, чем джойн десяти таблиц :)

В таком случае пользуйтесь чистым sql, составив оптимальный запрос и не мучая Active Record :) Потом можно результат передать в populateRecords и получить список объектов.

Придется задублировать механизм связей, так удачно реализованный в ActiveFinder’е.

По хорошему надо научить ActiveFinder отдавать запрос в виде строки и массива параметров.

Вижу, что ветка старая, но меня тоже интересует данный вопрос.

Что в итоге сделал, если не секрет?

Вы можете перегрузить компонент db приложения и добавить сохранение последнего запроса к БД. Решение через логгер не самое удачное, так как зависит от отладочного режима и уровня логирования (категорий).

Есть длинный и сложный запрос с кучей под запросов, хотелось бы узнать каким образом можно решить данную проблему


SELECT `id` FROM `product` WHERE `name` LIKE '$param%' OR `section` IN (SELECT DISTINCT idsection FROM section WHERE name_ru LIKE '$param%' OR name_ro LIKE '$param%') OR `material_ru` LIKE '$param%' OR `material_ro` LIKE '$param%' OR `fabricator` LIKE '$param%' OR `type` IN (SELECT idtype FROM types WHERE name_ru LIKE '$param%' OR name_ro LIKE '$param%') OR `country_ru` LIKE '$param%' OR `country_ro` LIKE '$param%' OR `id` IN (SELECT `idproduct` FROM `product_color` WHERE `idcolor` IN (SELECT `id` FROM `colors` WHERE `name_ru` LIKE '$param%' OR `name_ro` LIKE '$param%' ))

примерно так

просто до это писал проект на обычном php, сейчас его переписываю на YII

При правильном использовании relations такие запросы вам не придется писать. Если конечно у вас не высоконагруженный проект с 10 тысяч посетиителей в секунду. А вообще самый простой способ - расскомментировать в стандартном конфиге CWebLogRoute и все увидите.

спасибо

Я не читал все комментарии к этой теме, но исходя из названия топика могу дать действенный ответ: если Вам нужно получить sql-выражение, которое использует код $model->findAll($criteria), то просто сделайте ошибку в $criteria, например попытайтесь обратиться к несуществующему полю таблицы бд - название поля вы потом сможете изменить, а вот исключение (exeption) которое будет сгенерировано в результате ошибки, покажет Вам sql-запрос, который пытался выполнить ваш код.

Все-таки стоило почитать топик ;) Есть обычное логировние, не нужно будить эксепшены таким “элегантным” способом.