4

how can I use Zend_Db_Select to directly select from a subquery (derived table)?

See, I have 5 tables with the same structure, I want to get all rows from them, merge them and remove the duplicates. I am using UNION which removes duplicates automaticly. The problem is that I add a static column to each table before, so there is one column which is different => duplicatation occures.

Here is my query so far:

SELECT `news_main`.*, 'main' as `category` 
FROM `news_main` 
UNION SELECT `news_politics`.*, 'politics' as `category` FROM `news_politics` 
UNION SELECT `news_society`.*, 'society' as `category` FROM `news_society` 
UNION SELECT `news_world`.*, 'world' as `category` FROM `news_world` 
UNION SELECT `news_business`.*, 'business' as `category` FROM `news_business` 
ORDER BY `date` DESC LIMIT 8

See how I add static values to the new column category? Now everything else is the same (there are duplicate rows), but since they are from different categories, UNION can't remove them.

So I thought I could SELECT all rows from this sub-query and group them to remove duplicates, like this:

SELECT * 
FROM (
    SELECT `news_main`.*, 'main' as `category` 
    FROM `news_main` 
    UNION SELECT `news_politics`.*, 'politics' as `category` FROM `news_politics`
    UNION SELECT `news_society`.*, 'society' as `category` FROM `news_society` 
    UNION SELECT `news_world`.*, 'world' as `category` FROM `news_world` 
    UNION SELECT `news_business`.*, 'business' as `category` FROM `news_business` 
    ORDER BY `date` DESC LIMIT 8
) as subtable 
GROUP BY `source` 
ORDER BY `date` DESC

I did run this in MySQL and it works perfectly.. the only problem is....

How do I execute this using Zend_Db_Select's fancy functions?

Thanks in advance!

Tony Bogdanov
  • 7,436
  • 10
  • 49
  • 80

3 Answers3

1

I'm not sure if you can use nesting selects in the from construct of Zend_Db_Select or if you should even be doing it that way, but an alternative solution would be to just get the db adapter and build the sql query manually.

$db = Zend_Db_Table::getDefaultAdapter();
$db->query("SELECT * 
    FROM (
        SELECT `news_main`.*, 'main' as `category` 
        FROM `news_main` 
        UNION SELECT `news_politics`.*, 'politics' as `category` FROM `news_politics`
        UNION SELECT `news_society`.*, 'society' as `category` FROM `news_society` 
        UNION SELECT `news_world`.*, 'world' as `category` FROM `news_world` 
        UNION SELECT `news_business`.*, 'business' as `category` FROM `news_business` 
        ORDER BY `date` DESC LIMIT 8
    ) as subtable 
    GROUP BY `source` 
    ORDER BY `date` DESC
");

related: Zend_Db_Table subquery

Community
  • 1
  • 1
Mark Basmayor
  • 2,529
  • 2
  • 16
  • 14
0

Just define a class to quote your subquery, and then you'll be able to add some more processing upon it in one place:

class Acme_Db_Expr_Subquery extends Zend_Db_Expr {
    public function __toString()
    {
        return '( ' . $this->_expression . ' )';
    }
}

Then use it in FROM clause (my case, copypaste from actual application, working) or JOIN (speculating, did not try).

$innerSelect = $dbTableSomeModel->select(true);
// Configure it, maybe kick around many layers of abstarction

$nestedSelect->from(
    array(
        'derived_alias' => new Acme_Db_Expr_Subquery( $innerSelect ),
    )
    ,array(
        'column_alias' => 'column_expression',
    )
);
0

From what I can tell from the source code for Zend_Db_Select, its from() method calls its _join() method, which has a case for when the first parameter to from() is a Zend_Db_Select object: http://framework.zend.com/svn/framework/standard/trunk/library/Zend/Db/Select.php

} else if ($name instanceof Zend_Db_Expr|| $name instanceof Zend_Db_Select) {
        $tableName = $name;
        $correlationName = $this->_uniqueCorrelation('t');

If not, from() should support aliasing a subquery by wrapping it in parentheses to force it to be cast to a Zend_Db_Expr instance as in this example for joinRight(): Zend Framework: Zend_Db_Select - how to join custom subquery table?

Community
  • 1
  • 1
Matthew Turland
  • 763
  • 3
  • 11