# Datensätze und Tabellen

Datensätze sind der Kern jeder Ninox App. Du nutzt sie für Berichte, aktualisierst verknüpfte Daten und steuerst Workflows damit. Dieses Kapitel zeigt Funktionen für Datensätze und Datensatzlisten, wenn du bereits eine Auswahl oder eine Datensatzreferenz hast.

In diesem Kapitel lernst du:

* Datensatzlisten und Wertelisten für Berichte und Ansichten zu sortieren
* Auswahlen zu zählen, Duplikate zu entfernen und bestimmte Elemente aus einer Liste zu holen
* Datensätze per ID abzurufen und Tabellen- und Feld-IDs zu prüfen
* Felder per Name zu lesen und zu aktualisieren, einfache Schlüssel-Wert-Paare zu speichern und Datensätze zu duplizieren
* zwischengespeicherte Ergebnisse wiederzuverwenden und Daten bei Bedarf zu aktualisieren

<table><thead><tr><th width="204.02734375">Funktion (A-Z)</th><th>Aufgabe</th></tr></thead><tbody><tr><td><code>array()</code></td><td>Führt zwei Arrays desselben Datentyps zusammen</td></tr><tr><td><code>count()</code><br><code>cnt()</code></td><td>Zählt Elemente in einer Liste oder Auswahl</td></tr><tr><td><code>duplicate()</code></td><td>Erstellt eine Kopie eines Datensatzes</td></tr><tr><td><code>fieldId()</code></td><td>Gibt die interne ID eines Felds zurück</td></tr><tr><td><code>first()</code></td><td>Gibt das erste Element aus einer Liste oder Auswahl zurück</td></tr><tr><td><code>get()</code></td><td>Liest ein Feld per Name oder einen gespeicherten Schlüssel</td></tr><tr><td><code>item()</code></td><td>Gibt ein Element an einer bestimmten Position zurück</td></tr><tr><td><code>last()</code></td><td>Gibt das letzte Element aus einer Liste oder Auswahl zurück</td></tr><tr><td><code>record()</code></td><td>Ruft einen Datensatz per Tabelle und ID ab</td></tr><tr><td><code>removeItem()</code></td><td>Entfernt ein Schlüssel-Wert-Paar aus einem JSON-Objekt</td></tr><tr><td><code>rsort()</code></td><td>Sortiert Werte absteigend</td></tr><tr><td><code>set()</code></td><td>Aktualisiert ein Feld per Name in einem Datensatz</td></tr><tr><td><code>setItem()</code></td><td>Aktualisiert oder ergänzt ein Schlüssel-Wert-Paar in einem JSON-Objekt</td></tr><tr><td><code>slice()</code></td><td>Gibt einen Teil einer Liste zurück</td></tr><tr><td><code>sort()</code></td><td>Sortiert Werte aufsteigend</td></tr><tr><td><code>tableId()</code></td><td>Gibt die interne ID einer Tabelle zurück</td></tr><tr><td><code>unique()</code></td><td>Entfernt doppelte Werte aus einer Liste</td></tr></tbody></table>

## Datensatzlisten sortieren, zählen und bereinigen

Nutze diese Funktionen, wenn du die Reihenfolge steuern oder eine Liste zusammenfassen willst.

### Wertelisten mit `sort()` und `rsort()` sortieren

Nutze `sort()` und `rsort()`, wenn du bereits eine Werteliste hast und sie auf- oder absteigend sortieren willst. Nutze die `select`-Anweisung mit `order by`, wenn du Datensätze abfragen und aufsteigend sortieren willst.

Nutze sie, wenn du:

* extrahierte Feldwerte vor der Ausgabe sortieren willst
* Werte für Diagramme, Zusammenfassungen oder schnelle Vergleiche vorbereiten willst

`sort([any])`\
`rsort([any])`

* `[any]`: die Werteliste, die du sortieren willst

Für `sort()` und `rsort()` müssen alle übergebenen Werte denselben Datentyp haben.

Wenn du einzelne Werte statt eines Arrays übergibst, fasst Ninox sie zu einem Array zusammen und sortiert das Ergebnis.

Wenn du ein oder mehrere Arrays an `sort()` oder `rsort()` übergibst, führt Ninox sie zu einem sortierten Array zusammen.

