The goal of this project is to build a ClickHouse SQL parser in Go with the following key features:
- Parse ClickHouse SQL into AST
- Beautify ClickHouse SQL format
This project is inspired by memefish which is a SQL parser for Spanner in Go.
You can use it as your Go library or CLI tool, see the following examples:
- Use clickhouse-sql-parser as a Go library
package main
import (
clickhouse "github.com/AfterShip/clickhouse-sql-parser/parser"
)
query := "SELECT * FROM clickhouse"
parser := clickhouse.NewParser(query)
// Parse query into AST
statements, err := parser.ParseStmts()
if err != nil {
return nil, err
}- Install clickhouse-sql-parser as a CLI tool
On Linux:
$ go install github.com/AfterShip/clickhouse-sql-parser@latestOn macOS:
$ brew install clickhouse-sql-parserParse ClickHouse SQL into AST or format ClickHouse SQL:
## Parse query into AST
$ clickhouse-sql-parser "SELECT * FROM clickhouse WHERE a=100"
## Format query (compact, single-line output)
$ clickhouse-sql-parser -format "SELECT * FROM clickhouse WHERE a=100"
## Beautify query (formatted with proper indentation and line breaks)
$ clickhouse-sql-parser -beautify "SELECT * FROM clickhouse WHERE a=100"
## Parse query from file
$ clickhouse-sql-parser -f ./test.sqlThe -beautify flag formats SQL with proper indentation and line breaks, making complex queries more readable:
# Input (compact, hard to read)
$ clickhouse-sql-parser -beautify "SELECT user_id, COUNT(*) AS total, AVG(amount) AS avg_amount FROM orders WHERE status='completed' AND created_at>'2024-01-01' GROUP BY user_id HAVING COUNT(*)>5 ORDER BY total DESC LIMIT 10"
# Output (beautified, easy to read)
SELECT
user_id,
COUNT(*) AS total,
AVG(amount) AS avg_amount
FROM orders
WHERE
status = 'completed'
AND
created_at > '2024-01-01'
GROUP BY
user_id
HAVING COUNT(*) > 5
ORDER BY
total DESC
LIMIT 10- Parsed tree(AST) back into a SQL statement
parser := clickhouse.NewParser("SELECT * FROM clickhouse")
// Parse query into AST
statements, err := parser.ParseStmts()
if err != nil {
return nil, err
}
// Format AST back into a SQL string
for _, stmt := range statements {
fmt.Println(clickhouse.Format(stmt))
}The Walk pattern provides a simple and efficient way to traverse AST nodes. Use the Walk function to visit all nodes in the AST:
import (
clickhouse "github.com/AfterShip/clickhouse-sql-parser/parser"
)
parser := clickhouse.NewParser("SELECT * FROM table WHERE id = 1")
statements, err := parser.ParseStmts()
if err != nil {
return err
}
// Walk through all nodes in the AST
clickhouse.Walk(statements[0], func(node clickhouse.Expr) bool {
fmt.Printf("Node type: %T\n", node)
return true // return false to stop traversal for this subtree
})Walk(node Expr, fn WalkFunc)- Traverses all nodes in depth-first orderWalkWithBreak(node Expr, fn WalkFunc)- Allows early termination of traversalFind(root Expr, predicate func(Expr) bool)- Finds the first node matching a conditionFindAll(root Expr, predicate func(Expr) bool)- Finds all nodes matching a conditionTransform(root Expr, transformer func(Expr) Expr)- Applies transformations to nodes
Find all table identifiers:
tables := clickhouse.FindAll(stmt, func(node clickhouse.Expr) bool {
_, ok := node.(*clickhouse.TableIdentifier)
return ok
})Find the first WHERE clause:
whereClause, found := clickhouse.Find(stmt, func(node clickhouse.Expr) bool {
_, ok := node.(*clickhouse.WhereClause)
return ok
})For the files inside output and format dir are generated by the test cases,
if you want to update them, you can run the following command:
$ make update_testSee docs/benchmarks.md for how to run the benchmarks and the latest results.
Feel free to open a PR and add your projects here:
- SigNoz: OpenTelemetry-native observability platform with logs, metrics and traces in one tool.
- Unkey: The developer platform for modern APIs.
- Akvorado: Flow collector, enricher and visualizer.
- Trickster: HTTP reverse proxy cache and time series database query accelerator.
- Measure: Open source mobile monitoring for crashes, ANRs and performance issues.
- Clawpatrol: Security firewall for agents.
- Logchef: Lightweight, single-binary log analytics interface for ClickHouse.
- Substreams: Blockchain streaming data engine based on StreamingFast Firehose technology.
- Altinity MCP: Model Context Protocol server to use ClickHouse databases in your AI agents.
If you are an AI coding agent (or are using one) to contribute to this project, read AGENTS.md first and use it as your working context. It covers the project structure, coding style, testing workflow, and contribution practices — including validating SQL against clickhouse-local before adding new syntax or fixing parsing issues.
Feel free to open an issue or discussion if you have any issues or questions.