0% found this document useful (0 votes)
12 views45 pages

Snowflake SQL Notes

The document provides comprehensive notes on Snowflake SQL, covering query syntax, data definition language (DDL), data manipulation language (DML), functions, semi-structured data, and scripting. It includes detailed explanations, syntax, and examples for various SQL operations such as SELECT, JOINs, and creating tables. The notes serve as a reference for users to understand and utilize Snowflake SQL effectively.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views45 pages

Snowflake SQL Notes

The document provides comprehensive notes on Snowflake SQL, covering query syntax, data definition language (DDL), data manipulation language (DML), functions, semi-structured data, and scripting. It includes detailed explanations, syntax, and examples for various SQL operations such as SELECT, JOINs, and creating tables. The notes serve as a reference for users to understand and utilize Snowflake SQL effectively.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Snowflake SQL

Complete Notes with Examples

Query Syntax • DDL • DML • Functions • Semi-Structured • Scripting

6 6 60+ Detailed
Major Topic Topics Examples
Sections Categories Covered per Topic

SELECT, WHERE, JOINs, GROUP BY, CTEs, UNION, QUALIFY,


01 Query Syntax & Operators Subqueries

CREATE/ALTER/DROP: Databases, Tables, Views, Sequences,


02 DDL — Data Definition Clone

03 DML — Data Manipulation INSERT, UPDATE, DELETE, MERGE, COPY INTO, TRUNCATE

String, Date, Numeric, Aggregate, Window, Conditional, Type


04 Functions Conversion

VARIANT, JSON, ARRAY, OBJECT, FLATTEN, PARSE_JSON,


05 Semi-Structured Data OBJECT_KEYS

Snowflake SQL — Complete Notes Page 1


Variables, IF/LOOP, Exceptions, Stored Procedures, Tasks,
06 Scripting & Automation Streams

Snowflake SQL — Complete Notes Page 2


Section 1 — Query Syntax & Operators

Basic SELECT Statement


■ What it does
The SELECT statement retrieves rows from one or more tables. You can select specific columns, apply
aliases, and filter rows using WHERE.
■ Syntax

SELECT column1, column2, ...


FROM table_name
WHERE condition
ORDER BY column1 [ASC|DESC]
LIMIT n;

■ Example

SELECT employee_id, first_name, salary


FROM employees
WHERE department = 'Engineering'
ORDER BY salary DESC
LIMIT 10;

SELECT DISTINCT
■ What it does
DISTINCT eliminates duplicate rows from the result set, returning only unique combinations of the selected
columns.
■ Syntax

SELECT DISTINCT column1, column2


FROM table_name;

■ Example

SELECT DISTINCT country, city


FROM customers
ORDER BY country;

Snowflake SQL — Complete Notes Page 3


WHERE Clause & Operators
■ What it does
The WHERE clause filters rows using comparison operators (=, !=, <, >, <=, >=), logical operators (AND, OR,
NOT), IN, BETWEEN, LIKE, and IS NULL.
■ Syntax

WHERE column = value


WHERE column IN (v1, v2, v3)
WHERE column BETWEEN low AND high
WHERE column LIKE 'pattern%'
WHERE column IS NULL

■ Example

SELECT * FROM orders


WHERE status IN ('pending', 'processing')
AND order_date BETWEEN '2024-01-01' AND '2024-12-31'
AND customer_name LIKE 'A%'
AND discount IS NOT NULL;

GROUP BY and HAVING


■ What it does
GROUP BY groups rows by one or more columns for aggregate calculations. HAVING filters the grouped
results (similar to WHERE but applied after aggregation).
■ Syntax

SELECT column, AGG_FUNC(col)


FROM table_name
GROUP BY column
HAVING AGG_FUNC(col) condition;

■ Example

SELECT department, COUNT(*) AS emp_count, AVG(salary) AS avg_sal


FROM employees
GROUP BY department
HAVING COUNT(*) > 5
ORDER BY avg_sal DESC;

Snowflake SQL — Complete Notes Page 4


JOIN Types
■ What it does
JOINs combine rows from multiple tables. INNER JOIN returns matching rows; LEFT JOIN keeps all left rows;
RIGHT JOIN keeps all right rows; FULL OUTER JOIN keeps all rows from both sides.
■ Syntax

-- INNER JOIN
SELECT [Link], [Link] FROM a JOIN b ON [Link] = [Link];
-- LEFT JOIN
SELECT [Link], [Link] FROM a LEFT JOIN b ON [Link] = [Link];
-- FULL OUTER JOIN
SELECT [Link], [Link] FROM a FULL OUTER JOIN b ON [Link] = [Link];

■ Example

SELECT e.first_name, d.department_name, [Link]


FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
LEFT JOIN locations l ON d.location_id = l.location_id
WHERE [Link] = TRUE;

Subqueries
■ What it does
A subquery is a query nested inside another query. Subqueries can appear in SELECT, FROM, WHERE, or
HAVING clauses. Correlated subqueries reference the outer query.
■ Syntax

-- Subquery in WHERE
SELECT col FROM t WHERE col IN (SELECT col FROM t2);
-- Subquery in FROM (derived table)
SELECT * FROM (SELECT col, AGG(col2) FROM t GROUP BY col) sub;

■ Example

SELECT employee_id, salary


FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees)
ORDER BY salary DESC;

-- Derived table example


SELECT dept, avg_sal
FROM (SELECT department AS dept, AVG(salary) AS avg_sal
FROM employees GROUP BY department) sub
WHERE avg_sal > 80000;

Snowflake SQL — Complete Notes Page 5


CTEs (Common Table Expressions)
■ What it does
A CTE (WITH clause) defines a named temporary result set that can be referenced within the same query.
CTEs improve readability and can be referenced multiple times. Snowflake supports recursive CTEs.
■ Syntax

WITH cte_name AS (
SELECT ...
)
SELECT * FROM cte_name;

-- Multiple CTEs
WITH cte1 AS (...), cte2 AS (...)
SELECT * FROM cte1 JOIN cte2 ...;

■ Example

WITH high_earners AS (
SELECT department, AVG(salary) AS avg_sal
FROM employees
GROUP BY department
),
dept_info AS (
SELECT d.dept_name, h.avg_sal
FROM departments d
JOIN high_earners h ON d.dept_id = [Link]
)
SELECT * FROM dept_info WHERE avg_sal > 90000;

Snowflake SQL — Complete Notes Page 6


UNION, INTERSECT, EXCEPT
■ What it does
Set operators combine results from two queries. UNION removes duplicates; UNION ALL keeps all rows.
INTERSECT returns rows in both results. EXCEPT returns rows in the first but not the second.
■ Syntax