#### Schauen wir uns einige Beispiele an:

```ninox
sort((select orders).date)
```

Gibt die ausgewählten Bestelldaten in aufsteigender Reihenfolge zurück.

```ninox
rsort((select orders).amount)
```

Gibt die ausgewählten Bestellbeträge in absteigender Reihenfolge zurück.

```ninox
let statuses := ["Draft", "Closed", "Open"];
sort(statuses)
```

Sortiert die Liste alphabetisch.

```ninox
sort("B", "E", "A", "E", "D", "C")
```

Fasst die Werte zu einem Array zusammen und sortiert sie aufsteigend.

```ninox
sort(["B", "E", "A"], ["E", "D", "C"])
```

Führt beide Arrays zusammen und sortiert das Gesamtergebnis aufsteigend.

```ninox
rsort("B", "E", "A", "E", "D", "C")
```

Fasst die Werte zu einem Array zusammen und sortiert sie absteigend.

```ninox
rsort(["B", "E", "A"], ["E", "D", "C"])
```

Führt beide Arrays zusammen und sortiert das Gesamtergebnis absteigend.

Tipps:

* `order by` sortiert das Ergebnis nur aufsteigend. Für eine absteigende Sortierung nutze `rsort()`.

### Elemente mit `count()` und `cnt()` zählen

Nutze `count()`, um die Anzahl konkreter Elemente in einer Auswahl oder Liste zurückzugeben. `cnt()` macht genau dasselbe wie `count()`.

Nutze es, wenn du:

* Datensätze zählen willst, die zu einem Filter passen
* prüfen willst, ob eine Auswahl leer ist, bevor du weitermachst
* eine Liste mit `unique()` vergleichen willst, um Duplikate zu erkennen

`count([any])`\
`cnt([any])`

* `[any]`: die Liste oder Auswahl, die du zählen willst

`count()` und `cnt()` zählen Elemente, die nicht `null` und keine leeren Strings (`""`) sind.

#### Schauen wir uns einige Beispiele an:

```ninox
count(select orders)
```

Gibt die Anzahl der Datensätze in der Tabelle "Orders" zurück.

```ninox
count(select orders where status = "Open")
```

Gibt die Anzahl offener Bestellungen zurück.

```ninox
let openOrders := select orders where status = "Open";
if cnt(openOrders) = 0 then "Nothing to process" else "Ready" end
```

Nutzt `cnt()`, um zu prüfen, ob das gefilterte Ergebnis leer ist.

```ninox
count(["A", "B", ""])
```

Gibt `2` zurück, weil der leere String nicht gezählt wird.

```ninox
let ids := (select contacts).customer_id;
cnt(ids) = cnt(unique(ids))
```

Gibt `true` zurück, wenn alle Werte eindeutig sind. Gibt `false` zurück, wenn Duplikate vorhanden sind.

Tipps:

* Nutze `length()`, wenn du alle Array-Elemente zählen willst, einschließlich leerer Werte.

### Duplikate mit `unique()` entfernen

Nutze `unique()`, um wiederholte Werte aus einer Liste zu entfernen.

Nutze es, wenn du:

* aus vielen Datensätzen eine Liste eindeutiger Werte ableiten willst

`unique([any])`

* `[any]`: eine oder mehrere Listen, aus denen du Duplikate entfernen willst

Wenn du mehr als ein Array übergibst, führt Ninox sie zusammen und gibt ein Array mit nur eindeutigen Werten zurück.

#### Schauen wir uns einige Beispiele an:

```ninox
unique((select orders).customer)
```

Gibt jeden Kunden nur einmal zurück.

```ninox
unique(["D", "C", "A", "A", "D", "B"])
```

Gibt die eindeutigen Werte aus dem Array zurück: `["D", "C", "A", "B"]`.

```ninox
sort(unique(["A", "D", "A", "B"], ["B", "C", "E", "D"], ["F", "E"]))
```

Führt die Arrays zusammen, entfernt Duplikate und sortiert das Ergebnis: `["A", "B", "C", "D", "E", "F"]`.

Tipp:

