What I Want to Do
▶ スーパーの来店時刻データ
member_id | usage_date | usage_time | |
---|---|---|---|
123456 | 2024-02-01 | 08:09:00 | |
223456 | 2024-02-01 | 08:10:00 | |
223456 | 2024-02-11 | 08:10:00 | |
123456 | 2024-02-01 | 20:09:00 | |
323456 | 2024-02-01 | 20:09:00 |
という形でとあるスーパーの来店時刻データregmonkey-sample-data.restaurant_kawasaki.customer_record
が与えられているとします. このとき,以下の3つの処理を実施して,曜日×時間帯別平均来店者数の集計を行いたいとします.
▶ 処理1: 24時間オーバーのデータへ変換
00:01:00
→24:00:00
01:01:59
→25:00:00
のように夜中02:59:59
までは26:59:59
へ変換するという処理
▶ 処理2: TIME
型データを丸める
08:09:00
→08:00:00
08:20:00
→08:15:00
のようにTIME型データを15分刻みに丸める処理
▶ 処理3: DATE型データをISO day of weekへ変換
- 月曜日を
1
, 日曜日を7
とするISO day of weekに変換する - 祝日は
8
をアサインする2024-02-11
,2024-02-23
は8
がアサインされる
Query Example
▶ 処理1: 24時間オーバーのデータへ変換
TIME
型のままでは23:59:59
までしかカバーされないので,extended timeの表記を試みたい場合はSTRING
型へ変換する必要があります.
CREATE TEMP FUNCTION convert_extended_time(standard_time TIME)
RETURNS STRINGAS (
CASE
WHEN EXTRACT(HOUR FROM standard_time) < 3 THEN
"%02d:%02d:%02d", EXTRACT(HOUR FROM standard_time) + 24, EXTRACT(MINUTE FROM standard_time), EXTRACT(SECOND FROM standard_time))
FORMAT(ELSE
"%02d:%02d:%02d", EXTRACT(HOUR FROM standard_time), EXTRACT(MINUTE FROM standard_time), EXTRACT(SECOND FROM standard_time))
FORMAT(END
);
▶ 処理2: TIME型データを丸める
CREATE TEMP FUNCTION round_to_nearest_15_minute(usage_time TIME, round_level INT64)
TIME
RETURNS AS (
TIME_TRUNC(INTERVAL MOD(EXTRACT(MINUTE FROM usage_time), round_level) MINUTE),
TIME_SUB(usage_time, MINUTE
) );
▶ 処理3: DATE
型データをISO day of weekへ変換
BigQueryが提供する EXTRACT(DAYOFWEEK FROM <date-column>)
は日曜日1
から始まり土曜日7
で終わる形式となっているので自分で以下のように関数をUDFを定義することが必要になります.
CREATE TEMP FUNCTION convert_iso_dayofweek(usage_date DATE)
RETURNS INT64AS (
MOD(EXTRACT(DAYOFWEEK FROM usage_date) + 5, 7) + 1
);
▶ データ抽出クエリ
WITH
AS(
daily_summary SELECT
usage_date,15) AS rounded_usage_time,
round_to_nearest_15_minute(usage_time, CASE
WHEN usage_date in (DATE('2024-02-11'), DATE('2024-02-23')) THEN 8
ELSE convert_iso_dayofweek(usage_date)
END AS dayofweek,
COUNT(1) AS customer_count
FROM
-sample-data.restaurant_kawasaki.customer_record`
`regmonkeyGROUP BY
1, 2
)SELECT
dayofweek,AS rounded_usage_time,
convert_extended_time(rounded_usage_time) AVG(customer_count) AS mean_customer_count
FROM
daily_summary GROUP BY
1, 2
ORDER BY
1, 2;