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.

API References

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

Running a query

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.

Parameterizing queries

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,
)

Handling multi-statement queries

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)
}

Composing queries with QueryRaw

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)
}

Defining connection variables

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.

Learn more