Emmachi
@Emmachi (Emma)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

SQLではうまくいくのに、Laravelだとうまくデータが取得できない

解決したいこと

whereRawで複雑な条件のデータ取得をしたい

【環境】Laravel 5.5

業務日報の登録フォームで使用します。

登録時に、すでに登録済である日報データの日時と照らし合わせ、同じ日時で時間が重複している日報がないか確認するための処理です。
※作業ごとに分けて登録するような運用です。
※日付と時間を連結した日時でチェックしようとしています。
※このクエリで重複した件数が取得できることは確認済です。

発生している問題

クエリビルダで通すと、あるはずの重複データが取得できません。
クエリ実行後、logファイルから拾ったSQL文をそのままMYSQLに貼り付けるときちんと重複件数を拾ってくれるのですが、
laravel上だと取得件数が0件になります。

該当するソースコード

// リクエストの日報データ
$syain_code = 'testUser';
$nippou_date= '2022-03-04'; 
$start_time = '08:00';    
$end_time = '17:00';                                                                                                                                                                                
                                                                                                                                                                
$start_time = $nippou_date." ".$start_time;
$end_time   = $nippou_date." ".$end_time;

$start_time = new Carbon( $start_time );
$end_time   = new Carbon( $end_time );     

 // 終了時刻が 0 時を超えた場合 ⇒ 日付を翌日に変換
if($end_time < $start_time){
      $end_time->addDay();
} 

$start_time = $start_time->format('Y-m-d H:i:s');
$end_time   = $end_time->format('Y-m-d H:i:s'); 

$kuhaku = "' '";
$duplicates_nippouCNT = DB::table($my_db.'.t_nippou')
                ->where('t_nippou.syain_code', $syain_code)
                ->where('t_nippou.nippou_date', $nippou_date)
                ->whereRaw('( ? < CONCAT(CAST((CASE
                    WHEN
                        t_nippou.end_time < t_nippou.start_time
                    THEN
                        DATE_ADD(t_nippou.nippou_date, INTERVAL 1 DAY)
                    WHEN 
                        t_nippou.start_time < t_nippou.end_time 
                    THEN 
                        t_nippou.nippou_date
                    END) AS CHAR), ?, t_nippou.end_time)
                    AND CONCAT(CAST(t_nippou.nippou_date AS CHAR), ?, t_nippou.start_time)  < ? )', [ $start_time, $kuhaku, $kuhaku, $end_time ]) 
                ->count();

既に入力されている日報データ

-- t_nippouテーブル
 no syain_code, nippou_date, start_time, end_time
 1  'testUser', '2022-03-04', '10:00:00', '12:00:00'
 2  'testUser', '2022-03-04', '16:00:00', '00:00:00'
 3  'testUser', '2022-03-04', '05:00:00', '08:00:00'

-- no1,no2の2件を取得したい

logファイルクエリ成型後↓
これをMySQLで流すときちんと該当の2件が取得できます。

SELECT 
    COUNT(*) AS aggregate
FROM
   `t_nippou`
WHERE `t_nippou`.`syain_code` = 'testUser'
        AND `t_nippou`.`nippou_date` = '2022-03-04'
        AND ('2022-03-04 08:00:00' < CONCAT(CAST((CASE
                    WHEN
                        t_nippou.end_time < t_nippou.start_time
                    THEN
                        DATE_ADD(t_nippou.nippou_date,
                            INTERVAL 1 DAY)
                    WHEN t_nippou.start_time < t_nippou.end_time THEN t_nippou.nippou_date
                END)
                AS CHAR),
            ' ',
            t_nippou.end_time)
        AND CONCAT(CAST(t_nippou.nippou_date AS CHAR),
            ' ',
            t_nippou.start_time) < '2022-03-04 17:00:00')

自分で試したこと

・日付をフォーマットする⇒NG
・CASTをChar型からDATETIMEに変更してみる⇒NG
・CASTを全部消して実行⇒NG
・どこでうまくいかないのか確認するために、CASE WHEN文を消して実行⇒NG

その他かれこれ1日半いろいろ試しましたがうまくいきませんでした。
whereRawのバインドがうまくいってないのかな、と思ったのですが、SQLではうまくいくのに、laravelを通すとうまくいかない理由がわからず、いろいろ調べて検索しましたが、力不足です。

面倒なSQL文で申し訳ないのですが、もしよろしければ、どうかご教授お願いいたします。

0

3Answer

