Executing queries

The Go SDK provides two ways to execute SurrealQL queries: Query for typed, parameterized queries and QueryRaw for composing multiple statements with per-statement results. Both are generic functions that work with *DB, *Session, and *Transaction.

This page covers running queries, parameterizing them, handling multi-statement results, and managing connection-scoped variables.

FunctionDescription
surrealdb.Query[T](ctx, s, sql, vars)Executes a SurrealQL query with typed results
surrealdb.QueryRaw(ctx, s, queries)Executes a batch of query statements with per-statement results
db.Let(ctx, key, val)Defines a variable on the connection for use in queries
db.Unset(ctx, key)Removes a previously defined connection variable

The Query function executes a SurrealQL string and returns typed results. The first type parameter specifies the expected result type. The second parameter s can be a *DB, *Session, or *Transaction.

results, err := surrealdb.Query[[]Person](ctx, db,
"SELECT * FROM persons WHERE age > $min_age",
map[string]any{"min_age": 18},
)
if err != nil {
log.Fatal(err)
}

for _, qr := range *results {
fmt.Println(qr.Status, qr.Result)
}

The function returns *[]QueryResult[T], where each QueryResult contains the Status, execution Time, Result, and an optional Error for that statement.

Always use parameters ($name) instead of string interpolation to prevent injection attacks and ensure correct CBOR encoding of value types.

results, err := surrealdb.Query[[]Person](ctx, db,
"SELECT * FROM persons WHERE name = $name AND age > $age",
map[string]any{
"name": "Tobie",
"age": 25,
},
)

Pass nil for the variables map when no parameters are needed:

results, err := surrealdb.Query[[]Person](ctx, db,
"SELECT * FROM persons",
nil,
)

When a query string contains multiple statements, Query returns a QueryResult for each statement. Check the Error field on each result to detect per-statement failures.

results, err := surrealdb.Query[[]any](ctx, db,
"CREATE person:tobie SET name = 'Tobie'; SELECT * FROM person;",
nil,
)

for i, qr := range *results {
if qr.Error != nil {
fmt.Printf("Statement %d failed: %s\n", i, qr.Error.Message)
continue
}
fmt.Printf("Statement %d: %v\n", i, qr.Result)
}

QueryRaw lets you compose a batch of QueryStmt objects, each with its own SQL and variables. After execution, each statement's result is available via .GetResult().

stmts := []surrealdb.QueryStmt{
{SQL: "CREATE person:alice SET name = $name", Vars: map[string]any{"name": "Alice"}},
{SQL: "SELECT * FROM person", Vars: nil},
}

if err := surrealdb.QueryRaw(ctx, db, &stmts); err != nil {
log.Fatal(err)
}

var persons []Person
if err := stmts[1].GetResult(&persons); err != nil {
log.Fatal(err)
}

Use .Let() to define a variable that persists on the connection and is available in all subsequent queries. Use .Unset() to remove it.

if err := db.Let(ctx, "app_version", "1.0.0"); err != nil {
log.Fatal(err)
}

results, err := surrealdb.Query[[]any](ctx, db,
"RETURN $app_version",
nil,
)

db.Unset(ctx, "app_version")

Connection variables are scoped to the connection (or session if using sessions). They do not affect other connections. You can also build queries programmatically using the query builder.

Was this page helpful?