![](/img/trans.png)
[英]How to bind parameters to a raw DB query in Laravel that's used on a model?
[英]Bind data to DB::raw() in Laravel
我用原始SQL編寫了一個查詢,該查詢提取給定日期范圍內的所有記錄,根據插入日期和時間對記錄進行計數,並計算自插入“開始日期”以來的小時數。
我現在正在嘗試將該查詢填充到Laravel中。 我遇到的問題是,我需要一些Eloquent文檔中找不到的東西,因此我不得不使用DB::raw()
來完成它們。 這對於硬編碼的值可以很好地工作,但是后來我意識到我需要使用動態值,這使我想到了這個問題 。 這個問題幾乎可以解決,但是我遇到的問題是,由於我使用帶變量的where子句,因此會引起一些奇怪的副作用。
例如,使用以下查詢:
$clicks = Tracker::select(DB::raw("TIME_TO_SEC(TIMEDIFF(DATE_FORMAT(actual_date,'%Y-%m-%d %H:00:00'),'?'))/60/60+1 as hours_since_send"), DB::raw('COUNT(*)'))
->where('actual_date', '>', $start_date)
->where('actual_date', '<', $end_date)
->whereIn('link_id', $link_ids)
->groupBy(DB::raw('DAY(actual_date)'))
->groupBy(DB::raw('HOUR(actual_date)'))
->orderBy('actual_date', 'asc')
->setBindings([$start_date])
->get();
給我這個錯誤:
SQLSTATE[HY093]: Invalid parameter number (SQL: select TIME_TO_SEC(TIMEDIFF(DATE_FORMAT(actual_date,'%Y-%m-%d %H:00:00'),'2014-10-02 00:00:00'))/60/60+1 as hours_since_send, COUNT(*) from `trackers` where `actual_date` > ? and `actual_date` < ? and `link_id` in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) group by DAY(actual_date), HOUR(actual_date) order by `actual_date` asc)
這似乎很簡單,所以我嘗試了:
$clicks = Tracker::select(DB::raw("TIME_TO_SEC(TIMEDIFF(DATE_FORMAT(actual_date,'%Y-%m-%d %H:00:00'),'?'))/60/60+1 as hours_since_send"), DB::raw('COUNT(*)'))
->where('actual_date', '>', $start_date)
->where('actual_date', '<', $end_date)
->whereIn('link_id', $link_ids)
->groupBy(DB::raw('DAY(actual_date)'))
->groupBy(DB::raw('HOUR(actual_date)'))
->orderBy('actual_date', 'asc')
->setBindings(array_merge([$start_date], $link_ids))
->get();
這給了我錯誤:
SQLSTATE[HY093]: Invalid parameter number (SQL: select TIME_TO_SEC(TIMEDIFF(DATE_FORMAT(actual_date,'%Y-%m-%d %H:00:00'),'2014-10-02 00:00:00'))/60/60+1 as hours_since_send, COUNT(*) from `trackers` where `actual_date` > 1156 and `actual_date` < 1157 and `link_id` in (1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, ?, ?) group by DAY(actual_date), HOUR(actual_date) order by `actual_date` asc)
因此,似乎setBindings
只是覆蓋了laravel在后台設置的綁定。 我確實嘗試過用這些再次填充它們:
$clicks = Tracker::select(DB::raw("TIME_TO_SEC(TIMEDIFF(DATE_FORMAT(actual_date,'%Y-%m-%d %H:00:00'),'?'))/60/60+1 as hours_since_send"), DB::raw('COUNT(*)'))
->where('actual_date', '>', $start_date)
->where('actual_date', '<', $end_date)
->whereIn('link_id', $link_ids)
->groupBy(DB::raw('DAY(actual_date)'))
->groupBy(DB::raw('HOUR(actual_date)'))
->orderBy('actual_date', 'asc')
->setBindings(array_merge([$start_date, $start_date, $end_date], $link_ids))
->get();
盡管is不會引發錯誤,但它不會返回任何數據。
所以,我的問題是:如何在這樣的查詢中將DB::raw
表達式與綁定參數一起使用,而又不會弄亂背景中的laravel集呢? 或者,我該如何重寫此查詢以完成我所需要的?
這是原始原始查詢供參考:
SELECT
TIME_TO_SEC(TIMEDIFF(DATE_FORMAT(actual_date,'%Y-%m-%d %H:00:00'),'2014-10-02 00:00:00'))/60/60+1 as hours_since_send,
COUNT(*)
FROM
trackers
WHERE
link_id BETWEEN 1156 AND 1171
AND
actual_date > '2014-10-02 00:00:00'
AND actual_date < '2014-10-08 00:00:00'
GROUP BY
DAY(actual_date),
HOUR(actual_date)
ORDER BY
actual_date
不要使用setBindings
,因為您不需要覆蓋所有的where
綁定(這就是您所做的),只需執行以下操作:
$clicks = Tracker::select(DB::raw("TIME_TO_SEC(TIMEDIFF(DATE_FORMAT(actual_date,'%Y-%m-%d %H:00:00'),?))/60/60+1 as hours_since_send"), DB::raw('COUNT(*)'))
->addBinding($start_date, 'select')
->where('actual_date', '>', $start_date)
...
Eloquent實際上有一個whereBetween方法,該方法可以獲取兩個Carbon實例(以及正常的時間戳)並進行比較。
Tracker::whereBetween('actual_date', [$start, $end])->get();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.