SELECT col FROM t1


UNION [ALL]
SELECT col FROM t2;

INTERSECT / EXCEPT work the same way.

■ Example

-- All customers who bought in 2023 OR 2024


SELECT customer_id FROM orders WHERE YEAR(order_date) = 2023
UNION
SELECT customer_id FROM orders WHERE YEAR(order_date) = 2024;

-- Customers in 2023 but NOT 2024


SELECT customer_id FROM orders WHERE YEAR(order_date) = 2023
EXCEPT
SELECT customer_id FROM orders WHERE YEAR(order_date) = 2024;

QUALIFY (Window Function Filter)


■ What it does
QUALIFY filters rows after window functions are computed. It is unique to Snowflake and replaces the need to
wrap a query in a subquery just to filter on a window result.
■ Syntax

SELECT col, ROW_NUMBER() OVER (PARTITION BY x ORDER BY y) AS rn


FROM table
QUALIFY rn = 1;

■ Example

-- Get the most recent order per customer


SELECT customer_id, order_id, order_date
FROM orders
QUALIFY ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) =
1;

Snowflake SQL — Complete Notes Page 7


CASE Expression
■ What it does
CASE is a conditional expression that evaluates conditions and returns a value. It can be used in SELECT,
WHERE, ORDER BY, and GROUP BY clauses.
■ Syntax

CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE default_result
END

■ Example

SELECT order_id,
CASE
WHEN amount >= 1000 THEN 'Large'
WHEN amount >= 500 THEN 'Medium'
ELSE 'Small'
END AS order_size
FROM orders;

Lateral JOIN & FLATTEN


■ What it does
LATERAL JOIN lets each row reference columns from previous FROM items. Combined with FLATTEN, it is
used to explode semi-structured (ARRAY/VARIANT) data into rows.
■ Syntax

SELECT [Link], [Link]


FROM table t,
LATERAL FLATTEN(input => t.array_col) f;

■ Example

SELECT order_id, [Link]:product_name::STRING AS product


FROM orders,
LATERAL FLATTEN(input => items_array) item
WHERE [Link]:qty::INT > 2;

Snowflake SQL — Complete Notes Page 8


Section 2 — DDL: Data Definition Language

CREATE DATABASE & SCHEMA


■ What it does
Databases are top-level containers in Snowflake. Schemas sit inside databases and hold tables, views, and
other objects. Use IF NOT EXISTS to avoid errors on re-runs.
■ Syntax

CREATE DATABASE [IF NOT EXISTS] db_name


[DATA_RETENTION_TIME_IN_DAYS = n];

CREATE SCHEMA [IF NOT EXISTS] schema_name


[DATA_RETENTION_TIME_IN_DAYS = n];

■ Example

CREATE DATABASE analytics


DATA_RETENTION_TIME_IN_DAYS = 7;

CREATE SCHEMA [Link]


DATA_RETENTION_TIME_IN_DAYS = 14;

CREATE TABLE
■ What it does
Creates a permanent table. Snowflake supports all standard SQL data types plus VARIANT, ARRAY,
OBJECT for semi-structured data. Column constraints include NOT NULL, UNIQUE, DEFAULT, and
PRIMARY KEY.
■ Syntax

CREATE [OR REPLACE] TABLE table_name (


col1 datatype [NOT NULL] [DEFAULT val],
col2 datatype,
PRIMARY KEY (col1)
);

■ Example

CREATE OR REPLACE TABLE customers (


customer_id NUMBER NOT NULL PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
signup_date DATE DEFAULT CURRENT_DATE,
metadata VARIANT,
is_active BOOLEAN DEFAULT TRUE
);

Snowflake SQL — Complete Notes Page 9


CREATE TABLE AS SELECT (CTAS)
■ What it does
Creates a new table from the result of a SELECT query. The table structure is derived automatically from the
query output.
■ Syntax

CREATE [OR REPLACE] TABLE new_table AS


SELECT col1, col2 FROM existing_table [WHERE ...];

■ Example

CREATE OR REPLACE TABLE active_customers AS


SELECT customer_id, first_name, email, signup_date
FROM customers
WHERE is_active = TRUE
AND signup_date >= '2023-01-01';

ALTER TABLE — Add / Modify / Drop Column


■ What it does
ALTER TABLE modifies an existing table: adding columns, changing data types, renaming columns, or
dropping them. Snowflake allows changing column type if the new type is compatible.
■ Syntax

ALTER TABLE t ADD COLUMN col datatype;


ALTER TABLE t MODIFY COLUMN col SET DEFAULT val;
ALTER TABLE t RENAME COLUMN old TO new;
ALTER TABLE t DROP COLUMN col;

■ Example

ALTER TABLE customers ADD COLUMN phone VARCHAR(20);

ALTER TABLE customers MODIFY COLUMN first_name VARCHAR(150);

ALTER TABLE customers RENAME COLUMN phone TO phone_number;

ALTER TABLE customers DROP COLUMN phone_number;

Snowflake SQL — Complete Notes Page 10


DROP, TRUNCATE & UNDROP TABLE
■ What it does
DROP TABLE permanently removes a table. TRUNCATE removes all rows but keeps the structure. UNDROP
restores a dropped table using Snowflake's Time Travel (within the retention window).
■ Syntax

DROP TABLE [IF EXISTS] table_name;


TRUNCATE TABLE table_name;
UNDROP TABLE table_name;

■ Example

TRUNCATE TABLE temp_staging;

DROP TABLE IF EXISTS old_customers;

-- Oops! Restore it within retention period


UNDROP TABLE old_customers;

CREATE VIEW
■ What it does
A view is a named SQL query stored in the database. Views simplify complex queries, enforce security by
exposing only certain columns, and do not store data themselves.
■ Syntax

CREATE [OR REPLACE] VIEW view_name AS


SELECT col1, col2
FROM table_name
[WHERE condition];

■ Example

CREATE OR REPLACE VIEW vw_active_orders AS


SELECT o.order_id, o.order_date, [Link], o.total_amount
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE [Link] != 'cancelled';

Snowflake SQL — Complete Notes Page 11


MATERIALIZED VIEW
■ What it does
Materialized views precompute and store the query result. They are automatically refreshed by Snowflake
when the underlying data changes, making aggregation queries much faster.
■ Syntax

CREATE MATERIALIZED VIEW mv_name AS


SELECT agg_cols
FROM table_name
[WHERE ...];

■ Example

CREATE MATERIALIZED VIEW mv_daily_sales AS


SELECT DATE_TRUNC('day', order_date) AS sale_date,
SUM(amount) AS total_sales,
COUNT(*) AS order_count
FROM orders
WHERE status = 'completed'
GROUP BY 1;

