【问题标题】:Can I build this query using Laravel's Query Builder and if so, what would that look like? (DB::raw())我可以使用 Laravel 的 Query Builder 构建这个查询吗?如果可以,那会是什么样子? (数据库::原始())
【发布时间】:2021-09-18 16:37:00
【问题描述】:

我已经使用 Eloquent 和 Laravel 的查询构建器(混合)组合了这个生成的查询,我想删除这个“混合”并使用 Laravel 的查询构建器构建整个查询。

下面的查询在 Laravel 的查询构建器中会是什么样子?

SELECT id,
  name,
  clicks_count,
  conversions_count,
  Round(((100 / clicks_count) * conversions_count), 2) AS conversion_rate,
  Cast((cost_integral / clicks_count) AS UNSIGNED) AS cpc_integral,
  Cast((Ifnull(revenue_integral, 0) / clicks_count) AS UNSIGNED) AS epc_integral,
  Cast(Ifnull(revenue_integral, 0) AS signed) AS revenue_integral,
  Cast(Ifnull(cost_integral, 0) AS UNSIGNED) AS cost_integral,
  Cast((Ifnull(revenue_integral, 0) - cost_integral) AS signed) AS profit_integral,
  Round((CASE
    WHEN(Ifnull(revenue_integral, 0) = 0 AND Ifnull(cost_integral, 0) = 0) THEN 0
    WHEN(Ifnull(revenue_integral, 0) = 0 AND Ifnull(cost_integral, 0) > 0) THEN -100
    WHEN(Ifnull(revenue_integral, 0) > 0 AND Ifnull(cost_integral, 0) = 0) THEN 100
    WHEN(Ifnull(revenue_integral, 0) > 0 AND Ifnull(cost_integral, 0) > 0) THEN ((revenue_integral / cost_integral) * 100)
  END), 2) AS roi
FROM
  (SELECT device_types.*,
    (SELECT Count(clicks.id)
      FROM clicks
      WHERE device_types.id = clicks.device_type_id
        AND clicks.created_at BETWEEN "2021-07-06 00:00:00" AND "2021-07-08 23:59:59"
        AND clicks.campaign_id = 2) AS clicks_count,
    (SELECT Count(conversions.id)
      FROM conversions
      INNER JOIN clicks ON clicks.id = conversions.click_id
      WHERE device_types.id = clicks.device_type_id
        AND conversions.created_at BETWEEN "2021-07-06 00:00:00" AND "2021-07-08 23:59:59"
        AND clicks.campaign_id = 2) AS conversions_count,
    (SELECT sum(clicks.cost_integral)
      FROM clicks
      WHERE device_types.id = clicks.device_type_id
        AND clicks.created_at BETWEEN "2021-07-06 00:00:00" AND "2021-07-08 23:59:59"
        AND clicks.campaign_id = 2) AS cost_integral,
    (SELECT sum(conversions.payout_integral)
      FROM conversions
      INNER JOIN clicks ON clicks.id = conversions.click_id
      WHERE device_types.id = clicks.device_type_id
        AND conversions.created_at BETWEEN "2021-07-06 00:00:00" AND "2021-07-08 23:59:59"
        AND clicks.campaign_id = 2) AS revenue_integral
FROM device_types
INNER JOIN clicks ON clicks.device_type_id = device_types.id
WHERE clicks.campaign_id = 2
GROUP BY device_types.id) AS metrics
ORDER BY clicks_count DESC

感谢您的帮助和时间。


编辑:

一个例子就足够了——整个查询不需要重建。我只发布它是因为在最后一个线程中有人告诉我发布整个 SQL 命令,而不仅仅是一小部分(否则我肯定会缩短它)。

