0

我正在尝试使用 Zend 函数调用来构建查询来重现以下 SQL:

SELECT `0`.`id`, `0`.`abbrev` FROM 

  (SELECT  `abbreviations`.`id`, `abbreviations`.`abbrev` 
   FROM  `abbreviations` ,  `keywords` 
   WHERE  `keywords`.`keyword` LIKE  'aug%'
   AND  `keywords`.`abbrev_id` =  `abbreviations`.`id`) `0`

INNER JOIN 

  (SELECT  `abbreviations`.`id` 
   FROM  `abbreviations` ,  `keywords` 
   WHERE  `keywords`.`keyword` LIKE  'foo%'
   AND  `keywords`.`abbrev_id` =  `abbreviations`.`id`) `1` 

ON (`0`.`id` =  `1`.`id`) 

INNER JOIN

  (SELECT  `abbreviations`.`id` 
   FROM  `abbreviations` ,  `keywords` 
   WHERE  `keywords`.`keyword` LIKE  'augment%'
   AND  `keywords`.`abbrev_id` =  `abbreviations`.`id`) `2` 

ON (`0`.`id` = `2`.`id`)

ORDER BY `0`.`abbrev`

我知道这个 SQL 在我测试过它时有效。我更喜欢使用 SQL“INTERSECT”,但由于 MySQL 不支持它(就此而言,我不知道 Zend 是否也支持),我不得不使用子查询。

我遇到的困难是通过使用链接函数调用(例如 $this->getDbTable()->select()->from() 等)创建查询来以“Zend 方式”进行操作。

例如,我已经能够成功地创建子查询之一:

public function selectAbbrevIdsByKeyword($keyword, $abbrevFields) {
    return $this->getDbTable()->select()
    ->from(array('a' => 'abbreviations'), $abbrevFields)
    ->from(array('k' => 'keywords'), 'abbrev_id')
    ->where('`k`.`keyword` LIKE ?', $keyword . '%')
    ->where('`k`.`abbrev_id` = `a`.`id`')
    ->setIntegrityCheck(false);

然而,当我尝试将子查询组合到我的整体目标 SQL 语句中时,这一切都崩溃了:

$all_abbrev_cols = array('id', 'abbrev');
$first_subselect = $this->selectAbbrevIdsByKeyword('foo', $all_abbrev_cols);
$select = $this->getDbTable()->select();
$select->from(array('0' => $first_subselect), $all_abbrev_cols);
$select->join(array("1" => 
    $this->selectAbbrevIdsByKeyword($keywords[1], 
        array('id'))), "`0`.`id` = `1`.`id`");
$select->setIntegrityCheck(false);
Zend_Debug::dump($select->__toString());

通过“崩溃”,我的意思是产生了令人困惑的 SQL,尤其是所有无关的反引号。

string(1006) 
"SELECT ```id``)`.`id`, ```id``)`.`abbrev`, ```id``)`.`description`, ```id``)`.`status`, ```id``)`.`rec_practice`, ```id``)`.`type`, ```id``)`.`category`, `SELECT ``a``.``id``, ``k``.``abbrev_id`` FROM ``abbreviations`` AS ``a``
 INNER JOIN ``keywords`` AS ``k`` WHERE (``k``.``keyword`` LIKE 'aug%') AND (``k``.``abbrev_id`` = ``a``.``id``)_2`.* FROM (SELECT `a`.`id`, `a`.`abbrev`, `a`.`description`, `a`.`status`, `a`.`rec_practice`, `a`.`type`, `a`.`category`, `k`.`abbrev_id` FROM `abbreviations` AS `a`
 INNER JOIN `keywords` AS `k` WHERE (`k`.`keyword` LIKE 'foo%') AND (`k`.`abbrev_id` = `a`.`id`)) AS ```id``)`
 INNER JOIN (SELECT `a`.`id`, `k`.`abbrev_id` FROM `abbreviations` AS `a`
 INNER JOIN `keywords` AS `k` WHERE (`k`.`keyword` LIKE 'aug%') AND (`k`.`abbrev_id` = `a`.`id`)) AS `SELECT ``a``.``id``, ``k``.``abbrev_id`` FROM ``abbreviations`` AS ``a``
 INNER JOIN ``keywords`` AS ``k`` WHERE (``k``.``keyword`` LIKE 'aug%') AND (``k``.``abbrev_id`` = ``a``.``id``)_2` ON `0`.`id` = `1`.`id`"

有没有办法通过链式 Zend 函数调用生成 SQL 的“Zend 方式”,或者我应该放弃并说这个查询太复杂,而是将查询构建为字符串(使用 Zend_Db_Expr 和/或 quoteInto 用于参数/引用)?

4

1 回答 1

0

我最终做了亚伦在他的评论中描述的事情,只是因为我已经拥有的代码最简单。

我编写了一个辅助函数,它使用标准 Zend 方法基于参数构建子查询:

public function selectAbbrevIdsByKeyword($keyword, $abbrevFields) {
  return $this->getDbTable()->select()
              ->from(array('a' => 'abbreviations'), $abbrevFields)
              ->from(array('k' => 'keywords'), 'abbrev_id')
              ->where('`k`.`keyword` LIKE ?', $keyword . '%')
              ->where('`k`.`abbrev_id` = `a`.`id`')
              ->setIntegrityCheck(false)
              ->__toString();
}

然后,我使用子查询帮助器方法将查询构建为一个大字符串,并使用 Zend_Db_Adapter 的 query() 函数将其全部提交:

$all_abbrev_cols = array('id', 'abbrev', 'description', 'status', 'rec_practice', 'type', 'category'); 
$sql = 'SELECT DISTINCT ';
foreach ($all_abbrev_cols as $col) {
  $sql .= "`0`.`$col`, ";
}
$sql = substr_replace($sql, '', -2); // remove last comma-space
$sql .= " FROM \n\n";

// first subquery is special, has all cols and is "0"
$sql .= '  (';
$sql .= $this->selectAbbrevIdsByKeyword($keywords[0], $all_abbrev_cols);
$sql .= ") `0`\n\n";

// starting on SECOND element (index 1)
for ($i = 1; $i < count($keywords); $i++) {
  $sql .= "INNER JOIN\n\n  (";
  $sql .= $this->selectAbbrevIdsByKeyword($keywords[$i], array('id'));
  $sql .= ") `$i`\n\nON (`0`.`id` = `$i`.`id`)\n\n";
}

$sql .= 'ORDER BY `0`.`status`, `0`.`abbrev`';

$entities = array();
foreach ($this->getDb()->query($sql)->fetchAll() as $row) {
  $entities[] = $this->_populate($row);
}
return $entities;

这产生了与我原始问题中的 SQL 语句匹配的查询结果。

于 2013-06-18T17:39:22.230 回答