Внешнее соединение 3 или более таблиц в Laravel 8

Эта тема связана с моим превью один Соединить две таблицы со всеми записями

Сейчас я пытаюсь объединить 3 или более таблиц в моем коде контроллера Laravel и просмотреть их в одном Datatable.

Таблица 1

+--------------------+---------+
|     recordtime     | tempout |
+--------------------+---------+
| 4.12.2020 10:00:00 |     1.1 |
| 4.12.2020 10:30:00 |     1.2 |
| 4.12.2020 11:00:00 |     1.3 |
| 4.12.2020 11:30:00 |     1.4 |
| 4.12.2020 12:00:00 |     1.5 |
+--------------------+---------+

Таблица 2

+--------------------+---------+
|     recordtime     | tempout |
+--------------------+---------+
| 4.12.2020 10:00:00 |     2.1 |
| 4.12.2020 11:00:00 |     2.3 |
| 4.12.2020 12:00:00 |     2.5 |
| 4.12.2020 13:00:00 |     2.6 |
| 4.12.2020 14:00:00 |     2.7 |
| 4.12.2020 16:00:00 |     2.9 |
+--------------------+---------+

таблица3

+--------------------+---------+
|     recordtime     | tempout |
+--------------------+---------+
| 4.12.2020 15:00:00 |     3.1 |
| 4.12.2020 16:00:00 |     3.3 |
+--------------------+---------+

Необходимый результат таков:

+--------------------+---------+---------------+---------------+
|     recordtime     | tempout | tempoutstamb | tempoutstamb2 |
+--------------------+---------+---------------+---------------+
| 4.12.2020 10:00:00 | 1.1     | 2.1           | -             |
| 4.12.2020 10:30:00 | 1.2     | -             | -             |
| 4.12.2020 11:00:00 | 1.3     | 2.3           | -             |
| 4.12.2020 11:30:00 | 1.4     | -             | -             |
| 4.12.2020 12:00:00 | 1.5     | 2.5           | -             |
| 4.12.2020 13:00:00 | -       | 2.6           | -             |
| 4.12.2020 14:00:00 | -       | 2.7           | -             |
| 4.12.2020 15:00:00 | -       | -             | 3.1           |
| 4.12.2020 16:00:00 | -       | 2.9           | 3.3           |
+--------------------+---------+---------------+---------------+

Результат должен иметь все записи и основан на столбце «recordtime».

Я создаю код для 2 таблиц. Он работает с нами ожидаемо, как в таблице выше:

  $results2  = Tablemodel1::whereBetween('table1.recordtime', $dateScope)
    ->selectRaw('table1.recordtime')
    ->selectRaw('max(table1.tempout) as tempout')
    ->selectRaw('max(table2.tempout) as tempoutstamb')        
    ->leftJoin('table2', function($join){
        $join->on('table1.recordtime', '=', 'table2.recordtime');
    })
    ->groupBy('table1.recordtime');
  $results = Tablemodel2::whereBetween('table2.recordtime', $dateScope)
    ->selectRaw('table2.recordtime')
    ->selectRaw('max(table1.tempout) as tempout')
    ->selectRaw('max(table2.tempout) as tempoutstamb')        
    ->leftJoin('table1', function($join){
        $join->on('table1.recordtime', '=', 'table2.recordtime');
    })
    ->groupBy('table2.recordtime')       
    ->orderBy('recordtime', 'ASC')
    ->union($results2)
    ->get();

