使用Zend Framework 2 TableGateway加入子查询

时间:2013-09-25 03:17:00

标签: mysql sql zend-framework2

我正在尝试使用Zend Framework 2进行查询,其中我在JOIN语句中有一个SELECT。到目前为止,这是我尝试过的,但是将SELECT对象注入join()的第一个参数似乎不起作用。我采用了这种方法,因为我需要在进行任何分组之前先订购结果。关于如何使其发挥作用的任何想法?

public function getSearchKeyword($keyword, $limit)
{
    $select = $this->keywords->getSql()->select();

    $subquery = $this->pages->getSql()->select();
    $subWhere = new \Zend\Db\Sql\Where();
    $subWhere->equalTo('delete_flag', 'n')
             ->equalTo('published_flag', 'y');
    $subquery->where($subWhere);

    $where = new \Zend\Db\Sql\Where();
    $where->like('keyword', '%' . $keyword . '%')
          ->equalTo('delete_flag', 'n');

    $select->columns(array('display' => 'keyword', 'url'))
           ->join(array('sub' => $subquery), 'sub.page_id = keywords.page_id', array())
           ->where($where)
           ->group(array('keywords.page_id', 'keywords.keyword'))
           ->order(array('rank', 'keyword'))
           ->limit($limit);
    $row = $this->tableGateway->selectWith($select);
    return $row;
}

我正在尝试编写的查询如下:

SELECT keywords.keyword AS display, keywords.url
FROM keywords
INNER JOIN 
(
SELECT * FROM pages WHERE published_flag = 'y' AND delete_flag = 'n' ORDER BY page_id DESC
) pages 
ON pages.page_id = keywords.page_id
WHERE published_flag = 'y'
AND delete_flag = 'n'
AND keywords.keyword LIKE '%?%'
GROUP BY display, page_id;

4 个答案:

答案 0 :(得分:1)

我正在解决同样的问题,并没有找到解决问题的标准方法。所以我有一个工作但不是zf2标准

  1. 创建一个小型界面来管理Db连接
  2. 将其实现为一个小类,以获取PDO对象的连接 你的数据库
  3. 执行您的任意查询
  4. 代码示例

    // Filename: /module/MyTools/src/MyTools/Service/DbModelServiceInterface.php
    namespace MyTools\Service;
    
    interface DbModelServiceInterface
    {
        /**
         * Will return the result of querying the curret database
         * 
         * @param type $query
         * @result mixed
         */
        public function dbQuery($query);
    
        /**
         * Will return a connection object that links to curret database
         *
         * @result mixed
         */
        public function getConnection();
    }
    

    实现接口的类。它创建并提供PDO连接。 注意:它需要额外的代码来关闭conns和perfeorm安全性... 它测试它并且完全正常。 代码:

    // Filename: /module/MyTools/src/MyTools/Service/DbModelServiceMySql.php
    namespace MyTools\Service;
    
    use MyTools\Service\DbModelServiceInterface;
    use PDO;
    
    class DbModelServiceMySql implements DbModelServiceInterface
    {
        protected $driverConfig;
        protected $connection;
        protected $isconnected = FALSE;
        protected $dbname = '';
        /**
         * Creates a connection to main database
         */
        public function __construct()
        {
            $driverConfig = self::getDriverDef();
            $this->driverConfig = $driverConfig; // new PDO($driverConfig['dsn'], $driverConfig['username'], $driverConfig['password']);
            $this->_connect();
        }
    
        protected function _connect(){
            $dsn = (isset($this->driverConfig['dsn'])) ? $this->driverConfig['dsn'] : '';
            $username = (isset($this->driverConfig['username'])) ? $this->driverConfig['username'] : '';
            $password = (isset($this->driverConfig['password'])) ? $this->driverConfig['password'] : '';
            if( ($dsn) && ($username) && ($password)){
                $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', ];
                try {
                    $this->connection = new PDO($dsn, $username, $password, $options);
                    $this->isconnected = TRUE;
                    $this->_setdbname($dsn);
                } catch (Exception $ex) {
                    throw new RuntimeException('YOUR ERROR MESSAGE.'); 
                }            
            }
            return $this->isconnected;
        }
    
        protected function _setdbname($dsn){
            if($dsn){
                $chunks = explode(';', ''.$dsn);
                foreach($chunks as $chunk){
                    if(strpos('***'.$chunk, 'dbname') > 2){
                        $nombre = explode('=', $chunk);
                        $this->dbname = $nombre[1];
                        break;
                    }
                }
            }
        }
    
        /**
         * {@inheritDoc}
         */
        public function dbQuery($query) {
            if($this->connection){
                $resultset = $this->connection->query($query);
                if($resultset){
                    return $resultset->fetchAll(PDO::FETCH_ASSOC);
                }else{
                    return ['Error' => 'YOUR CUSTOM ERROR MESSAGE.'];
                }
            }else{
                return ['Error' => 'OTHER CUSTOM ERROR MESSAGE'];
            }
        }
    
        public static function getDriverDef()
        {
        $autoloadDir = __DIR__ . '../../../../../../config/autoload/';
        $credentialsdb = include $autoloadDir . 'local.php';
        $globaldb = include $autoloadDir . 'global.php';
            $def = (isset($globaldb['db'])) ? $globaldb['db'] : array();
            $credentials = (isset($credentialsdb['db'])) ? $credentialsdb['db'] : $credentialsdb;
            return array_merge($def, $credentials);
        }
        /**
         * {@inheritDoc}
         */
        public function getConnection() {
            if($this->connection){
                return $this->connection;
            }else{
                return 'Error: YOUR CUSTOM ERROR MESSAGE';
            }
        }
    
        /**
         * {@inheritDoc}
         */
        public function getDbName(){
            return $this->dbname;
        }
    }
    

    现在你有一个类可以在别处实例化以执行你需要的查询。

    使用: 代码:

    $myQuery = 'the very very complex query you need to execute'
    $myDbConn = new MyTools\Service\DbModelServiceMySql();
    $result = $myDbConn->dbQuery($myQuery);
    

    如果成功,你得到了一对resulset数组对列columnName =>值

