> For the complete documentation index, see [llms.txt](https://docs.ninox.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ninox.com/ninox-scripting/automate-your-workflows/explore-core-scripting-elements/statements.md).

# Statements

Statements are the building blocks of Ninox logic. They decide what runs, which records to work with, and when logic should repeat.\
Once you know these patterns, you can turn simple logic into workflows that are easier to read, test, and maintain.

{% hint style="info" %}
If you are new to scripting, focus on three basics first:

* use `if` to make decisions
* use `select` to find records
* use `for ... in ... do ... end` to work through those records one by one
  {% endhint %}

| Statement                            | What it does                                         |
| ------------------------------------ | ---------------------------------------------------- |
| `create`                             | Creates a new record in a table                      |
| `delete`                             | Deletes one record or a selection of records         |
| `else if`                            | Adds more conditions to an `if` statement            |
| `for ... from ... to ... do ... end` | Loops through a numeric range                        |
| `for ... in ... do ... end`          | Loops through each item in a list or selection       |
| `if ... then ... else ... end`       | Returns or runs different logic based on a condition |
| `order by`                           | Sorts a record selection by a field or expression    |
| `select ... where`                   | Queries records and filters them by a condition      |
| `switch ... case`                    | Maps one value to one of several fixed outcomes      |
| `while ... do ... end`               | Repeats logic while a condition stays true           |

## **Use `if ... then ... else ... end`**

Use `if ... then ... else ... end` when Ninox should decide between two outcomes.

The condition after `if` must return a Yes/No result:

* `true` means the `then` branch runs
* `false` means the `else` branch runs

The basic pattern looks like this:

```ninox
if condition then
	resultIfTrue
else
	resultIfFalse
end
```

### **Return one value or another**

This example checks the value in `Total` and returns a payment method:

```ninox
if total >= 30 then
	"Card"
else
	"Cash"
end
```

If `total` is `30` or more, the result is `Card`. If `total` is below `30`, the result is `Cash`.

This pattern works well in a logic field when you want the field to return one result based on a condition.

### **Use comparison operators in a condition**

Conditions often use comparison operators. Common operators are:

* `=` equal to
* `!=` not equal to
* `>` greater than
* `>=` greater than or equal to
* `<` less than
* `<=` less than or equal to
* `not` is not true

For example:

```ninox
if total >= 30 then
	"Card"
else
	"Cash"
end
```

Here, `total >= 30` returns either `true` or `false`. Ninox then uses that result to choose the next branch.

### **Omit `else` when nothing should happen**

You do not need to add an `else` branch every time. Use this pattern when logic should only run if a condition is met:

```ninox
let paymentMethod := "Cash";
if total >= 30 then
	paymentMethod := "Card"
end;
paymentMethod
```

This logic works in three steps:

* `paymentMethod` starts as `Cash`
* if `total` is `30` or more, Ninox changes it to `Card`
* the last line returns the final value

This pattern is useful when you want a default value first and only change it in specific cases.

{% hint style="info" %}
Use an `else` branch when you need two explicit outcomes. Leave it out when the logic only needs to react to one case.
{% endhint %}

### **Check whether a field is empty**

Use `null` to check whether a field has no value.\
`null` means empty. It does **not** mean `0`.

```
if total = null then
	"Please enter an amount!"
end
```

Another possibility is:

```ninox
if not total then
	"Please enter an amount!"
end
```

If `total` is empty, Ninox returns the message `Please enter an amount!`.

To check whether a field contains a value, use its internal field name directly in the condition. The condition returns `true` when the field has content and `false` when it is empty.

This is useful when logic depends on user input and should react before a calculation runs.

### **Avoid common mistakes**

These issues are common in conditional logic:

* treating `null` like `0`
* using the wrong comparison operator
* forgetting that a condition must return `true` or `false`

Compare these two checks:

```ninox
if total = 0 then
	"No amount entered"
end
```

```ninox
if total = null then
	"No amount entered"
end
```

The first checks for the numeric value `0`. The second checks whether the field is empty. That difference matters.

### **When to use conditional logic**

Use `if` statements when you need to:

* return different text or values
* set a variable only in certain cases
* validate input before continuing
* handle empty fields safely

Conditional logic is one of the most important building blocks in Ninox. You will use it in logic fields, buttons, and automation.

### **Use multiple conditions with `else if`**

Use `else if` when you need more than two possible outcomes. This lets Ninox test conditions from top to bottom until one matches.

```ninox
if total = null then
	"Please enter an amount!"
else if total >= 30 then
	"Card"
else
	"Cash"
end
```

This example returns one of three results:

* `Please enter an amount!` if `total` is empty
* `Card` if `total` is `30` or more
* `Cash` in all other cases

Order matters here. Ninox checks the first condition first. If `total` is empty, the rest of the logic is skipped.

{% hint style="info" %}
Put the most specific or most important checks first. This helps you avoid unexpected results.
{% endhint %}

### **Use `switch ... case` for many fixed outcomes**

Use `switch ... case` when one expression can lead to several known results. This is often easier to read and faster executed by Ninox than a long chain of `else if` branches.

The basic pattern looks like this:

```ninox
switch expression do
case value1:
	result1
case value2:
	result2
default:
	fallbackResult
end
```

### **Example with a choice field**

This example checks the choice field `payment_method` and returns a matching message:

```ninox
switch payment_method do
case 1:
	"Payment method: " + text(payment_method) + "."
case 2:
	"Payment method: " + text(payment_method) + ". Only from €30."
case 3:
	"Payment method: " + text(payment_method) + ". Do not forget your signature."
default:
	"Please select a payment method."
end
```

If the field contains one of the configured options, Ninox returns the matching text. If no option is selected, Ninox returns the default message.

In this example:

* `case 1` refers to the option with the index `1`
* `case 2` refers to the option with the index `2`
* `case 3` refers to the option with the index `3`

This works well for choice fields with a fixed list of options.

All static choice and multiple choice fields use internal option IDs (index) such as `1`, `2`, and `3`. That is why the example uses `case 1`, `case 2`, and `case 3`.

{% hint style="info" %}
Use `switch` when one value should map to one known result. Choice fields are a common example.
{% endhint %}

### **When to use `else if` or `switch`**

Use `else if` when:

* each condition is different
* you need comparisons such as `>= 30`
* later conditions depend on earlier checks

Use `switch` when:

* one field or expression is checked against fixed values
* you want cleaner logic for many options
* you are working with a choice field or other known set of results

### **Avoid deeply nested conditions**

Nested conditions get hard to read quickly. Instead of stacking many `if` blocks inside each other, prefer:

* `else if` for ordered checks
* `switch` for fixed outcomes

This keeps your logic shorter, easier to test, and easier to update later.

## **Use `select` to query records**

Use `select` to read records from a table.

This statement returns a record selection. It is the starting point for many reports, views, and automations.

The basic pattern looks like this:

```ninox
select internal_table_name
```

This returns all records from the table.

```ninox
select customers_new
```

This returns all records from the "Customers (New)" table with the internal table name `customers_new`.

### **Filter records with `where`**

Use `where` to limit the result to records that match a condition.

```ninox
select customers where country = "Germany" or country = "Austria" or country = "Switzerland"
```

This returns only records where `country` matches one of these values:

* `Germany`
* `Austria`
* `Switzerland`

This pattern is useful when you want to show only a subset, such as a region, a group of statuses, or a date range.

### **Check for empty values in a query**

You can also check for empty values inside a query.

```ninox
select customers where email = null
```

This returns only customer records where the field "Email" is empty.

That helps when you want to find incomplete records before sending messages or exporting data.

### **Filter an existing selection**

You can also filter records after selecting them. This is useful when you first select a broader set of records and then narrow it with additional conditions. That way, you do not need to load the initial selection again each time.

```ninox
let myCustomers := select customers_new;
myCustomers[country = "Germany"]
```

This first selects all records and then filters the result. Use the brackets when you already have a selection and want to narrow it further.

### **Prefer `select ... where` for performance**

These two patterns can return similar results:

```ninox
select customers_new where country = "Germany"
```

```ninox
let customers := select customers_new;
customers[country = "Germany"]
```

The first approach is usually faster because Ninox only selects matching records from the start.

The second approach first loads all records, then filters them afterward.

{% hint style="info" %}
Prefer `select ... where` when performance matters, especially in large tables.
{% endhint %}

### **When to use `select`**

Use `select` when you need to:

* load records for a report or view that are not already linked to the current record
* filter records for later use in your logic
* pass a selection to functions such as `count`, `first`, `last`, or `item`

## **Use `order by` to sort records**

Use `order by` to sort a selection of records by one field or expression. Use it after a selection when you want to process records in a predictable order.

The basic pattern looks like this:

```ninox
(select invoices) order by total
```

This sorts the `invoices` records by `total` from low to high.

### **Sort a filtered selection**

You can combine `order by` with `where` or a bracket filter.

This next example is more advanced. You can skip it for now if you only need to sort by a regular field.

```ninox
(select invoices where date = today()) order by number(substr(invoice_no, 3))
```

This example does two things:

* selects only invoices with today's date
* sorts them by the numeric part of `invoice_no`

Here, `3` is the start position of the number inside the text.

For an invoice number like `NO-12574`:

* `N` is position `0`
* `O` is position `1`
* `-` is position `2`
* `1` is position `3`

This shows that the value after `order by` does not have to be a field name. It can also be an expression.

### **Sort text carefully**

Text values are sorted by character order, not always in the alphabetical order users expect. Mixed uppercase and lowercase text can produce surprising results.

For example, assume the field `First name` contains these values:

* `Aaron`
* `beate`
* `Conrad`
* `dahlia`
* `Eddi`
* `fatima`

If you sort that selection directly:

```ninox
concat(((select example_for_order_by) order by first_name).first_name)
```

This can return:

`Aaron, Conrad, Eddi, beate, dahlia, fatima`

That result follows a case-sensitive sort order. Names that start with uppercase letters come before names that start with lowercase letters.

To normalize the text before sorting, use `upper()` or `lower()`:

```ninox
concat(((select example_for_order_by) order by upper(first_name)).first_name)
```

This returns:

`Aaron, beate, Conrad, dahlia, Eddi, fatima`

The displayed names keep their original capitalization. Only the value used for sorting is normalized.

{% hint style="info" %}
When you sort text fields, normalize the values with `upper()` or `lower()` if you want a case-insensitive sort order.
{% endhint %}

### **Use `sort()` or `rsort()` when you only need values**

Use `order by` when you need sorted records. Use `sort()` when you only need a sorted list of values.

```ninox
concat(sort((select example_for_order_by).first_name))
```

This returns the names in alphabetical ascending order without sorting the records themselves.

For sorting the results in descending order use the function `rsort()`.

```ninox
concat(rsort((select invoices).total))
```

### **When to use `order by`**

Use `order by` when you need to:

* sort records before using `first`, `last`, or `item`
* control report output
* sort by a calculated expression instead of a stored field

If you only need a list of field values, use `sort()` or `rsort()` instead.

### **Repeat logic with loops**

Loops run the same block of logic several times.

Use them when you want to:

* update many records
* work through every item in a list
* repeat a calculation with numeric positions
* continue until a condition changes

In most cases, `for ... in ... do ... end` is the best place to start.

#### **Use `for ... in ... do ... end`**

Use this loop to go through each item in a list or selection.

The basic pattern looks like this:

```ninox
for item in list do
	statement
end
```

### **Example: update selected records**

This example selects customers with status `2` and changes each one to status `1`:

```ninox
let myCustomers := select customers_new where status = 2;
for cust in myCustomers do
	cust.status := 1
end
```

This logic works in two steps:

* the first line stores the matching records
* the loop updates each selected record one by one

This is one of the most common loop patterns in Ninox.

{% hint style="info" %}
Use `for ... in ... do ... end` when you already have a list, array, or record selection.
{% endhint %}

#### **Use `for ... from ... to ... do ... end`**

Use this loop when you want to iterate over a range of numbers.

It starts with the value after `from` and stops before the value after `to`.

The basic pattern looks like this:

```ninox
for item from 0 to 3 do
	statement
end
```

This uses:

* `0` as the first value
* `3` as the stop value, meaning it is not processed further
* an increment of `1`

### **Example: add values by position**

```ninox
let array := [10, 20, 30, 20, 10];
let result := 0;
for i from 0 to 3 do
	result := result + item(array, i)
end;
result
```

This adds the values at positions `0`, `1`, and `2`:

* `10`
* `20`
* `30`

The result is `60`.

### **Change the increment with `step`**

Use `step` when you do not want to increment by `1`.

```ninox
let array := [10, 20, 30, 20, 10];
let result := 0;
for i from 0 to 5 step 2 do
	result := result + item(array, i)
end;
result
```

This uses the positions `0`, `2`, and `4`.

The result is `50`.

{% hint style="info" %}
`for i in range(0, 10)` is equivalent to `for i from 0 to 10`.
{% endhint %}

#### **Use `while ... do ... end`**

Use `while` when logic should repeat as long as a condition stays true.

The basic pattern looks like this:

```ninox
while condition do
	statement
end
```

This loop keeps running until the condition becomes false.

### **Example: build a sequence**

```ninox
let i := 0;
let result := "";
while i < 10 do
	if result = "" then
		result := text(i)
	else
		result := result + " " + text(i)
	end;
	i := i + 1
end;
result
```

This returns exactly:

`0 1 2 3 4 5 6 7 8 9`

The loop works because `i` changes on every pass. Once `i` reaches `10`, the condition is false and the loop stops.

{% hint style="warning" %}
Always make sure a `while` loop can stop. If the condition never becomes false, the loop keeps running and can block your system.
{% endhint %}

### **When to use each loop**

Use `for ... in ... do ... end` when:

* you loop through records
* you loop through array items
* you already have a prepared selection

Use `for ... from ... to ... do ... end` when:

* you need numeric positions
* you work with array indexes
* you want to control the increment with `step`

Use `while ... do ... end` when:

* the number of passes is not fixed in advance
* the loop should stop when a condition changes

For most record updates and list processing, prefer `for ... in ... do ... end`.

## **Use `create` to add records**

Use `create` to create a new record in a table.

The basic pattern looks like this:

```ninox
create table_name
```

### **Create a record and update its fields**

If you want to fill the new record with data, store it in a variable first.

Then use the dot operator to update its fields.

```ninox
let newCustomer := create customers;
newCustomer.(
	name := "Company ABC";
	status := 1
)
```

This logic does two things:

* creates a new record in `customers`
* writes values into fields on the new record

In this example, the customer in the new record gets a name and a status.

This pattern is useful when you want to create a record and populate several fields right away.

{% hint style="info" %}
Store the new record in a variable when you want to update several fields after creation.
{% endhint %}

## **Use `delete` to remove records**

Use `delete` to remove one record or several records.

### **Delete the current record**

Use `delete this` when you want to remove the current record.

```ninox
delete this
```

This is useful in a button when deletion should happen together with another action.

For example, you might send a message or update related records first, then remove the current record.

### **Delete several records**

Combine `delete` with `select` when you want to remove multiple records at once.

```ninox
delete select customers where archived = true
```

This deletes all records in `customers` where `archived` is `true`.

{% hint style="warning" %}
Be careful with bulk deletes. Test the `select` first so you know exactly which records will be removed.
{% endhint %}

### **When to use `create` and `delete`**

Use `create` when you need to add a new record together with related actions, such as:

* refering the new record to the current record
* filling key fields immediately
* running further automations after creating the new record

Use `delete` when you need to:

* remove the current record
* clean up records that match a condition
* connect deletion to another automated step


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ninox.com/ninox-scripting/automate-your-workflows/explore-core-scripting-elements/statements.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
