Как стать автором
Обновить

Комментарии 45

А где вы там нашли, что можно задавать не имя таблицы строкой, а переменную типа Zend_Db_Select?
Ой а это гдето в другом месте есть :) Там сказано примерно следующее: Zend_Db_Select есть магический __toString() который и превращает обьект запроса в строку.

Но вот с вложенными запросами — это прикольно. Все время писал raw-sql. Спасибо!
Это есть в исходниках. А вы разве не читаете исходники ZF на ночь??? :)
Шутки-шутками, а это точно, что в исходниках есть намного больше, чем в мануалах и апи. Правда не стоит начинать сразу с них, если только почитать больше нечего =).
А ещё после долгих мучений с мануалом и различными статьями, лезешь в исходники зенда и через пару минут понимаешь, что что-то не доделано или чего-то не хватает :( Всё-таки приятнее как у Вас — найти то, что искал, но не ожидал, что оно там есть :)
О! Может вы мне подскажете?
Как с помощью Zend_Db_Select сделать «SELECT SQL_CALC_FOUND_ROWS DISTINCT»?
Мне нужно знать количество удовлетворяющих условию строк для пагинатора, чтобы он мог расчитать количество страниц.
Zend_Db_Expr вас спасет, по идее
А можно работающий пример? Вот чтобы именно так, в таком порядке, перед перечислением полей?
Оно?
$select->from('TableName' ,array(
new Zend_Db_Expr('SQL_CALC_FOUND_ROWS DISTINCT *'),
'row2',
'row3'
));
echo $select;

==>
SELECT SQL_CALC_FOUND_ROWS DISTINCT *, `TableName`.`row2`, `TableName`.`row3` FROM `TableName`
Ага, оно, но больше похоже на грязный хак.

Да и какой смысл использовать Zend_Db_Select, если половину запроса всё равно приходится писать в «сыром» виде в конструкторе дополнительного объекта?

Добавьте сюда ещё невозможность конструирования сложных WHERE-условий, которые тоже приходится вписывать в сыром виде типа ->where('((A or (B and C)) and D) or E)').

Проще уж обычной строкой.
Ну учитывая что SQL_CALC_FOUND_ROWS врятли найдеться в спицификации SQL (хотя я не уверен;), то хак на хаке :)
Для Oracle в Zend определен свой специфический LIMIT (тоже хак, кстати). Так что это они поддерживают. Дело не в стандартах, а в том, насколько часто та или иная фишка используется программистами.
Интересно, через псевдостолбец и группировку или как-то красивей сделали…

Я помню, так и не смог сделать этот LIMIT (ещё в «дозендовские» времена), просто забил, так как размер таблицы теоретически не мог превысить даже тысячи записей (на деле около сотни) — фетчил все строки до лимита, т.е. если limit 10, то только первые десять строк, а если Limit с 100 по 110, то 110 строк, игнорируя ненужные. Для последней страницы, соответственно, приходилось выбирать всю таблицу :)
Можете посмотреть тут:
Zend\Db\Adapter\Oracle.php

Вкратце:

$limit_sql = «SELECT z2.*
FROM (
SELECT z1.*, ROWNUM AS \»zend_db_rownum\"
FROM (
". $sql. "
) z1
) z2
WHERE z2.\«zend_db_rownum\» BETWEEN ". ($offset+1). " AND ". ($offset+$count);
Дык может и SQL_CALC_FOUND_ROWS будет как-то поддерживаться. А пока можно расширить класс для себя, добавив свою константу следующим образом:
class My_Db_Select extends Zend_Db_Select
{
  const SQL_CALC_FOUND_ROWS = 'sql_calc_found_rows';

  public function __construct(Zend_Db_Adapter_Abstract $adapter)
  {
    self::$_partsInit = array_merge(array(
      self::SQL_CALC_FOUND_ROWS => false
    ), self::$_partsInit);
    parent::__construct($adapter);
  }

  public function calcFoundRows($flag)
  {
    $this->_parts[self::SQL_CALC_FOUND_ROWS] = (bool)$flag;
    return $this;
  }
}


* This source code was highlighted with Source Code Highlighter.

Не проверил работоспособность, но логика правильная.
Спасибо за код :)