* Vergleiche `count(list)` mit `count(unique(list))`, um zu prüfen, ob eine Liste bereits nur eindeutige Werte enthält.

### Zwei Arrays mit `array()` zusammenführen

Nutze `array()`, um zwei Arrays desselben Datentyps zu einem neuen Array zusammenzuführen.

Nutze es, wenn du:

* zwei Ergebnis-Arrays vor einer gemeinsamen Prüfung zusammenführen willst

`array([any], [any])`

* erstes `[any]`: das erste Array
* zweites `[any]`: das zweite Array

`array()` gibt ein Array zurück.

{% hint style="info" %}

* Nutze `array()`, wenn du genau zwei Arrays zusammenführen musst. Für mehr Arrays rufst du `array()` erneut mit dem Ergebnis und dem nächsten Array auf.
* Beide Eingabe-Arrays müssen Werte desselben Datentyps enthalten.
  {% endhint %}

#### Schauen wir uns einige Beispiele an:

```ninox
let myArray1 := ["1", "2", "3"];
let myArray2 := ["4", "5", "6"];
let myArray3 := array(myArray1, myArray2);
myArray3
```

Gibt ein zusammengeführtes Array mit den Werten aus beiden Arrays zurück: `["1", "2", "3", "4", "5", "6"]`.

```ninox
let myArray1 := ["A", "B", "C"];
let myArray2 := ["D", "E", "F"];
let myArray3 := ["G", "H", "J"];
let myArray4 := ["K", "M", "W"];
let myArray5 := array(myArray1, myArray2);
let myArray6 := array(myArray3, myArray4);
let myArrayTotal:= array(myArray5, myArray6);
myArrayTotal
```

Gibt ein zusammengeführtes Array mit den Werten aus 4 Arrays zurück:\
`["A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "M", "W"]`.

## Auf Elemente in Datensatzlisten zugreifen

Nutze diese Funktionen, wenn du einen einzelnen Datensatz, den Anfang oder das Ende einer Liste oder nur einen Teil eines größeren Ergebnisses brauchst.

### Das erste oder letzte Element mit `first()` und `last()` holen

Nutze `first()` und `last()`, um ein einzelnes Element vom Anfang oder Ende einer Liste oder Auswahl zurückzugeben.

Nutze sie, wenn du:

* den frühesten oder spätesten Datensatz aus einer sortierten Auswahl holen willst
* nur ein Ergebnis aus einer größeren Liste lesen willst

`first([any])`\
`last([any])`

* `[any]`: die Liste oder Auswahl, aus der du ein Rand-Element holen willst

`first()` gibt das erste Element aus einem Array oder einer Auswahl zurück. `last()` gibt das letzte Element aus einem Array oder einer Auswahl zurück.

#### Schauen wir uns einige Beispiele an:

```ninox
first(["B", "A", "C"])
```

Gibt `"B"` zurück.

```ninox
first(select orders where status = "Open" order by date)
```

Gibt die erste offene Bestellung in Datumsreihenfolge zurück.

```ninox
last(select orders order by date)
```

Gibt die letzte Bestellung in Datumsreihenfolge zurück.

```ninox
last(["B", "A", "C"])
```

Gibt `"C"` zurück.

```ninox
last(select customer)
```

Gibt den letzten Datensatz aus der Tabelle "Customer" zurück.

```ninox
first((select customer where substr(last_name, 0, 1) = "A") order by last_name)
```

Gibt den ersten `customer`-Datensatz zurück, dessen Nachname mit `A` beginnt.

```ninox
last((select customer where substr(last_name, 0, 1) = "A") order by last_name)
```

Gibt den letzten `customer`-Datensatz zurück, dessen Nachname mit `A` beginnt.

Tipps:

* Prüfe, ob die Auswahl leer ist, bevor du vom Ergebnis abhängst.
* Wenn das Array Datensatz-IDs enthält, kann das Ergebnis je nach Plattform unterschiedlich sein, weil Datensatz-IDs unterschiedlich sortiert werden.

### Ein Element über seine Position mit `item()` holen

Nutze `item()`, um einen Wert oder Datensatz an einer bestimmten Position in einer Liste zurückzugeben oder einen Wert per Schlüssel aus einem JSON-Objekt zu lesen.

