如何在单个SQL查询中获取最新日期和日期之后的所有内容

时间:2017-03-09 18:16:50

标签: sql sql-server tsql

好的,所以我吮吸SQL ... 如果我在SQL Server(2015+)中有一个 CityName WeatherProviderName TimeStamp TempCelcius 下, 我想要的是每个天气提供商的每个城市的预测,这些预测已在过去 2天内报告 plus 每个 City + 提供商的最新预测,这些预测在过去 2天内未预测任何内容

是否只有一个查询可以获得更高效的信息,只需单独请求2? 我知道我可以得到最新的值(基于this article),如下所示:

select t.CityName, t.WeatherProviderName, t.TimeStamp, t.TempCelcius from Forecasts t
  inner join (
    select CityName, WeatherProviderName, TempCelcius, max(TimeStamp) as maxTime 
    from Forecasts where TimeStamp < DATEADD(DAY,-2, GETDATE())
    group by CityName, WeatherProviderName
    ) tm on t.CityName = tm.CityName AND t.WeatherProviderName = tm.WeatherProviderName AND t.TimeStamp = tm.maxTime

(也尝试使用that SO question的分区,但我的测试集的速度慢了3倍)

我可以通过以下方式获取最近2天的所有内容:

select CityName, WeatherProviderName, TimeStamp, TempCelcius from Forecasts where TimeStamp > DATEADD(DAY,-2, GETDATE())

但是不是将它们分别运行到2个集合和组合中,有没有办法在快速的单个查询中同时使用它们?

答案备注

我按照@Forklift(谢谢)的建议去了联盟,在下面的评论中。这是建议的最快选择。它看起来像这样:

SELECT t.CityName, t.WeatherProviderName, t.TimeStamp, t.TempCelcius FROM 
Forecasts t
  INNER JOIN (
    SELECT CityName, WeatherProviderName, TempCelcius, max(TimeStamp) AS maxTime 
    FROM Forecasts WHERE TimeStamp < DATEADD(DAY,-2, GETDATE())
    GROUP BY CityName, WeatherProviderName
    ) tm ON t.CityName = tm.CityName AND t.WeatherProviderName = tm.WeatherProviderName AND t.TimeStamp = tm.maxTime
    UNION
    SELECT CityName, WeatherProviderName, TimeStamp, TempCelcius FROM Forecasts WHERE TimeStamp > DATEADD(DAY,-2, GETDATE())

我还将@SqlZsm标记为答案,因为它确实在单个查询中执行...所以根据您的确切需要,您可以使用@Forklift或@SqlZsm来感谢:)

2 个答案:

答案 0 :(得分:3)

这将返回过去两天的所有行,以及使用带有 row_number() 的子查询在过去两天内没有行的行的最新行:

select s.CityName, s.WeatherProviderName, s.TimeStamp, s.TempCelcius 
from (
  select t.CityName, t.WeatherProviderName, t.TimeStamp, t.TempCelcius 
    , rn = row_number() over (
        partition by t.CityName, t.WeatherProviderName
        order by t.TimeStamp desc
        )
  from Forecasts t
  ) as s
where s.TimeStamp > dateadd(day,-2, getdate())
  or rn = 1

rextester演示:http://rextester.com/YQS70477

测试设置:

create table Forecasts (
    CityName varchar(32)
  , WeatherProviderName varchar(32)
  , TimeStamp datetime
  , TempCelcius float
)
insert into Forecasts values 
 ('Sierra Leon','CNN','19881230',30)
,('Sierra Leon','CNN','19881231',30)
,('Sierra Leon','BBC','19881231',30)
,('Sierra Leon','BBC',dateadd(day,-2, getdate()),28)
,('Sierra Leon','BBC',dateadd(day,-1, getdate()),29)
,('Sierra Leon','BBC',getdate(),30)

查询:

select s.CityName, s.WeatherProviderName, s.TimeStamp, s.TempCelcius 
from (
  select t.CityName, t.WeatherProviderName, t.TimeStamp, t.TempCelcius 
    , rn = row_number() over (
        partition by t.CityName, t.WeatherProviderName
        order by t.TimeStamp desc
        )
  from Forecasts t
  ) as s
where s.TimeStamp > dateadd(day,-2, getdate())
  or rn = 1

返回:

+-------------+---------------------+---------------------+-------------+
|  CityName   | WeatherProviderName |      TimeStamp      | TempCelcius |
+-------------+---------------------+---------------------+-------------+
| Sierra Leon | BBC                 | 09.03.2017 19:49:06 |          30 |
| Sierra Leon | BBC                 | 08.03.2017 19:49:06 |          29 |
| Sierra Leon | CNN                 | 31.12.1988 00:00:00 |          30 |
+-------------+---------------------+---------------------+-------------+

答案 1 :(得分:0)

你可以试试这个

select CityName, WeatherProviderName, TimeStamp, TempCelcius from Forecasts where TimeStamp > DATEADD(DAY,-2, GETDATE())
union all
select * from (
    select CityName, WeatherProviderName, TimeStamp, TempCelcius, row_number() over (partition by concat(CityName, WeatherProviderName) order by TimeStamp desc) as rn from Forecasts where TimeStamp < DATEADD(DAY,-2, GETDATE())
)
where rn = 1