-
Notifications
You must be signed in to change notification settings - Fork 0
/
zadanie6.sql
108 lines (93 loc) · 3.08 KB
/
zadanie6.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#standardSQL
-- Number of days in a year
CREATE TEMPORARY FUNCTION days(d DATE)
RETURNS INT64 AS (
CASE
WHEN
(MOD(EXTRACT(YEAR FROM d),4) = 0
AND MOD((EXTRACT(YEAR FROM d)),100) != 0)
OR MOD((EXTRACT(YEAR FROM d)),400) = 0
THEN 365
ELSE 366
END
);
-- Convert angle to radians
CREATE TEMPORARY FUNCTION rad(ang FLOAT64)
RETURNS FLOAT64 AS (3.141592 * ang / 180);
-- Calculate declination of the sun
CREATE TEMPORARY FUNCTION delta(d DATE)
RETURNS FLOAT64 AS (
rad(-23.45)
* cos(rad((360 / days(d))
* (EXTRACT(DAYOFYEAR FROM d) + 10)))
);
-- Returns latitude of the New York
CREATE TEMPORARY FUNCTION psi()
RETURNS FLOAT64 AS (rad(40.748433));
-- Calculates hour angle of the earth from sun eguation
CREATE TEMPORARY FUNCTION sun_equation(d DATE)
RETURNS FLOAT64 AS (ACOS(- TAN(psi()) * TAN(delta(d))));
-- Converts time of the day to float in range from [1, to 24)
CREATE TEMPORARY FUNCTION time_to_float(t TIME)
RETURNS FLOAT64 AS (
EXTRACT(HOUR FROM t)
+ EXTRACT(MINUTE FROM t) / 60 + EXTRACT(SECOND FROM t) / 3600
);
-- Calculates noon time due to daylight saving
CREATE TEMPORARY FUNCTION noon(d DATE)
RETURNS FLOAT64 AS (
CASE
WHEN EXTRACT(MONTH FROM d) < 3 OR EXTRACT(MONTH FROM d) > 10 THEN 12
ELSE 13
END
);
-- Calculate length of half of a day
CREATE TEMPORARY FUNCTION halfday(d DATE)
RETURNS FLOAT64 AS (sun_equation(d) * 12 / 3.1415);
-- Calculate time of sunrise
CREATE TEMPORARY FUNCTION sunrise(d DATE)
RETURNS FLOAT64 AS (noon(d) - halfday(d));
-- Calculate time of sunset
CREATE TEMPORARY FUNCTION sunset(d DATE)
RETURNS FLOAT64 AS (noon(d) + halfday(d));
-- Return smallest distance of t from a and b,
-- positive when t in (a, b)
-- negative otherwise
CREATE TEMPORARY FUNCTION closest(t FLOAT64, a FLOAT64, b FLOAT64)
RETURNS FLOAT64 AS (
CASE
WHEN t < a THEN t - a
WHEN t > b THEN b - t
ELSE
(CASE WHEN t - a < b - t THEN t - a ELSE b - t END)
END
);
WITH
-- Extract times of start and stop
times AS (
SELECT * FROM (
SELECT DATE(starttime) as d, starttime as timestamp,
time_to_float(TIME(starttime, "America/New_York")) as time
FROM `bigquery-public-data.new_york.citibike_trips`)
UNION ALL (
SELECT DATE(starttime) as d, stoptime as timestamp,
time_to_float(TIME(stoptime, "America/New_York")) as time
FROM `bigquery-public-data.new_york.citibike_trips`)),
-- Extract offset as number of five minutes intervals from sunset/sunrise of given start/stop
data AS (
SELECT d, timestamp, time,
CAST(TRUNC(12 * closest(time, sunrise(d), sunset(d))) AS INT64) as offset
FROM times),
-- Aggregate offsets
offsets AS (
SELECT count(*) as number, offset
FROM data
GROUP by offset),
-- Count given interval as daily or nightly
gradation AS (
SELECT offset,
CAST(offset > 0 AS INT64) * number as day,
CAST(offset <= 0 AS INT64) * number as night
FROM offsets)
-- Accumulate results
SELECT sum(day), sum(night) from gradation;