---
title: QueryScope
---

> [!WARNING]
> Legacy documentation: This documentation applies to **Legacy Deephaven Enterprise only** and does not apply to Core+.

> [!NOTE]
> For Core+ workers, see Community Core documentation for [query scope](/core/groovy/docs/reference/query-language/variables/scope).

Variables in your formula are either taken from columns or the QueryScope, which dictates what variables and methods are accessible within a query. Furthermore, using variables from the QueryScope can reduce execution time. Changing QueryScope variables does not require query strings to be recompiled, while changing literal values in query strings may require the query string to be recompiled.

Consider the following query:

`t2=t1.update("X=f.call(A,b)")`

`X` and `A` are columns, `f` is a function, and `b` is some variable. The `"X=f.call(A,b)"` string is called a "query string".

This query string gets dynamically converted into code, which is compiled to improve execution speed while having an expressive query language. It is obvious that the columns come from the table. It is less obvious where the variable b comes from. These variables come from the "query scope".

## Python

If you are at the top level of a Python program, the variables are automatically added to the scope. For example, the following query **will** work:

```python
from deephaven import TableTools

z = 3
result2 = TableTools.emptyTable(10).update("X=i", "Y=z+X")
```

If you are in a function, the variables are not automatically added to the binding, so this query **will not** work:

```python should-fail
def y():
    b = 3
    return TableTools.emptyTable(10).update("X=i", "Y=b=X")


y()
```

The variables can be explicitly added to the binding as in this example:

```python
from deephaven import TableTools
from deephaven import QueryScope


def f(a, b):
    return a * b


def compute(a):
    # Values must be added to the query scope to be used in query strings.
    QueryScope.addParam("a", a)
    return TableTools.emptyTable(10).update("X=i", "Y=(int)f.call(a,X)")


result1 = compute(10)
# Because variable "z" is in the top level scope of the Python file,
# it is automatically added to the scope
z = 3
result2 = TableTools.emptyTable(10).update("X=i", "Y=(int)f.call(z,X)")
```

![img](../../assets/coreops/queryscope1.png)

> [!NOTE]
> The QueryScope is the scope for the query; it does not map to the scope of the programming language. As a result, if you add an item within a code block, the item is still in the query scope after the code block returns (in other words, the variable is still in the query scope after the function that sets it returns).

If you later call a function using the variable `a`, you could get bad results:

```python should-fail
def computeBadScope(a: int):
    return TableTools.emptyTable(10).update("X=i", "Y=a+X")
```

This query will execute because `a` is already in the query scope from an earlier call to `compute()`. However, the `a` set by `compute` may be totally different than the argument to `computeBadScope()`, which will produce unintended results.

## Groovy

Variables that are in the global Groovy binding are automatically added to the QueryScope, as in the following query:

```groovy skip-test
z=3
result2 = emptyTable(10).update("X=i","Y=(int)f.call(z,X)")
```

If you are in a function, the variables are not automatically added to the binding, so this query **will not** work:

```groovy should-fail
f = {int a, int b -> a*b}
```

The variables can be explicitly added to the binding as in this example:

```groovy
// Variable "a" is not in the global Groovy binding, so it must be added to the QueryScope.
compute = { int a ->
   QueryScope.addParam("a",a)
   return emptyTable(10).update("X=i", "Y=X+a")
}
result1 = compute(10)
```

![img](../../assets/coreops/queryscope2.png)

> [!NOTE]
> The QueryScope is the scope for the query; it does not map to the scope of the programming language. As a result, if you add an item within a code block, the item is still in the query scope after the code block returns (in other words, the variable is still in the query scope after the function that sets it returns). For instance, if you later call a function using the variable `a`, you could get bad results.

Variables defined without `"def"` inside closures are added to the global Groovy binding, so they are automatically available in the QueryScope:

```groovy skip-test
y = { ->
    b=3
    return emptyTable(10).update("X=i","Y=b=X")
}
result3 = y()
result4 = = emptyTable(10).update("Z=b")
```

However, Groovy variables defined with "def" are not part of the global Groovy binding, so they are not available, unless they are added to the QueryScope.

So the following query **does not** work:

```groovy should-fail
def v1 = 4
result5 = emptyTable(10).update("V1=v1")
```

The following query **does** work:

```groovy
v1 = 4
result5 = emptyTable(10).update("V1=v1")
```

Groovy variables defined with a type are also not part of the global Groovy binding, so they are not available, unless they are added to the QueryScope.

So the following query **does not** work:

```groovy should-fail
int v2 = 4
result5 = emptyTable(10).update("V2=v2")
```

The following query **does** work:

```groovy
v2 = 4
result5 = emptyTable(10).update("V2=v2")
```