Nutze es, wenn du:

* den n-ten Wert aus einem Array lesen willst

Positionen sind nullbasiert. Position `0` ist das erste Element.

`item([any], number)` `item(JSON, number)`\
`item(JSON, string)`

* `[any]`: die Liste oder Auswahl, aus der du lesen willst
* `number`: die nullbasierte Position oder ein numerischer JSON-Schlüssel
* `string`: der JSON-Schlüssel

#### Schauen wir uns einige Beispiele an:

```ninox
item(["A", "B", "C"], 0)
```

Gibt `"A"` zurück.

```ninox
item(select orders order by date, 2)
```

Gibt die dritte Bestellung aus der sortierten Auswahl zurück.

```ninox
item(["Apple", "Cucumber", "Orange"], 1)
```

Gibt `"Cucumber"` zurück.

```ninox
item(split("John D Ventures, 2311 Great Ave., 10178 Central City", ","), 0)
```

Gibt `John D Ventures` zurück.

```ninox
let data := {
    firstName: "Jane",
    lastName: "Doe"
};
item(data, "firstName")
```

Gibt `"Jane"` zurück.

Tipps:

* Nutze `first()` oder `last()`, wenn du nur den Anfang oder das Ende einer Liste brauchst.
* Nutze einen String-Schlüssel oder numerischen Schlüssel, wenn du aus JSON liest.

### Einen Teil einer Liste mit `slice()` zurückgeben

Nutze `slice()`, um eine Teilliste aus einem größeren Array oder einer Auswahl zurückzugeben oder einen Teil eines Texts zu extrahieren.

Nutze es, wenn du:

* eine Liste in kleinere Abschnitte aufteilen willst

`slice([any], from, to)`\
`slice(string, from, to)`

* `[any]`: die Liste oder Auswahl, die du zuschneiden willst
* `string`: der Text, den du zuschneiden willst
* `from`: die Startposition, einschließlich dieses Werts
* `to`: die Endposition, ohne diesen Wert

Positionen sind nullbasiert.

Wenn `to` größer ist als die verfügbare Anzahl an Elementen oder Zeichen, gibt Ninox alles von `from` bis zum Ende zurück.

#### Schauen wir uns einige Beispiele an:

```ninox
slice([1, 2, 3, 4], 1, 3)
```

Gibt eine Teilliste mit den mittleren Werten zurück: `[2, 3]`.

```ninox
let amounts := rsort((select orders).amount);
slice(amounts, 0, 5)
```

Gibt die ersten fünf Werte aus der sortierten Betragsliste zurück.

```ninox
slice(["Apple", "Bagel", "Cake", "Donut"], 1, 3)
```

Gibt `["Bagel", "Cake"]` zurück.

```ninox
slice("Mermaid", 3, 7)
```

Gibt `"maid"` zurück.

Tipps:

* `from` ist inklusive und `to` ist exklusiv.
* Bei Text funktioniert `slice()` wie `substring()`.

## Mit Datensätzen, Tabellen und IDs arbeiten

Nutze diese Funktionen, wenn du einen bestimmten Datensatz oder Metadaten zu deiner aktuellen Struktur brauchst.

### Einen Datensatz per ID mit `record()` abrufen

Nutze `record()`, um einen Datensatz aus einer Tabelle zu laden, wenn du seine numerische ID bereits kennst.

Nutze es, wenn du:

* einen referenzierten Datensatz per ID erneut öffnen willst
* eine Datensatzreferenz aus gespeicherten Metadaten wiederherstellen willst

`record(table, id)`

* `table`: die Tabelle, die den Datensatz enthält
* `id`: die numerische Datensatz-ID

`record()` gibt eine Datensatzreferenz zurück.

Der zurückgegebene Wert ist eine Referenz und nicht der vollständige Datensatz.

`record()` gibt immer einen Datensatzreferenz-Typ zurück, auch wenn die numerische ID nicht existiert.

Wenn du prüfen willst, ob der Datensatz existiert, nutze `record(table, id)._id`. Das gibt die Datensatz-ID nur für vorhandene Datensätze zurück.

#### Schauen wir uns einige Beispiele an:

```ninox
record(orders, 123)
```