CREATE SEQUENCE
■ What it does
A sequence generates unique sequential numbers, typically used for surrogate primary keys. NEXTVAL
generates the next value; CURRVAL retrieves the current value.
■ Syntax

CREATE SEQUENCE seq_name


START = 1 INCREMENT = 1;

-- Use in INSERT
seq_name.NEXTVAL

■ Example

CREATE SEQUENCE order_seq START = 1000 INCREMENT = 1;

INSERT INTO orders (order_id, customer_id, order_date)


VALUES (order_seq.NEXTVAL, 42, CURRENT_DATE);

Snowflake SQL — Complete Notes Page 12


CLONE (Zero-Copy Clone)
■ What it does
Snowflake's CLONE creates an instant copy of a database, schema, or table without duplicating storage. The
clone initially shares data blocks with the source and diverges only when data changes.
■ Syntax

CREATE TABLE new_table CLONE source_table;


CREATE SCHEMA new_schema CLONE source_schema;
CREATE DATABASE new_db CLONE source_db;

-- Clone at a point in time


CREATE TABLE t_backup CLONE t AT (TIMESTAMP => '2024-01-01');

■ Example

-- Quick dev copy of production table


CREATE TABLE orders_dev CLONE orders;

-- Clone before a migration for safety


CREATE TABLE customers_backup CLONE customers
AT (OFFSET => -3600); -- 1 hour ago

TEMPORARY & TRANSIENT Tables


■ What it does
Temporary tables exist only for the current session and are automatically dropped when it ends. Transient
tables persist across sessions but have limited Time Travel (max 1 day) and no Fail-safe, reducing storage
costs.
■ Syntax

CREATE TEMPORARY TABLE t (col datatype);


CREATE TRANSIENT TABLE t (col datatype);

■ Example

-- Temp table for session-only intermediate work


CREATE TEMPORARY TABLE temp_calc AS
SELECT customer_id, SUM(amount) AS total
FROM orders GROUP BY 1;

-- Transient for staging (cost-efficient)


CREATE TRANSIENT TABLE stg_orders (
order_id NUMBER, raw_data VARIANT
);

Snowflake SQL — Complete Notes Page 13


Section 3 — DML: Data Manipulation Language

INSERT — Single & Multi-Row


■ What it does
INSERT adds new rows to a table. You can insert a single row with VALUES, multiple rows in one statement,
or insert the results of a SELECT query.
■ Syntax

-- Single row
INSERT INTO table (col1, col2) VALUES (v1, v2);

-- Multiple rows
INSERT INTO table (col1, col2) VALUES (v1,v2), (v3,v4);

-- Insert from SELECT


INSERT INTO table SELECT col1, col2 FROM other_table;

■ Example

INSERT INTO products (product_id, name, price)


VALUES (1, 'Laptop', 999.99),
(2, 'Mouse', 29.99),
(3, 'Keyboard', 79.99);

-- Load from staging


INSERT INTO orders
SELECT order_id, customer_id, amount, order_date
FROM stg_orders
WHERE order_date >= '2024-01-01';

Snowflake SQL — Complete Notes Page 14


UPDATE
■ What it does
UPDATE modifies existing rows in a table. Always use a WHERE clause to avoid updating every row.
Snowflake supports updating from a subquery or JOIN.
■ Syntax

UPDATE table_name
SET col1 = val1, col2 = val2
WHERE condition;

-- Update from another table


UPDATE t SET [Link] = [Link] FROM source s WHERE [Link] = [Link];

■ Example

-- Update single column


UPDATE products
SET price = price * 1.10
WHERE category = 'Electronics';

-- Update from another table


UPDATE employees e
SET [Link] = s.new_salary
FROM salary_updates s
WHERE e.employee_id = s.employee_id;

DELETE
■ What it does
DELETE removes specific rows from a table based on a WHERE condition. Without WHERE, it removes all
rows (use TRUNCATE instead for a full wipe, as it is faster).
■ Syntax

DELETE FROM table_name


WHERE condition;

-- Delete using a subquery


DELETE FROM t WHERE id IN (SELECT id FROM t2 WHERE ...);

■ Example

DELETE FROM orders


WHERE status = 'cancelled'
AND order_date < DATEADD('year', -2, CURRENT_DATE);

-- Delete rows that exist in another table


DELETE FROM customers
WHERE customer_id IN (
SELECT customer_id FROM churn_list
);

Snowflake SQL — Complete Notes Page 15


MERGE (Upsert)
■ What it does
MERGE combines INSERT, UPDATE, and DELETE in a single statement. It is ideal for incremental loads —
inserting new rows and updating existing ones based on a matching key.
■ Syntax

MERGE INTO target t


USING source s ON [Link] = [Link]
WHEN MATCHED THEN
UPDATE SET [Link] = [Link]
WHEN NOT MATCHED THEN
INSERT (col1, col2) VALUES (s.col1, s.col2)
WHEN MATCHED AND condition THEN DELETE;

■ Example

MERGE INTO customers tgt


USING customer_updates src
ON tgt.customer_id = src.customer_id
WHEN MATCHED AND src.is_deleted = TRUE THEN
DELETE
WHEN MATCHED THEN
UPDATE SET
[Link] = [Link],
[Link] = [Link],
tgt.updated_at = CURRENT_TIMESTAMP
WHEN NOT MATCHED THEN
INSERT (customer_id, email, phone, created_at)
VALUES (src.customer_id, [Link], [Link], CURRENT_TIMESTAMP);

Snowflake SQL — Complete Notes Page 16


COPY INTO — Bulk Load
■ What it does
COPY INTO loads data from a Snowflake stage (internal or external S3/Azure/GCS) into a table. It is the
primary bulk-load mechanism and is highly parallelized.
■ Syntax

COPY INTO table_name


FROM @stage_name/path/
FILE_FORMAT = (TYPE = 'CSV' FIELD_DELIMITER = ',' SKIP_HEADER = 1)
[ON_ERROR = 'CONTINUE' | 'ABORT'];

■ Example

COPY INTO orders


FROM @my_s3_stage/data/orders/
FILE_FORMAT = (TYPE = 'CSV'
FIELD_DELIMITER = ','
NULL_IF = ('NULL', 'null', '')
SKIP_HEADER = 1
EMPTY_FIELD_AS_NULL = TRUE)
ON_ERROR = 'CONTINUE';

TRUNCATE TABLE
■ What it does
TRUNCATE removes all rows from a table instantly without logging individual row deletions. It is much faster
than DELETE for large tables but cannot be rolled back (no DML transaction).
■ Syntax

