- BigQuery Style Guide
- ๋ชฉ์ฐจ (Table of Contents)
- ์ผ๋ฐ ๊ฐ์ด๋ (General Guide)
- ์ด๋ฆ์ง๊ธฐ์ ์ฌ์ฉํ๊ธฐ (Naming Conventions)
- ์ปฌ๋ผ ์ด๋ฆ ์ง๊ธฐ์ ์ฌ์ฉํ๊ธฐ (Column Naming)
- ํ ์ด๋ธ ์ด๋ฆ ์ง๊ธฐ์ ์ฌ์ฉํ๊ธฐ (Table Naming)
- ๋ฌธ์ฅ ๊ตฌ์กฐํ ํ๊ธฐ (Statement Structure)
- Window Function
- User Defined Function
- BigQuery Scripting
- BigQuery ์คํ์ผ ์์
- ์ฐธ๊ณ (references)
์ด ๋ฌธ์๋ ๋น ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ์์ง๋์ด(data engineer), ๋ฐ์ดํฐ ๋ถ์๊ฐ(data analyst)์ ๋ฐ์ดํฐ ๊ณผํ์(data scientist)๊ฐ BigQuery ์ธ์ด๋ก ์ฝ๋ ์์ฑ์์ ์ง์นจ(guide)๊ณผ ์คํ์ผ(style)์ ์ ์ํ๊ณ ์๋ค.
- ๋ฌธ์ฅ ๊ตฌ์กฐ์ ์ฝ๋ ์คํ์ผ์ ์ผ๊ด์ฑ์ ์ ์งํ์ฌ ๊ฐ๋ ์ฑ์ด ๋์ ์ฝ๋๊ฐ ๋๋๋ก ํ๋ค.
- ์ฝ๊ธฐ ์ฝ๊ณ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ ์ฝ๋๋ฅผ ์ต์ฐ์ ์ผ๋ก ํ๋ค.
- ์ค์ธ๋ถ์ธ์ด๋ ๊ตฐ๋๋๊ธฐ ์๋ ๊ฐ๊ฒฐํ ์ฝ๋๊ฐ ๋๋๋ก ํ์ด๋ค.
- ์ฝ๋๋ง์ผ๋ก ํํํ์ง ๋ชปํ๋ ๋งฅ๋ฝ์ ์ฃผ์์ ์ถ๊ฐํ์ฌ ์ดํด๋ฅผ ๋๋๋ค.
- ์ค๋ฐ๊ฟ๊ณผ ๋ค์ฌ์ฐ๊ธฐ๋ฅผ ์ ์ ํ ์ฌ์ฉํ์ฌ ๋ฌธ์ฅ์ด ์๋ฏธ ๋จ์๋ก ์ฝํ ์ ์๋๋ก ๋ง๋ ๋ค.
- ๋ค์ฌ์ฐ๊ธฐ๋ ํญ์ด ์๋ ๊ณต๋ฐฑ์ ์ด์ฉํ๋ฉฐ 2์นธ ๋ค์ฌ์ฐ๊ธฐ๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ํ๋ค.
- ๋ฌธ์ฅ(statement)์ ๊ฐ ์ (clause)์ ์๋ก์ด ๋ผ์ธ์์ ์์ํ๋ฉฐ ๊ฐ ์ ์ ์์ ํค์๋๊ฐ ์ค๋ฅธ์ชฝ ์ ๋ ฌ์ด ๋๋๋ก ํ๋ค.
DDL(Data Definition Language) ๋ฌธ์ ์์ธ์ ์ผ๋ก ์ผ์ชฝ์ผ๋ก ์ ๋ ฌ์ํจ๋ค.
- ์ค๋ฐ๊ฟ์ด ์ง๋์ณ ์ข๊ณ ๊ธธ์ญํ (skinny) ๊ตฌ์กฐ๊ฐ ๋๋ ๊ฒฝ์ฐ ์ฐ๊ด๋ ์ฝ๋ ๋ญ์น๋ฅผ ํ๋์ ๋ผ์ธ์ผ๋ก ํฉ์น ์ ์๋ค.
- ๋ฐ๋๋ก ํ ๋ผ์ธ์ ๊ธธ์ด๊ฐ 80 ๊ธ์ ๋ด์ธ์ ์์ผ ๋ฒ์๋ฅผ ๋์ด์๋ ๊ฒฝ์ฐ ๊ฐ๋ก๋ก ์ง๋์น๊ฒ ๊ธธ์ด์ง์ง (flat and wide) ์๋๋ก ์ค๋ฐ๊ฟ์ ํตํด ์ ์ ํ ํญ์ ์ ์งํ๋ค.
- ์ธ์ด์์ ์ ๊ณตํ๋ ์ฅ์น๋ค์ ์ด์ฉํ์ฌ ๋ฐ๋ณต์ ์ต์ํํ๋ค. ๊ณตํต ํ
์ด๋ธ ํํ์
CTE(Common Table Expression)๊ณผ ์ฌ์ฉ์ ์ ์ ํจ์UDF(User Defined Function)๋ฑ์ ์ฝ๋์ ๋ชจ๋ํ๋ฅผ ๋๋ ์ฅ์น๋ค๋ก ์ค๋ณต์ ์ ๊ฑฐํ๋๋ฐ ์ ์ฉํ๋ค.
SQL ๋ฌธ์ฅ์ ์๋์ ๊ฐ์ด ์ธ๋ถํํ ์ ์๋ค. ๊ฐ ๋ฌธ์ฅ์ ๋ํด ์คํ์ผ ๊ฐ์ด๋๋ฅผ ์ ์ฉํ ์์๋ค์ ๋ช๊ฐ์ง ์ดํด๋ณด๋๋ก ํ์.
SELstatement -SELECTDDL(Data Definition Language) statement -CREATE,ALTER,DROPDML(Data Manipulation Language) statement -INSERT,UPDATE,DELETE,TRUNCATE,MERGEDCL(Data Constraint Language) statement - BigQuery์์๋ Data Constraint Language ๊ตฌ๋ฌธ๋ฅผ ์ง์ํ์ง ์๋๋ค.
SELECT๋ DML์ ํ ์ข
๋ฅ์ด์ง๋ง ๋ค๋ฅธ DML ๋ฌธ๊ณผ ๋ฌ๋ฆฌ ํ
์ด๋ธ์ ๋ด์ฉ์ ๋ณ๊ฒฝํ์ง ์๋๋ค๋ ์ ์์ ๊ตฌ๋ถ๋๊ธฐ๋ ํ๋ค.
SELECTstatement ์์
๋ณธ ๊ฐ์ด๋๋ SELECT ๋ฌธ์ฅ์ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ฑํ๋ ํค์๋๋ ๋๋ฌธ์๋ก ์ค๋ฅธ์ชฝ ์ ๋ ฌ์ ์ํค๊ณ , ๋น์ฆ๋์ค ๋ก์ง์ ์๋ฌธ์๋ฅผ ์์ฃผ๋ก ์ผ์ชฝ ์ ๋ ฌ์์ผ ๋ฌธ์ฅ์ ๊ตฌ์กฐ(Syntax)์ ์๋ฏธ(Semantics)๊ฐ ๊ตฌ๋ถ๋๋๋ก ํ๊ณ ์๋ค.
/* ๊ฐ ์ ์ ์์ ํค์๋์ธ SELECT, FROM, LEFT, WHERE, GROUP ๋ฑ์ ์ค๋ฅธ์ชฝ ์ ๋ ฌ */
SELECT station_id,
name,
status,
latitude, longitude, -- ์ฐ๊ด ์ปฌ๋ผ๋ค์ ๊ฐ์ ๋ผ์ธ์ ๋์ดํ๋ ๊ฒ๋ ๊ฐ๋ฅ
ST_DISTANCE(
ST_GEOGPOINT(longitude, latitude), ST_GEOGPOINT(-0.118092, 51.509865)
) AS distance_from_city_centre,
COUNT(1) AS cnt,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations` s
LEFT JOIN `bigquery-public-data.austin_bikeshare.bikeshare_trips` t
ON s.station_id = t.start_station_id
WHERE s.status IN ('active')
AND s.latitude > 15.0
GROUP BY 1, 2, 3, 4, 5
HAVING cnt > 1
LIMIT 1000
;DDLstatement ์์
DDL๋ฌธ์ SEL ๋ฌธ์ฅ๊ณผ ๋ฌ๋ฆฌ ์์ ํค์๋๋ฅผ ์ผ์ชฝ์ผ๋ก ์ ๋ ฌ์ ์ํจ๋ค.
-- https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#creating_a_new_table
CREATE TABLE my_dataset.new_table (
x INT64 OPTIONS (description = 'An optional INTEGER field'),
y STRUCT<
a ARRAY<STRING> OPTIONS (description = 'A repeated STRING field'),
b BOOL
>,
)
PARTITION BY _PARTITIONDATE
OPTIONS (
expiration_timestamp = TIMESTAMP '2025-01-01 00:00:00 UTC',
partition_expiration_days = 1,
description = 'a table that expires in 2025, with each partition living for 24 hours',
labels=[("org_unit", "development")]
)
;-- https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#examples_6
ALTER TABLE mydataset.mytable
SET OPTIONS (
expiration_timestamp = TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 7 DAY),
description = "Table that expires seven days from now"
)
;DMLstatement ์์
-- https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax#insert_using_explicit_values
INSERT dataset.Inventory (
product,
quantity
)
VALUES ('top load washer', 10),
('front load washer', 20),
('dryer', 30),
('refrigerator', 10),
('microwave', 20),
('dishwasher', 30),
('oven', 5)
;-- https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax#update_using_joins
UPDATE dataset.Inventory
SET quantity = quantity + (
SELECT quantity
FROM dataset.NewArrivals
WHERE Inventory.product = NewArrivals.product
),
supply_constrained = false
WHERE product IN (SELECT product FROM dataset.NewArrivals)
;
UPDATE dataset.Inventory i
SET quantity = i.quantity + n.quantity,
supply_constrained = false
FROM dataset.NewArrivals n
WHERE i.product = n.product
;-- https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax#merge_examples
MERGE dataset.DetailedInventory T
USING dataset.Inventory S
ON T.product = S.product
WHEN NOT MATCHED AND quantity < 20 THEN
INSERT (product, quantity, supply_constrained, comments)
VALUES (
product, quantity, true,
ARRAY<STRUCT<created DATE, comment STRING>>[
(DATE('2016-01-01'), 'comment1')
]
)
WHEN NOT MATCHED THEN
INSERT (product, quantity, supply_constrained)
VALUES (product, quantity, false)์ด ์ฅ์์๋ ๋ฌธ์ฅ์ ์ด๋ฃจ๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋จ์์ธ ํค์๋์ ์๋ณ์ ์ด๋ฆ์ ๋ํ ๋ด์ฉ์ ๋ค๋ฃฌ๋ค.
์๋ณ์(identifier)๋ ๋ฌธ์ฅ๋ด์์ ์ ์ผํ๊ฒ ๊ตฌ๋ณ๋์ด ์ธ์๋๋ ์ด๋ฆ์ผ๋ก ์๋ ํญ๋ชฉ๋ค์ ํฌํจํ๋ค.
- ์ธ์ด์ ๋ฌธ๋ฒ๊ตฌ์กฐ๋ฅผ ๊ธฐ์ ํ๋ ํ ํฐ(token) - ex.
SELECT,JOIN,FROM, ... - ํ ์ด๋ธ, ์ปฌ๋ผ์ ๋ช ์นญ์ด๋ ๋ณ์นญ(alias)
- ๊ธฐ๋ณธ ์ ๊ณต ํจ์ ๋๋ ์ฌ์ฉ์ ์ ์ ํจ์ ์ด๋ฆ - ex.
SUM(),STRPOS(), ...
ํค์๋(keyword) ๋ ์์ฝ๋ ์๋ณ์(reserved identifier) ๋ก์ SQL ๋ช ์ธ์ ์ํด ๊ทธ ์ฐ์์ด ์ด๋ฏธ ์ ํด์ ธ ์๋ ์ด๋ฆ์ ๋งํ๋ค.
๋ณธ ๊ฐ์ด๋์์๋ ์๋ ์์ ๋ ๊ด๋ก์ ๋ฐ๋ผ ์ด๋ฆ์ ์ ์ํ๊ณ ํ๊ธฐํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
- ํค์๋๋ ๋๋ฌธ์๋ก ๊ทธ ์ธ์ ์๋ณ์๋ ์๋ฌธ์๋ก ์์ฑํ๋๋ก ํ๋ค.
- ์ฌ๋ฌ ๋จ์ด๋ก ์ด๋ฃจ์ด์ง ์๋ณ์๋
camelCase๊ฐ ์๋snake_case์ ํํ๋ก ์์ฑํ ๋ก ํ๋ค. - ๊ธฐ๋ณธ ์ ๊ณต ํจ์ ํน์ ๋ด์ฅ ํจ์(built-in function)๋ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์์ผ๋ ๋๋ฌธ์๋ก ์์ฑํ๋ ๊ฒ์ ๊ธฐ๋ณธ์ผ๋ก ํ๋ค.
- ์ฌ์ฉ์ ์ ์ ํจ์(UDF, user-defined function)๋ ์๋ฌธ์๋ฅผ ์ฌ์ฉํ์ฌ ํจ์ ์ด๋ฆ์ ์ ์ํ๋๋ก ํ๋ค. UDF ์ด๋ฆ์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ๋ค.
์์ ๊ด๋ก์ ๋ฐ๋ฅธ ์์๋ ๋ค์๊ณผ ๊ฐ๋ค.
๐ ๊ถ์ฅ (recommend)
SELECT first_name, last_name FROM my_dataset.my_table๐ ๊ธฐํผ (avoid)
select firstName, lastName from myDataset.myTable -- camel case ์ฌ์ฉ
-- OR
SELECT FIRST_NAME, LAST_NAME FROM MY_DATASET.MY_TABLE๋ด์ฅ ํจ์์ ๋ฌ๋ฆฌ ์ฌ์ฉ์ ์ ์ ํจ์์ ์ด๋ฆ์ ์๋ฌธ์๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ๋ค.
์ฌ์ฉ์ ์ ์ ํจ์๋ฅผ ์์ ํจ์ (persistent function) ๋ก ์ ์ํ๋ ๊ฒฝ์ฐ ๋ฐ์ดํฐ์ ์ด๋ฆ์ ํฌํจํ ํ์ ๋ ํจ์ ์ด๋ฆ (qualified function name)์ ์ฌ์ฉํด์ผ ํ๋ค. ์ด๋ ํจ์๋ฅผ ํ์ ์ํค๊ธฐ ์ํด ์ฌ์ฉํ๋ ํ๋ก์ ํธ ์ด๋ฆ์ด๋ ๋ฐ์ดํฐ์ ์ ์ด๋ฆ์ด ์๋ฌธ์๋ก ์์ฑ๋๊ธฐ ๋๋ฌธ์ ํ๋์ ์๋ฏธ ๋จ์๋ด์์ ๋์๋ฌธ์๊ฐ ํผ์ฉ๋์ง ์๊ฒ ํ๊ธฐ ์ํด์์ด๋ค.
์ด๋ฅผ ํตํด ์๋์ ์ค๋ช ํ FQTN (Fully Qualified Table Name) ํ ์ด๋ธ ์ด๋ฆ ๊ท์น๊ณผ์ ์ผ๊ด์ฑ๋ ์ ์งํ ์ ์๋ค.
-- ์์ ํ์ ๋ ํจ์ ์ด๋ฆ์ ์ - fully qualified function name
SELECT bqutils.fn.last_day('2021-03-07')๋์๋ฌธ์์ ๊ตฌ๋ถ์ ๋ฌธ์ฅ๋ด์์ ๊ฐ ์ด๋ฆ์ด ์ ์ญํ ์ ๋๋ฌ๋ด๋๋ก ํ๋๋ฐ ๋์์ ์ค๋ค.
๋๋ฌธ์ SELECT, FROM ๋ฑ์ ํค์๋๋ ์ฃผ๋ก ๋ฌธ์ฅ ๊ตฌ์กฐ์ ํํ์ ์ฌ์ฉ๋๋๋ฐ ์๋ฌธ์๋ก ํ๊ธฐ๋๋ ๊ฐ์ฒด(entity)๋ ์์ฑ(attribute)์ ์๋ณ์ ์ด๋ฆ๊ณผ ์๊ฐ์ ์ผ๋ก ๊ตฌ๋ถ์ด ๋๋ค. ์ด๋ ์ ์ฒด์ ์ธ ๋ฌธ์ฅ ๊ตฌ์กฐ์ ํ์
์ ์ฉ์ดํ๊ฒ ํ๋ค.
- ํค์๋๊ฐ ๋ถ๋์ดํ๊ฒ ์ปฌ๋ผ์ ์ด๋ฆ์ผ๋ก ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ backtick(`)์ ์ด์ฉํ์ฌ ๊ฐ์ธ์ค๋ค (quoted identifiers).
-- from ์์ฝ์ด๊ฐ ์ปฌ๋ผ๋ช
์ผ๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
SELECT 'asia-northeast3' AS `from` FROM ...- ๋ฌธ์์ด ๋ฆฌํฐ๋ด(string literal)์ ์์๋ฐ์ดํ(')๋ฅผ ์ฌ์ฉํ๋ค.
- ์์(constant)๊ฐ์ ๊ฐ๋ ๋ณ์ ์ด๋ฆ์ ๋๋ฌธ์๋ก ํ๋ค.
DECLARE START_DATE DATE DEFAULT '2021-02-19'์ปฌ๋ผ์ด๋ฆ์ camelCase๊ฐ ์๋ ์๋ฌธ์๋ฅผ ์ด์ฉํ์ฌ snake_case ๋ก ํํํ๋ฉฐ ํ๊ฐ๋ฆฌ์ธ ํ๊ธฐ ๋ ์๋ฏธ๋ฅผ ์ ์ถํ๊ธฐ ํ๋ ์ง๋์น๊ฒ ์ถ์ฝ๋ ์ ๋์ด(prefix), ์ ๋ฏธ์ด(suffix)์ ์ฌ์ฉ์ ์์ ํ๋ค.
๊ธฐ์ค์ ๋ณด์ ๊ฐ์ด ํ๋ด์์ ํ์ค์ผ๋ก ๊ด๋ฆฌ๋๋ ์์ฑ๋ค์ด ์๋ ๊ฒฝ์ฐ์๋ ํด๋น ํ์ค์์ ์ ์๋ ๋ช ๋ช ๊ท์น์ ์ฐ์ ํ๋ค. ์๋ฅผ ๋ค์ด, ๊ตญ๊ฐ์ฝ๋๋ฑ ๊ธฐ์ค์ ๋ณด๋ก ์ฌ์ฉ๋๋ ์ปฌ๋ผ์ ์ด๋ฆ์ ํ์ค์์ ์ ์๋ ๋ช ๋ช ๊ท์น์ ์ฐจ์ฉํด์ ์ฌ์ฉํ๋๋ก ํ๋ค.
SELECT cnty_cd, mcc, mnc, csc, FROM ...๋ฐฐ์ดํ์ด๋ ๋ณต์์ ์๋ฏธ๋ฅผ ์ง๋๋ ์ปฌ๋ผ์ธ ๊ฒฝ์ฐ๋ ์ด๋ฆ์ ๋ณต์ํ์ผ๋ก ํ ์ ์๋ค.
SELECT hits, -- ARRAY<STRUCT<>> ํ
totals.visits, -- INT64ํ, ์ด ์ธ์
ํ์
totals.hits, -- INT64ํ, ์ธ์
๋ด ์กฐํ์
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
;์ ๋์ด๋ ์ ๋ฏธ์ด๋ ์ด๋ฆ์ ๋ถ๊ฐ์ ์ธ ์๋ฏธ(semantics)๋ฅผ ๋ถ์ฌํ๊ธฐ ์ํ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ๋ ์ง๋์น๊ฒ ์ถ์ฝ๋ ์ฝ์ด๋ ๊ณผ๋ํ ์ฌ์ฉ์ ์คํ๋ ค ๊ฐ๋ ์ฑ์ ๋จ์ด๋จ๋ฆด ์ ์์ด ์ฌ์ฉ์ ์ ์คํด์ผ ํ๋ค.
์๋๋ ๋ช๊ฐ์ง ์ฌ์ฉ ๊ฐ๋ฅํ ์์์ด๋ค.
- Boolean ํ์ ๊ฒฝ์ฐ
is_,has_์ ๊ฐ์ ์ ๋์ด๋ฅผ ์ฌ์ฉํ ์ ์๋ค. - Dateํ์
_dt์ ๋ฏธ์ด๋ฅผ ๋ถ์ผ ์ ์๋ค. - DateTime์ด๋ Timestampํ์
_at์ ๋ฏธ์ด๊ฐ ๊ฐ๋ฅํ๋ค. user_id,device_id์ฒ๋ผ ์๋ณ์(id) ์ ๋ฏธ์ด์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
SELECT is_active,
registered_dt,
updated_at,
FROM ...์ปฌ๋ผ์ ๋ณ์นญ ์ด๋ฆ์ ์ปฌ๋ผ ์ด๋ฆ ๊ธฐ๋ณธ ๊ฐ์ด๋์ ์คํ์ฌ ์์ฑํ๋ค. ๋ณ์นญ ์์ AS ํค์๋ ๋ ์๋ต ๊ฐ๋ฅํ๋ ๋ณธ ๊ฐ์ด๋์์๋ ๋ช
์์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ๊ธฐ๋ณธ์ผ๋ก ํ๋ค.
๋ณ์นญ์ ๋ชฉ์ ์ ๋ฐ๋ผ์ ์ปฌ๋ผ ์ด๋ฆ๋ณด๋ค ์์ธํ ์์ฑ๋๋ ๊ฒฝ์ฐ๋ ์๊ณ ๋ฐ๋๋ก ๊ฐ๋ตํ๊ฒ ์ถ์ฝ๋ ํํ๋ก ์ฌ์ฉํ๊ธฐ๋ ํ๋ค.
์ปฌ๋ผ์ ์๋ฏธ๋ฅผ ๋ช ํํ ํ๊ธฐ ์ํด์ ์๋์ ๊ฐ์ด ๊ธด ์ด๋ฆ์ ๋ณ์นญ์ ์ฌ์ฉํ ์ ์๋ค.
SELECT fname AS first_name,
lname AS last_name,
FROM ...๋ฐ๋ฉด์ ์ปฌ๋ผ ์ด๋ฆ์ด ์ ๋๋ ์ปฌ๋ผ(derived column) ๋๋ ๊ณ์ฐ๋ ์ปฌ๋ผ(calculated column)์ ๋ง๋ค์ด ๋ด๋ ์ฐ์ฐ์์์ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉ๋์ด์ง๋ ๊ฒฝ์ฐ๋ ๊ฐ๊ฒฐํจ์ ์ํด์ ์ถ์ฝ๋ ์ด๋ฆ์ ์ฌ์ฉํ๊ธฐ๋ ํ๋ค.
๐ ๊ธฐํผ (avoid)
WITH locations AS (
SELECT x_position,
y_position,
city_centre_x_position,
city_center_y_position,
FROM ...
)
SELECT SQRT(
(city_center_x_position - x_position) * (city_center_x_position - x_position) +
(city_center_y_position - y_position) * (city_center_y_position - y_position)
) AS distince, -- calculated(or derived) column
FROM locations์์ ์์๋ ํ ์ด๋ธ์ด ๊ฐ์ง๋ ๊ธฐ๋ณธ ์ปฌ๋ผ (base column) ์ผ๋ก๋ถํฐ ์๋ก์ด ์ปฌ๋ผ์ ํ์์ํค๋ ์ฐ์ฐ์์ ์ปฌ๋ผ ์ด๋ฆ์ด ๋ฐ๋ณต์ ์ผ๋ก ๋ฑ์ฅํ์ฌ ๋ผ์ธ์ด ๊ธธ์ด์ง๊ณ ์๋ค. ์ด๋ฅผ ์๋์ ๊ฐ์ด ์ถ์ฝ๋ ๋ณ์นญ์ ์ฌ์ฉํ์ฌ ์ฐ์ฐ์์ ๊ฐ๊ฒฐํ๊ฒ ํํํ ์ ์๋ค.
๐ ๊ถ์ฅ (recommend)
WITH location AS (
SELECT x_position AS x,
y_position AS y,
city_centre_x_position AS cx,
city_center_y_position AS cy,
FROM ...
)
SELECT SQRT((cx - x) * (cx - x) + (cy - y) * (cy - y)) AS distince,
FROM locationํ ์ด๋ธ ์ด๋ฆ์ ์๋ฌธ์ ์ฌ์ฉ์ ๊ธฐ๋ณธ์ผ๋ก ํ๋ ์๊ตฌ ํ ์ด๋ธ(permanent table)์ ๋ํ ํ๋ด ๋ช ๋ช ๊ท์น์ด ๋ณ๋๋ก ์ ํด์ ธ ์๋ ๊ฒฝ์ฐ ๊ทธ๊ฒ์ ์ฐ์ ํ๋ค.
๋ค๋ง, ์์ํ ์ด๋ธ(temporary table)์ด๋ ๊ณตํต ํ ์ด๋ธ ํํ์(CTEs) ์ด๋ฆ์ ๊ฒฝ์ฐ๋ ์๋ฌธ์๋ฅผ ์ฌ์ฉํ๋๋ก ํ๋ค. ํ ์ด๋ธ ์ด๋ฆ์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ๋ค.
- ์ฌ๋ ๊ฐ์ ๋จ์ด๋ฅผ ์กฐํฉํ์ฌ ์ด๋ฆ๋ฅผ ์ง์ ๊ฒฝ์ฐ dash(-)๊ฐ ์๋ underscore(_)๋ฅผ ์ฌ์ฉํ์ฌ snake_case ์ด๋ฆ์ด ๋๋๋ก ํ๋ค.
- ๊ณผ์ ๋ณ ๋ช ๋ช ๊ท์น์ ์ํด ์ด๋ฏธ ์์ฑ๋์ด ์ด์๋๊ณ ์๋ ๋ฐ์ดํฐ์ ๊ณผ ํ ์ด๋ธ ์ด๋ฆ๋ค์ ๊ฐ์ด๋์ ๊ถ๊ณ ๋ฅผ ๋ฐ๋ฅด์ง ์๋๋ผ๋ As-Is ์ด๋ฆ์ ๊ทธ๋๋ก ์ฌ์ฉํ ๋ก ํ๋ค.
โ Fully Qualified Table Name (FQTN)
'์์ ํ๊ฒ ํ์ ๋ ํ ์ด๋ธ ์ด๋ฆ ๋๋ ์ ๊ทํ๋ ํ ์ด๋ธ ์ด๋ฆ'์ ์๋ฏธ๋ ๊ทธ ์ด๋ฆ์ ๊ฐ์ง๊ณ ์คํ์ปจํ ์คํธ์ ์๊ด์์ด ์ ์ผํ๊ฒ ํ ์ด๋ธ๋ฅผ ํน์ ํ ์ ์๋ค๋ ๋ง์ด๋ค. ์๋ฅผ ๋ค์ด,
customer.devices๋ผ๋ ์ผ๋ถ ํ์ ๋ ํ ์ด๋ธ ์ด๋ฆ ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ฟผ๋ฆฌ๊ฐ ์คํ๋๋ ํ๋ก์ ํธ์ ๋ฐ๋ผ ๊ฐ๊ธฐ ๋ค๋ฅธcustomer.devicesํ ์ด๋ธ์ ์ ๊ทผ๋ ์ ์๋ค.
BigQuery๋ก DWH(Data Ware House)๋ฅผ ๊ตฌ์ถํ๋ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋ ํ๋ก์ ํธ์ BigQuery Job์ ์คํ์์ผ์ฃผ๋ ํ๋ก์ ํธ๊ฐ ๋ค๋ฅผ ์ ์๊ธฐ ๋๋ฌธ์ ์คํ์ปจํ ์คํธ์ ์ํฅ์ ๋ฐ์ง ์๋๋ก ์ ๊ทํ๋ ํํ์ ํ ์ด๋ธ ์ด๋ฆ์ ์ฌ์ฉํ๋๋ก ํ๋ค. ํ ์ด๋ธ ์ด๋ฆ์ ํ๋ก์ ํธ ๋ช ์ ์๋ตํ๋ ๊ฒฝ์ฐ BigQuery Job ์ด ์ํ๋๊ณ ์๋ ํ๋ก์ ํธ ์ด๋ฆ์ ์๋ฌต์ ์ผ๋ก ์ฌ์ฉํ๋ค.
์ด์ธ์, ๋จ์ผ ๋ฌธ์ฅ(single statement)์ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ BigQuery ์คํฌ๋ฆฝํธ(script)๋ก ๋ณต์์ ๋ฌธ์ฅ(multiple statements)์ ์คํํ๋ ๊ฒฝ์ฐ์๋ GCP Project ์ด๋ฆ์ ํฌํจ๋ dash(-)๊ฐ ๋บ์ ๋ฑ์ ๋ค๋ฅธ ์๋ฏธ๋ก ํด์์ด ๋์ง ์๋๋ก ์ ๊ทํ๋ ํ ์ด๋ธ ์ด๋ฆ ์ backtick(`)์ ์ฌ์ฉํ์ฌ ๊ฐ์ธ์ค๋ค.
์ด๋ dash๊ฐ ํฌํจ๋ ํ๋ก์ ํธ ์ด๋ฆ๋ง backtick์ผ๋ก ๊ฐ์ธ์ฃผ์ด๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง๋ ์์ผ๋ FQTN ์ ์ฒด๋ฅผ backtick์ ๊ฐ์ธ์ฃผ์ด ์๋ฏธ์ ์ผ๋ก ํ๋์ ๋จ์์์ ๋ช ์์ ์ผ๋ก ๋ํ๋ด๋๋ก ํ๋ค.
๐ ๊ถ์ฅ (recommend)
SELECT * FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`๐ ๊ธฐํผ (avoid)
SELECT * FROM `bigquery-public-data.austin_bikeshare`.bikeshare_stations
-- or
SELECT * FROM `bigquery-public-data.austin_bikeshare`.`bikeshare_stations`
-- or
SELECT * FROM `bigquery-public-data`.`austin_bikeshare`.`bikeshare_stations`๋ณํ(*)๋ฅผ ํฌํจํ๋ ์์ผ๋์นด๋(wildcard) ํ
์ด๋ธ ์ด๋ฆ๋ backtick(`)์ผ๋ก ๊ฐ์ธ์ฃผ์ด์ผ ํ๋ค.
/* Valid standard SQL query with wildcard table name*/
SELECT max
FROM `bigquery-public-data.noaa_gsod.gsod*`
WHERE max != 9999.9 # code for missing data
AND _TABLE_SUFFIX = '1929'
ORDER BY max DESC
;โ ์ฃผ์
ํ ์ด๋ธ ์ด๋ฆ์ด ๋ฐ์ดํ๋ก ๋ฌถ์ธ ์๋ณ์(quoted identifier)์ธ ๊ฒฝ์ฐ ์ฐธ์กฐ(reference)์ ๋ฌถ์ ๋จ์๋ก ์ฌ์ฉํด์ผ ํ๋ค. ์ฌ๋ฌ ํ ์ด๋ธ์ ๋ค๋ฃจ๋ JOIN ๊ตฌ๋ฌธ์์ ์๋์ ๊ฐ์ด ํ ์ด๋ธ์ ์ฐธ์กฐํ ๊ฒฝ์ฐ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
-- Error
SELECT *
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
JOIN `bigquery-public-data.san_francisco.bikeshare_trips`
ON bikeshare_stations.station_id = bikeshare_trips.start_station_idUnrecognized name: bikeshare_stations
์ด๋ FQTN ์ ์ฒด๊ฐ ๋ฐ์ดํ๋ก ๋ฌถ์ธ ์๋ณ์์ฌ์ ํ๋์ ๋ฌถ์์ผ๋ก ์ฐธ์กฐ๋์ด์ผ ํ๊ณ ๋ฌถ์ ์์ ํ ์ด๋ธ ์ด๋ฆ์ ๋ฐ๋ก ๊บผ๋ด ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
FQTN ์ ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ์๋ ์ฟผ๋ฆฌ๋ ์ ์ ์ํ๋๋ ๋ณด๊ธฐ์ ์ข์ ์ฝ๋๋ ์๋๋ค.
-- working but looks ugly
SELECT *
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
JOIN `bigquery-public-data.san_francisco.bikeshare_trips`
ON `bigquery-public-data.austin_bikeshare.bikeshare_stations`.station_id =
`bigquery-public-data.san_francisco.bikeshare_trips`.start_station_id์ด๋ฐ ๊ฒฝ์ฐ ํ ์ด๋ธ ๋ณ์นญ(alias)๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํ๋ก ๋ฌถ์ธ FQTN ์ด ์๋ ๋ณ์นญ์ ์ฐธ์กฐํ๋๋ก ํ์ฌ ํ ์ด๋ธ ์ด๋ฆ ์ง๊ธฐ ์ง์นจ์ ๋ฐ๋ฅด๋ฉด์๋ ๊ฐ๊ฒฐํจ์ ์ ์งํ ์ ์๋ค.
SELECT *
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations` s
JOIN `bigquery-public-data.san_francisco.bikeshare_trips` t
ON s.station_id = t.start_station_idSQL ๋ฌธ๋ฒ์ ์ ์๋ ํค์๋๋ค๊ณผ ์์์ ๋ช ๋ช ๊ท์น์ ์ํด ์ง์ด์ง ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ๊ฐ ๊ตฌ์ ์ ๊ธฐ์ ํ๊ณ ์ด๋ฅผ ๋ธ๋ญ์ฒ๋ผ ์์ ๋ฌธ์ฅ์ผ๋ก ๊ตฌ์กฐํํด ๋ณด๋๋ก ํ๋ค.
SQL์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ SELECT ๋ฌธ์ฅ์ ์ปฌ๋ผ ๋ฆฌ์คํธ๋ ์๋์ ์ง์นจ์ ๋ฐ๋ผ ์์ฑํ๋ค.
SELECT๋ฆฌ์คํธ์ ๋ฑ์ฅํ๋ ์ปฌ๋ผ์ด ๋ณต์๊ฐ์ผ ๊ฒฝ์ฐ ํ ๋ผ์ธ์ ํ๋์ฉ ์์ฑํ๋ ๊ฒ์ ๊ธฐ๋ณธ์ผ๋ก ํ๋ค.SELECT *๋ก ์ ์ฒด ์ปฌ๋ผ์ ๊ฐ์ ธ์ค๊ธฐ ๋ณด๋ค๋ ํ์ํ ์ปฌ๋ผ๋ง์SELECT๋ฆฌ์คํธ์ ์ด๊ฑฐํ๋๋ก ํ๋ค.
SELECT station_id,
name,
status,
latitude,
longitude,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`- ์ผ๋ถ ์ปฌ๋ผ์ ์ ์ธํ ์ ์ฒด ์ปฌ๋ผ์ด ํ์ํ ๊ฒฝ์ฐ๋ EXCEPT ๊ตฌ๋ฌธ์ ํ์ฉํ๋ค.
SELECT * EXCEPT(latitude, longitude)
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`- ์๋ฏธ์ ์ผ๋ก ๊ด๋ จ์ด ์๊ฑฐ๋ ์์ผ ๋ฒ์๋ด์์ ํ ๋์ ์ฝํ๊ณ ์ดํด๋ ์ ์๋ค๋ฉด 80์๋ฅผ ๋์ง ์๋ ์ ์์ ํ๋์ ๋ผ์ธ์ ๋ณต์์ ์ปฌ๋ผ๋ค์ ๊ธฐ์ ํ ์ ์๋ค.
- ์ฃผ์์ ์ฌ์ฉํ์ฌ ์ปฌ๋ผ์ ์๋ฏธ๋ฅผ ๋ถ์ฐ ์ค๋ช ํ ์ ์๋ค.
- ๋ง์ง๋ง ์ปฌ๋ผ๋ช ์ ๋ค์ ์ฝค๋ง(,)๋ฅผ ์ถ๊ฐํ๋ค.
SELECT station_id,
name,
status,
latitude, longitude, -- ํ๋์ ์ปฌ๋ผ ๋ญ์น(Column Family)๋ก ์๋ฏธ์ ์ผ๋ก ๋ฌถ์
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
;
-- ๋๋
SELECT station_id, name, status, latitude, longitude,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
;- ์ปฌ๋ผ ๋ณ์นญ(alias)์ ํฌํจํ๋ ๊ฒฝ์ฐ์๋ ์์ ๋ด์ฉ๋ค์ด ๋์ผํ๊ฒ ์ ์ฉ๋๋ค.
- ์ปฌ๋ผ ๋ณ์นญ์
ASํค์๋ ๋ค์์ ์์น์ํค๋ฉฐ ๋ณ์นญ์ ์์ ์์น๋ ๋ฐ๋ก ์ ๋ ฌ์ํค์ง ์๋๋ค.
๐ ๊ถ์ฅ (recommend)
SELECT station_id AS station_id,
name AS station_name,
status AS bike_status,
latitude,
longitude,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`๐ ๊ธฐํผ (avoid)
SELECT station_id AS station_id,
name AS station_name,
status AS bike_status,
latitude,
longitude,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`BigQuery์์๋ SELECT ๋ฆฌ์คํธ์ ๋ง์ง๋ง ์ปฌ๋ผ ๋ค์ ์ฝค๋ง(,)๋ฅผ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ณธ ๊ฐ์ด๋์์๋ ๋ค๋ฐ๋ฅด๋ ์ผํ๋ฅผ ์ฌ์ฉํ๋ค.
๐ ๊ถ์ฅ recommend
SELECT station_id,
name,
status,
latitude,
longitude, -- ๋ง์ง๋ง ์ปฌ๋ผ ๋ค ์ฝค๋ง(,) ์ถ๊ฐ
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`๐ ๊ธฐํผ avoid
SELECT station_id
, name
, status
, latitude
, longitude
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`๋ค๋ฐ๋ฅด๋ ์ผํ๋ฅผ ์ง์ํ์ง ์๋ SQL ์ธ์ด์์๋ ์์ ์ผํ๋ฅผ ์ฌ์ฉํด์ SELECT ๋ฆฌ์คํธ์ ์๋ก์ด ์ปฌ๋ผ์ ์ถ๊ฐํด๋ ์ง์ ๋ผ์ธ์ ์ํฅ์ ์ฃผ์ง ์๋๋ก ํ์์ผ๋ BigQuery์์๋ ๋ค๋ฐ๋ฅด๋ ์ผํ๋ฅผ ์ง์ํ๋ฏ๋ก ์ด๋ฅผ ๊ธฐ๋ณธ ์คํ์ผ๋ก ์ผ๋๋ค.
-- ๋ค๋ฐ๋ฅด๋ ์ผํ ์ฌ์ฉ
SELECT station_id,
name
FROM ...
-- ์ปฌ๋ผ ์ถ๊ฐ์
SELECT station_id,
name, -- ์๋ ๋๋ฌธ์ comma๊ฐ ์ถ๊ฐ๋จ.
status -- ์ ๊ท์ปฌ๋ผ ์ถ๊ฐ
FROM ...-- ์์ ์ผํ ์ฌ์ฉ
SELECT station_id
, name
FROM ...
-- ์ปฌ๋ผ ์ถ๊ฐ์
SELECT station_id
, name -- ์๋ ์ปฌ๋ผ ์ถ๊ฐ๋ก ๋ณ๊ฒฝ๋๋ ๋ด์ฉ์ด ์์
, status -- ์ ๊ท์ปฌ๋ผ ์ถ๊ฐ
FROM ...์ด์ธ์ ๋ฒ์ฉ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ ๋์ (dynamic) SQL์ ์ฌ์ฉํ์ฌ SELECT ๋ฌธ์ ์ปฌ๋ผ ๋ฆฌ์คํธ๋ฅผ ์๋ ์์ฑํ ๋ ๋ค๋ฐ๋ฅด๋ ์ผํ๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ๋ฆฌ์คํธ์ ๋ง์ง๋ง ์ปฌ๋ผ์ ์ผํ๊ฐ ์๋ต๋๋๋ก ์์ธ ์ฒ๋ฆฌํ ํ์๊ฐ ์์ด ๊ตฌํ ๋ก์ง์ด ๋จ์ํด์ง๋ ์ฅ์ ์ด ์๋ค.
- ๊ธฐ๋ณธํค(PK, Primary Key)์ ํด๋นํ๋ ์ปฌ๋ผ๋ช ์ ๋จผ์ ์์น์ํจ๋ค.
- (optional) ํํฐ์ ๋ ํ ์ด๋ธ ์ฌ์ฉ์ ํํฐ์ ์ปฌ๋ผ๋ช ์ ๋ง์ง๋ง์ ์์น์ํจ๋ค. ์ด์์ค์ ์คํค๋ง ๋ณ๊ฒฝ์ผ๋ก ์ธํ ์ปฌ๋ผ ์ถ๊ฐ์๋ ์์ธ๊ฐ ๋๋ค.
GROUP BY๋ฅผ ๋๋ฐํ ์ง๊ณ ์ฟผ๋ฆฌ์์๋ ์ฐจ์(dimension)์ ํด๋นํ๋ ์ปฌ๋ผ๋ช ์ ๋จผ์ ๋์ดํ ํ ์งํ(metric)์ ํด๋นํ๋ ์ปฌ๋ผ๋ช ์ ๊ธฐ์ ํ๋ค.
FROM ์ ์๋ ํ
์ด๋ธ ๋๋ ์ด์ ์์ํ๋ ์๋ธ์ฟผ๋ฆฌ๊ฐ ์์นํ๊ฒ ๋๋ค. ์๋ธ์ฟผ๋ฆฌ์ ๋ํ ๋ํ ์คํ์ผ์ ๋ค์ ์ฅ์์ ๋ค์ ์ธ๊ธํ๋๋ก ํ๋ค.
FROM์ ์SELECT๋ฆฌ์คํธ์ ๋ค์ ๋ผ์ธ์ ์์นํ๋ฉฐ ํ ์ด๋ธ ์ด๋ฆ, ์๋ธ์ฟผ๋ฆฌ ํน์ UNNEST์ ๊ฐ์ ํ ์ด๋ธ ํจ์ ์ด๋ฆ์ดFROMํค์๋์ ์ด์ด ์์ฑ๋๋ค.FROMํค์๋๋SELECTํค์๋์ ์ค๋ฅธ์ชฝ ์ ๋ ฌ(right-aligned)์ด ๋๋๋ก ์์น์ํจ๋ค.
FROMํค์๋ ๋ค์์ ๋ฑ์ฅํ๋ ํ ์ด๋ธ ์ด๋ฆ์ผ๋ก๋ ์๊ตฌ ํ ์ด๋ธ(permanent table)๊ณผ ์์ ํ ์ด๋ธ(temporary table) ์ด๋ฆ ๋๋ CTE(common table expression) ๊ตฌ๋ฌธ์ ์ํด ์ ์๋ ์ด๋ฆ์ ์ฌ์ฉํ ์ ์๋ค.- ์๊ตฌ ํ
์ด๋ธ ์ด๋ฆ์
FQTNํ์์ ์ฌ์ฉํ๋ฉฐ ์์ ํ ์ด๋ธ์ด๋ CTE ์ด๋ฆ์snake_caseํ์์ ์ฌ์ฉํ๋ค. - ์์ ํ ์ด๋ธ์ด๋ CTE ์ด๋ฆ์ ํ ์ด๋ธ์ ์ฌ์ฉ๋ชฉ์ ์ด ๋ช ํํ ๋ค์ด๋๋๋ก ์์ฑํ๋ค.
-- Permanent Table
SELECT *
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`;-- Temporara Table (ex. CTAS ๊ตฌ๋ฌธ์ผ๋ก ์์ํ
์ด๋ธ ์์ฑ)
CREATE TEMP TABLE tmp_table AS SELECT ... ;
SELECT * FROM tmp_table;-- CTEs - named subquery
WITH cte_name AS ( -- snake_case ๊ท์น์ ๋ฐ๋ผ ๊ธฐ์
SELECT ... -- ์ผ์ชฝ ๋์นธ ๋ค์ฌ์ฐ๊ธฐ๋ฅผ ํ๋ค.
FROM ...
)
SELECT * FROM cte_name;ํ
์ด๋ธ ์ด๋ฆ์ด๋ CTE ์ด๋ฆ์ด ์๋ธ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ FROM ์ ์ ๊ตฌ์ฑํ ๊ฒฝ์ฐ์ ์๋์ ๊ฐ์ด ๋ค์ํ ์คํ์ผ์ด ๊ฐ๋ฅํ๋ค. ์ด ๊ฐ์ด๋์์๋ from_style_#2 ๋ฅผ ์ฌ์ฉํ ๊ตฌ์ฑ์ ๊ถ์ฅํ๋ค.
๐ ๊ธฐํผ (avoid)
-- ํ
์ด๋ธ ์๋ธ์ฟผ๋ฆฌ ์คํ์ผ #1 (from_style_#1)
SELECT *
FROM (SELECT station_id,
name,
status
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`)๐ ๊ถ์ฅ (recommend)
-- ํ
์ด๋ธ ์๋ธ์ฟผ๋ฆฌ ์คํ์ผ #2 (from_style_#2)
SELECT *
FROM (
SELECT station_id, -- FROM ํค์๋๋ก๋ถํฐ ๋ ์นธ ๋ค์ฌ์ฐ๊ธฐ
name,
status,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
) -- ๋ซ๋ ๊ดํธ๋ ์์ด ๋๋ ์ฌ๋ ๊ดํธ์ ํค์๋ ์์์ ๊ณผ ๋ผ์ธ์ ๋ง์ถ๋ค.๋ณธ ๊ฐ์ด๋์์ from_style_#2 ๋ฅผ ์ ํธํ๋ ์ด์ ๋ ์๋์ ๊ฐ๋ค. ์ฐ์ ์์ ์ฟผ๋ฆฌ๋ฅผ JOIN์ ์ด์ฉํ์ฌ ํ์ฅํด ๋ณด๋๋ก ํ์.
/* JOIN์ ์ด์ฉํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ํ์ฅํ ์์ */
-- ํ
์ด๋ธ ์๋ธ์ฟผ๋ฆฌ ์คํ์ผ #1 (from_style_#1)
SELECT *
FROM (SELECT station_id,
name,
status
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`) AS a
LEFT JOIN (SELECT station_id,
name,
status
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`) AS b
ON a.station_id = b.station_id
;
-- ํ
์ด๋ธ ์๋ธ์ฟผ๋ฆฌ ์คํ์ผ #2 (from_style_#2)
SELECT *
FROM (
SELECT station_id,
name,
status,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
) AS a
LEFT JOIN (
SELECT station_id,
name,
status,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
) AS b
ON a.station_id = b.station_id
;from_style_#1 ์ ๋์ผํ ์์ค(level or depth)์ ์์นํ ๋ ์๋ธ์ฟผ๋ฆฌ a, b์ ๋ค์ฌ์ฐ๊ธฐ๊ฐ ์๋ก ๋ฌ๋ผ์ ธ ์๋ค. ๋ฐ๋ฉด์ from_style_#2 ์ ๋ ์๋ธ์ฟผ๋ฆฌ๊ฐ ๋์ผํ ๋ค์ฌ์ฐ๊ธฐ๋ฅผ ์ ์งํ๋ฉด์ ๋์์ ํ
์ด๋ธ ๋ณ์นญ(alias)์ ๋ผ์ธ์ ๋์ด ์๋ ์์ชฝ์ ์์นํจ์ผ๋ก์จ ON์ ์์ ์์ ์ ํฌ๊ฒ ์ด๋์ํค์ง ์๊ณ ์๋ ํ์ธ ๊ฐ๋ฅํ๋ค.
WHERE ์ ์๋ FROM ์ ์ ๊ฒฐ๊ณผ๋ฅผ ํํฐ๋งํ๊ธฐ ์ํ ์กฐ๊ฑด์ ๊ธฐ์ ํ๋ค. WHERE ์ ์ ์๋์ ๊ฐ์ด๋์ ๋ฐ๋ผ ์์ฑํ๋ค.
- ๋น๊ต ์ฐ์ฐ์์ ์ ๋ค๋ก ๊ณต๋ฐฑ์ ๋๋๋ก ํ๋ค.
- ๋น๋๋ฑ์ฐ์ฐ์๋
!=์<>๋ชจ๋ ์ฌ์ฉ๊ฐ๋ฅํ๋ค. SQL-1999์์๋<>๋ฅผ ํ์ค์ผ๋ก ์ ์ํ๊ณ ์๋ค. - ์กฐ๊ฑด์ ์
AND์OR๋ ผ๋ฆฌ ์ฐ์ฐ์์ ์ํด ๋ณต์๊ฐ๊ฐ ์ฐ๊ฒฐ(chaining)๋ ์ ์๋ค. - ๋ณต์๊ฐ์ ์กฐ๊ฑด์ ๊ธฐ์ ํ๋ ๊ฒฝ์ฐ๋ ํ๋์ ๋ผ์ธ์ ํ๋์ ์กฐ๊ฑด์ ๊ธฐ์ ํ๋ ๊ฒ์ ๊ธฐ๋ณธ์ผ๋ก ํ๋ ์ฐ๊ด๋ ์กฐ๊ฑด์ ๊ฒฝ์ฐ์๋ 80์๋ฅผ ๋์ง ์๋ ์ ์์ ํ๋์ ๋ผ์ธ์ ๊ฐ์ด ์์ฑ ๊ฐ๋ฅํ๋ค.
AND์OR๋ ผ๋ฆฌ ์ฐ์ฐ์๋WHEREํค์๋์ ์ค๋ฅธ์ชฝ ์ ๋ ฌ์ด ๋๋๋ก ํ๋ค. ๋จ, ํผ์ฉ๋์ด ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ๋ ๋ ผ๋ฆฌ ์ฐ์ฐ์์ ํผ์ฉ (mixed logical operators) ๊ฐ์ด๋๋ฅผ ๋ฐ๋ฅธ๋ค.BETWEEN์ด๋IN์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ณต์๊ฐ์ ์กฐ๊ฑด์ ๋ฌถ์ ์ ์๋ ๊ฒฝ์ฐ๋ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ์กฐ๊ฑด์ ๊ฐ๊ฒฐํ๊ฒ ํํํ๋ค.
SELECT station_id,
name,
status,
latitude, longitude,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
WHERE status = 'active'
AND latitude > 135.0 -- AND ๋ก ์กฐ๊ฑด ์ฐ๊ฒฐ
;ํ
์ด๋ธ ์กฐํ์ AND์ OR๋ฅผ ํผ์ฉํ์ฌ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ ์๋์ ๊ฐ์ด๋์ ๋ฐ๋ผ ์ฝ๋๋ฅผ ๊ตฌ์กฐํํ๋ค.
- ์ฃผ์ด์ง ํ
์ด๋ธ์์
AND์กฐ๊ฑด์ผ๋ก ๊ฒฐ๊ณผ์ (result set)์ ์ค์ฌ๋๊ฐ๋์ง ๋ฐ๋๋กOR์กฐ๊ฑด์ผ๋ก ๋์์ ๋๋ ค๋๊ฐ๋์ง๋ฅผ ๋ณด๊ณ ์ต์์ ์กฐ๊ฑด์ ์ ๊ตฌ์กฐ๋ฅผ ๋จผ์ ํ์ ํ๋ค. - ๊ฐ ์์ ์กฐ๊ฑด๋ค์ด ๋ค์ ์ธ๋ถ์ ์ธ ์กฐ๊ฑด์ผ๋ก ๋๋๋ ๊ฒฝ์ฐ์ ๊ดํธ๋ฅผ ์ด์ฉํ์ฌ ํด๋น ์ธ๋ถ์กฐ๊ฑด์ ๋ฌถ๋๋ค. ๊ดํธ๋ฅผ ํตํด์ ์ฐ์ฐ์ ์ฐ์ ์์์ ๋ฐ๋ฅธ ๋ถ์์ฉ(side effect)์ ์์ค๋ค.
- ์ธ๋ถ ์กฐ๊ฑด์ ๋ฑ์ฅํ๋
AND๋๋OR์ฐ์ฐ์๋ ๋ผ์ธ์ ๋์ ์์น์ํค๋๋ก ํ๋ค. - 3 ๋จ๊ณ ์ด์์ ๊น์ด์์ ๋ ผ๋ฆฌ์ฐ์ฐ์ด ์ด๋ฃจ์ด์ง๋ ๊ฒฝ์ฐ ๋ถ๋ฐฐ ๋ฒ์น์ ์ด์ฉํ์ฌ ๊น์ด๋ฅผ ๋ฎ์ถ ์ ์๋ค.
-- ์ต์์ ์กฐ๊ฑด๋ค์ AND๋ก ๋ฌถ๊ณ ์ธ๋ถ์กฐ๊ฑด์ด OR๋ก ๋ฌถ์ด๋ ๊ฒฝ์ฐ
SELECT station_id,
name,
status,
latitude, longitude,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
WHERE status = 'active'
AND (latitude > 135.0 OR
longitude > 80.0)
AND ...
;
-- ๋๋, ์ต์์ ์กฐ๊ฑด๋ค์ OR๋ก ๋ฌถ๊ณ ์ธ๋ถ์กฐ๊ฑด์ AND๋ก ๋ฌถ๋ ๊ฒฝ์ฐ
SELECT station_id,
name,
status,
latitude, longitude,
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
WHERE status = 'active'
OR (latitude > 135.0 AND longitude > 80.0) -- ์๋ฏธ๋จ์๋ก ๋ฌถ์ด์ ํ ์ค์ ํํ
OR ...SELECT *
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
WHERE status = 'active'
OR (latitude > 135.0 AND (longitude = 80.0 OR longitude = 90.0))
OR ...
-- ์์์์ ๊ฐ์ด 3 ๋จ๊ณ ์ด์์ ๊น์ด์์ ๋
ผ๋ฆฌ์ฐ์ฐ ์ด๋ฃจ์ด์ง๋ ๊ฒฝ์ฐ ๋ถ๋ฐฐ๋ฒ์น์ ์ด์ฉํ์ฌ ์๋์ ๊ฐ์ด ๊ฒฐ๊ณผ์ ์ผ๋ก ๋์น์ธ ๋ฌธ์ฅ์ผ๋ก ํ์ด์ธ ์ ์๋ค. a ยท (b + c) = (a ยท b) + (a ยท c)
WHERE status = 'active'
OR (latitude > 135.0 AND longitude = 80.0)
OR (latitude > 135.0 AND longitude = 90.0)
OR ...- ์ง๊ณํจ์์ ์ํด์ ๋ง๋ค์ด์ง๋ ์งํ(metric) ์ปฌ๋ผ์ ๋ณ์นญ(alias)๋ฅผ ์ฌ์ฉํ์ฌ ์ต๋ช (anonymous)์ด ์๋ ์ด๋ฆ์ ๋ถ์ฌํ๋ค.
GROUP BY๋ฆฌ์คํธ์๋ ์ปฌ๋ผ์ ๋ณ์นญ์ด๋ ์ปฌ๋ผ ์์(ordinal position)๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก ์ปฌ๋ผ ์์๋ฅผ ์ฐ์ ํด์ ์ฌ์ฉํ๋๋ก ํ๋ค.- ํนํ, ๊ธฐ๋ณธ์ปฌ๋ผ์์
CASE๋ฌธ ๋ฑ์ผ๋ก ๊ณ์ฐ๋ ์ปฌ๋ผ(calculated column)์ด ์ฐจ์์ผ๋ก ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ์๋ ๋ฐ๋์ ๋ณ์นญ์ด๋ ์ปฌ๋ผ ์์๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋๊ฐ ๋ฐ๋ณต๋์ด ์ฌ์ฉ๋์ง ์๋๋ก ํ๋ค. HAVING์ ์ง๊ณ๊ฒฐ๊ณผ๋ฅผ ํํฐ๋งํ๊ธฐ ์ํ ์ง๊ณ๊ฐ์ ์กฐ๊ฑด์ ๊ธฐ์ ํ๋ ๊ตฌ๋ฌธ์ผ๋ก ORDER BY ์์์ ๊ฐ์ด ์ปฌ๋ผ ๋ณ์นญ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
SELECT station_id,
name AS station_name,
status,
CASE
WHEN ST_DISTANCE (
ST_GEOGPOINT(longitude, latitude),
ST_GEOGPOINT(-0.118092, 51.509865)
) < 7000000 THEN 'downtown'
ELSE 'outskirt'
END AS downtown_or_outskirt,
COUNT(1) AS cnt, -- ์ง๊ณํจ์์ ์ํด ๊ณ์ฐ๋ metric ์ปฌ๋ผ์ ๋ณ์นญ ๋ถ์ฌ
FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations`
WHERE s.status IN ('active')
AND s.latitude > 135.0
GROUP BY 1, 2, 3 -- ordinal position
HAVING cnt > 1 -- column alias
;์๋ ์์์ฒ๋ผ SELECT ๋ฆฌ์คํธ์ ๊ณ์ฐ๋ ์ปฌ๋ผ์ ์ ์ํ๊ณ ํด๋น ์ปฌ๋ผ์ ์ฐจ์์ผ๋ก GROUP BY ์ง๊ณ๋ฅผ ํ๋ ๊ฒฝ์ฐ GROUP BY ๋ฆฌ์คํธ์์ ์ฝ๋๊ฐ ๋ฐ๋ณต๋์ด ๋ฌธ์ฅ์ด ๊ธธ์ด์ง๊ณ ํฅํ ์ ์ง๋ณด์๊ฐ ์ด๋ ค์์ง๊ฒ ๋๋ค.
๐ ๊ถ์ฅ (recommend)
SELECT CASE
WHEN is_male = TRUE THEN 'Male'
WHEN is_male = FALSE THEN 'Female'
END AS gender,
COUNT(1) AS cnt,
FROM `bigquery-public-data.samples.natality`
GROUP BY 1
HAVING cnt > 1000
;๐ ๊ธฐํผ (avoid)
SELECT CASE
WHEN is_male = TRUE THEN 'Male'
WHEN is_male = FALSE THEN 'Female'
END,
COUNT(1) AS cnt,
FROM `bigquery-public-data.samples.natality`
GROUP BY
CASE
WHEN is_male = TRUE THEN 'Male'
WHEN is_male = FALSE THEN 'Female'
END
;๋ํ, ๊ณ์ฐ๋ ์ปฌ๋ผ์ ์งํ๋ก ์ฌ์ฉํ์ฌ ์ง๊ณ๋ฅผ ์ํํ๋ ๊ฒฝ์ฐ์ ์ปฌ๋ผ ์ด๋ฆ๊ณผ ๋ณ์นญ์ ํผ๋ํ์ฌ ์ฌ์ฉํ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ด ์์น ์๋ ๊ฒฐ๊ณผ๊ฐ ๋ง๋ค์ด์ง ์ ์์ผ๋ ์ฃผ์๊ฐ ํ์ํ๋ค.
DECLARE data ARRAY<STRUCT<region STRING, amount INT64>> DEFAULT [
('', 1), ('NULL', 2), ('KOR', 2), ('USA', 3), ('KOR', 4), ('CHN', 1)
];
SELECT IF(d.region IN ('', 'NULL'), 'UNKNOWN', d.region) AS rgn,
SUM(d.amount) AS totals,
FROM UNNEST(data) d GROUP BY region; -- ๋ณ์นญ์ด ์๋ ์ปฌ๋ผ ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ๊ทธ๋ฃนํ| ํ | rgn | totals |
|---|---|---|
| 1 | UNKNOWN | 1 |
| 2 | UNKNOWN | 2 |
| 3 | KOR | 6 |
| 4 | USA | 3 |
| 5 | CHN | 1 |
Common Table Expression ์ ์๋ธ ์ฟผ๋ฆฌ์ ์ด๋ฆ์ ๋ถ์ฌํ์ฌ ์ฐธ์กฐํ ์ ์๋๋ก ํ๋ ํํ๋ฐฉ์์ด๋ค. ์๋ธ์ฟผ๋ฆฌ์ ์ด๋ฆ์ ๋ถ์ฌํ Named Subquery ์ธ ์ ์ด๋ค.
์๋ธ์ฟผ๋ฆฌ๋ ์ ์๋ ํด๋น ์์น์์๋ง ์ฐธ์กฐ ๊ฐ๋ฅํ์ง๋ง, ๊ณตํต ํ ์ด๋ธ ํํ์์ ๋ฌธ์ฅ ๋ด ์ฌ๋ฌ ๊ณณ์์ ๋ฐ๋ณต์ ์ผ๋ก ์ฐธ์กฐ๋ ์ ์๋ค.
CTE๋ ๋ณต์กํ ์ฟผ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ์ฌ๊ตฌ์ฑํ๋๋ฐ ํต์ฌ์ ์ธ ์ญํ ์ ํ๋ค.
์ฝ๋ ๋ด์ 2๋จ๊ณ๋ฅผ ๋์ด ์ค์ฒฉ๋๋ ์๋ธ์ฟผ๋ฆฌ๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ์๋ ์๋ธ์ฟผ๋ฆฌ๋ฅผ CTE ๊ตฌ๋ฌธ์ผ๋ก ๋์ฒดํ์ฌ ์ ์ฒด ์ฟผ๋ฆฌ ๊ตฌ์กฐ๊ฐ ์ ์ ํ ๊น์ด(2 depth)๋ฅผ ์ ์ง ํ๋๋ก ํ๋ค.
CTE๋ ํ ์ด๋ธ ์๋ธ์ฟผ๋ฆฌ(table subquery)์ธ์๋ ์ค์นผ๋ผ ์๋ธ์ฟผ๋ฆฌ(scalar subquery)๋ฅผ ๋์ฒดํ์ฌ ์ฝ๋๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ๋ง๋๋๋ฐ๋ ์ ์ฉํ๋ค.
์๋์ ์์์์๋ 2๋จ๊ณ ์ด์ ์ค์ฒฉ๋ ์๋ธ์ฟผ๋ฆฌ๋ฅผ CTE ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ์ฝ๋์ ๊น์ด๊ฐ ํ ๋จ๊ณ๊ฐ ๋๋๋ก ํ๊ณ ์๋ค. ์ดํ ๋จ๊ณ๋ณ ์ค๊ฐ ํ ์ด๋ธ ์ญ์ CTE๋ก ์ ์ํ์ฌ ์ฌ์ฉํ๋ฉด์ ์ต์ข ์ ์ผ๋ก๋ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๋ด๊ฒ ๋๋ค.
๐ ๊ธฐํผ avoid
SELECT *
FROM (
SELECT *
FROM (
SELECT *
FROM base_table
) AS first_subquery
) AS second_subquery๐ ๊ถ์ฅ recommend
WITH first_subquery ( -- ๊ฐ์ฅ ์์ชฝ์ ์๋ธ์ฟผ๋ฆฌ
SELECT *
FROM base_table
),
second_subquery ( -- ์์ ์๋ธ์ฟผ๋ฆฌ
SELECT *
FROM first_subquery
)
SELECT * -- ๋ฉ์ธ ์ฟผ๋ฆฌ
FROM second_subquery
;FROM ์ ์ ์ง์ ์๋ธ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์๋์ชฝ์ ์์นํ ์๋ธ์ฟผ๋ฆฌ๋ฅผ ๋จผ์ ์ฝ๊ณ ๋ค์ ์์ชฝ์ ์ฟผ๋ฆฌ๋ฅผ ์ฝ์ด์ผ ํ๋ ๋ฐ๋ฉด, CTE๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ์์์๋ถํฐ ์์ฐ์ค๋ฝ๊ฒ ์๋๋ก ์ฝ๋ ์ฝ๊ธฐ๊ฐ ๊ฐ๋ฅํ ์ฅ์ ์ด ์๋ค.
์๋๋ CTEs๋ฅผ ์ด์ฉํ์ฌ ๊ณ์ฐ๋ ์ปฌ๋ผ์ด ๋ฐ๋ณต๋์ง ์๋๋ก ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ ์์์ด๋ค. ์ค๋ณต์ ์ฝ๋ ๊ธธ์ด๋ฅผ ์ฆ๊ฐ์ํค๊ณ ์ ์ง๋ณด์๋ฅผ ์ด๋ ต๊ฒ ํ๊ธฐ ๋๋ฌธ์ ์๋ธ์ฟผ๋ฆฌ๋ CTE๋ฅผ ์ด์ฉํ์ฌ ์ฝ๋๊ฐ ๋ฐ๋ณต๋์ง ์๋๋ก ๋ง๋๋ ๊ฒ์ด ์ข๋ค.
๐ ๊ธฐํผ (avoid)
SELECT name AS station_name,
ST_DISTINCE (
ST_GEOPOINT(longitude, latitude), ST_GEOPOINT(-0.118092, 51.509865)
) AS distance_from_city_centre_m
FROM `bigquery-public-data.london_bicycles.cycle_stations`
WHERE ST_DISTINCE (
ST_GEOPOINT(longitude, latitude),
ST_GEOPOINT(-0.118092, 51.509865)
) <= 500
ORDER BY distance_from_city_centre_m๐ ๊ถ์ฅ (recommend)
WITH stations (
SELECT name AS station_name,
ST_DISTINCE (
ST_GEOPOINT(longitude, latitude), ST_GEOPOINT(-0.118092, 51.509865)
) AS distance_from_city_centre_m
FROM `bigquery-public-data.london_bicycles.cycle_stations`
)
SELECT *
FROM stations
WHERE distance_from_city_centre_m <= 500
ORDER BY distance_from_city_centre_mINNER์OUTERํค์๋๋ ์๋ต๋๋๋ผ๋ ์๋ฏธ์ ์ผ๋ก ํผ๋์ ์ฃผ์ง ์๊ธฐ ๋๋ฌธ์ ์๋ตํ๋ค. ๋ด๋ถ์กฐ์ธ์JOIN, ์ธ๋ถ์กฐ์ธ์LEFT JOIN,OUTER JOIN์ ์ฌ์ฉํ๋ค.- Cartesian Product๋
CROSS JOIN์ฌ์ฉํ ์กฐ์ธ ํ์์ ์ฝค๋ง(,)๋ฅผ ์ฌ์ฉํ ์ค๋ผํด ์กฐ์ธ ํ์ ๋ณด๋ค ์ฐ์ ํ๋ค. ๋ค๋ง, ์๋์์ ์ธ๊ธํ ์๊ด ํฌ๋ก์ค ์กฐ์ธ (correlated cross-join)์ ๊ฒฝ์ฐ๋ ์ฝค๋ง ์กฐ์ธ ํ์์ ์ฐ์ ํ๋ค. ON์ ์JOIN์ ๋ฐ๋ก ์๋์ ์์ฑํ๋ฉฐ ๊ฒฐํฉ์กฐ๊ฑด์ด ์ฌ๋ฌ ๊ฐ ๋ฑ์ฅํ๋ ๊ฒฝ์ฐ๋WHERE์ ์ ์ฐธ๊ณ ํ์ฌ ๋ณต์๊ฐ์ ๊ฒฐํฉ ์กฐ๊ฑด์ ๊ธฐ์ ํ๋ค.- ํ ์ด๋ธ ๋ณ์นญ์ ์ฌ์ฉํ์ฌ ๊ธด ํ ์ด๋ธ ์ด๋ฆ์ด ๋ฐ๋ณต๋์ง ์๋๋ก ํ๋ค.
๐ ๊ธฐํผ (avoid)
SELECT m.*,
d.*,
FROM masters
LEFT OUTER JOIN details
ON masters.mid = details.did๐ ๊ถ์ฅ (recommend)
SELECT m.*,
d.*,
FROM masters AS m
LEFT JOIN details AS d
ON m.mid = d.did
AND m.status = d.stsBigQuery์ ๋ฐฐ์ด์ ํํํ(flattening) ํ ํ์ CROSS JOIN ์ ์๊ด ํฌ๋ก์ค ์กฐ์ธ์ด๋ผํ๊ณ ์ฌ๊ธฐ์์ ์๊ด(correleated)์ ํฌ๋ก์ค ์กฐ์ธ์ ๋ฒ์๊ฐ ํ
์ด๋ธ ์ ์ฒด ํ(row)์ด ์๋ ๋ฐฐ์ด์ ๋ณด์ ํ๊ณ ์๋ ํ(row)์ ์ฎ์ฌ ๊ตญํ๋๋ค๋ ์๋ฏธ์ด๋ค.
์๋ ์์์ ๊ฒฝ์ฐ data ํ
์ด๋ธ๊ณผ y ๋ฐฐ์ด์ด ์ค๋ผํด ํ์์ ํฌ๋ก์ค ์กฐ์ธ์ ์ํํ๊ณ ์์ผ๋, ์ผ๋ฐ์ ์ธ ํฌ๋ก์ค ์กฐ์ธ ์ฒ๋ผ y ๋ฐฐ์ด์ ์์๋ค์ด data ํ
์ด๋ธ์ ๋ชจ๋ ํ(row) ๊ณผ ๊ฒฐํฉ๋์ด m X n์ ์กฐํฉ์ ๋ง๋ค์ง ์๊ณ y๋ฐฐ์ด์ ํฌํจํ ํ๋์ ํ๊ณผ 1 X n(y๋ฐฐ์ดํฌ๊ธฐ) ์ ํ์ ๋ ์กฐ์ธ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด ๋ธ๋ค.
-- Correlated Cross-Join
WITH data AS (
SELECT 1 AS w, 'a' AS x, ['P', 'Q'] AS y
UNION ALL
SELECT 2 AS w, 'b' AS x, ['R', 'S', 'T'] AS y
)
-- Comma Join --> data CROSS JOIN data.y ๋์ผ
SELECT w, x, y_ FROM data, data.y y_
;
-- ์์์ ๋ฉ์ธ `SELECT` ๋ฌธ์ฅ์ ์๋ ์ฝ๋๊ฐ ์ถ์ฝ๋ ํํ์ด๋ค.
-- UNNEST()๋ฅผ ์๋ตํ๊ณ y ์ปฌ๋ผ์ด๋ฆ์ data.y๋ก ํ์ ์ํด.
SELECT w, x, y_ FROM data, UNNEST(y) y_์๋๋ UNNEST๋ฅผ ์ฐ์์ ์ผ๋ก ์๊ด ์กฐ์ธ์ ์ํํ๋ ๊ฒฝ์ฐ์ ์คํ์ผ ์์์ด๋ค. ** FROM(์๋ธ์ฟผ๋ฆฌ)** ์ฒ๋ผ ๋ฐฐ์ด์ ์๋ธ์ฟผ๋ฆฌ๋ก ๊ฐ์ฃผํ๊ณ ๋น์ทํ๊ฒ ์คํ์ผ๋งํ๋ ๋ณํ์ด ๊ฐ๋ฅํ๋ค.
DECLARE rectangular_table ARRAY<STRUCT<A STRING, B STRING, C STRING>> DEFAULT [
('1', '1', '1'), ('2', 'other', '2'), ('TRUE', '3', '3'), ('4', '4', '4')
];
-- Style #1 - preferred
SELECT SUM(SAFE_CAST(v AS FLOAT64)) AS `sum`
FROM UNNEST(rectangular_table) t,
UNNEST(REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r':"?([-0-9.]*)"?[,}]')) v
;
-- Style #2 -- UNNEST๋ฅผ FROM๊ณผ ์ ์ฌํ๊ฒ ๊ฐ์ฃผ
SELECT SUM(SAFE_CAST(v AS FLOAT64)) AS `sum`
FROM UNNEST(rectangular_table) t,
UNNEST (REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r':"?([-0-9.]*)"?[,}]')) v๋ถ์ ํจ์ ๋๋ ์๋์ฐ ํจ์๋ฅผ ์ฌ์ฉํ ์ปฌ๋ผ์ ๊ตฌ์กฐ๋ ๋๋ต ์๋์ ๊ฐ๋ค.
OVERํค์๋๋ฅผ ์ค์ฌ์ผ๋ก ์ผ์ชฝ์ ๋ถ์ ํจ์๊ฐ ๋์ด๊ณ ์ค๋ฅธ์ชฝ์๋ ๋ถ์ ํจ์๋ฅผ ์ ์ฉํ ์๋์ฐ ํ๋ ์ (window frame)์ ์ ์ํ๋ ๊ตฌ๋ฌธ์ด ๋์จ๋ค.- ์๋์ฐ ํ๋ ์(window frame) ์ ์ ๊ตฌ๋ฌธ์ ๋ค์ ์๋์ 3๊ฐ์ ๊ตฌ๋ฌธ์ผ๋ก ์ธ๋ถํ ๋๋ค. 3๊ฐ์ง ๊ตฌ๋ฌธ์ ๋ชจ๋ ์ ํ์ ์ผ๋ก(optional)๋ก ์ฌ์ฉ๋๋ค.
PARTITION BY๋ก ํํฐ์ (partition)์ ์ ์ORDER BY๋ก ๊ฐ ํํฐ์ ์ ์ด๋ค ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํ ์ง ์ ์ROWS๋RANGE๋ก ๊ฐ ํํฐ์ ์์์ ๋ฌผ๋ฆฌ์ ๋๋ ๋ ผ๋ฆฌ์ ์ธ ์๋์ฐ ํ๋ ์(window frame)์ ์ด๋ป๊ฒ ์ ์ฉํ ์ง ์ ์
์ด๋ฌํ ๊ตฌ์กฐ์ ๋ํ ์ฝ๋ฉ ์คํ์ผ์ ๋ค์ ์ง์นจ์ ๋ฐ๋ผ ์์ฑํ ๋ก ํ๋ค.
- ๋ถ์ ํจ์์
OVERํค์๋๋ ์ปฌ๋ผ์ ์ฒซ๋ฒ์งธ ๋ผ์ธ์ ์์น์ํจ๋ค. OVER ()๊ตฌ๋ฌธ๋ด์ ์๋์ฐ ํ๋ ์์ ์ ์ํ๋ ๊ตฌ๋ฌธ์ด ๊ธธ์ด์ง๋ ๊ฒฝ์ฐ ์ค๋ฐ๊ฟ์ ํ ํ ๊ฐ ๊ตฌ๋ฌธ์ ํ๋์ ๋ผ์ธ์ ๊ธฐ์ ํ๋ค.- ์ค๋ฐ๊ฟ๋ ์๋์ฐ ํ๋ ์ ์ ์ ๊ด๋ จ ํค์๋๋ค์ ์๋์ฐ ํจ์ ์ด๋ฆ์ ๊ธฐ์ค์ผ๋ก ๋ ์นธ ๋ค์ฌ์ฐ๊ธฐ๋ฅผ ํ ํ ์ผ์ชฝ ์ ๋ ฌ์ํจ๋ค.
- select-list ์ ์ ์๋์ฐ ํ๋ ์ ์ ์ ๊ตฌ๋ฌธ ์์ฑ์ ๋ผ์ธ์ด ๊ธธ์ด์ง๋ฏ๋ก WINDOW ์ ์ ์ ์ํ๊ณ ์ ์๋ ์๋์ฐ ํ๋ ์ ์ด๋ฆ์ ์ฌ์ฉํ๋ค.
์์ ์คํ์ผ์ ์ ์ฉํ์ฌ ์์ฑํ ์ฝ๋ ์์๋ ์๋์ ๊ฐ๋ค.
- ์ฒซ๋ฒ์งธ ์์
SELECT item, purchases, category,
SUM(purchases) OVER (
PARTITION BY category -- ๋ ์นธ ๋ค์ฌ์ฐ๊ธฐ ๋ฐ
ORDER BY purchases -- PARTITION, ORDER ํค์๋ ์ผ์ชฝ ์ ๋ ฌ
) AS total_purchases, -- ๋ถ์ํจ์ ์ปฌ๋ผ์ ๋ํ ๋ณ์นญ(alias)
SUM(purchases) OVER (
PARTITION BY category
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_purchases,
LAST_VALUE(item) OVER (
PARTITION BY category ORDER BY purchases
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS most_popular,
FROM Produce
;
SELECT animal, population, category,
COUNT(*) OVER (
ORDER BY population
RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING
) AS similar_population,
FROM Farm
;WINDOW ๊ตฌ๋ฌธ์ ์ฌ์ฉํ ์คํ์ผ ์์์ด๋ค. ์ด๋ฆ์ ๊ฐ์ง ์๋์ฐ ํ๋ ์์ ์ด์ด์ง๋ ์๋์ฐ ํ๋ ์์์ ์ฐธ์กฐ ๊ฐ๋ฅํ๋ฏ๋ก ๋ฐ๋ณต๋๋ ์ ์๋ฅผ ์ค์ผ ์ ์๋ค.
SELECT item, purchases, category,
SUM(purchases) OVER w1 AS total_purchases,
SUM(purchases) OVER w2 AS cumulative_purchases,
LAST_VALUE(item) OVER w3 AS most_popular,
FROM Produce
WINDOW w0 AS (PARTITION BY category),
w1 AS (W0 ORDER BY purchases),
W2 AS (W0 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),
W2 AS (W1 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
;- ๋ ๋ฒ์งธ ์์
SELECT name,
division,
FORMAT_TIMESTAMP('%X', finish_time) AS finish_time,
FORMAT_TIMESTAMP('%X', fastest_time) AS fastest_time,
TIMESTAMP_DIFF(finish_time, fastest_time, SECOND) AS delta_in_seconds
FROM (
SELECT name, finish_time, division,
FIRST_VALUE(finish_time) OVER (
PARTITION BY division ORDER BY finish_time ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS fastest_time
FROM finishers
);BigQuery์ ์ฌ์ฉ์ ์ ์ ํจ์๋ SQL๊ณผ JavaScript ๋ ๊ฐ์ง ์ธ์ด๋ก ์์ฑ ๊ฐ๋ฅํ๋ค.
- ํจ์ ๋ณธ๋ฌธ(function body)์ ์์ฑํ ๋๋ ๊ฐ ์ธ์ด์ ๊ธฐ๋ณธ ์คํ์ผ ๊ฐ์ด๋๋ฅผ ๋ฐ๋ฅธ๋ค.
SQL์ธ์ด๋ก ์์ฑ์๋ ์ด ๋ฌธ์์ ๋ด์ฉ์ ์ฐธ๊ณ ํ๋ค.JavaScript์ธ์ด๋ก ์์ฑ์๋ ํ ๋ด ์ฌ์ฉ์ค์ธ ์คํ์ผ ๊ฐ์ด๋๋ฅผ ๋ฐ๋ฅธ๋ค. ์์ ๊ฒฝ์ฐ์๋ ๋ค์์ ์ฐธ์กฐํ๋ค.
- JavaScript UDF
CREATE TEMP FUNCTION multiply_inputs(x FLOAT64, y FLOAT64)
RETURNS FLOAT64
LANGUAGE js AS r"""
return x * y;
""";
SELECT multiplyInputs(3, 5) as product;- SQL UDF
CREATE TEMP FUNCTION multiplyInputs(x FLOAT64, y FLOAT64) AS (
x * y
);
SELECT multiplyInputs(3, 5) as product;CREATE TEMPORARY FUNCTION dayOfWeek(x TIMESTAMP) AS (
['Sun','Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
[ORDINAL(EXTRACT(DAYOFWEEK from x))]
);
CREATE TEMPORARY FUNCTION getDate(x TIMESTAMP) AS (
EXTRACT(DATE FROM x)
);
WITH overnight_trips AS (
SELECT duration, dayOfWeek(start_date) AS start_day
FROM `bigquery-public-data.london_bicycles.cycle_hire`
WHERE getDate(start_date) != getDate(end_date)
)
SELECT * FROM overnight_trips LIMIT 100;SQL UDF ์์ SELECT ๋ฌธ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ผ๋ฐ์ ์ธ ์ค์นผ๋ผ ์๋ธ์ฟผ๋ฆฌ(scalar subquery)์ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ดํธ๋ก ๊ฐ์ธ์ค์ผ ํ๋ค. ์ด ๋ ๊ดํธ๋ ์๋์ฒ๋ผ ํจ์ ๋ณธ๋ฌธ (_functon body)์ ๊ดํธ์ ๊ฐ์ด ์ฌ์ฉํ์ด ์ด์ค ๊ดํธ ํํ๊ฐ ๋๋๋ก ํ์ฌ UDF ๋ณธ๋ฌธ์ด ๊ดํธ๊ฐ ์๋ SELECT๋ก ์์๋๋๋ก ๋ง๋ ๋ค.
CREATE OR REPLACE FUNCTION `jaeseok-park.fn.median` (arr ANY TYPE) AS ((
SELECT IF(MOD(ARRAY_LENGTH(arr), 2) = 0,
(arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2) - 1)] +
arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))] ) / 2,
arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))]
) AS median
FROM (SELECT ARRAY_AGG(x ORDER BY x) AS arr FROM UNNEST(arr) AS x)
));TBD
์๋๋ ์ง๊ธ๊น์ง์ ๊ฐ์ด๋์ ๋ฐ๋ผ ์ค์ ๋ถ์์ฉ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ์กฐํํ ์์์ด๋ค. ์ฟผ๋ฆฌ๋ ์๋ ๋งํฌ์ ๋ด์ฉ์ ์ฌ์ฉํ์๋ค.
#standardSQL
WITH variants AS (
-- Retrieve the variants in this cohort, flattening by alternate bases and
-- counting affected alleles.
SELECT REPLACE(reference_name, 'chr', '') as reference_name,
start_position,
end_position,
reference_bases,
alternate_bases.alt AS alt,
(SELECT COUNTIF(gt = alt_offset + 1) FROM v.call, call.genotype gt) AS num_variant_alleles,
(SELECT COUNTIF(gt >= 0) FROM v.call, call.genotype gt) AS total_num_alleles,
FROM `bigquery-public-data.human_genome_variants.platinum_genomes_deepvariant_variants_20180823`,
UNNEST(alternate_bases) alternate_bases WITH OFFSET alt_offset
),
intervals AS (
-- Define an inline table that uses five rows
-- selected from silver-wall-555.TuteTable.hg19.
SELECT *
FROM UNNEST([
STRUCT<Gene STRING, Chr STRING,
gene_start INT64, gene_end INT64,
region_start INT64, region_end INT64>
('PRCC', '1', 156736274, 156771607, 156636274, 156871607),
('NTRK1', '1', 156785541, 156852640, 156685541, 156952640),
('PAX8', '2', 113972574, 114037496, 113872574, 114137496),
('FHIT', '3', 59734036, 61238131, 59634036, 61338131),
('PPARG', '3', 12328349, 12476853, 12228349, 12576853)
])
),
gene_variants AS (
--
-- JOIN the variants with the genomic intervals overlapping
-- the genes of interest.
--
-- The JOIN criteria is complicated because the task is to see if
-- an SNP overlaps an interval. With standard SQL you can use complex
-- JOIN predicates, including arbitrary expressions.
SELECT reference_name,
start_position,
reference_bases,
alt,
num_variant_alleles,
total_num_alleles,
FROM variants v
JOIN intervals i
ON v.reference_name = i.Chr
AND i.region_start <= v.start_position
AND i.region_end >= v.end_position
)
--
-- And finally JOIN the variants in the regions of interest
-- with annotations for rare variants.
SELECT DISTINCT
Chr,
annots.Start AS Start,
Ref,
annots.Alt,
Func,
Gene,
PopFreqMax,
ExonicFunc,
num_variant_alleles,
total_num_alleles,
FROM `silver-wall-555.TuteTable.hg19` AS annots
JOIN gene_variants AS vars
ON vars.reference_name = annots.Chr
AND vars.start_position = annots.Start
AND vars.reference_bases = annots.Ref
AND vars.alt = annots.Alt
WHERE PopFreqMax <= 0.01 -- Retrieve annotations for rare variants only.
ORDER BY Chr, Start
;