Теперь я попытался добавить 3-й столбец в переменную $results3 и объединить его с другими:

  $results2  = Tablemodel1::whereBetween('table1.recordtime', $dateScope)
    ->selectRaw('table1.recordtime')
    ->selectRaw('max(table1.tempout) as tempout')
    ->selectRaw('max(table2.tempout) as tempoutstamb')        
    ->leftJoin('table2', function($join){
        $join->on('table1.recordtime', '=', 'table2.recordtime');
    })
    ->groupBy('table1.recordtime');
    
  $results3  = Tablemodel3::whereBetween('table3.recordtime', $dateScope)
    ->selectRaw('table3.recordtime')
    ->selectRaw('max(table1.tempout) as tempout')
    ->selectRaw('max(table3.tempout) as tempoutstamb2')        
    ->leftJoin('table1', function($join){
        $join->on('table3.recordtime', '=', 'table2.recordtime');
    })
    ->groupBy('table3.recordtime');
    
  $results = Tablemodel2::whereBetween('table2.recordtime', $dateScope)
    ->selectRaw('table2.recordtime')
    ->selectRaw('max(table1.tempout) as tempout')
    ->selectRaw('max(table2.tempout) as tempoutstamb')        
    ->leftJoin('table1', function($join){
        $join->on('table1.recordtime', '=', 'table2.recordtime');
    })
    ->groupBy('table2.recordtime')       
    ->orderBy('recordtime', 'ASC')
    ->union($results2)
    ->union($results3)
    ->get();

Это дает мне, что все записи, которые должны быть в столбце tempoutstamb2, неправильно переносятся в tempoutstamb. Любая идея, как сделать это правильно?

Необработанный ответ SQL тоже хорош.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
0
0
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Этот метод прекрасно работает:

  $results2  = Tablemodel1::whereBetween('table1.recordtime', $dateScope)
    ->selectRaw('table1.recordtime')
    ->selectRaw('max(table1.tempout) as tempout')
    ->selectRaw('max(table2.tempout) as tempoutstamb')  
    ->selectRaw('max(table3.tempout) as tempoutstamb2')       
    ->leftJoin('table2','table1.recordtime', '=', 'table2.recordtime')
    ->leftJoin('table3','table1.recordtime', '=', 'table3.recordtime')
    ->groupBy('table1.recordtime');
    
  $results3  = Tablemodel3::whereBetween('table3.recordtime', $dateScope)
    ->selectRaw('table3.recordtime')
    ->selectRaw('max(table1.tempout) as tempout')
    ->selectRaw('max(table2.tempout) as tempoutstamb')  
    ->selectRaw('max(table3.tempout) as tempoutstamb2')        
    ->leftJoin('table1','table1.recordtime', '=', 'table3.recordtime')
    ->leftJoin('table2','table2.recordtime', '=', 'table3.recordtime')
    ->groupBy('table3.recordtime');
    
  $results = Tablemodel2::whereBetween('table2.recordtime', $dateScope)
    ->selectRaw('table2.recordtime')
    ->selectRaw('max(table1.tempout) as tempout')
    ->selectRaw('max(table2.tempout) as tempoutstamb')  
    ->selectRaw('max(table3.tempout) as tempoutstamb2')       
    ->leftJoin('table1','table1.recordtime', '=', 'table2.recordtime')
    ->leftJoin('table3','table2.recordtime', '=', 'table3.recordtime')
    ->groupBy('table2.recordtime')       

    ->union($results2)
    ->union($results3)
    ->orderBy('recordtime', 'ASC')
    ->get();

Я подожду, чтобы отметить мой ответ как решенный, если скоро не будет другого ответа с оптимизированным кодом, например, с использованием цикла или чего-то еще.

Ответ принят как подходящий

Можно решить проще:

select ts recordtime, max(to1) tempout, max(to2) tempoutstamb, max(to3) tempoutstamb2
from (
  select ts, tempout to1, cast (null as numeric(10,1)) to2, cast (null as numeric(10,1)) to3
  from table1
union all 
  select ts, null, tempout, null
  from table2
union all
  select ts, null, null, tempout
  from table3
) tt
group by ts
order by ts; 

Вы можете найти его в скрипке https://www.db-fiddle.com/f/eJsPZijRnQFGXugLGHnn93/0

ПРИМЕЧАНИЕ. Я предположил, что нулевые значения, отображаемые как «-», являются просто форматированием вывода. Если это не так, вывод с NULL можно преобразовать в '-'.

ПРИМЕЧАНИЕ 2: я не знаю, как конвертировать в код Laravel/PHP, надеюсь, у вас будет идея получше.

Что такое to1,to2,to3, ts?

Hristian Yordanov 11.12.2020 11:51

@HristianYordanov Это таблица1, таблица2, таблица3. Я только что изменил имена обратно.

igr 11.12.2020 15:00

Другие вопросы по теме