TRUNCATE TABLE table_name;


TRUNCATE TABLE IF EXISTS table_name;

■ Example

-- Clear staging before reload


TRUNCATE TABLE stg_daily_sales;

-- Load fresh data


COPY INTO stg_daily_sales
FROM @daily_stage/sales/
FILE_FORMAT = (TYPE = 'PARQUET');

Snowflake SQL — Complete Notes Page 17


Section 4 — Functions

String: UPPER / LOWER / TRIM


■ What it does
UPPER and LOWER convert string case. TRIM removes leading/trailing whitespace (or specific characters).
LTRIM and RTRIM trim only one side.
■ Syntax

UPPER(str) / LOWER(str)
TRIM(str [, chars])
LTRIM(str [, chars]) / RTRIM(str [, chars])

■ Example

SELECT UPPER('hello world'), -- 'HELLO WORLD'


LOWER('SNOWFLAKE'), -- 'snowflake'
TRIM(' spaces '), -- 'spaces'
TRIM('***hello***', '*'); -- 'hello'

String: CONCAT / CONCAT_WS


■ What it does
CONCAT joins strings together. CONCAT_WS (Concat With Separator) joins strings with a delimiter,
automatically skipping NULL values.
■ Syntax

CONCAT(str1, str2, ...) or str1 || str2


CONCAT_WS(separator, str1, str2, ...)

■ Example

SELECT CONCAT(first_name, ' ', last_name) AS full_name,


first_name || ' ' || last_name AS full_name2,
CONCAT_WS(', ', city, state, country) AS address
FROM customers;

Snowflake SQL — Complete Notes Page 18


String: SUBSTR / LEFT / RIGHT
■ What it does
SUBSTR (or SUBSTRING) extracts part of a string by position and length. LEFT returns the first N characters;
RIGHT returns the last N characters.
■ Syntax

SUBSTR(str, start [, length])


LEFT(str, n) / RIGHT(str, n)

■ Example

SELECT SUBSTR('Snowflake', 1, 4), -- 'Snow'


LEFT('Snowflake', 4), -- 'Snow'
RIGHT('Snowflake', 5), -- 'flake'
SUBSTR(phone, 1, 3) AS area_code
FROM contacts;

String: REPLACE / REGEXP_REPLACE


■ What it does
REPLACE substitutes all occurrences of a substring. REGEXP_REPLACE uses a regular expression pattern
for more flexible substitutions.
■ Syntax

REPLACE(str, search, replacement)


REGEXP_REPLACE(str, pattern [, replacement])

■ Example

SELECT REPLACE('Hello World', 'World', 'Snowflake'),


-- 'Hello Snowflake'

REGEXP_REPLACE(phone_number, '[^0-9]', '') AS digits_only


-- removes all non-digit characters
FROM contacts;

Snowflake SQL — Complete Notes Page 19


String: SPLIT / SPLIT_PART
■ What it does
SPLIT splits a string on a delimiter and returns an ARRAY. SPLIT_PART returns a specific part (1-indexed)
after splitting.
■ Syntax

SPLIT(str, delimiter) -- returns ARRAY


SPLIT_PART(str, delimiter, n) -- returns nth part

■ Example

SELECT SPLIT('a,b,c', ','), -- ['a','b','c']


SPLIT_PART('2024-07-15', '-', 1), -- '2024'
SPLIT_PART('2024-07-15', '-', 2), -- '07'
SPLIT_PART(email, '@', 2) AS domain
FROM users;

String: LIKE / ILIKE / REGEXP


■ What it does
LIKE matches patterns with % (any chars) and _ (one char). ILIKE is case-insensitive. REGEXP and RLIKE
match regular expression patterns.
■ Syntax

col LIKE 'pattern%'


col ILIKE '%pattern%'
col REGEXP 'regex_pattern'
col RLIKE 'regex_pattern'

■ Example

SELECT name FROM products WHERE name ILIKE '%snowflake%';

SELECT email FROM users


WHERE email LIKE '%@[Link]'
OR email REGEXP '^[a-z]+\.[a-z]+@company\.com$';

Snowflake SQL — Complete Notes Page 20


Date: CURRENT_DATE / CURRENT_TIMESTAMP
■ What it does
Returns the current date or timestamp in the session's timezone. GETDATE() is an alias for
CURRENT_TIMESTAMP. SYSDATE() returns UTC.
■ Syntax

CURRENT_DATE -- date only


CURRENT_TIMESTAMP -- date + time with timezone
GETDATE() -- same as CURRENT_TIMESTAMP
SYSDATE() -- UTC timestamp

■ Example

SELECT CURRENT_DATE,
CURRENT_TIMESTAMP,
SYSDATE()
;

-- Filter today's records


SELECT * FROM orders WHERE order_date = CURRENT_DATE;

Date: DATEADD / DATEDIFF


■ What it does
DATEADD adds or subtracts a time interval from a date or timestamp. DATEDIFF calculates the difference
between two dates in the specified unit.
■ Syntax

DATEADD(unit, n, date_expr)
DATEDIFF(unit, start_date, end_date)
Units: year, quarter, month, week, day, hour, minute, second

■ Example

SELECT DATEADD('day', 30, CURRENT_DATE), -- 30 days from now


DATEADD('month', -3, CURRENT_DATE), -- 3 months ago
DATEDIFF('day', '2024-01-01', '2024-12-31'), -- 365
DATEDIFF('month', hire_date, CURRENT_DATE) AS months_employed
FROM employees;

Snowflake SQL — Complete Notes Page 21


Date: DATE_TRUNC
■ What it does
DATE_TRUNC truncates a date or timestamp to the specified precision (year, quarter, month, week, day,
hour, etc.), setting lower-order parts to their minimum values.
■ Syntax

DATE_TRUNC('unit', date_expr)

■ Example

SELECT DATE_TRUNC('month', CURRENT_DATE), -- first of current month


DATE_TRUNC('year', order_date), -- Jan 1 of that year
DATE_TRUNC('week', event_ts), -- Monday of that week

-- Monthly revenue
SELECT DATE_TRUNC('month', order_date) AS month,
SUM(amount) AS revenue
FROM orders GROUP BY 1 ORDER BY 1;

Date: EXTRACT / DATE_PART


■ What it does
EXTRACT and DATE_PART retrieve a specific component (year, month, day, hour, etc.) from a date or
timestamp. They are functionally equivalent.
■ Syntax

EXTRACT(unit FROM date_expr)


DATE_PART('unit', date_expr)

■ Example

SELECT EXTRACT(year FROM CURRENT_DATE) AS yr,


