我有两个表,一个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中执行此操作(如果它甚至可能)。
答案 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。