2012-07-30 95 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

相關問題