Gibt den Datensatz mit der ID `123` aus der Tabelle "Orders" zurück.

```ninox
let orderId := 123;
let orderRecord := record(orders, orderId);
orderRecord."Status"
```

Lädt die Bestellung und liest dann ihren Status.

```ninox
record(customers, 540).date
```

Gibt das Feld `date` aus dem `customers`-Datensatz mit der ID `540` zurück.

```ninox
if record(customers, 540)._id then
    "Exists"
else
    "Not found"
end
```

Prüft, ob der Datensatz mit der ID `540` existiert.

### Interne IDs mit `tableId()` und `fieldId()` abrufen

Nutze diese Funktionen, wenn du Metadaten für Logging, API-Calls, Diagnose oder Admin-Skripte brauchst.

Nutze sie, wenn du:

* API-URLs dynamisch aufbauen willst
* interne Objektreferenzen prüfen willst

`tableId(table)`\
`tableId(record)`\
`tableId(string)`\
`fieldId(field)`\
`fieldId(record, string)`\
`fieldId(string, string)`

* `table`: die Tabelle, für die du mit `tableId(table)` die interne ID holen willst
* `record`: ein Datensatz aus der Tabelle, für die du mit `tableId(record)` die interne ID holen willst
* `string`: der Tabellenname für `tableId(string)` oder der Feldname beziehungsweise Tabellen- und Feldname für `fieldId()`
* `field`: das Feld, für das du mit `fieldId(field)` die interne ID holen willst

`tableId()` gibt den internen Bezeichner einer Tabelle als String zurück.

Tabellen-IDs nutzen Großbuchstaben und beginnen mit `A`.

`fieldId()` gibt den internen Bezeichner eines Felds als String zurück. Feld-IDs sind buchstabenbasierte Werte wie `A`, `B`, `AA` oder `AB`.

#### Schauen wir uns einige Beispiele an:

```ninox
tableId(orders)
```

Gibt die interne ID der Tabelle "Orders" zurück.

```ninox
tableId(this)
```

Gibt die interne ID der aktuellen Tabelle zurück.

```ninox
fieldId(status)
```

Gibt die interne ID des Felds `status` zurück.

```ninox
fieldId(this, "Name")
```

Gibt die Feld-ID für `Name` in der aktuellen Tabelle zurück.

Tipps:

* Nutze `tableId()` als stabilen Bezeichner in API-Calls.
* Behalte Feld-IDs für technische Workflows. Nutze sie nicht als Nutzer-Bezeichnungen.

## Werte lesen, aktualisieren, kopieren und speichern

Nutze diese Funktionen, wenn du einen Datensatz per Feldname ändern oder einen kleinen gespeicherten Wert für später behalten willst.

### Felder mit `get()` und `set()` lesen und aktualisieren

Nutze `get()`, um ein Feld aus einem Datensatz zu lesen. Nutze `set()`, um ein Feld in einem Datensatz zu aktualisieren.

Nutze sie, wenn du:

* ein Feld dynamisch lesen willst
* einen anderen Datensatz innerhalb eines Skripts aktualisieren willst
* generische Hilfslogik schreiben willst, die über mehrere Felder hinweg funktioniert

`get(record, string)`\
`set(record, string, any)`

* `record`: der Datensatz, den du lesen oder aktualisieren willst
* `string`: der Feldname oder die Feld-ID
* `any`: der Wert, den du mit `set` schreiben willst

`get()` kann verschiedene Wertetypen zurückgeben, zum Beispiel Text, Zahlen, boolesche Werte oder einen leeren Wert.

`set()` aktualisiert ein Feld per Name oder über seine Feld-ID als Text, zum Beispiel `"Name"` oder `"A"`.

`set()` gibt keinen Wert zurück.

#### Schauen wir uns einige Beispiele an:

```ninox
get(this, "Status")
```

Liest das Feld `Status` aus dem aktuellen Datensatz.

```ninox
set(this, "Status", "Closed")
```

Aktualisiert das Feld `Status` im aktuellen Datensatz.

```ninox
set(this, "Age", 42)
```

Aktualisiert das Feld `Age` im aktuellen Datensatz.

```ninox
set(this, "isActive", true)
```

Aktualisiert das Feld `isActive` im aktuellen Datensatz.

