我如何通过从 PostgreSQL 转换为 DQL 来完成这种动态平均?
How can I accomplish this dynamic averaging by casting from PostgreSQL to 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)进行过滤。如果它们在任何一个类别中都没有被审查,则该类别的值为零,我必须从平均计算中丢弃它们(因此从布尔值到整数的双重转换以获得不为零的评级数)。我也不能除以零,解释 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]);
}
我必须添加一个过滤条件来获取带有 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)进行过滤。如果它们在任何一个类别中都没有被审查,则该类别的值为零,我必须从平均计算中丢弃它们(因此从布尔值到整数的双重转换以获得不为零的评级数)。我也不能除以零,解释 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]);
}