試してないので解決するかわかりませんが、

AND CAST(CONCAT(t_nippou.nippou_date, ?,

のt_nippou.nippou_date ,<- 半角スペース入れるとどうなりますか?

すぐ上の

CAST(CONCAT(t_nippou.nippou_date , ?

と同じように

0Like

Comments

  1. @Emmachi

    Questioner

    ご回答ありがとうございます。

    早速半角スペース入れて試してみましたが、結果は変わらずでした。。。
    確認できないような質問で申し訳ないです。
    1つも回答来ないかもしれないと思っていたので大変嬉しいです。
  2. だめでしたか。。
    妥協すると、最初のwhere2つで取得したデータからwhereRawの部分の処理をプログラムでやるって感じになりますかね。
    だけどsqlだけで取得できた方がいいと思いますので解決できることを祈ってます!🙇‍♂️
  3. @Emmachi

    Questioner

    そうですね。。。おっしゃる通り、今のところwhereRowの部分はプログラムに変更しました。
    本当にありがとうございます!
    もし解決したらまたこちらにあげますね。

不思議ですね、、:cry:
mysql打っている箇所でないとこをLaravelが見ているとかもあったりしないかなとか思ったりしました!:shamrock:
一旦シンプルなSQLで意図したデータが取れるか気になったりしました!

0Like

Comments

  1. @Emmachi

    Questioner

    回答いただきありがとうございます。
    そうですね。。。一応シンプルなSQLでwhereRowにバインドした場合は正しくデータ取得できることは確認したのですが、どうやらconcatが付くとよくないようです。
  2. > 正しくデータ取得できることは確認した
    そうなのですね。検討違いな回答してしまいすみません。できること祈ってます!
  3. @Emmachi

    Questioner

    とんでもないです。ご回答くださりありがとうございます!
    めげずに頑張ってみますね。

DB Facade には toSQL があるので、一度書き出して見るのはどうでしょうか?

> php artisan tinker
Psy Shell v0.9.12 (PHP 7.1.33 — cli) by Justin Hileman
>>> \DB::table('t_nippou')->where('t_nippou.syain_code', '0021')->where('t_nippou.nippou_date', '2022-03-03')->toSQL();
=> "select * from `t_nippou` where `t_nippou`.`syain_code` = ? and `t_nippou`.`nippou_date` = ?"
0Like

Comments

  1. @Emmachi

    Questioner

    回答いただきありがとうございます。
    そうですね。
    toSql()で書き出したものを同じくMYSQLに貼り付けると、やはり同じくデータ取得できるのですが・・・うーむ謎です。

    一応書き出したものを張り付けておきますね。


    ```sql

    >>> $sql = preg_replace_array('/\?/', $query->getBindings(), $query->toSql());
    => "select * from `my_db`.`t_nippou` where `t_nippou`.`syain_code` = testUser and `t_nippou`.`nippou_date` = 2022-03-04 and ( 2022-03-04 08:00:00 < CONCAT(CAST((CASE WHEN t_nippou.end_time < t_nippou.start_time THEN DATE_ADD(t_nippou.nippou_date, INTERVAL 1 DAY) WHEN t_nippou.start_time < t_nippou.end_time THEN t_nippou.nippou_date END) AS CHAR), ' ', t_nippou.end_time) AND CONCAT(CAST(t_nippou.nippou_date AS CHAR), ' ', t_nippou.start_time) < 2022-03-04 17:00:00 )"

    ```
  2. @Emmachi

    Questioner

    す、すみません。
    不甲斐ないことに、コメント内にソースを張り付ける方法がググってもわからず・・・
    見づらくて申し訳ないです。
  3. > 不甲斐ないことに、コメント内にソースを張り付ける方法がググってもわからず・・・
    いえいえ〜、寧ろコメントのコメントは code syntax が使えないっぽいですね……

    見た感じ、何も問題なさそうに見えますね。
    DB は何をお使いになのかちょっとわからないですが、もしmysqlでしたら、select クエリログを取り敢えず出す方法があるので、何が実行されたか見てみるのはどうでしょうか?
    参考リンクはこちらです: https://weblabo.oscasierra.net/mysql-general-query-log-1/
  4. @Emmachi

    Questioner

    コメントのコメントの場合は使えなかったですか。なるほどありがとうございます。
    DBはmysqlを使用しております。
    クエリログ!出してみたことがないのでやってみます。ありがとうございます!

Your answer might help someone💌