SQL查询 - 仅当值落在“最后n条记录”的范围内时才获取行(特定于记录)

时间:2012-07-30 14:10:44

标签: mysql sql

我有两个表,一个Countries表和一个Weather表。我想要检索过去15天内没有下雨的国家的所有名称。

天气表有一个名为“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中执行此操作(如果它甚至可能)。

4 个答案:

答案 0 :(得分: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    

我认为你已经适当地索引了你的表

答案 1 :(得分: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;

答案 2 :(得分:0)

也许您可以使用一个简单的变量来存储所需的最小天数?我不是一个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
    )

这里我只是将每个国家的最小日期存储在临时表中。希望它有所帮助...

答案 3 :(得分:0)

  

我有两个表,一个Countries表和一个Weather表。我想要检索过去15天内没有下雨的国家的所有名称。

你走了:

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

在计划英语中:对于每个国家/地区,请检查是否有比指定日期更新的阴雨天。如果有,请从结果中删除国家。

2替换为15天前的日期编号。关于体面表现的{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