EXTRACT(month FROM CURRENT_DATE) AS mo,
DATE_PART('dow', CURRENT_DATE) AS day_of_week,
DATE_PART('hour', CURRENT_TIMESTAMP) AS hr
;

Snowflake SQL — Complete Notes Page 22


Date: TO_DATE / TO_TIMESTAMP
■ What it does
Converts strings or numbers to DATE or TIMESTAMP types. A format model can be provided when the string
is in a non-standard format.
■ Syntax

TO_DATE(str [, format])
TO_TIMESTAMP(str [, format])
TO_TIMESTAMP_NTZ(str) -- no timezone
TO_TIMESTAMP_TZ(str) -- with timezone

■ Example

SELECT TO_DATE('2024-07-15'),
TO_DATE('15/07/2024', 'DD/MM/YYYY'),
TO_TIMESTAMP('2024-07-15 08:30:00'),
TO_TIMESTAMP_NTZ('2024-07-15T08:30:00Z')
;

Numeric: ROUND / CEIL / FLOOR / TRUNC


■ What it does
ROUND rounds to N decimal places. CEIL rounds up to the nearest integer (or decimal). FLOOR rounds
down. TRUNC truncates (removes fractional part) without rounding.
■ Syntax

ROUND(n [, d]) -- round to d decimal places


CEIL(n) / FLOOR(n)
TRUNCATE(n [, d]) or TRUNC(n [, d])

■ Example

SELECT ROUND(3.14159, 2), -- 3.14


ROUND(3.567), -- 4
CEIL(3.1), -- 4
FLOOR(3.9), -- 3
TRUNC(3.987, 1) -- 3.9
;

Snowflake SQL — Complete Notes Page 23


Numeric: ABS / MOD / POWER / SQRT
■ What it does
ABS returns the absolute value. MOD returns the remainder of division. POWER raises a number to a power.
SQRT returns the square root.
■ Syntax

ABS(n) / MOD(n, d) / POWER(n, exp) / SQRT(n)

■ Example

SELECT ABS(-42), -- 42
MOD(17, 5), -- 2
POWER(2, 10), -- 1024
SQRT(144) -- 12
;

SELECT order_id, ABS(balance) AS outstanding


FROM accounts WHERE balance < 0;

Numeric: DIV0 / NULLIF


■ What it does
DIV0 divides two numbers but returns 0 (instead of an error) if the divisor is zero. NULLIF returns NULL when
two values are equal, useful for preventing division-by-zero.
■ Syntax

DIV0(numerator, denominator) -- returns 0 if denominator = 0


NULLIF(expr1, expr2) -- returns NULL if expr1 = expr2

■ Example

SELECT DIV0(total_sales, num_orders) AS avg_order_value,


total_sales / NULLIF(num_orders, 0) AS avg_order_value2
FROM sales_summary;

Snowflake SQL — Complete Notes Page 24


Aggregate: COUNT / SUM / AVG / MIN / MAX
■ What it does
Core aggregate functions. COUNT(*) counts all rows; COUNT(col) skips NULLs. SUM, AVG, MIN, MAX
operate on numeric or comparable columns. All ignore NULLs except COUNT(*).
■ Syntax

COUNT(*) / COUNT(col) / COUNT(DISTINCT col)


SUM(col) / AVG(col) / MIN(col) / MAX(col)

■ Example

SELECT department,
COUNT(*) AS headcount,
COUNT(DISTINCT manager_id) AS managers,
SUM(salary) AS total_payroll,
ROUND(AVG(salary),2) AS avg_salary,
MIN(hire_date) AS earliest_hire,
MAX(salary) AS top_salary
FROM employees
GROUP BY department;

Aggregate: LISTAGG (String Aggregation)


■ What it does
LISTAGG concatenates string values from multiple rows into a single delimited string, optionally ordered.
Similar to GROUP_CONCAT in MySQL.
■ Syntax

LISTAGG(col, delimiter) WITHIN GROUP (ORDER BY col)

■ Example

SELECT department,
LISTAGG(first_name, ', ') WITHIN GROUP (ORDER BY first_name)
AS employee_list
FROM employees
GROUP BY department;

-- Result: Engineering | Alice, Bob, Carol

Snowflake SQL — Complete Notes Page 25


Aggregate: PERCENTILE_CONT / MEDIAN
■ What it does
PERCENTILE_CONT computes a percentile value using linear interpolation. MEDIAN is a shorthand for the
50th percentile.
■ Syntax

PERCENTILE_CONT(p) WITHIN GROUP (ORDER BY col)


MEDIAN(col)

■ Example

SELECT department,
MEDIAN(salary) AS median_salary,
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY salary) AS p25,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY salary) AS p75
FROM employees
GROUP BY department;

Window: ROW_NUMBER / RANK / DENSE_RANK


■ What it does
ROW_NUMBER assigns a unique sequential integer to each row. RANK assigns the same rank to ties but
skips numbers. DENSE_RANK assigns the same rank to ties without skipping.
■ Syntax

ROW_NUMBER() OVER (PARTITION BY col ORDER BY col)


RANK() OVER (PARTITION BY col ORDER BY col)
DENSE_RANK() OVER (PARTITION BY col ORDER BY col)

■ Example

SELECT employee_id, department, salary,


ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_
num,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dens
e_rnk
FROM employees;

-- Get top earner per department


SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) rn
FROM employees
) WHERE rn = 1;

Snowflake SQL — Complete Notes Page 26


Window: LAG / LEAD
■ What it does
LAG accesses a value from a previous row. LEAD accesses a value from a following row. Both take an
optional offset (default 1) and a default value for when no row exists.
■ Syntax

LAG(col [, offset [, default]]) OVER (PARTITION BY ... ORDER BY ...)


LEAD(col [, offset [, default]]) OVER (PARTITION BY ... ORDER BY ...)

■ Example

SELECT order_date, revenue,


LAG(revenue, 1, 0) OVER (ORDER BY order_date) AS prev_revenue,
LEAD(revenue, 1, 0) OVER (ORDER BY order_date) AS next_revenue,
revenue - LAG(revenue) OVER (ORDER BY order_date) AS delta
FROM daily_sales;

Window: SUM / AVG with Frame Clause


■ What it does
Running totals and moving averages use window aggregate functions with a ROWS or RANGE frame clause,
specifying how many preceding/following rows to include.
■ Syntax

