Laravel Fluent Query Builder соединение с подзапросом



хорошо после нескольких часов исследований и все еще используя DB::select я должен задать этот вопрос. Потому что я собираюсь через мой компьютер ;).



Я хочу получить последний ввод пользователя (база на отметке времени). Я могу сделать это с помощью raw sql



SELECT  c.*, p.*
FROM users c INNER JOIN
(
SELECT user_id,
MAX(created_at) MaxDate
FROM `catch-text`
GROUP BY user_id
) MaxDates ON c.id = MaxDates.user_id INNER JOIN
`catch-text` p ON MaxDates.user_id = p.user_id
AND MaxDates.MaxDate = p.created_at


Я получил этот запрос из другого сообщения здесь на stackoverflow.



Я пробовал все, чтобы сделать это с помощью fluent query builder в Laravel, однако без успеха.



Я знаю, что руководство говорит, что вы можете сделать это:



DB::table('users')
->join('contacts', function($join)
{
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);
})
->get();


но это не очень помогает, потому что я не вижу, как я мог бы использовать подзапрос там?
Кто может осветить мой день?

549   4  

4 ответов:

хорошо для всех вас, которые прибыли сюда в отчаянии, ища ту же проблему. Я надеюсь, что вы найдете это быстрее, чем я сделал; О.

вот как это решается. JoostK сказал мне в github, что " первый аргумент для объединения-это таблица (или данные), к которой вы присоединяетесь.". И он был прав.

вот код. Разные таблицы и имена, но вы получите идею правильно? Это Т

DB::table('users')
        ->select('first_name', 'TotalCatches.*')

        ->join(DB::raw('(SELECT user_id, COUNT(user_id) TotalCatch,
               DATEDIFF(NOW(), MIN(created_at)) Days,
               COUNT(user_id)/DATEDIFF(NOW(), MIN(created_at))
               CatchesPerDay FROM `catch-text` GROUP BY user_id)
               TotalCatches'), 
        function($join)
        {
           $join->on('users.id', '=', 'TotalCatches.user_id');
        })
        ->orderBy('TotalCatches.CatchesPerDay', 'DESC')
        ->get();

Я искал решение довольно связанной проблемы: поиск новейших записей в группе, которая является специализацией типичного самый большой-n-на-группу С N = 1.

решение включает в себя проблему, с которой Вы имеете дело здесь (т. е. Как построить запрос в Eloquent), поэтому я публикую его, поскольку это может быть полезно для других. Он демонстрирует более чистый способ построения подзапросов с использованием мощного красноречивого интерфейса fluent с несколькими столбцами соединения и where условие внутри присоединенного суб-выбора.

в моем примере я хочу получить самые новые результаты сканирования DNS (таблица scan_dns) на группу, идентифицированную watch_id. Я строю подзапрос отдельно.

SQL я хочу красноречиво генерировать:

SELECT * FROM `scan_dns` AS `s`
INNER JOIN (
  SELECT x.watch_id, MAX(x.last_scan_at) as last_scan
  FROM `scan_dns` AS `x`
  WHERE `x`.`watch_id` IN (1,2,3,4,5,42)
  GROUP BY `x`.`watch_id`) AS ss
ON `s`.`watch_id` = `ss`.`watch_id` AND `s`.`last_scan_at` = `ss`.`last_scan`

Я сделал это следующим образом:

// table name of the model
$dnsTable = (new DnsResult())->getTable();

// groups to select in sub-query
$ids = collect([1,2,3,4,5,42]);

// sub-select to be joined on
$subq = DnsResult::query()
    ->select('x.watch_id')
    ->selectRaw('MAX(x.last_scan_at) as last_scan')
    ->from($dnsTable . ' AS x')
    ->whereIn('x.watch_id', $ids)
    ->groupBy('x.watch_id');
$qqSql = $subq->toSql();  // compiles to SQL

// the main query
$q = DnsResult::query()
    ->from($dnsTable . ' AS s')
    ->join(
        DB::raw('(' . $qqSql. ') AS ss'),
        function(JoinClause $join) use ($subq) {
            $join->on('s.watch_id', '=', 'ss.watch_id')
                 ->on('s.last_scan_at', '=', 'ss.last_scan')
                 ->addBinding($subq->getBindings());  
                 // bindings for sub-query WHERE added
        });

$results = $q->get();

запрос с подзапросом в Laravel

$resortData = DB::table('resort')
        ->leftJoin('country', 'resort.country', '=', 'country.id')
        ->leftJoin('states', 'resort.state', '=', 'states.id')
        ->leftJoin('city', 'resort.city', '=', 'city.id')
        ->select('resort.*', 'country.name as country_name', 'states.name as state_name','city.name as city_name', DB::raw("(SELECT GROUP_CONCAT(amenities.name) from resort_amenities LEFT JOIN amenities on amenities.id= resort_amenities.amenities_id WHERE resort_amenities.resort_id=resort.id) as amenities_name"))->groupBy('resort.id')
        ->orderBy('resort.id', 'DESC')
       ->get();

Я не могу комментировать, потому что моя репутация не достаточно высоко. @Franklin Rivero если вы используете Laravel 5.2, вы можете установить привязки для основного запроса вместо соединения с помощью метода setBindings.

таким образом, основной запрос в ответе @ph4r05 будет выглядеть примерно так:

$q = DnsResult::query()
    ->from($dnsTable . ' AS s')
    ->join(
        DB::raw('(' . $qqSql. ') AS ss'),
        function(JoinClause $join) {
            $join->on('s.watch_id', '=', 'ss.watch_id')
                 ->on('s.last_scan_at', '=', 'ss.last_scan');
        })
    ->setBindings($subq->getBindings());

Comments

    Ничего не найдено.