Billy ONeal
Billy ONeal

Reputation: 106609

How does one convert complex SQL queries into Zend_Db_Select statements?

The MySQL website has an excellent tutorial on storing hierarchal data in a database. I'm trying to write the query that returns a node's immediate children. I don't want to just copy/paste the query from the MySQL website, because I'm trying to work on this in a database agnostic manner.

This is the query I'm trying to Zend_Db_Select-ify

SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
    nested_category AS parent,
    nested_category AS sub_parent,
    (
        SELECT node.name, (COUNT(parent.name) - 1) AS depth
        FROM nested_category AS node,
        nested_category AS parent
        WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND node.name = 'PORTABLE ELECTRONICS'
        GROUP BY node.name
        ORDER BY node.lft
    )AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
    AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
    AND sub_parent.name = sub_tree.name
GROUP BY node.name
ORDER BY node.lft;

Upvotes: 2

Views: 889

Answers (2)

Jake N
Jake N

Reputation: 10583

You can just paste in the query directly like this

$result = $db->query("SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
        FROM nested_category AS node,
        nested_category AS parent,
        nested_category AS sub_parent,
        (
            SELECT node.name, (COUNT(parent.name) - 1) AS depth
            FROM nested_category AS node,
            nested_category AS parent
            WHERE node.lft BETWEEN parent.lft AND parent.rgt
            AND node.name = 'PORTABLE ELECTRONICS'
            GROUP BY node.name
            ORDER BY node.lft
        )AS sub_tree
    WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
        AND sub_parent.name = sub_tree.name
    GROUP BY node.name
    ORDER BY node.lf");

Be sure to use quote() to input any of your own parameters into this query.

This is a bit of a cheat and isn't something I have resorted to yet.

Upvotes: 1

Radek
Radek

Reputation: 8386

You can try spliting your query into two Zend_Db_Select statements - parent query and subquery. You can use Zend_Db_Select object as param of from() method, like below:

$mainQuery = $db->select();
$mainQuery->from('user');

$sub = $db->select();
$sub->from('company');

$mainQuery->from(array('subquery' => $sub));

And you will get that kind of query:

SELECT `user`.*, `sub`.* FROM `user` 
    INNER JOIN (
        SELECT `company`.* FROM `company`
    ) AS `sub`

As you see, it automatically adds INNER JOIN when you add second from() - but I think, it's possible to rewrote your query to user joins instead of multi from syntax. So you should use joinInner() method, because then you can specify join condition as second param of it.

Notice, that subquery is similar to main query, so you could build main query, clone it as subquery, and thanks to Zend_Db_Select possibilities remove unnecessary parts (reset() method) and replace them:

$mainQuery = $db->select(); //and rest
$subQuery = clone $mainQuery;
$subQuery->reset(Zend_Db_Select::WHERE);
$subQuery->where(); // and add valid conditions for subquery

Upvotes: 1

Related Questions