SUM(col) OVER (ORDER BY col ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AVG(col) OVER (ORDER BY col ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)

■ Example

SELECT order_date, daily_sales,


SUM(daily_sales) OVER (ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative,
AVG(daily_sales) OVER (ORDER BY order_date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS rolling_7d_avg
FROM daily_sales;

Snowflake SQL — Complete Notes Page 27


Window: FIRST_VALUE / LAST_VALUE / NTH_VALUE
■ What it does
FIRST_VALUE and LAST_VALUE return the first or last value in a window frame. NTH_VALUE returns the
value at a specific position. Useful for per-group comparisons.
■ Syntax

FIRST_VALUE(col) OVER (PARTITION BY x ORDER BY y)


LAST_VALUE(col) OVER (PARTITION BY x ORDER BY y
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
NTH_VALUE(col, n) OVER (...)

■ Example

SELECT employee_id, department, salary,


FIRST_VALUE(salary) OVER (PARTITION BY department ORDER BY salary DESC)
AS dept_max_salary,
salary / FIRST_VALUE(salary) OVER (PARTITION BY department
ORDER BY salary DESC) AS pct_of_max
FROM employees;

Window: NTILE
■ What it does
NTILE divides the rows in an ordered partition into N approximately equal groups (buckets) and assigns each
row a bucket number from 1 to N.
■ Syntax

NTILE(n) OVER (PARTITION BY col ORDER BY col)

■ Example

-- Segment customers into 4 quartiles by spend


SELECT customer_id, total_spend,
NTILE(4) OVER (ORDER BY total_spend) AS spend_quartile
FROM customer_summary;

-- Q1 = lowest 25%, Q4 = top 25%

Snowflake SQL — Complete Notes Page 28


Conditional: COALESCE / NVL / IFF / NULLIF
■ What it does
COALESCE returns the first non-NULL value from a list. NVL is a 2-arg shorthand. IFF is a single-line
IF-ELSE. NULLIF returns NULL when two values match.
■ Syntax

COALESCE(val1, val2, ..., fallback)


NVL(val, fallback)
IFF(condition, true_val, false_val)
NULLIF(expr1, expr2)

■ Example

SELECT customer_id,
COALESCE(phone_mobile, phone_home, phone_work, 'N/A') AS contact,
NVL(discount, 0) AS discount_clean,
IFF(amount > 1000, 'High', 'Low') AS value_tier,
NULLIF(comments, '') AS comments_clean
FROM orders;

Type Conversion: CAST / TO_CHAR / TRY_CAST


■ What it does
CAST converts a value to another data type. TO_CHAR formats numbers or dates as strings. TRY_CAST is
the safe version — returns NULL instead of an error on failure.
■ Syntax

CAST(expr AS datatype) or expr::datatype


TO_CHAR(num_or_date [, format])
TRY_CAST(expr AS datatype) -- NULL on failure

■ Example

SELECT CAST('42' AS INTEGER),


'3.14'::FLOAT,
TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD'),
TO_CHAR(99999.99, '$999,999.99'),
TRY_CAST('not_a_number' AS INTEGER) -- returns NULL
;

Snowflake SQL — Complete Notes Page 29


Section 5 — Semi-Structured Data

VARIANT Data Type


■ What it does
VARIANT is Snowflake's universal semi-structured type that can hold JSON, Avro, ORC, Parquet, or XML.
Any structured value can be stored. Use :: to cast extracted values to a SQL type.
■ Syntax

col:field -- access field from VARIANT


col:field::datatype -- cast to SQL type
col['field'] -- bracket notation

■ Example

CREATE TABLE events (


event_id NUMBER,
raw_data VARIANT
);

-- Query fields from VARIANT


SELECT raw_data:user_id::INT AS user_id,
raw_data:event_name::STRING AS event_name,
raw_data:properties:page::STRING AS page
FROM events;

PARSE_JSON — Load JSON Strings


■ What it does
PARSE_JSON converts a JSON string into a Snowflake VARIANT. Useful when JSON is stored as a
VARCHAR column or provided as a literal string.
■ Syntax

PARSE_JSON(json_string) -- returns VARIANT

■ Example

SELECT PARSE_JSON('{"name": "Alice", "age": 30}') AS parsed,


PARSE_JSON('{"name": "Alice"}'):name::STRING AS name
;

-- Column stored as string, query as JSON


SELECT PARSE_JSON(json_col):status::STRING AS status
FROM raw_events;

Snowflake SQL — Complete Notes Page 30


TO_JSON — VARIANT to JSON String
■ What it does
TO_JSON converts a VARIANT value back to a JSON-formatted string. Useful for exporting or comparing
structured data.
■ Syntax

TO_JSON(variant_expr) -- returns VARCHAR

■ Example

SELECT TO_JSON(PARSE_JSON('{"a":1,"b":2}')),
-- '{"a":1,"b":2}'

TO_JSON(OBJECT_CONSTRUCT('name', first_name, 'dept', dept))


AS user_json
FROM employees;

OBJECT_CONSTRUCT
■ What it does
OBJECT_CONSTRUCT builds a Snowflake OBJECT (JSON object) from key-value pairs. Keys must be string
literals; values can be any expression. NULL values are omitted by default.
■ Syntax

OBJECT_CONSTRUCT('key1', val1, 'key2', val2, ...)


OBJECT_CONSTRUCT_KEEP_NULL(...) -- keeps NULL values

■ Example

SELECT OBJECT_CONSTRUCT(
'employee_id', employee_id,
'name', first_name || ' ' || last_name,
'department', department,
'salary', salary
) AS employee_json
FROM employees
WHERE department = 'Engineering';

Snowflake SQL — Complete Notes Page 31


ARRAY_CONSTRUCT & ARRAY Functions
■ What it does
ARRAY_CONSTRUCT builds an ARRAY literal. Other functions: ARRAY_SIZE (length), ARRAY_CONTAINS
(membership test), ARRAY_APPEND / ARRAY_PREPEND (add elements), ARRAY_SLICE (subset).
■ Syntax

ARRAY_CONSTRUCT(v1, v2, ...) -- [v1, v2, ...]


ARRAY_SIZE(arr) -- number of elements
ARRAY_CONTAINS(val, arr) -- TRUE/FALSE
ARRAY_APPEND(arr, val) -- add to end
ARRAY_SLICE(arr, from, to) -- subset

■ Example

SELECT ARRAY_CONSTRUCT(1, 2, 3, 4), -- [1,2,3,4]


ARRAY_SIZE(ARRAY_CONSTRUCT('a','b','c')), -- 3
ARRAY_CONTAINS('b', ARRAY_CONSTRUCT('a','b')), -- TRUE
ARRAY_APPEND(ARRAY_CONSTRUCT(1,2), 3), -- [1,2,3]
ARRAY_SLICE(ARRAY_CONSTRUCT(10,20,30,40), 1, 3) -- [20,30]
;

FLATTEN — Explode Arrays to Rows


■ What it does
FLATTEN is a table function that converts an array or object into rows. Each array element becomes a
separate row. Use the VALUE column to access the element.
■ Syntax

FROM table, LATERAL FLATTEN(input => array_col) f


-- or
FROM table t, TABLE(FLATTEN(t.array_col)) f

-- Key columns: [Link], [Link], [Link], [Link]

■ Example

-- Explode tags array into rows


SELECT p.product_id,
[Link]::STRING AS tag
FROM products p,
LATERAL FLATTEN(input => [Link]) f;

-- Explode nested JSON array


SELECT e.event_id,
[Link]:product_id::INT AS product_id,
[Link]:qty::INT AS quantity
FROM events e,
LATERAL FLATTEN(input => e.raw_data:items) item;

Snowflake SQL — Complete Notes Page 32


GET / GET_IGNORE_CASE / GET_PATH
■ What it does
GET extracts a field from a VARIANT/OBJECT/ARRAY by key or index. GET_IGNORE_CASE does a
case-insensitive key lookup. GET_PATH extracts deeply nested fields.
■ Syntax

GET(variant, 'key') -- same as variant:key


GET(array, index) -- same as array[n]
GET_IGNORE_CASE(variant, 'KEY')
GET_PATH(variant, 'a.b.c') -- nested path

■ Example

SELECT GET(raw_data, 'status')::STRING AS status,


GET(raw_data, 0) AS first_element,
GET_IGNORE_CASE(raw_data, 'UserID')::INT AS user_id,
GET_PATH(raw_data, '[Link]')::STRING AS city
FROM events;

ARRAY_AGG — Aggregate Rows into Array


■ What it does
ARRAY_AGG collects values from multiple rows into an ARRAY. Useful for grouping child records under a
parent, or creating JSON-like nested structures.
■ Syntax

ARRAY_AGG(col) WITHIN GROUP (ORDER BY col)

■ Example

SELECT customer_id,
ARRAY_AGG(product_id) WITHIN GROUP (ORDER BY order_date)
AS purchased_products
FROM order_items
GROUP BY customer_id;

-- Result per customer: [101, 203, 88, 310, ...]

Snowflake SQL — Complete Notes Page 33


CHECK_JSON / CHECK_XML
■ What it does
CHECK_JSON validates whether a string is valid JSON — returns NULL if valid, or an error message string if
invalid. CHECK_XML does the same for XML strings.
■ Syntax

CHECK_JSON(str) -- NULL if valid JSON, else error string


CHECK_XML(str) -- NULL if valid XML, else error string

■ Example

SELECT raw_payload,
CHECK_JSON(raw_payload) AS json_error
FROM raw_events
WHERE CHECK_JSON(raw_payload) IS NOT NULL;

-- Only process valid JSON rows


INSERT INTO clean_events
SELECT PARSE_JSON(raw_payload) FROM raw_events
WHERE CHECK_JSON(raw_payload) IS NULL;

OBJECT_KEYS & TYPEOF


■ What it does
OBJECT_KEYS returns an ARRAY of all keys in a VARIANT object. TYPEOF returns the data type of a
VARIANT value as a string (e.g., 'OBJECT', 'ARRAY', 'INTEGER').
■ Syntax

OBJECT_KEYS(variant_object) -- returns ARRAY of key names


TYPEOF(variant_expr) -- returns type string

■ Example

SELECT raw_data,
OBJECT_KEYS(raw_data) AS keys,
TYPEOF(raw_data) AS outer_type,
TYPEOF(raw_data:items) AS items_type,
TYPEOF(raw_data:count) AS count_type
FROM events
LIMIT 5;

Snowflake SQL — Complete Notes Page 34


Section 6 — Scripting & Automation

Snowflake Scripting Block (BEGIN...END)


■ What it does
Snowflake Scripting allows procedural SQL code in anonymous blocks or stored procedures. An anonymous
block starts with BEGIN and ends with END. Variables, control flow, and exception handling are all supported.
■ Syntax

DECLARE
var_name datatype [DEFAULT value];
BEGIN
-- statements
END;

■ Example

DECLARE
row_cnt INTEGER DEFAULT 0;
BEGIN
SELECT COUNT(*) INTO :row_cnt FROM orders;
RETURN 'Row count: ' || row_cnt;
END;

Snowflake SQL — Complete Notes Page 35


Variables: LET & SET
■ What it does
Inside scripting blocks, LET declares and assigns variables. In SQL sessions (outside blocks), SET assigns
session variables and GETVARIABLE or $var retrieves them.
■ Syntax

-- Session variables
SET var_name = value;
SELECT $var_name;

-- Scripting block variables


LET var_name := expression;
LET var_name datatype := expression;

■ Example

-- Session variables
SET my_date = '2024-01-01';
SELECT * FROM orders WHERE order_date >= $my_date;

-- Scripting block
DECLARE
greeting VARCHAR;
BEGIN
LET name VARCHAR := 'Snowflake';
greeting := 'Hello, ' || name || '!';
RETURN greeting;
END;

Snowflake SQL — Complete Notes Page 36


IF / ELSEIF / ELSE
■ What it does
Conditional branching in Snowflake Scripting. IF evaluates a boolean condition and executes a block. Multiple
conditions use ELSEIF. The optional ELSE handles all other cases.
■ Syntax

IF (condition) THEN
-- statements
ELSEIF (condition2) THEN
-- statements
ELSE
-- statements
END IF;

■ Example

DECLARE
score INT DEFAULT 85;
grade VARCHAR;
BEGIN
IF (score >= 90) THEN
grade := 'A';
ELSEIF (score >= 80) THEN
grade := 'B';
ELSEIF (score >= 70) THEN
grade := 'C';
ELSE
grade := 'F';
END IF;
RETURN grade; -- Returns 'B'
END;

Snowflake SQL — Complete Notes Page 37


LOOP, WHILE, FOR Loops
■ What it does
Snowflake Scripting supports LOOP (infinite until BREAK), WHILE (condition-based), and FOR (iterate over a
resultset or range). Use these for iterative data processing.
■ Syntax

-- WHILE
WHILE (condition) DO ... END WHILE;

-- FOR over query result


FOR rec IN (SELECT ...) DO ... END FOR;

-- LOOP with BREAK


LOOP ... IF (cond) THEN BREAK; END IF; END LOOP;

■ Example

DECLARE
total INT DEFAULT 0;
BEGIN
FOR rec IN (SELECT amount FROM orders WHERE status = 'pending')
DO
total := total + [Link];
END FOR;
RETURN total;
END;

-- WHILE loop
DECLARE
i INT DEFAULT 1;
BEGIN
WHILE (i <= 5) DO
INSERT INTO log_table VALUES (i, CURRENT_TIMESTAMP);
i := i + 1;
END WHILE;
END;

Snowflake SQL — Complete Notes Page 38


CASE Statement (Scripting)
■ What it does
The CASE statement in scripting (not to be confused with the CASE expression in SQL) evaluates a variable
against multiple values and executes the matching branch.
■ Syntax

CASE variable
WHEN val1 THEN -- statements;
WHEN val2 THEN -- statements;
ELSE -- statements;
END CASE;

■ Example

DECLARE
status VARCHAR DEFAULT 'active';
msg VARCHAR;
BEGIN
CASE status
WHEN 'active' THEN msg := 'User is active';
WHEN 'inactive' THEN msg := 'User is inactive';
WHEN 'banned' THEN msg := 'User is banned';
ELSE msg := 'Unknown status';
END CASE;
RETURN msg;
END;

Snowflake SQL — Complete Notes Page 39


EXCEPTION Handling
■ What it does
Snowflake Scripting supports structured exception handling. The EXCEPTION block catches errors by name
or catches all errors with WHEN OTHER. Use RAISE to re-throw or throw custom exceptions.
■ Syntax

BEGIN
-- risky statements
EXCEPTION
WHEN exception_name THEN -- handle;
WHEN OTHER THEN
RAISE; -- re-throw
END;

■ Example

BEGIN
INSERT INTO audit_log VALUES (1, 'start', CURRENT_TIMESTAMP);
-- This might fail
INSERT INTO orders VALUES (NULL, NULL, NULL);
EXCEPTION
WHEN OTHER THEN
INSERT INTO error_log
VALUES (SQLCODE, SQLERRM, CURRENT_TIMESTAMP);
RAISE;
END;

Snowflake SQL — Complete Notes Page 40


Stored Procedures — CREATE PROCEDURE
■ What it does
Stored procedures encapsulate reusable logic. In Snowflake, procedures can be written in JavaScript,
Snowpark (Python/Java/Scala), or SQL Scripting. They can return a value and accept parameters.
■ Syntax

CREATE OR REPLACE PROCEDURE proc_name(param1 TYPE, ...)


RETURNS return_type
LANGUAGE SQL
AS
BEGIN
-- body
RETURN value;
END;

CALL proc_name(arg1);

■ Example

CREATE OR REPLACE PROCEDURE archive_old_orders(cutoff_date DATE)


RETURNS VARCHAR
LANGUAGE SQL
AS
BEGIN
INSERT INTO orders_archive
SELECT * FROM orders WHERE order_date < cutoff_date;

DELETE FROM orders WHERE order_date < cutoff_date;

RETURN 'Archived orders before ' || cutoff_date;


END;

CALL archive_old_orders('2022-01-01');

Snowflake SQL — Complete Notes Page 41


Stored Procedures — JavaScript Runtime
■ What it does
Snowflake stored procedures can be written in JavaScript using the Snowflake JS API. Use
[Link]() to run SQL, and getColumnValue() to read results.
■ Syntax

CREATE OR REPLACE PROCEDURE proc()


RETURNS VARIANT
LANGUAGE JAVASCRIPT
AS
$$
var result = [Link]({sqlText: 'SELECT ...'});
[Link]();
return [Link](1);
$$;

■ Example

CREATE OR REPLACE PROCEDURE get_row_count(table_name VARCHAR)


RETURNS FLOAT
LANGUAGE JAVASCRIPT
AS
$$
var sql = 'SELECT COUNT(*) FROM ' + TABLE_NAME;
var stmt = [Link]({sqlText: sql});
var result = [Link]();
[Link]();
return [Link](1);
$$;

CALL get_row_count('orders');

Snowflake SQL — Complete Notes Page 42


Tasks — Scheduled SQL Execution
■ What it does
Tasks automate SQL or stored procedure execution on a schedule (using CRON syntax or interval). Tasks
can be chained to build pipelines. They require a warehouse or can use serverless compute.
■ Syntax

CREATE TASK task_name


WAREHOUSE = warehouse_name
SCHEDULE = 'USING CRON 0 * * * * UTC'
AS
-- SQL statement or CALL proc;

ALTER TASK task_name RESUME;

■ Example

CREATE OR REPLACE TASK daily_refresh


WAREHOUSE = compute_wh
SCHEDULE = 'USING CRON 0 2 * * * UTC' -- 2am UTC daily
AS
CALL refresh_sales_summary();

ALTER TASK daily_refresh RESUME;

-- Check task history


SELECT * FROM TABLE(INFORMATION_SCHEMA.TASK_HISTORY())
WHERE NAME = 'DAILY_REFRESH'
ORDER BY SCHEDULED_TIME DESC LIMIT 10;

Snowflake SQL — Complete Notes Page 43


Streams — Change Data Capture
■ What it does
A stream tracks DML changes (INSERT, UPDATE, DELETE) on a table. Querying the stream returns new
changes with metadata columns: METADATA$ACTION, METADATA$ISUPDATE, METADATA$ROW_ID.
■ Syntax

CREATE STREAM stream_name ON TABLE table_name;

-- Consume stream (DML that consumes the offset)


INSERT INTO target SELECT * FROM stream_name WHERE METADATA$ACTION='INSERT';

■ Example

CREATE STREAM orders_stream ON TABLE orders;

-- See pending changes


SELECT * FROM orders_stream;

-- Process new inserts into a target


INSERT INTO orders_processed
SELECT order_id, customer_id, amount, CURRENT_TIMESTAMP AS processed_at
FROM orders_stream
WHERE METADATA$ACTION = 'INSERT';

-- Check if stream has unconsumed data


SELECT SYSTEM$STREAM_HAS_DATA('orders_stream');

Snowflake SQL — Complete Notes Page 44


Dynamic Tables
■ What it does
Dynamic tables automatically refresh their contents based on a target lag time (how stale the data can be).
They declaratively define a transformation and Snowflake handles incremental refresh.
■ Syntax

CREATE DYNAMIC TABLE dyn_table_name


TARGET_LAG = 'n minutes'
WAREHOUSE = wh_name
AS
SELECT ... FROM source_table;

■ Example

CREATE OR REPLACE DYNAMIC TABLE daily_sales_summary


TARGET_LAG = '1 hour'
WAREHOUSE = compute_wh
AS
SELECT DATE_TRUNC('day', order_date) AS sale_date,
product_id,
SUM(amount) AS total_revenue,
COUNT(*) AS order_count
FROM orders
GROUP BY 1, 2;

Snowflake SQL — Complete Notes Page 45

You might also like