【问题标题】:Use UNION with DISTINCT in Laravel Eloquent query builder with relations在具有关系的 Laravel Eloquent 查询构建器中使用 UNION 和 DISTINCT
【发布时间】:2019-03-04 15:24:31
【问题描述】:

我有两张桌子,

properties
+----+-----------+
| id | parent_id |
+----+-----------+
|  1 | null      |
|  2 | 1         |
|  3 | null      |
|  4 | 3         |
|  5 | 3         |
|  6 | null      |
+----+-----------+

sale_services
+----+-------------+------+
| id | property_id | rank |
+----+-------------+------+
|  1 |           2 |    5 |
|  2 |           4 |    4 |
|  3 |           5 |    6 |
|  4 |           6 |    7 |
+----+-------------+------+

和相应的 Eloquent 模型(SaleServiceProperty)通过关系(sale_service.property_id = property.id)相互链接。 Property 可以链接到同一个表中的另一个 Property

我需要获取 SaleService 实例的集合,其中相关的 property.parent_id 为空,或者 sale_services 表中的某些记录共享相同的 parent_idproperties 表,区分按该字段并按rank 排序。

结果应该是

+----+-------------+------+
| id | property_id | rank |
+----+-------------+------+
|  1 |           2 |    5 |
|  3 |           5 |    6 |
|  4 |           6 |    7 |
+----+-------------+------+

- sale_services 表中的所有项目,除了 (sale_service.id = 2),因为它的属性与项目 (sale_service.id = 3) 共享相同的 parent_id > 并且具有 (sale_service.id = 3) 的项目具有最高的rank

我想出了 SQL 代码来得到想要的结果,

 SELECT *
    FROM
      (SELECT DISTINCT ON (properties.parent_id) *
       FROM "sale_services"
       INNER JOIN "properties" ON "sale_services"."property_id" = "properties"."id"
       WHERE ("properties"."parent_id") IS NOT NULL
       ORDER BY "properties"."parent_id", "sale_services"."rank" DESC) AS sub
    UNION
    SELECT *
    FROM "sale_services"
    INNER JOIN "properties" ON "sale_services"."property_id" = "properties"."id"
    WHERE ("properties"."parent_id") IS NULL

但我无法使用 Eloquent Builder。

我试过这样的

$queryWithParent = SaleService::query()
    ->select(\DB::raw('DISTINCT ON (properties.parent_id) *'))
    ->whereNotNull('properties.parent_id')
    ->join('properties', 'sale_services.property_id', '=', 'properties.id')
    ->orderBy('parent_id')
    ->orderBy('sale_services.index_range', 'desc');

$queryWithoutParent = SaleService::query()
    ->join('properties', 'sale_services.property_id', '=', 'properties.id')
    ->whereNull('properties.parent_id');

$query = $queryWithParent->union($queryWithoutParent);

但出现错误

SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "union" LINE 1: ...perties.type <> 'hotel') order by "parent_id" asc union sele... ^ (SQL: select DISTINCT ON (properties.parent_id) * from "sale_services" inner join "properties" on "sale_services"."property_id" = "properties"."id" where ("properties"."parent_id") is not null and ("sale_services"."deleted_at") is null and "published" = 1 and exists (select 1 from "properties" where properties.id = sale_services.property_id AND properties.type <> 'hotel') order by "parent_id" asc union select * from "sale_services" inner join "properties" on "sale_services"."property_id" = "properties"."id" where ("properties"."parent_id") is null and ("sale_services"."deleted_at") is null and "published" = 1 and exists (select 1 from "properties" where properties.id = sale_services.property_id AND properties.type <> 'hotel') order by "index_range" desc limit 12 offset 0)

如果我从第一个查询 ($queryWithParent) 中删除排序,它似乎可以正常工作,但在不同的查询中选择了随机项目。

有没有其他方法可以达到相同的结果,或者我做错了什么?

【问题讨论】:

  • 你使用的是哪个版本的 Laravel?
  • Laravel 5.7,PostgreSQL 10
  • 什么版本的 Laravel 5.7?
  • Laravel 版本 5.7.15
  • UNION 问题已在 Laravel 5.7.28 中修复:github.com/laravel/framework/pull/27589

标签: laravel postgresql eloquent distinct union


【解决方案1】:

“Distinct”的 laravel 查询创建器是 distinct(),如:

$queryWithParent = SaleService::query()
->distinct('properties.parent_id')
->whereNotNull('properties.parent_id')
->join('properties', 'sale_services.property_id', '=', 'properties.id')
->orderBy('parent_id')
->orderBy('sale_services.index_range', 'desc');

这行得通吗?

【讨论】:

  • 作为旁注,集合的等价物是“unique()”。
  • Eloquent Builder distinct() 方法没有参数并且与PostgreSQL DISTINCT ON 运算符不兼容,所以不是,它不起作用...
  • 你说得对,我已经在我的代码中尝试过,但在你的情况下似乎没有用。如果您没有找到一种数据库方法来获取答案并且没有提取大量数据,那么您可以像我一样使用集合 unique() :$db_query->get()->unique('participant_id' );
  • 问题是在这个阶段之后我需要通过~10-20个参数进行巨大的过滤和急切的关系加载,所以收集方法不是一个可行的方法。无论如何,谢谢你。我现在正在考虑自定义数据库视图。
【解决方案2】:

终于找到了解决办法。

  1. 使用 Laravel ^5.7.28(Laravel 5.7.28 中已修复 UNION 问题:github.com/laravel/framework/pull/27589),您将不需要子查询!
  2. 指定要选择的表列以避免列名冲突sale_services.*

    $queryWithParent = SaleService::query()
        ->select(\DB::raw('DISTINCT ON (properties.parent_id) sale_services.*'))
        ->from('sale_services')
        ->join('properties', 'sale_services.property_id', '=', 'properties.id')
        ->whereNotNull('properties.parent_id')
        ->orderBy('properties.parent_id')
        ->orderBy('sale_services.index_range', 'desc');
    
    $queryWithoutParent = SaleService::query()
        ->select(\DB::raw('sale_services.*'))
        ->join('properties', 'sale_services.property_id', '=', 'properties.id')
        ->whereNull('properties.parent_id');
    
    $query = $queryWithParent->union($queryWithoutParent);
    

【讨论】:

    猜你喜欢
    • 2021-12-28
    • 1970-01-01
    • 2013-10-03
    • 2020-12-10
    • 2017-06-05
    • 2021-08-31
    • 2018-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多