2012-07-30 96 views
3

我有两个表,一个国家表和一个天气表。我想检索过去15天内没有下雨的所有国家的名称。SQL查询 - 仅当值落在“最后n条记录”范围内时才获取行(特定记录)

天气表有一个名为“DayNum”的列,该列从1 - >无穷大,每天增加1,这是唯一的。此表格还有一个名为“Rain”的列,它只是布尔值为0或1.

此外,并非所有国家都在同一天添加,因此每个国家/地区的最大DayNum会有所不同。下面的表

例子(数据被剪断的可读性):

国家

ID  Name 
    1  USA 
    2  Cananda 
    3  Brazil 

天气

ID Country_id DayNum Rain 
    1  1   1   0 
    2  1   2   0 
    3  1   3   1 

这里是(这方面的工作我在查询当前的尝试几天):

SELECT countries.name, weather.daynum 
    FROM countries INNER JOIN weather ON countries.id = weather.country_id 
    GROUP BY countries.name 
    HAVING weather.daynum > (MAX(weather.day_num) - 15) AND SUM(weather.rain) = 0; 

认为这应该工作,但我有严重的性能问题。我需要编写的实际查询处理不同的数据(相同的确切概念)和数百万行。这个查询似乎以指数速度变慢。

任何人都可以提供任何建议吗?

我的另一个想法是以某种方式限制JOIN只抓取前15条记录(而ORDERING BY weather.day_num),但我还没有找到一种方法在JOIN中完成此操作(如果甚至可能的话) 。

回答

0

你不感兴趣的雨水量,只是它是否存在,所以......

select * from countries 
left join 
(
     select weather.country_id 
     from weather 
      inner join 
      (select country_id, MAX(daynum) as maxdaynum from weather group by country_id) maxday 
       on weather.country_id = maxday.country_id 
       and weather.daynum>maxday.maxdaynum-3 
       where rain=1 
     ) rainy 
on countries.id = rainy.country_id 
where country_id is null  

我想你已经收录你的表适当

+0

我需要熟悉declare和BEGIN ... END,但我不认为这会起作用,因为我所有的国家都有不同的最大DayNum(我想我的例子在这个意义上有点微弱)。所以,如果美国是在任何其他国家前15天加入的,我想我会得到不好的结果。我已经更新了我的OP来反映这一点。 – 2012-07-30 14:40:56

+0

我只会优化出最大值(daynum),因为我认为他们会一样的......我将编辑回 – podiluska 2012-07-30 14:44:13

0

您不包括有关表格中索引的任何信息,但我认为您遇到的性能问题与国家/地区名称字段中的群组相关。如果该列没有编入索引,它肯定会解释你的性能问题。

话虽如此,这可能需要一个子查询而不是内部连接。我会试图这样写查询:

SELECT countries.id, countries.name 
FROM countries 
INNER JOIN 
(
    SELECT country_id 
    FROM weather 
    GROUP BY country_id 
    HAVING weather.daynum > (MAX(weather.day_num) - 15) AND SUM(weather.rain) = 0 
) AS weather 
ON weather.country_id = countries.id; 
+0

这给了我错误:错误1111(HY000):无效使用组函数。 我认为这是由于在WHERE子句中使用聚合函数(max,sum)而不是在HAVING子句中造成的? – 2012-07-30 14:31:41

+0

是的,这很可能。已更新以更正此问题。 – Thomas 2012-07-30 14:58:40

0

也许你可以使用一个简单的变量来存储所需的最小daynum?我不是一个MySQL开发,但这样的事情会做的伎俩,我认为:

SELECT @minDaynum := (MAX(daynum)-15) FROM weather; 

SELECT DISTINCT countries.name 
FROM weather 
INNER JOIN countries ON weather.country_id = countries.id 
WHERE 
    weather.daynum >= @minDaynum AND 
    weather.rain = 1; 

编辑>>如果只有一个变量不适合你的情况下工作,也许尝试使用临时表来加快速度(不知道是否mysql中的临时表的性能是非常好的,但...):

CREATE TEMPORARY TABLE min_daynums (country_id int, country_name, min_daynum int); 
INSERT INTO min_daynum 
    SELECT countries.id, countries.name, MAX(weather.daynum)-15 
    FROM weather 
    INNER JOIN countries ON countries.id = weather.country_id 
    GROUP BY countries.id, countries.name 

SELECT min_daynums.country_name 
FROM min_daynums 
WHERE 
    EXISTS(
     SELECT 1 
     FROM weather 
     WHERE 
      weather.country_id = min_daynums.country_id 
      and weather.daynum >= min_daynums.min_daynum 
      and weather.rain = 1 
    ) 

在这里我只是存放分钟daynum在每个国家的临时表。希望能帮助到你...

+0

@podiluska提出了这个建议(并已编辑他们的帖子)。问题在于,并非每个国家都有MAX(Daynum)相同的价值。如果他们这样做,这可能会起作用。 – 2012-07-30 15:15:26

+0

对不起。我刚刚更新了我的答案,希望它有帮助 – 2012-07-30 15:42:36

0

I have two tables, a Countries table and a Weather table. I would like to retrieve all of the names of countries where it has not rained within the last 15 days.

在这里你去:

SELECT * FROM Country 
WHERE 
    NOT EXISTS (
     SELECT * FROM Weather 
     WHERE 
      Rain = 1 
      AND DayNum >= 2 
      AND Country_id = Country.ID 
    ); 

在计划英文:每个国家,检查是否有任何阴雨天比一天号更新。如果有的话,从结果中消除国家。

用15天前的天数替换2。索引{Country_id, DayNum, Rain}体面的表现。不幸的是,MySQL不太可能以最佳方式执行这个查询,但只有很多国家如此嵌套循环不应该太糟糕,因为DBMS应该能够执行内部查询作为单个索引查找。

另外,考虑重写它作为JOIN,例如:

SELECT Country.* 
FROM Country LEFT JOIN Weather 
    ON Country_id = Country.ID 
    AND Rain = 1 
    AND DayNum >= 2 
GROUP BY Country.ID, Country.Name 
HAVING MAX(Rain) IS NULL OR MAX(Rain) = 0; 

的工作SQL小提琴例子是here

相关问题