```ninox
get(this, "B")
```

Liest den Wert des Felds mit der internen ID `B`.

```ninox
let nextOrder := first(select orders where status = "Open" order by date);
set(nextOrder, "Status", "In progress")
```

Aktualisiert die erste offene Bestellung in Datumsreihenfolge.

Tipps:

* Nutze normalen Feldzugriff, wenn der Feldname feststeht.
* Nutze eine Feld-ID, wenn dein Skript stabil bleiben soll, auch wenn sich der Feldname ändert.
* `get(this, "")` gibt einen leeren Wert zurück.
* Nutze `set()`, wenn du viele Felder aktualisieren willst, ohne eine Zuweisung pro Feld zu wiederholen.

Beispiel für dynamisches Feld-Mapping:

```ninox
let me := this;
let fields := ["Object name", "Date", "Value"];
for i in range(3) do
    let newSubRecord := create subtable;
    newSubRecord.(report := me.report);
    for name in fields do
        set(newSubRecord, name, get(me, name + " " + (i + 1)))
    end
end
```

Das liest nummerierte Felder aus dem aktuellen Datensatz und schreibt sie in neue `Subtable`-Datensätze.

Beispiel für dynamische Aktualisierungen aus JSON-Daten im API-Stil:

```ninox
for i in response do
    let newContact := create contacts;
    for key, value in i.fields do
        set(newContact, key, value)
    end
end
```

Das durchläuft die Felder in jedem Antwortelement und aktualisiert die passenden Ninox Felder dynamisch.

### Gespeicherte Werte mit `get()` lesen und JSON-Objekte mit `setItem()` und `removeItem()` aktualisieren

Nutze `get()`, wenn du einen gespeicherten Schlüssel-Wert-Eintrag lesen willst. Nutze `setItem()`, um ein Schlüssel-Wert-Paar in einem vorhandenen JSON-Objekt zu aktualisieren oder hinzuzufügen. Nutze `removeItem()`, um ein Schlüssel-Wert-Paar aus einem JSON-Objekt zu entfernen.

Nutze sie, wenn du:

* einen Wert in einem JSON-Objekt aktualisieren willst
* einen neuen Schlüssel zu einem JSON-Objekt hinzufügen willst
* einen Schlüssel aus einem JSON-Objekt entfernen willst, bevor du es wiederverwendest oder sendest

`get(string)`\
`setItem(JSON, string, any)`\
`removeItem(JSON, string)`

* `string`: der Speicherschlüssel für `get`
* `JSON`: das JSON-Objekt, das du ändern willst
* `string`: der Schlüssel, den du aktualisieren, hinzufügen oder entfernen willst
* `any`: der Wert, den du mit `setItem` schreiben willst

#### Schauen wir uns einige Beispiele an:

```ninox
get("theme")
```

Liest den gespeicherten Wert für `"theme"`.

```ninox
let data := {
    lastName: "Rogers",
    firstName: "Steve"
};
setItem(data, "firstName", "Brian")
```

Aktualisiert den Schlüssel `firstName` im Objekt `data`.

```ninox
let data := {
    lastName: "Rogers",
    firstName: "Steve"
};
setItem(data, "age", 112)
```

Fügt dem Objekt `data` das Schlüssel-Wert-Paar `age: 112` hinzu.

```ninox
let data := {
    lastName: "Rogers",
    firstName: "Brian"
};
removeItem(data, "firstName")
```

Entfernt das Schlüssel-Wert-Paar `firstName` aus dem Objekt `data`.

`data` wird direkt geändert.

Tipps:

* `get(this, "Field")` liest ein Datensatzfeld. `get("key")` liest einen gespeicherten Schlüssel-Wert-Eintrag. Halte die beiden `get()`-Formen in deinen Skripten getrennt.
* Wenn das JSON-Objekt in einer Variablen gespeichert ist, ändert `removeItem()` dieses Objekt auch dann, wenn du das Ergebnis nicht erneut zuweist.
* Wenn das JSON-Objekt in einer Variablen gespeichert ist, ändert `setItem()` dieses Objekt ebenfalls, auch wenn du das Ergebnis nicht erneut zuweist.