答案 1 :(得分:0)

你可以试试这个。

  $select->columns(array('display' => 'keyword', 'url'))
         ->join(array('sub' => 'pages'), 'sub.page_id = keywords.page_id', 
                array(), $select::JOIN_INNER)
         ->where($where)
         ->group(array('keywords.page_id', 'keywords.keyword'))
         ->order(array('rank', 'keyword'))
         ->limit($limit);

答案 2 :(得分:0)

在您的代码中,您将获得page_id位于sub page_id中的所有关键字,其中delete_flag =' n'和published_flag =' y'。

join(..., 'sub.page_id = keywords.page_id', array())

当您不需要任何页面列表时,可以使用IN而不是JOIN 例如,当您需要知道哪些关键字位于哪些页面时,您应该使用JOIN,但是当您需要知道任何页面中的哪些键盘时,您可以使用IN语句。
无论如何:
ZF2中没有标准方法,但您可以尝试以下代码。

public function getSearchKeyword($keyword, $limit)
{
    $select = $this->keywords->getSql()->select();

    $subquery = $this->pages->getSql()->select();
    $subWhere = new \Zend\Db\Sql\Where();
    $subWhere->equalTo('delete_flag', 'n')
             ->equalTo('published_flag', 'y');
    $subquery->columns(array('page_id'))
             ->where($subWhere);

    $where = new \Zend\Db\Sql\Where();
    $where->like('keyword', '%' . $keyword . '%')
          ->equalTo('delete_flag', 'n')
          ->in('keywords.page_id', $subquery);

    $select->columns(array('display' => 'keyword', 'url')) 
           ->where($where)
           ->group(array('keywords.page_id', 'keywords.keyword'))
           ->order(array('rank', 'keyword'))
           ->limit($limit);
    $row = $this->tableGateway->selectWith($select);
    return $row;
}

答案 3 :(得分:0)

我遇到过类似的问题。由于FROM table和子查询的FROM table不同,我收到了错误。 我的解决方法是提取SQL并创建一个语句。

        $sql    = $select->getSqlString(new \Zend\Db\Adapter\Platform\Mysql());
        $stmt = $this->getAdapter()->createStatement($sql);
        $stmt->prepare($sql);
        $result = $stmt->execute();

        $resultSet = new ResultSet(); \\ Class Zend\Db\ResultSet\ResultSet

        $resultSet->initialize($result);