這是我能想出的最好的解決辦法:
#standardSQL
CREATE TEMP FUNCTION distance(lat1 FLOAT64, lat2 FLOAT64, lon1 FLOAT64, lon2 FLOAT64) AS((
WITH data AS(
SELECT POW(SIN((ACOS(-1)/180 * (lat1 -lat2))/2), 2) + COS(ACOS(-1)/180 * (lat1)) * COS(ACOS(-1)/180 * (lat2)) * POW(SIN((ACOS(-1)/180 * (lon1 -lon2))/2), 2) a
)
SELECT 6371 * 2 * ATAN2(SQRT((SELECT a FROM data)), SQRT(1 - (SELECT a FROM data)))
));
WITH temperature_data AS(
SELECT
CONCAT(year, mo, da) date,
temp,
b.lat lat,
b.lon lon
FROM `bigquery-public-data.noaa_gsod.gsod2016` a
JOIN `bigquery-public-data.noaa_gsod.stations` b
ON a.stn = b.usaf AND a.wban = b.wban
WHERE concat(year, mo, da) BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(PARSE_DATE('%Y%m%d', '20160725'), INTERVAL 7 DAY)) AND '20160725'
)
SELECT
date,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 20, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 20, temp, NULL)) AS std_temp) data_20km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 50, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 50, temp, NULL)) AS std_temp) data_50km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 100, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 100, temp, NULL)) AS std_temp) data_100km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 200, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 200, temp, NULL)) AS std_temp) data_200km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 500, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 500, temp, NULL)) AS std_temp) data_500km
FROM temperature_data t
WHERE
distance(t.lat, 10.1, t.lon, 10.2) < 2000
GROUP BY date
ORDER BY date
我會試着解釋以及您的問題:
我怎樣才能過去特定日期的7天?
查詢temperature_data
內,發現有WHERE
子句條件:
WHERE concat(year, mo, da) BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(PARSE_DATE('%Y%m%d', '20160725'), INTERVAL 7 DAY)) AND '20160725'
這是過去7天指定日期的選擇。只需更改值「20160725」即可選擇要分析的日期。
可以通過查詢直接計算最大和最小經緯度嗎?
是的。我想你的意思是,如果可以選擇給定範圍內的空間點(比如說20公里)。這樣做的 一種方法是定義一個臨時的函數來計算所需點和車站分,這是在查詢中所表達之間的距離:
CREATE TEMP FUNCTION distance(lat1 FLOAT64, lat2 FLOAT64, lon1 FLOAT64, lon2 FLOAT64) AS((
WITH data AS(
SELECT POW(SIN((ACOS(-1)/180 * (lat1 -lat2))/2), 2) + COS(ACOS(-1)/180 * (lat1)) * COS(ACOS(-1)/180 * (lat2)) * POW(SIN((ACOS(-1)/180 * (lon1 -lon2))/2), 2) a
)
SELECT 6371 * 2 * ATAN2(SQRT((SELECT a FROM data)), SQRT(1 - (SELECT a FROM data)))
));
可以隨意修改並測試這個功能,比如:
SELECT distance(50, 60, 30, 10) # result is ~ 1680km
該功能在這裏使用:
WHERE
distance(t.lat, 10.1, t.lon, 10.2) < 2000
濾除點多於2000公里遠離(10.1°,10.2°)。在您的查詢中,您可以選擇不同的輸入值而不是(10.1°,10.2°)。
很多時候它並沒有找到任何數據,因爲最有可能的是20km的半徑太小而無法找到電臺。我如何修改查詢到 找到最近的車站,如果在20公里範圍內找不到它的話?
一種可能的解決方案是在一次查詢幾個不同的距離:
SELECT
date,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 20, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 20, temp, NULL)) AS std_temp) data_20km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 50, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 50, temp, NULL)) AS std_temp) data_50km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 100, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 100, temp, NULL)) AS std_temp) data_100km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 200, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 200, temp, NULL)) AS std_temp) data_200km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 500, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 500, temp, NULL)) AS std_temp) data_500km
FROM temperature_data t
WHERE
distance(t.lat, 10.1, t.lon, 10.2) < 2000
GROUP BY date
注意,這個查詢中提取站點範圍從輸入點(10.1°,10.2°)到2000公里程。然後應用過濾器來選擇20km,50km,100km,200km和500km範圍內的點。
您可以根據需要更改這些值。如果你想從另一個角度得到平均溫度,比如說(40°,30°),只需將數值(10.1,10.2)改爲(40,30)即可。另外,如果您希望距離此點不同,則可以將表達式IF(distance(t.lat, 10.1, t.lon, 10.2) < 200
更改爲更適合您需要的範圍。該WHERE
子句的條件
說明:
distance(t.lat, 10.1, t.lon, 10.2) < 2000
因此,這是由多於2000公里濾除所有站遠離點(10.1,10.2)。您也可以根據需要更改此值。
關於這個的最後說明:我還帶了STDDEV_SAMP
這是standard deviation of a sampling。這對您來說可能有一定的價值,並且它可以讓您瞭解平均值在平均值附近傳播的程度(通過採樣數據大小的影響進行校正)。如果我們不知道我們真的有多接近正確的價值,平均數本身並不是那麼有價值。
有沒有更好的免費歷史天氣數據可以得到?
不知道。希望這個公共數據集對你來說足夠好。
請顯示一些數據,說明您的問題;我不完全遵循它。 –
什麼部分不清楚?如果您運行上面的查詢,您將從多個工作站獲取數據。它們應該按日期和月份進行平均分組。查詢也只顯示給定月份的數據。但我寧願有一個給定日期的過去一週。 – Chris
不能以任何方式直接回答,但[遷移指南中的示例](https://cloud.google.com/bigquery/docs/reference/standard-sql/migrating-from-legacy-sql#correlated_subqueries)可能會有用。 –