重要的是这些“子选择”并不简单DB::raw("(SELECT COUNT(clicks.id) FROM ...。相反,我想知道如何使用 Laravel 查询构建器来构建这些。

【问题讨论】:

  • 您能否也addDB::raw() 代码来回答您的问题?
  • 您需要在查询中进行强制转换,还是希望将这些转换为 eloquent 模型并在模型级别进行强制转换?
  • 是的,CAST 应该通过 SQL 发生,因为我直接返回来自查询的数据。

标签: sql laravel eloquent laravel-query-builder


【解决方案1】:

我就是这样做的:

use Illuminate\Database\Query\Builder;

$clicksCount = DB::table('clicks')
    ->whereColumn('device_types.id', 'clicks.device_type_id')
    ->whereBetween('clicks.created_at', [ "2021-07-06 00:00:00", "2021-07-08 23:59:59" ])
    ->where('clicks.campaign_id', 2)
    ->select(DB::raw('Count(clicks.id)');
$conversionsCount = DB::table('conversions')
    ->join('clicks', 'clicks.id', 'conversions.click_id')
    ->whereColumn('device_types.id', 'clicks.device_type_id')
    ->whereBetween('conversions.created_at', [ "2021-07-06 00:00:00", "2021-07-08 23:59:59" ])
    ->where('clicks.campaign_id', 2)
    ->select(DB::raw('Count(conversions.id)'));
$costIntegral = DB::table('clicks')
    ->whereColumn('device_types.id', 'clicks.device_type_id')
    ->whereBetween('clicks.created_at', [ "2021-07-06 00:00:00", "2021-07-08 23:59:59" ])
    ->where('clicks.campaign_id', 2)
    ->select(DB::raw('sum(clicks.cost_integral)'));
$revenueIntegral = DB::table('conversions')
    ->join('clicks', 'clicks.id', 'conversions.click_id')
    ->whereColumn('device_types.id', 'clicks.device_type_id')
    ->whereBetween('conversions.created_at', [ "2021-07-06 00:00:00", "2021-07-08 23:59:59" ])
    ->where('clicks.campaign_id', 2)
    ->select(DB::raw('sum(clicks.payout_integral)'));

$metrics = DB::table('device_types')
    ->join('clicks', 'clicks.device_type_id', 'device_types.id')
    ->where('clicks.campaign_id', 2)
    ->groupBy('device_types.id')
    ->select('device_types.*')
    ->selectSub($clicksCount, 'clicks_count')
    ->selectSub($conversionsCount, 'conversions_count')
    ->selectSub($costIntegral, 'cost_integral')
    ->selectSub($revenueIntegral, 'revenue_integral');

Builder::newQuery()->select(
    'id',
    'name',
    'clicks_count',
    'conversions_count'
)
->selectRaw('
  Round(((100 / clicks_count) * conversions_count), 2) AS conversion_rate,
  Cast((cost_integral / clicks_count) AS UNSIGNED) AS cpc_integral,
  Cast((Ifnull(revenue_integral, 0) / clicks_count) AS UNSIGNED) AS epc_integral,
  Cast(Ifnull(revenue_integral, 0) AS signed) AS revenue_integral,
  Cast(Ifnull(cost_integral, 0) AS UNSIGNED) AS cost_integral,
  Cast((Ifnull(revenue_integral, 0) - cost_integral) AS signed) AS profit_integral,
  Round((CASE
    WHEN(Ifnull(revenue_integral, 0) = 0 AND Ifnull(cost_integral, 0) = 0) THEN 0
    WHEN(Ifnull(revenue_integral, 0) = 0 AND Ifnull(cost_integral, 0) > 0) THEN -100
    WHEN(Ifnull(revenue_integral, 0) > 0 AND Ifnull(cost_integral, 0) = 0) THEN 100
    WHEN(Ifnull(revenue_integral, 0) > 0 AND Ifnull(cost_integral, 0) > 0) THEN ((revenue_integral / cost_integral) * 100)
  END), 2) AS roi')
->fromSub($metrics, 'metrics')
->orderByDesc('clicks_count')

【讨论】:

  • ->select(DB::raw('sum(clicks.payout_integral)')) 缺少 $revenueIntegral->innerJoin 似乎不存在,所以我选择了 ->join。非常感谢您抽出宝贵时间,它奏效了,我学到了很多东西,可以在未来使用它。
  • 感谢您的提示。我修复了我的代码。不客气。发现 Laravel 的查询构建器提供的功能远远超出了记录的范围,这总是很有趣。
  • 是的,“速度”对我来说很重要,只需将结果返回,不需要模型、集合或类似的东西,我只能再次感谢您。
  • 啊,我明白了。我的荣幸。
猜你喜欢
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
  • 1970-01-01
  • 2016-01-05
  • 2019-10-29
  • 2020-12-07
  • 2011-11-09
  • 2016-04-01
相关资源
最近更新 更多