Используйте UNION с DISTINCT в Laravel Eloquent построителя запросов со связями - PullRequest
0 голосов
/ 04 марта 2019

У меня есть 2 таблицы,

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 |
+----+-------------+------+

и соответствующие красноречивые модели ( SaleService и Свойство ), связанные сдруг с другом по отношению ( sale_service.property_id = property.id ). Свойство может быть связано с другим Свойством в той же таблице.

Мне нужно получить коллекцию SaleService экземпляров, где они связаны property.parent_id равно нулю ИЛИ, если в таблице sale_services есть несколько записей, совместно использующих одну и ту же таблицу parent_id - properties, различаемую этим полем и порядком на rank.

результат должен быть

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

- все элементы из таблицы sale_services, за исключением (sale_service.id = 2) , потому что его свойства совпадают parent_id с элементом (sale_service.id = 3) и элемент с (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 ) кажется, что работает, но со случайным элементом, выбранным в отдельном запросе.

Есть ли другой способ достиженияНакануне тот же результат или что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Наконец-то найдено решение.

  1. Использовать Laravel ^ 5.7.28 (проблема с UNION была исправлена ​​в Laravel 5.7.28: 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);
    
0 голосов
/ 04 марта 2019

Создатель запроса 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');

Это работает?

...