2013-01-20 93 views
6

尝试使用Zend\Db\Sql\Select获取嵌套选择,在文档或谷歌中根本看不到任何内容。使用ZF2嵌套选择

想要做这样的事情:

SELECT 
    table1.*, 
    (SELECT x,y,z FROM table2 WHERE table2.a = table1.a) as b 
FROM table1 

没有嵌套查询,这将是这个样子:

$select = new Zend\Db\Sql\Select; 
$select 
->columns(array(
    '*' 
)) 
->from('table1') 

ZF1看了有关创建子查询项目,然后将其添加为表达式在列表中,但在ZF2中,它抱怨表达式需要是一个字符串。

编辑:嵌套选择需要作为列,因为当在同一列名称上使用GROUP BY时,我最终得到的是相乘的行。这是正确的查询我试图进入Zend\Db\Sql\Select

SELECT 
    users.id, 
    (SELECT count(explorations.id) FROM explorations WHERE user_id = users.id) as total_explorations, 
    count(villages.id) 
FROM 
    users 
INNER JOIN 
    villages 
     on (villages.user_id = users.id) 
GROUP BY 
    users.id 

回答

4

我建议你重组你的SQL查询。我不确定你正在使用哪个数据库,但是如果你使用MySQL,COUNT函数可以使用DISTINCT关键字。这样你就不会计算重复的ID。我已经将SQL查询调整为我将要使用的内容,这样就消除了对内部选择的需要。

SELECT 
    users.id, 
    COUNT(DISTINCT explorations.id) AS total_explorations, 
    COUNT(DISTINCT villages.id) AS total_villages 
FROM users 
    INNER JOIN villages ON villages.user_id = users.id 
    INNER JOIN explorations ON explorations.user_id = users.id 
GROUP BY users.id 

我还没有运行这个查询,但我相信它应该工作,并给你你想要的结果。希望我不会误解你的情况。下面是等效的Zend Framework 2选择。

$select = $sql->select('users'); 
$select->columns(array('id')); 
$select->join('villages', 
       'villages.user_id = users.id', 
       array(
        'total_villages' => new Expression("COUNT(DISTINCT villages.id)") 
       ) 
); 
$select->join('explorations', 
       'explorations.user_id = users.id', 
       array(
        'total_explorations' => new Expression("COUNT(DISTINCT explorations.id)") 
       ) 
); 
0

我希望我正确地得到您的问题...

还没升级自己ZF2但是这是你的方式一个可以在ZF1中创建嵌套的Select语句(如果使用MVC体系结构的话)(也可以在ZF2中使用它)。

$table1 = new table1(); 
    $table1->select()->from('table1',array('*', 
     'b' => '(SELECT x,y,z FROM table2 WHERE table2.a = table1.a)', 
    )); 

更新:

回来给你对此有何评论后意识到,我写的代码将无法正常工作,你将无法选择从另一个多列表成一列(即b中的x,y,z)。

但是,它会工作,如果你必须执行一些agg。功能在另一个表上,它给出了一列。例如

$table1 = new table1(); 
    $table1->select()->from('table1',array('*', 
     'b' => '(count (*) FROM table2 WHERE table2.a = table1.a)', 
    )); 

所以这将工作。 通过这种方式,您可以获得一些在其上执行某些功能的列。 其他表格(表格2)中的其他列可以使用连接。

+0

这是目前我回避的事情,因为我无法做到这一点。刚刚写出了SQL,如你所说,但后来一半是抽象的,另一半是原始的:D正在考虑ZF2只是允许它在列部分 –

0

您所描述的内容定义为JOIN。有一些不同的连接方案,我不会介绍它们之间的差异,但最常见的是INNER JOIN或LEFT JOIN。

而这的确给ZF2-Documentation of Zend\Db\Sql#Join

内找到查询应该是这样的:

Select 
    t1.*, 
    t2.field1, 
    t2.field2, 
    t2.field3 
FROM 
    tablename1 t1, 
    tablename2 t2 
WHERE 
    t1.field = t2.field 

综观ZF2-Documentation of Zend\Db\Sql#Join的文档,我认为的选择是这样的:

$select = new \Zend\Db\Sql\Select(); 

$select->columns(array(
    'id', 
    'title', 
    // List ALL Columns from TABLE 1 - * is bad/slow! 
), true)->from(array(
    't1' => 'tablename1' 
))->join(
    'tablename2', 
    'id = t1.id', 
    array(
     'username', 
     'email', 
     // List ALL Columns from TABLE 2 u want to select 
    ), 
    $select::JOIN_INNER 
) 

另外我认为:如果你不使用columns(),你会为SELECT *,但为了你自己的利益,开始编写好的查询;)更多地控制你的代码!

不能保证这段代码能够正常工作,因为我自己并没有使用Zend \ Db,但在正确的点上使用文档应该可以让你继续运行。

+0

嗯,我使用其他连接以及不能做另一个,因为它我使用多个count()和sum()来倍增行。我是由一个特定的字段分组,但是这也被用在了连接表中,所以我认为除了嵌套选择以外,没有其他解决办法。 –

6

Ralph Schindler拥有一个他在Zend \ Db中专门实现的不同DB模式的存储库。这里有一个子查询:https://github.com/ralphschindler/Zend_Db-Examples/blob/master/example-20.php

内容是这样的:

<?php 

/** @var $adapter Zend\Db\Adapter\Adapter */ 
$adapter = include ((file_exists('bootstrap.php')) ? 'bootstrap.php' : 'bootstrap.dist.php'); 
refresh_data($adapter); 

use Zend\Db\Sql; 
use Zend\Db\ResultSet\ResultSet; 

$sql = new Sql\Sql($adapter); 

$subselect = $sql->select(); 
$subselect->from('artist') 
    ->columns(array('name')) 
    ->join('album', 'artist.id = album.artist_id', array()) 
    ->where->greaterThan('release_date', '2005-01-01'); 


$select = $sql->select(); 
$select->from('artist') 
    ->order(array('name' => Sql\Select::ORDER_ASCENDING)) 
    ->where 
     ->like('name', 'L%') 
     ->AND->in('name', $subselect); 

$statement = $sql->prepareStatementForSqlObject($select); 

$result = $statement->execute(); 

$rows = array_values(iterator_to_array($result)); 

assert_example_works(
    count($rows) == 2 
    && $rows[0]['name'] == 'Lady Gaga' 
    && $rows[1]['name'] == 'Linkin Park' 
); 

基本上,你可以使用一个选择作为另一个选择的谓词的值。

+0

是否有可能做一个SubSelect作为额外的列,虽然没有进行其他数据库调用?如果我有超过1个计数,我会得到相乘的行,所以有一个子选择来解决这个问题。我在我的原始问题中发布了一个示例SQL来展示我的意思:) –