我在Postgres中有以下widgets
表:
(该截图是它的粗略Excel表示。)我正在尝试编写一个将返回我的SQL查询:
widgets
记录;或widgets
,那么加载时间最早的那个(整个表格)所以,使用上面的图片:
widget_id = 3
的加载时间早于另一个,因此这是查询返回的记录。widget_id = 1
,因为它在2010年被加载。这是我对查询的初步尝试:
SELECT
MIN(w.loaded_date_time)
FROM
widgets w
WHERE
w.loaded_date_time >= now()
OR
1=1
但是,我立即知道这在语法上是不正确的。有任何想法吗?提前谢谢!
答案 0 :(得分:3)
SELECT *
FROM widgets
ORDER BY loaded_date_time < now()::date, loaded_date_time
LIMIT 1;
..首先有效地排序今天的时间戳(+不存在的未来),因为boolean
表达式已排序FALSE
- &gt; TRUE
- &gt; NULL
。
如果可以未来日期:
ORDER BY
(loaded_date_time::date = now()::date) DESC NULLS LAST
,loaded_date_time
仅当NULLS LAST
可以为NULL时, loaded_date_time
才有意义,应该不允许这样做。在这种情况下删除该条款。
SELECT DISTINCT ON (widget_id)
widget_id, loaded_date_time
FROM widgets
ORDER BY
widget_id
,(loaded_date_time::date = now()::date) DESC
,loaded_date_time;
DISTINCT ON
:
在ORDER BY
条款中......
...... widget_id
首先显然 - 必须与DISTINCT
条款相匹配
...然后先对“今天”的记录进行排序。如果没有,其他记录会自动上移
......最后,早期的记录先排序。
因此,所需的行首先出现并由DISTINCT
选取。一切都完成了。
如果您将表达式(loaded_date_time::date = now()::date)
重写为
(loaded_date_time >= now()::date AND
loaded_date_time < (now()::date + 1)) -- note: < not: <=
.. loaded_date_time
上的普通索引可能会更快。因为,如果你在等号的两边都有一个表达式,你根本就不能使用普通索引。你应该在widget_id(很明显)上有一个索引,而在loaded_date_time
上可能有另一个索引:
CREATE INDEX foo_idx ON widgets (loaded_date_time)
多列索引可能会快一点:
CREATE INDEX foo_idx ON widgets (widget_id, loaded_date_time);
使用EXPLAIN ANLYZE
进行测试,是否使用它。应该是,我没有测试。如果没有,就没有意义了。
答案 1 :(得分:1)
使用union
来处理逻辑,将查询分成两个查询并not exists()
查询:
select * from widget
where <primary criteria>
union
select * from widget
where <secondary criteria>
and not exists (
select * from widget
where <primary criteria>
)
这样编码也很容易阅读和维护,特别是如果你以后添加另一种选择类别的方式。
答案 2 :(得分:1)
select w.id, w.name, w.loaded_date_time
from (
select min(loaded_date_time) loaded_date_time
from widgets
where loaded_date_time::date = current_date
union
select min(loaded_date_time) loaded_date_time
from widgets
order by loaded_date_time desc
limit 1
) s inner join widgets w on w.loaded_date_time = s.loaded_date_time
答案 3 :(得分:0)
这是一个排名功能的应用程序。关键是订单:
select w.*
from (select w.*,
row_number() over (partition by widget_id
order by isToday, datetime desc) as seqnum
from (select w.*,
(case when cast(widget_loaded_date_time as date) = cast(now() as date)
then 0
else 1
end) as isToday
from widgets w
) w
) w
where seqnum = 1