Podzapytanie w COALESCE

0

Nie wiem, czy ja coś robie źle, czy faktycznie z Doctrinem trzeba się tak szaprać. Chciałem zrobić mniej więcej cos takiego:

SELECT COALESCE((SELECT JSON_AGG(id) FROM customers), '[]') FROM ...
$related_customers = .... ->getDQL();
$qb = $this->_em->createQueryBuilder()
    ->select(...)
    ->addSelect("coalesce(($related_customers), '[]') AS related_customers")

Niestety użycie subquery w połączeniu z coalesce nie zostało przewidziane. No to co, zaczynam grzebać w parserze w poszukiwaniu rozwiązania.
Na szybkości zmodyfikowałem metodę CoalesceExpression, żeby mi przeparsowała to (Parser.php):

public function CoalesceExpression()
    {
        $this->match(Lexer::T_COALESCE);
        $this->match(Lexer::T_OPEN_PARENTHESIS);

        // Process ScalarExpressions (1..N)
        $scalarExpressions = array();

        if($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
            $expr = $this->SimpleSelectExpression();
            $scalarExpressions[] = $expr;
        } else {
            $scalarExpressions[] = $this->ScalarExpression();
        }

        while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
            $this->match(Lexer::T_COMMA);

            if($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
                $expr = $this->SimpleSelectExpression();
                $scalarExpressions[] = $expr;
            } else {
                $scalarExpressions[] = $this->ScalarExpression();
            }
        }

        $this->match(Lexer::T_CLOSE_PARENTHESIS);

        return new AST\CoalesceExpression($scalarExpressions);
    }

Niestety to nie wystarczy, bo Doctrine mi na siłę aliasuje wszytko... no to co, może tak (SqlWalker.php):

public function walkSimpleSelectExpression($simpleSelectExpression) {
// ...
        case ($expr instanceof AST\Subselect):
            if($expr->no_alias) {
                $sql .= '(' . $this->walkSubselect($expr) . ')';
                break;
        }

Great success. Z tym że coś mi się nie chce wierzyć, że trzeba się z tym tak mordować. Już nawet nie chodzi o słuszność tego zapytania, tylko dziwi mnie dlaczego coś co jest valid sql nie działa. Tak samo byłem zdziwiony, że nie ma gotowego JSON_AGG, lub JSON_BUILD_OBJECT

1

Zawsze w takich sytuacjach możesz użyć natywnego SQLa zamiast DQLa: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html .

Natomiast jeśli chodzi o JSON_AGG, JSON_BUILD_OBJECT to możesz je łatwo zarejestrować w DQLu: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/dql-user-defined-functions.html . Te funkcje są specyficzne dla konkretnego dialektu SQLa (strzelam że postgresql) więc dlatego nie są dostępne "z pudełka"

0

@Adawo: a jak powstanie sytuacja, w której będę chciał nakładać warunki do zapytania w zależności od tego co tam użytkownik sobie wymyśli, to co wtedy? Z użyciem QueryBuildera robię tak:

class Filters_User extends Query_Filters {
    public function groupName($groupName) {
        return $this->builder
            ->andWhere('p.name IN (:params)')
            ->setParameter(':params', (array) $groupName, Connection::PARAM_STR_ARRAY);
    }

   //.... itd
}
public function findAll(Doctrine_Query_Filters $filters = null)
{
    // ...
    if ($filters) {
        $qb = $filters->apply($qb);
    }
    // ...
}

Czyli po prostu operuję na obiekcie, a nie na stringu. Przy użyciu native query miałbym robić tak (chyba, że nie rozumiem, jak native query działa w Doctrine)?

$where .= 'AND ...';
0

A widzisz, jest różnica czy się zrobi $this->_em->createQueryBuilder(), czy $this->_em->getConnection()->createQueryBuilder(). Dzięki, nie doczytałem :)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.