将 MySQL 查询转换为 Laravel 查询构建器代码

Posted

技术标签:

【中文标题】将 MySQL 查询转换为 Laravel 查询构建器代码【英文标题】:Convert MySQL query to Laravel query builder code 【发布时间】:2021-12-11 16:38:27 【问题描述】:

我正在使用农产品管理系统。我有一个关于 mysql 查询的问题。我想知道如何使用 Laravel 查询生成器创建相同的查询:

SELECT
    vegitables.name, vegitables.image, vegitables.catagory,
    AVG(price_wholesale),
    SUM(CASE WHEN rank = 1 THEN price_wholesale ELSE 0 END) today,
    SUM(CASE WHEN rank = 2 THEN price_wholesale ELSE 0 END) yesterday
FROM (
    SELECT
        veg_id, price_wholesale, price_date,
        RANK() OVER (PARTITION BY veg_id ORDER BY price_date DESC) as rank
    FROM old_veg_prices
) p
INNER JOIN vegitables ON p.veg_id = vegitables.id
WHERE rank in (1,2)
GROUP BY veg_id

在数据库中运行查询时得到的输出结果:

以下两个表格用于获取每个产品的今天价格昨天价格和平均价格。

CREATE TABLE `vegitables` (
  `id` bigint(20) UNSIGNED NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `image` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `catagory` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `total_area` int(11) NOT NULL COMMENT 'Total area of culativate in Sri Lanka (Ha)',
  `total_producation` int(11) NOT NULL COMMENT 'Total production particular product(mt)',
  `annual_crop_count` int(11) NOT NULL COMMENT 'how many time can crop pre year',
  `short_dis` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

ALTER TABLE `vegitables`
  ADD PRIMARY KEY (`id`);
ALTER TABLE `vegitables`
  MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
COMMIT;

CREATE TABLE `old_veg_prices` (
  `id` bigint(20) UNSIGNED NOT NULL,
  `veg_id` int(11) NOT NULL,
  `price_wholesale` double(8,2) NOT NULL,
  `price_retial` double(8,2) NOT NULL,
  `price_location` int(11) NOT NULL,
  `price_date` date NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    ALTER TABLE `old_veg_prices`
  ADD PRIMARY KEY (`id`);
ALTER TABLE `old_veg_prices`
  MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
COMMIT;

我尝试将this site 转换为 MySQL 查询以查询构建器代码。但它显示一些错误可以找到它。任何方式我想用任何方法在 Laravel 中运行这段代码?

【问题讨论】:

谷歌“Laravel 原始查询” “我已尝试过此站点”并收到错误消息。发布您尝试过的代码,并将错误添加到您的问题中。也许有人可以帮助你 查询不会显示昨天和今天的汇率,而是最后两个汇率(一行可能是前天,另一行可能是几年前)。这是预期的结果吗? 【参考方案1】:

抽象产品的“查询构建器”功能通常会遗漏一些可能的 SQL 构造。我建议你放弃对 SQL 进行逆向工程的目标,回到 Laravel 并简单地执行“原始”查询。

还有……

rank() OVER (PARTITION BY veg_id ORDER BY price_date DESC) as rank

需要 MySQL 8.0 (MariaDB 10.2)。

并建议您避免使用别名“rank”,因为它与函数的名称相同。

【讨论】:

我也尝试了原始查询方法,但也出现错误 请向我们展示完整的错误信息。 SQLSTATE[42000]: 语法错误或访问冲突:1140 没有 GROUP 列的 GROUP 列 (MIN(),MAX(),COUNT(),...) 的混合是非法的,如果有没有 GROUP BY 子句 DB::select('myquery')->get(); GROUP 消息指出 veg_id 1 有 2 个价格;因此查询是模棱两可的,需要澄清。参照ONLY_FULL_GROUP_BY【参考方案2】:

您的查询不会返回昨天和今天的数据;它将返回最近两个日期的数据(例如,如果今天是 2021 年 11 月 1 日,胡萝卜的最近两个日期是 2021 年 10 月 25 日和 2021 年 10 月 20 日,它将使用这两个日期)。使用RANK() ... IN (1, 2) 也是不正确的,因为它可以返回等级,例如 1 后跟 3 而不是 2。

要获得今天和昨天的价格,您不需要窗口函数。只需使用适当的 where 子句和条件聚合:

SELECT vegitables.name
     , vegitables.image
     , vegitables.catagory
     , AVG(old_veg_prices.price_wholesale) AS avgwholesale
     , SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE - INTERVAL 1 DAY THEN old_veg_prices.price_wholesale END) AS yesterday
     , SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE THEN old_veg_prices.price_wholesale END) AS today
FROM vegitables
INNER JOIN old_veg_prices ON vegitables.id = old_veg_prices.veg_id
WHERE old_veg_prices.price_date IN (CURRENT_DATE - INTERVAL 1 DAY, CURRENT_DATE)
GROUP BY vegitables.id -- other columns from vegitables table are functionally dependent on primary key

Laravel 等价物是:

DB::table('vegitables')
    ->Join('old_veg_prices', 'old_veg_prices.veg_id', '=', 'vegitables.id')
    ->whereRaw('old_veg_prices.price_date IN (CURRENT_DATE - INTERVAL 1 DAY, CURRENT_DATE)')
    ->select(
        'vegitables.name',
        'vegitables.image',
        'vegitables.catagory',
        DB::raw('AVG(old_veg_prices.price_wholesale) AS avgwholesale'),
        DB::raw('SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE - INTERVAL 1 DAY THEN old_veg_prices.price_wholesale END) AS yesterday'),
        DB::raw('SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE THEN old_veg_prices.price_wholesale END) AS today')
    )
    ->groupBy(
        'vegitables.id',
        'vegitables.name',
        'vegitables.image',
        'vegitables.catagory'
    )
    ->get();

【讨论】:

SQLSTATE[42000]:语法错误或访问冲突:1055 'slagro.vegitables.name' 不在 GROUP BY 中 运行查询时出现上述错误 vegitables.name, vegitables.image, vegitables.catagory 添加到群组中。但如果将vegitables.id 定义为主键,在 MySQl 5.7 或 MySQL 8 上应该不会有问题。 非常感谢您的宝贵贡献

以上是关于将 MySQL 查询转换为 Laravel 查询构建器代码的主要内容,如果未能解决你的问题,请参考以下文章

如何将此 MySQL 查询转换为 Laravel?

如何将此查询从SQL(mysql)转换为Eloquent(Laravel)

需要将查询转换为 Eloquent Model laravel

我想将 MySQL 查询转换为 Laravel Eloquent / Laravel ORM

将子选择 sql 查询转换为 laravel 查询

如何将许多语句 mysql 转换为 laravel eloquent?