【问题标题】:Eloquent query with COALESCE, IF, complex ON clause使用 COALESCE、IF、复杂 ON 子句的雄辩查询
【发布时间】:2023-02-23 04:21:45
【问题描述】:

我想问一下,你会如何在 Laravel Eloquent 中编写以下查询?

请注意 COALESCEIF 和复杂的 LEFT JOIN ... ON (... AND ...)

SELECT COALESCE(IF(customer_group_id=6, prices.price, NULL), products.price) AS finalPrice, prices.customer_group_id, products.*, product_translations.*
FROM `product_categories`
    LEFT JOIN `products` ON `product_categories`.`product_id` = `products`.`id`
    LEFT JOIN `product_translations` ON `product_translations`.`product_id` = `products`.`id`
    LEFT JOIN `prices` 
        ON (`products`.`id` = `prices`.`product_id` AND `prices`.`customer_group_id` = 6 )
WHERE `product_translations`.`locale` = 'it'
    AND `products`.`online` = 1
    AND `products`.`sellable` = 1
    AND `category_id` = 22

更新:到目前为止,我想出的是以下内容:

ProductCategory::leftjoin('products', 'product_categories.product_id', '=', 'products.id')
                    ->leftJoin('product_translations', 'product_translations.product_id', 'products.id')
                    ->leftJoin('prices', function($join) use($customer_group_id) {
                        $join->on('products.id', '=', 'prices.product_id')
                             ->on('prices.customer_group_id', '=', DB::raw($customer_group_id));
                      })
                    ->select(
                        DB::raw('coalesce(if(customer_group_id='.$customer_group_id.',prices.price,NULL), products.price) AS finalPrice'),
                        'prices.customer_group_id',
                        'products.*',
                        'product_translations.*'
                    )
                    ->where('product_translations.locale', '=', $locale)
                    ->where('products.online', '=', true)
                    ->where('products.sellable', '=', true)
                    ->where('category_id', '=', $this->id);

【问题讨论】:

  • 您的代码的输出与 SQL 的输出是什么?请澄清什么在这里不起作用。此外,还有一个 ->toSql() 方法,您可以调用它来生成用于比较的 SQL。
  • @TimLewis 我想出的代码的输出与 sql 查询相同,我在问是否有一些方法可以改进我的代码,使其更具可读性或语法正确。我不确定特别是 DB::raw 语句
  • 那么它已经可以正常工作了吗?如果语法不正确,它根本不会执行。至于可读性,那是见仁见智的问题
  • 啊,明白了!老实说,我觉得你的东西很好! Laravel 中没有 ->coalesce() 方法(以及其他方法),因此一些语句需要使用 DB::raw() 语法。您可以尝试在codereview.stackexchange.com 上发帖,看看他们是否有任何改进建议,但如果您的代码有效,它可能不是最适合 Stackoverflow 的。

标签: php sql laravel eloquent


【解决方案1】:

Laravel 10 现在支持具有特定语法格式的数据库表达式,这使得编写与数据库引擎无关的 ORM 查询成为可能(无需 DB::raw 一切): https://github.com/laravel/framework/pull/44784

class Alias implements Expression
{
    public function __construct(
    public readonly Expression|string $expression,
    public readonly string $name,
    ) { }

    public function getValue(Grammar $grammar): string
    {
        return match ($grammar->isExpression($this->expression)) {
            true => "{$grammar->getValue($this->expression)} as {$grammar->wrap($this->name)}",
            false => $grammar->wrap("{$this->name} as {$this->name}"),
        };
    }
}

class Coalesce implements Expression
{
    public function __construct(
        public readonly array $expressions,
    ) { }

    public function getValue(Grammar $grammar): string
    {
        $expressions = array_map(function ($expression) use($grammar): string {
            return match ($grammar->isExpression($expression)) {
                true => $grammar->getValue($expression),
                false => $grammar->wrap($expression),
            };
        }, $this->expressions);
        $expressions = implode(', ', $expressions);

        return "coalesce({$expressions})";
    }
}

使用这个你现在可以:

    DB::table('table')
    ->select(new Alias(new Coalesce(['user', 'admin']), 'count'));

【讨论】:

    猜你喜欢
    • 2017-02-17
    • 2014-01-16
    • 2014-04-12
    • 1970-01-01
    • 2019-12-19
    • 2013-02-02
    • 1970-01-01
    • 2020-07-22
    • 2018-06-29
    相关资源
    最近更新 更多