### Einen Datensatz mit `duplicate()` kopieren

Nutze `duplicate()`, um eine Kopie eines vorhandenen Datensatzes zu erstellen.

Nutze es, wenn du:

* einen ähnlichen Datensatz als Vorlage wiederverwenden willst

`duplicate(record)`

* `record`: der Datensatz, den du kopieren willst

`duplicate()` gibt den duplizierten Datensatz mit einer anderen Datensatz-ID zurück.

Wenn du einen Datensatz duplizierst, kopiert Ninox alle Feldwerte, aber keine Dateianhänge. Datensätze aus Subtabellen vom Typ Composition werden ebenfalls dupliziert.

#### Schauen wir uns einige Beispiele an:

```ninox
duplicate(this)
```

Erstellt eine Kopie des aktuellen Datensatzes.

```ninox
let newCopy := duplicate(this);
newCopy.status := "Draft"
```

Erstellt eine Kopie und setzt dann das Feld "Status" auf `Draft` zurück.

```ninox
let newRecord := duplicate(this);
openRecord(newRecord)
```

Erstellt ein Duplikat des aktuellen Datensatzes und öffnet es.

Tipps:

* Setze eindeutige Werte nach dem Duplizieren bei Bedarf zurück.
* Prüfe kopierte Statusfelder, Zahlen oder Referenzen, bevor du weitermachst.

## Zwischengespeicherte Ergebnisse aktualisieren und SQL-Verbindungen abfragen

Nutze diese Funktionen, wenn dein Skript von externen Daten, wiederholten Berechnungen oder einer verbundenen SQL-Datenbank abhängt.

### Aufwendige Ergebnisse mit `cached()` wiederverwenden

Nutze `cached()`, um ein Skript einmal auszuführen, sein Ergebnis zu speichern und bei späteren Aufrufen den gespeicherten Wert zurückzugeben.

Nutze es, wenn du:

* das Ergebnis eines aufwendigen Skripts wiederverwenden willst
* eine Auswahl zwischenspeichern willst, deren Aufbau teuer ist
* die Performance in Skripten verbessern willst, die dieselbe Berechnung wiederholen

`cached(script)`

* `script`: das Skript oder der Ausdruck, den du einmal ausführen und zwischenspeichern willst

#### Schauen wir uns einige Beispiele an:

```ninox
let cache := cached(
    let currentUser := user();
    select Tasks where due_date > today() and assigned_user.ninox_user = currentUser
);
cache
```

Gibt die offenen `Tasks`-Datensätze zurück, die dem aktuellen Nutzer zugewiesen sind. Das Ergebnis wird zwischengespeichert und bei späteren Aufrufen wiederverwendet.

Tipps:

* `cached()` gibt immer das zurück, was das innere Skript zurückgibt.
* Berechne das zwischengespeicherte Ergebnis neu, indem du in den Builder-Modus wechselst oder `invalidate()` ausführst.
* Nutze Caching für aufwendige Skripte, die deine App sonst verlangsamen würden.

## Häufige Muster für Datensätze und Tabellen

Diese kurzen Muster decken häufige Abfragen und Aktualisierungen von Datensätzen in Ninox ab.

### Offene Bestellungen zählen

```ninox
count(select Orders where status = "Open")
```

Gibt die Anzahl offener Bestellungen zurück.

### Datensätze für einen Bericht sortieren

```ninox
select orders where status = "Open" order by customer + amount
```

Gibt offene Bestellungen in einer vorhersehbaren Reihenfolge für Berichte zurück.

### Den aktuellen Datensatz duplizieren und den Status zurücksetzen

```ninox
let copy := duplicate(this);
copy.status := "Draft"
```

Erstellt einen neuen Entwurf aus dem aktuellen Datensatz.

Nutze dieses Kapitel zusammen mit Logik für Filter, Formatierung und Berichte:

* Nutze Datumsfunktionen in `where`- und `order by`-Klauseln.
* Nutze Textfunktionen, um ausgewählte Werte für die Ausgabe zu formatieren.
* Nutze numerische Funktionen, um ausgewählte Beträge zusammenzufassen.


---

# Agent Instructions: 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/de/automate-your-workflows/work-with-functions/records-and-tables.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.
