AI 기반 SQL 생성
AI 기반 SQL 생성
ClickHouse 25.7부터 ClickHouse Client와 clickhouse-local에는 자연어 설명을 SQL 쿼리로 변환하는 AI 기반 기능이 포함되어 있어요. 이 기능을 사용하면 데이터 요구 사항을 평문으로 설명하기만 하면 시스템이 그에 해당하는 SQL 문장으로 변환해줘요. 이 기능은 복잡한 SQL 구문에 익숙하지 않거나 탐색적 데이터 분석용 쿼리를 빠르게 생성해야 할 때 특히 유용해요. 이 기능은 표준 ClickHouse 테이블과 함께 동작하며 필터링, 집계, 조인을 포함한 일반적인 쿼리 패턴을 지원해요. 다음의 내장 도구/함수의 도움을 받아 동작해요:
list_databases- ClickHouse 인스턴스에 있는 모든 데이터베이스 나열list_tables_in_database- 특정 데이터베이스의 모든 테이블 나열get_schema_for_table- 특정 테이블의CREATE TABLE문(스키마) 가져오기
출처: 문서
본문
준비 사항 (Prerequisites)
Anthropic 또는 OpenAI 키를 환경 변수로 추가해야 해요.
export ANTHROPIC_API_KEY=your_api_key
export OPENAI_API_KEY=your_api_key
또는 구성 파일을 제공할 수도 있어요.
ClickHouse SQL 플레이그라운드에 연결하기
이 기능을 ClickHouse SQL 플레이그라운드로 탐색해볼 거예요. 다음 명령으로 ClickHouse SQL 플레이그라운드에 연결할 수 있어요.
clickhouse client -mn \
--host sql-clickhouse.clickhouse.com \
--secure \
--user demo --password ''
ClickHouse가 설치되어 있다고 가정할게요. 아니라면 설치 가이드를 참고해요.
자연어로 ClickHouse에 질문하기
이제 질문을 시작할 시간이에요! 텍스트를 SQL로 변환하는 이 기능은 본질적으로 원샷(one-shot) 쿼리 생성 도구예요. 대화 기록을 유지하지 않으므로 질문에 최대한 많은 유용한 문맥을 포함해야 해요. 구체적으로 명시할 것들: 시간 범위나 날짜 범위, 원하는 분석 유형(평균, 합계, 순위 등), 필터링 기준.
비싼 주택 시장 찾기
주택 가격에 대한 질문부터 시작해볼게요. SQL 플레이그라운드에는 UK 주택 가격 데이터셋이 있는데, AI가 자동으로 발견할 거예요.
?? Can you tell me the most expensive place to buy a house in 2021?;
엔터를 누르면 AI가 우리 질문에 답하려는 사고 과정이 보여요.
• Starting AI SQL generation with schema discovery...
─────────────────────────────────────────────────
🧠 thinking...[INFO] Text generation successful - model: claude-3-5-sonnet-latest, response_id: msg_01QpQd35ZD8HM9QSYFZuQ8Wh
🔧 Calling: list_databases [toolu_01...]
🧠 thinking✓ list_databases completed
└─ Found 37 databases: - amazon - bluesky - country - covid - default - dns - en...
🔧 Calling: list_databases [toolu_01...]
✓ list_databases completed
└─ Found 37 databases: - amazon - bluesky - country - covid - default - dns - en...
🧠 thinking[INFO] Text generation successful - model: claude-3-5-sonnet-latest, response_id: msg_016DxK8SMVKGrUPfFwi43AzE
🔧 Calling: list_tables_in_database [toolu_01...]
└─ Args: {"database":"uk"}
🧠 thinking.✓ list_tables_in_database completed
└─ Found 9 tables in database 'uk': - uk_codes - uk_postcode_to_iso - uk_price_p...
🔧 Calling: list_tables_in_database [toolu_01...]
└─ Args: {"database":"uk"}
✓ list_tables_in_database completed
└─ Found 9 tables in database 'uk': - uk_codes - uk_postcode_to_iso - uk_price_p...
🧠 thinking.[INFO] Text generation successful - model: claude-3-5-sonnet-latest, response_id: msg_015giF12wm619beNGC5aTrmw
🔧 Calling: get_schema_for_table [toolu_01...]
└─ Args: {"database":"uk","table":"uk_price_paid"}
✓ get_schema_for_table completed
└─ Schema for uk.uk_price_paid: CREATE TABLE uk.uk_price_paid ( `price` UInt...
🔧 Calling: get_schema_for_table [toolu_01...]
└─ Args: {"database":"uk","table":"uk_price_paid"}
🧠 thinking..✓ get_schema_for_table completed
└─ Schema for uk.uk_price_paid: CREATE TABLE uk.uk_price_paid ( `price` UInt...
🧠 thinking[INFO] Text generation successful - model: claude-3-5-sonnet-latest, response_id: msg_01HxT1HKbaTT3165Wx5bDtY9
─────────────────────────────────────────────────
• ✨ SQL query generated successfully!
:) SELECT town, district, county, round(avg(price), 2) as avg_price, count() as total_sales FROM uk.uk_price_paid WHERE date >= '2021-01-01' AND date <= '2021-12-31' GROUP BY town, district, county HAVING total_sales >= 10 ORDER BY avg_price DESC LIMIT 10
AI는 다음 단계를 따릅니다:
- 스키마 탐색 - 사용 가능한 데이터베이스와 테이블 탐색
- 테이블 분석 - 관련 테이블의 구조 검사
- 쿼리 생성 - 질문과 발견된 스키마를 기반으로 SQL 생성
uk_price_paid 테이블을 찾아 실행할 쿼리를 생성한 것을 볼 수 있어요. 그 쿼리를 실행하면 다음과 같은 출력이 보여요.
┌─town───────────┬─district───────────────┬─county──────────┬──avg_price─┬─total_sales─┐
│ ILKLEY │ HARROGATE │ NORTH YORKSHIRE │ 4310200 │ 10 │
│ LONDON │ CITY OF LONDON │ GREATER LONDON │ 4008117.32 │ 311 │
│ LONDON │ CITY OF WESTMINSTER │ GREATER LONDON │ 2847409.81 │ 3984 │
│ LONDON │ KENSINGTON AND CHELSEA │ GREATER LONDON │ 2331433.1 │ 2594 │
│ EAST MOLESEY │ RICHMOND UPON THAMES │ GREATER LONDON │ 2244845.83 │ 12 │
│ LEATHERHEAD │ ELMBRIDGE │ SURREY │ 2051836.42 │ 102 │
│ VIRGINIA WATER │ RUNNYMEDE │ SURREY │ 1914137.53 │ 169 │
│ REIGATE │ MOLE VALLEY │ SURREY │ 1715780.89 │ 18 │
│ BROADWAY │ TEWKESBURY │ GLOUCESTERSHIRE │ 1633421.05 │ 19 │
│ OXFORD │ SOUTH OXFORDSHIRE │ OXFORDSHIRE │ 1628319.07 │ 405 │
└────────────────┴────────────────────────┴─────────────────┴────────────┴─────────────┘
후속 질문을 하고 싶다면 질문을 처음부터 새로 해야 해요.
그레이터 런던에서 비싼 부동산 찾기
이 기능은 대화 기록을 유지하지 않으므로 각 쿼리는 자체적으로 완결되어야 해요. 후속 질문을 할 때는 이전 쿼리를 참조하기보다 전체 문맥을 제공해야 해요. 예를 들어 이전 결과를 본 뒤 그레이터 런던 부동산에 집중하고 싶을 수 있어요. “What about Greater London?”과 같이 묻는 대신 완전한 문맥을 포함해야 해요.
?? Can you tell me the most expensive place to buy a house in Greater London across the years?;
방금 이 데이터를 검사했음에도 AI가 같은 탐색 과정을 거치는 것에 주목하세요.
• Starting AI SQL generation with schema discovery...
─────────────────────────────────────────────────
🧠 thinking[INFO] Text generation successful - model: claude-3-5-sonnet-latest, response_id: msg_012m4ayaSHTYtX98gxrDy1rz
🔧 Calling: list_databases [toolu_01...]
✓ list_databases completed
└─ Found 37 databases: - amazon - bluesky - country - covid - default - dns - en...
🔧 Calling: list_databases [toolu_01...]
🧠 thinking.✓ list_databases completed
└─ Found 37 databases: - amazon - bluesky - country - covid - default - dns - en...
🧠 thinking.[INFO] Text generation successful - model: claude-3-5-sonnet-latest, response_id: msg_01KU4SZRrJckutXUzfJ4NQtA
🔧 Calling: list_tables_in_database [toolu_01...]
└─ Args: {"database":"uk"}
🧠 thinking..✓ list_tables_in_database completed
└─ Found 9 tables in database 'uk': - uk_codes - uk_postcode_to_iso - uk_price_p...
🔧 Calling: list_tables_in_database [toolu_01...]
└─ Args: {"database":"uk"}
✓ list_tables_in_database completed
└─ Found 9 tables in database 'uk': - uk_codes - uk_postcode_to_iso - uk_price_p...
🧠 thinking[INFO] Text generation successful - model: claude-3-5-sonnet-latest, response_id: msg_01X9CnxoBpbD2xj2UzuRy2is
🔧 Calling: get_schema_for_table [toolu_01...]
└─ Args: {"database":"uk","table":"uk_price_paid"}
🧠 thinking.✓ get_schema_for_table completed
└─ Schema for uk.uk_price_paid: CREATE TABLE uk.uk_price_paid ( `price` UInt...
🔧 Calling: get_schema_for_table [toolu_01...]
└─ Args: {"database":"uk","table":"uk_price_paid"}
✓ get_schema_for_table completed
└─ Schema for uk.uk_price_paid: CREATE TABLE uk.uk_price_paid ( `price` UInt...
🧠 thinking...[INFO] Text generation successful - model: claude-3-5-sonnet-latest, response_id: msg_01QTMypS1XuhjgVpDir7N9wD
─────────────────────────────────────────────────
• ✨ SQL query generated successfully!
:) SELECT district, toYear(date) AS year, round(avg(price), 2) AS avg_price, count() AS total_sales FROM uk.uk_price_paid WHERE county = 'GREATER LONDON' GROUP BY district, year HAVING total_sales >= 10 ORDER BY avg_price DESC LIMIT 10;
이것은 그레이터 런던에 대해서만 구체적으로 필터링하고 연도별로 결과를 나누는 더 표적화된 쿼리를 생성해요. 쿼리의 출력은 아래와 같아요.
┌─district────────────┬─year─┬───avg_price─┬─total_sales─┐
│ CITY OF LONDON │ 2019 │ 14504772.73 │ 299 │
│ CITY OF LONDON │ 2017 │ 6351366.11 │ 367 │
│ CITY OF LONDON │ 2016 │ 5596348.25 │ 243 │
│ CITY OF LONDON │ 2023 │ 5576333.72 │ 252 │
│ CITY OF LONDON │ 2018 │ 4905094.54 │ 523 │
│ CITY OF LONDON │ 2021 │ 4008117.32 │ 311 │
│ CITY OF LONDON │ 2025 │ 3954212.39 │ 56 │
│ CITY OF LONDON │ 2014 │ 3914057.39 │ 416 │
│ CITY OF LONDON │ 2022 │ 3700867.19 │ 290 │
│ CITY OF WESTMINSTER │ 2018 │ 3562457.76 │ 3346 │
└─────────────────────┴──────┴─────────────┴─────────────┘
CITY OF LONDON이 가장 비싼 지역으로 일관되게 나타나요! AI가 합리적인 쿼리를 만들었지만 결과가 시간순이 아니라 평균 가격 순으로 정렬된 것을 볼 수 있어요. 전년 대비 분석을 원한다면 "the most expensive district each year"를 구체적으로 요청하도록 질문을 다듬어 다른 방식으로 그룹화된 결과를 얻을 수 있어요.