Ага, я думал об этом, но мне было лень жаль тратить время ради одного запроса. Хотя в этом чате я уже потратил его больше :)
Ну зато потом можно будет юзать для любого запроса. Только в случае миграции на какую-нить другую БД они порушатся…
Как-то странно получилось.
Сперва (давно) всё работало, а сегодня вдруг перестало.
Нужно добавить вот такой метод:

protected function _renderSql_calc_found_rows($sql)
{
if ($this->_parts[self::SQL_CALC_FOUND_ROWS]) {
$sql .= ' '. self::SQL_CALC_FOUND_ROWS;
}

return $sql;
}
Ну это скорее не грязный хак, а просто отвод для пока неподдерживаемых вещей. Но другого пути я тоже не знаю.
> ->where('((A or (B and C)) and D) or E)')
Кстати, можно раскрыть скобки (A and D or B and C and D or E) и записать при помощи соответствующих методов:
$query = $db->select()
      ->from('test')
      ->where('A')
      ->where('D')
      ->orWhere('B')
      ->where('C')
      ->where('D')
      ->orWhere('E');
echo $query->assemble();


* This source code was highlighted with Source Code Highlighter.

Получим:
SELECT `test`.* FROM `test` WHERE (A) AND (D) OR (B) AND (C ) AND (D) OR (E)

* This source code was highlighted with Source Code Highlighter.

Приоритеты операций — наше всё =)
Чёрт.
Ты прав :)

Но после раскрытия скобок логика условия уже не такая явная.
Допустим, А — это проверка авторизации (прав на просмотр), а ВCDE — это уже какие-то условия выборки, то:
если у меня было «A and (B or C or D or E)», то получится «A and B or A and C or A and D or A and E». И через месяц долго будешь втыкать в этот столбик
->where(B)
->where(A)
->orWhere(С)
->where(A)
->orWhere(D)
->where(A)
->orWhere(E)
->where(A)


А условий может быть больше и вложенность глубже :)
Я полностью согласен, что ясность теряется абсолютно. Просто задумался… все основные логические операции введены и не может так получаться, что какое-то условие реализовать нельзя. =)
Понятно, что полумера, но:
//A and (B or C or D or E)
->where(B)
->where(A)
->orWhere(С)
->where(A)
->orWhere(D)
->where(A)
->orWhere(E)
->where(A)
? :)
Если посмотреть в тикеты зенда то можно увидеть что в ближайшем будущем планируется переделать where так чтобы он принимал массив.
Но это всё равно не спасёт от сложных условий.
Мы с вами переписываемся одновременно в двух темах и трех ветках :D
Сдаётесь? =)
и без запятых!
Для вас самый простой способ
$adapter = new Zend_Paginator_Adapter_DbSelect($select);
echo $adapter->count();
А как это работает на деле?
Выполняется дополнительный запрос 'select count(*)'?
упрощенно — да
Ну, я, по сути, так и делал сперва, сперва вызов текущей страницы с «LIMIT», потом count(*) для подсчёта страниц, и потом именно для ускорения работы переделал на «SQL_CALC_FOUND_ROWS», чтобы сервер два раза за одним запросом не гонять :)
И много выиграли в производительности =)?
без понятия. не мерил. запрос с тремя джойнами, в таблице, теоретически, могут быть сотни тысяч записей. когда писал код, было 10 записей :)
Экономите на спичках :) Запрос конечно дело тяжёлое для системы, но время потраченное на лишние строки кода, можно потратить на что-либо более существенное.
я сегодня в этом чате больше времени потратил, чем на написание «лишних» строчек кода
да и больше кода не получилось
Думаете зря потратили время? =)
Да простятся мне грехи мои.
Я использую Postrge и твёрдо веровал в силу Zend_Db пока не пришёл к

select
a,
b,
array_to_string(
array(
ещё один запрос
),
','
) as с
from
table name
where
where clause

Пока не знаю как тут поступить.
Жесть, у нас за такие запросы — расстрел на месте.
Ну до этого все понимали, что я просто привёл пример вложенного запроса. Или у вас всегда расстреливают за них вне зависимости от того увеличивают они быстродействие или нет? =)
Я понимаю что это пример (за что спасибо), извиняюсь что ввел в заблуждение.
Но вот запрос получился страшный если представить себе большой набор данных :)
Ну просто вытаскивать рабочий пример, где мне понадобилась такая функциональность, не хотелось, т.к. там был довольно большой запрос… И акцент был бы безнадёжно потерян.
Возможно вы правы.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории