Laravel - 查询构建器以选择具有唯一列值的多行(具有另一列的最大值)
Posted
技术标签:
【中文标题】Laravel - 查询构建器以选择具有唯一列值的多行(具有另一列的最大值)【英文标题】:Laravel - query builder to select multiple rows with unique column value (which has max value from another column) 【发布时间】:2016-06-17 11:35:38 【问题描述】:我有一张这样的桌子
data | usage_date | usage_hour
x | 03/03/2016 | 05:30:30
y | 03/02/2016 | 11:30:30
z | 03/03/2016 | 07:30:30
p | 03/02/2016 | 05:30:30
当我运行 Laravel 查询时,我希望看到以下行被选中
y | 03/02/2016 | 11:30:30
z | 03/03/2016 | 07:30:30
所以基本上我想构建一个查询,它将为“usage_date”提供唯一值,最大“usage_hour”。如何构建此查询?
【问题讨论】:
我尝试使用 ->max('usage_hour') 但失败并出现分组错误:7 【参考方案1】:首先,你需要知道如何在纯 SQL 中做到这一点,因为 Laravel 的 QueryBuilder 只是一个构建 SQL 查询的工具。
您描述的任务有点棘手,不幸的是,没有简短的 SQL 查询可以解决这个问题。
可以用window functions:
SELECT DISTINCT usage_date,
first_value(usage_hour) OVER (PARTITION BY usage_date ORDER BY usage_hour DESC) as usage_hour,
first_value(data) OVER (PARTITION BY usage_date ORDER BY usage_date DESC, usage_hour DESC) as data
FROM t
(sqlfiddle example)
使用 QueryBuilder 将如下所示:
DB::table('t')
->distinct()
->select([
'usage_date',
DB::raw('first_value(usage_hour) OVER (PARTITION BY usage_date ORDER BY usage_hour DESC) as usage_hour'),
DB::raw('first_value(data) OVER (PARTITION BY usage_date ORDER BY usage_date DESC, usage_hour DESC) as data')
])
->get()
或者可以通过子查询来完成(效率低且不酷):
SELECT usage_date, max(usage_hour) as usage_hour,
(SELECT data FROM t AS t2
WHERE t2.usage_date = t.usage_date AND t2.usage_hour = max(t.usage_hour)
LIMIT 1) AS data
FROM t
GROUP BY usage_date
如果有人知道没有子查询和窗口函数的方法,请告诉我。
【讨论】:
【参考方案2】:试试这个,看看效果如何
$table = \DB::table('table name')->distinct('usage_date')->groupBy('usage_date')->orderBy('usage_hour','desc')->get();
【讨论】:
错了。会产生错误ERROR: column "table_name.data" must appear in the GROUP BY clause or be used in an aggregate function
那我猜你使用的是 mysql 5.7。它的 sql_mode 更严格。它可以在我的机器上运行。我已经改变了我的 sql_mode。
其实我们说的是postgresql
。但是我在sqlfiddle
中检查了您的查询,它产生了错误的结果。 sqlfiddle.com/#!2/bb0ae/1
哦,好的。从来不知道它是 postgresql。
我的意思是即使mysql
,您的查询也不正确。检查我之前给出的 sqlfiddle 链接。以上是关于Laravel - 查询构建器以选择具有唯一列值的多行(具有另一列的最大值)的主要内容,如果未能解决你的问题,请参考以下文章