質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

1回答

548閲覧

空きのある車の一覧を取得する実装で困っています

mackintosh

総合スコア228

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2020/04/03 16:15

編集2020/04/04 06:23

前提・実現したいこと

社内システムなのですが、空きのある社用車の一覧を取得する部分をLaravelで実装しています。
全ては見せられませんが、一部ERDの抜粋です。

イメージ説明

空きのある社用車の一覧を取得する部分の条件を考えているのですが、やりたいことは日本語にすることはできるのですが、条件を反転すると
2020-04-04 13:00迄、かつ、2020-04-04 18:00以降の車の一覧を取得するSQLになってしまいうまくSQLが組み立てられません。

同じような機能を実装された方がいらっしゃいましたらアドバイスいただきたいです。

該当のソースコード

/** * @param array $relations * * @return Car[]|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection */ public function getXxx(array $relations = []) { /** * DB設計的に、車(Car)は複数の予約(Reservations)を持っている。 * 2020-04-04 13:00 ~ 2020-04-04 18:00の空きのある車の一覧を取得する条件を考える! */ $cars = Car::with(['reservations']) ->where('is_abolition', false) ->whereHas('reservations', function(\Illuminate\Database\Eloquent\Builder $query) { $query->where('start_datetime', '>', '2020-04-04 13:00'); $query->where('end_datetime', '<', '2020-04-04 18:00'); }) ->orderBy('display_priority') ->get(); dd($cars); return $cars; }

ちなみに予約できる時間は08:00~20:00までです。

試したこと

3日ほどSQL条件考えたり、似たような機能の記事がないか調べたりしていますが、記事もなかなか見つからず困っています。

とりあえず、普通に考えると以下になると思います。

・CarsテーブルとReservationsテーブルをFULL (OUTER) JOIN (完全外部結合)する
・Reservationsテーブルの2020-04-04 13:00 ~ 2020-04-04 18:00なレコードを除外する。
・余ったレコードをCars.idでgroup化する
・これらが空きのある車

レンタカーのような実装は初めてなので
このロジックが適切なのか、そもそもテーブル設計がこれで良いのかという疑問もあります。
このロジックが適切だったとしても、レコードを除外するという部分が自分の中では曲者で、取得とは逆のことをするので...

他にも
ユーザーが同じタイミングで予約してしまった時はサーバー側ではどういう処理をするのが適切なのか
ユーザーが同じタイミングで予約できないようにする(Reservationsテーブルにstatusカラムを持たせておいて、日時入力後の検索結果から該当の車をクリックしたタイミングでstatusを仮としたレコードを追加しておく?)案など
アドバイスいただけると助かります。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

意図した結果にはなりましたが、なぜこうなるのかが頭で理解できていない。人に日本語で説明ができない。。。

イメージ説明
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2020/04/04 00:49

クエリビルダに確かwhereBetween というものがあったはずですが、 それでは不足ですか?
mackintosh

2020/04/04 05:15

whereBetweenの存在は分かっているのですが、どういう条件にすれば 「この時間〜この時間まで予約の無い車」の一覧を取得できるかの部分で悩んでいます。
guest

回答1

0

ベストアンサー

whereDoesntHave を使って以下のようにできないでしょうか。

php

1 // 時間帯が重なる予約を持たないCarに絞る 2 ->whereDoesntHave('reservations', function ($query) { 3 $query->where('end_datetime', '>', '2020-04-04 13:00'); 4 $query->where('start_datetime', '<', '2020-04-04 18:00'); 5 })

参考: 存在しないリレーションのクエリ

(補足)xは時間帯が重なる例、oは重ならない例

13:00 18:00 -----+--------------+----- <-----> x <-----> x <----> x <--------------------> x <--> o <--> o

なお、予約の時間帯には、準備(クルマの移動とか手続など)に要する時間も含まれている必要があるかとは思います。例えば、13時ちょうどに返却されてしまっても、次の人が13時から直ぐに借りれなくなってしまいます。

投稿2020/04/04 01:48

編集2020/04/05 02:44
Lulucom

総合スコア1899

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mackintosh

2020/04/04 06:26

回答ありがとうございます。 意図したデータが取得できるようになりましたが私自身なぜこの条件なのか頭が追いついておらず、他人に日本語で説明できないので、じっくり見つめる必要がありそうです。 ありがとうございました。
mackintosh

2020/04/04 06:32 編集

直ぐに借りれなくなってしまう問題は、SQL条件に30分とか60分とかの加減調整を追加するつもりです。 ここまで書いていただいたのであとはがんばれそうです。
Lulucom

2020/04/04 06:32

それは何よりです、素晴らしいです。 > なぜこの条件なのか 図にしてみると理解できるのではないかなという気がしています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問