php - 我如何通过从 PostgreSQL 转换为 DQL 来完成这种动态平均?

标签 php postgresql casting doctrine dql

我必须添加一个过滤条件来获取带有 andWhere() 的评论列表。这是 PostgreSQL 版本:

SELECT *
FROM listing_review
WHERE(
    (
      edited_rating_meals_nutrition +
      edited_rating_treatment_effectiveness +
      rating_accommodations_amenities
    )
    /
    (
      COALESCE(
        NULLIF(
              (
                (edited_rating_meals_nutrition::BOOLEAN)::INTEGER +
                (edited_rating_effectiveness::BOOLEAN)::INTEGER +
                (rating_accommodations_amenities::BOOLEAN)::INTEGER
              )
            , 0
        ), 1
      )
    )
 )
 >= 3;

基本上,我需要对每行三个评分(评论)进行平均,并根据它们的平均值是否等于或大于某个整数(在本例中为 5)进行过滤。如果它们在任何一个类别中都没有被审查,则该类别的值为零,我必须从平均计算中丢弃它们(因此从 bool 值到整数的双重转换以获得不为零的评级数)。我也不能除以零,解释 COALESCE

我可以像这样除以三的天真方法来完成这个:

if (isset($searchParams[self::PARAM_MINIMUM_RATING])) {
$qb
   ->andWhere('((r.editedRatingTreatmentEffectiveness + r.editedRatingAccommodationsAmenities + r.editedRatingMealsNutrition) / 3) >= :minimum_rating')
   ->setParameter('minimum_rating', $searchParams[self::PARAM_MINIMUM_RATING]);

我如何在 DQL 中执行此操作,使除数动态(如我的 PostgreSQL 查询)而不是硬编码为 3?

最佳答案

我在这个 post 的帮助下解决了我自己的问题.

基本上,DQL 包含 NULLIF() 以及 COALESCE() 但不包含 CAST()。我添加了以下类:

<?php
namespace DoctrineFunctions;


use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;

class CastToBoolean extends FunctionNode
{
    public $stringPrimary;

    public function getSql(SqlWalker $sqlWalker)
    {
        return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS boolean)';
    }

    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->stringPrimary = $parser->StringPrimary();

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

以及这个非常相似的转换为整数的转换函数:

<?php

namespace DoctrineFunctions;


use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;

class CastToInteger extends FunctionNode
{
    public $stringPrimary;

    public function getSql(SqlWalker $sqlWalker)
    {
        return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS integer)';
    }

    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->stringPrimary = $parser->StringPrimary();

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

然后我在 doctrine.yml 中注册这些方法:

orm:
    auto_generate_proxy_classes: ""
    default_entity_manager: default
    entity_managers:
        default:
            connection: default
            mappings:
                RBundle: ~
                ABundle: ~
            result_cache_driver:
                type: memcached
                host: ''
                port: 
            query_cache_driver:
                type: memcached
                host: ''
                port: 
            metadata_cache_driver:
                type: memcached
                host: ''
                port: 
            naming_strategy: doctrine.orm.naming_strategy.underscore
            filters:
                softdeleteable:
                    class: 
                    enabled: 
            dql:
                numeric_functions:
                    cast_to_int: DoctrineFunctions\CastToInteger
                string_functions:
                    cast_to_boolean: DoctrineFunctions\CastToBoolean

最后,我使用所有必要的方法将 SQL 查询重构为 DQL 查询:

 if (isset($searchParams[self::PARAM_MINIMUM_RATING])) {
        $qb
            ->andWhere('((r.editedRatingTreatmentEffectiveness + r.editedRatingAccommodationsAmenities + r.editedRatingMealsNutrition) / (COALESCE(NULLIF(cast_to_int(cast_to_boolean(r.editedRatingTreatmentEffectiveness)) + cast_to_int(cast_to_boolean(r.editedRatingAccommodationsAmenities)) + cast_to_int(cast_to_boolean(r.editedRatingMealsNutrition)), 0), 1))) >= :minimum_rating')
            ->setParameter('minimum_rating', $searchParams[self::PARAM_MINIMUM_RATING]);
    }

关于php - 我如何通过从 PostgreSQL 转换为 DQL 来完成这种动态平均?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52998681/

相关文章:

javascript - 处理Ajax请求反馈

java - 错误的泛型转换没有 ClassCastException [Java]

c - 如何将 char 指针转换为 int 指针?

c++ - 在没有显式转换的情况下将字符显示为整数

php - 给出所选行的结果

javascript - 无法 getElementById(HTMLDOM 对象假定为 null)。我哪里搞砸了?

php - 如何在 PHP 上使用 DAL

php - 通过 PHP 清理 PostgreSQL 中所有用户的输入

ruby-on-rails - rails 5 左外连接

Postgresql 创建日志模式