AugmentClaude

Snowflake SQL

Write optimized Snowflake queries using QUALIFY, FLATTEN, and semi-structured data patterns.

Installation

  1. Make sure Claude is on your device and in your terminal.

    Skills load from ~/.claude/skills/ when Claude Code starts up — so you need it on your machine first. If you don't have it yet, install it once with the command below, then run claude in any terminal to verify.

    One-time setup
    npm i -g @anthropic-ai/claude-code

    Already have it? Skip ahead.

  2. Paste into Claude Code or into your terminal.

    This copies the whole skill folder into ~/.claude/skills/snowflake-sql-signalpilot-labs/ — the SKILL.md plus any scripts, reference docs, or templates the skill ships with. Safe default: works for every skill.

    Faster alternative (instruction-only skills)

    Skips the clone and grabs only the SKILL.md file. Don't use this if the skill ships Python scripts, reference markdowns, or asset templates — they won't be downloaded and the skill will fail when it tries to load them.

    Quick install (SKILL.md only)
    Sign up to copy
  3. Restart Claude Code.

    Quit and reopen Claude Code (or any other agent that loads from ~/.claude/skills/). New skills are picked up on startup.

  4. Just ask Claude.

    Skills auto-activate when your request matches the skill's description — no slash command needed. Trigger phrases live in the skill's own frontmatter; you can read them in the “What this skill does” section above.

Prefer to read the source first? Open on GitHub.

When Claude uses it

Snowflake-specific SQL patterns: QUALIFY for window filtering, LATERAL FLATTEN for arrays, semi-structured VARIANT data, ILIKE for case-insensitive matching, date functions, and time travel.

What this skill does

Snowflake SQL Skill

1. Window Function Filtering — Use QUALIFY

Instead of wrapping in a subquery, use QUALIFY:

-- Find the latest record per customer
SELECT customer_id, order_date, amount
FROM orders
QUALIFY ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) = 1;

-- Top 5 products by sales
SELECT product_id, total_sales
FROM sales_summary
QUALIFY DENSE_RANK() OVER (ORDER BY total_sales DESC) <= 5;

2. Case-Insensitive Matching — Use ILIKE

-- Case-insensitive LIKE
WHERE product_name ILIKE '%widget%'

-- Case-insensitive equality
WHERE UPPER(status) = 'ACTIVE'
-- or
WHERE status ILIKE 'active'

3. Arrays and Semi-Structured Data — LATERAL FLATTEN

-- Explode an ARRAY column
SELECT t.id, f.value AS item
FROM table t,
LATERAL FLATTEN(input => t.array_col) f;

-- Access VARIANT fields
SELECT col:field_name::STRING AS field_value
FROM table;

-- Parse JSON string
SELECT PARSE_JSON(json_col):key::STRING AS val
FROM table;

4. Date Functions

-- Add/subtract time
DATEADD(day, 7, order_date)          -- 7 days from order_date
DATEADD(month, -1, current_date())   -- 1 month ago

-- Difference between dates
DATEDIFF(day, start_date, end_date)  -- days between dates
DATEDIFF(month, start_date, end_date)

-- Truncate to period
DATE_TRUNC('month', event_ts)
DATE_TRUNC('year', event_ts)

-- Current timestamp
CURRENT_TIMESTAMP()
CURRENT_DATE()

5. String Functions

SPLIT_PART(col, '/', 1)              -- split by delimiter, get Nth part
REGEXP_SUBSTR(col, '[0-9]+')         -- first match of regex
TRIM(col)                            -- remove leading/trailing whitespace
LTRIM(col, '0')                      -- remove leading zeros
UPPER(col) / LOWER(col)
CONCAT(col1, '-', col2)              -- or col1 || '-' || col2

6. Null-Safe Equality

-- NULL-safe: TRUE when both are NULL or both equal
col1 IS NOT DISTINCT FROM col2

-- COALESCE for default values
COALESCE(col, 'unknown')

7. Time Travel (querying historical data)

-- Query table as it was 1 hour ago
SELECT * FROM my_table AT (OFFSET => -3600);

-- Query at a specific timestamp
SELECT * FROM my_table AT (TIMESTAMP => '2024-01-01'::TIMESTAMP);

8. Common Anti-Patterns to Avoid

  • Do NOT use = NULL — use IS NULL
  • Do NOT use <> for NULL comparison — use IS NOT NULL
  • Prefer QUALIFY over subquery wrapping for window filters
  • When accessing VARIANT fields, always cast: col:field::STRING

9. Benchmark Patterns

  • Numeric precision: Snowflake returns DECIMAL/NUMBER with configurable precision. Do NOT cast to FLOAT unless needed — precision loss fails exact-match evaluation.
  • IDENTIFIER case: Snowflake upper-cases identifiers by default. Use double-quotes "lower_case_col" when column names are lowercase in source. Always check with describe_table.
  • LISTAGG: Use LISTAGG(col, ',') WITHIN GROUP (ORDER BY col) for string aggregation (not GROUP_CONCAT).
  • TRY_CAST / TRY_TO_NUMBER: Use for safe type conversion that returns NULL instead of error.
  • OBJECT_KEYS / ARRAY_SIZE: Useful for introspecting semi-structured data before querying.

Related skills