訂正:2010/04/09
通りすがりさんにコメントを頂き、UNIONで連結した全体にhavingをかけるのはできないということで正しいということが分かりました。
たまたま、$select2の方にだけhavingでフィルターされるデータがあったため、結果的に意図通りのデータが出力されただけで、全体にhavingが掛かっているわけではありませんでした。
サブクエリを使う方法が適切です。
// $adapterはZend_Db_Adapterのクラス。MySQLを利用。
$select1 = $adapter->select()->from(....)->where(....);
$select2 = $adapter->select()->from(....)->where(....);
$select = $adapter->select()->union(array($select1, $select2));
echo $adapter->select()->from($select)->where(....); ←havingで書いてた条件
=========
UNIONとHAVINGを同時に使うSQLを組んでいたときに、Zend_Db_Selectから生成されたSQLからHAVING句が抜け落ちていました。
プログラムは以下のようなものです。
// $adapterはZend_Db_Adapterのクラス。MySQLを利用。
$select1 = $adapter->select()->from(....)->where(....);
$select2 = $adapter->select()->from(....)->where(....);
$select = $adapter->select()->union($select1, $select2)->having(.....);
echo $select; ← ここで HAVING句がなくなってる
上記でできるSQLのイメージは、これです。
select ...... from .... where ....
union
select ...... from .... where ....
having .....
このSQLをDBサーバで実行すると、動くので構文はあってます。
そこで、Zend_Db_Selectクラスのhaving句を出力するところを見たら、こうなってました。(バージョンは10.2)
/**
* Render HAVING clause
*
* @param string $sql SQL query
* @return string
*/
protected function _renderHaving($sql)
{
if ($this->_parts[self::FROM] && $this->_parts[self::HAVING]) {
$sql .= ' ' . self::SQL_HAVING . ' ' . implode(' ', $this->_parts[self::HAVING]);
}
Zend_Debug::dump($sql);
return $sql;
}
FROM句とHAVING句が両方ある場合に、HAVINGをつけるって処理ですね。確かにこれだと、UNIONと同時に使ったときは、FROM句がないので、HAVING句がつかないのは納得です。
というわけで、以下のように修正して、UNIONとHAVINGが同時に使えることを確認しました。
/**
* Render HAVING clause
*
* @param string $sql SQL query
* @return string
*/
protected function _renderHaving($sql)
{
// FROMかUNIONがあればOKに変更
if (($this->_parts[self::FROM] || $this->_parts[self::UNION]) && $this->_parts[self::HAVING]) {
$sql .= ' ' . self::SQL_HAVING . ' ' . implode(' ', $this->_parts[self::HAVING]);
}
Zend_Debug::dump($sql);
return $sql;
}
そのうちZend本体でも実装してくれることに期待します。