# SQL-Knoten (/docs/de/analytical-apps/pipeline/sql-nodes)



Ein **SQL**-Knoten ist ein Schritt, der Ihre Daten transformiert. Er liest die
Ausgabe früherer Knoten und formt sie zu etwas Neuem um, zum Beispiel indem er zwei
Tabellen kombiniert, Zeilen filtert oder eine Summe berechnet. SQL ist die
Standardsprache für die Arbeit mit Daten, und ein SQL-Knoten verwendet eine
Abfrage, die aus den einspeisenden Knoten liest.

## Sie müssen kein SQL beherrschen [#sie-müssen-kein-sql-beherrschen]

Das ist der wichtige Teil: Sie müssen SQL nicht selbst schreiben. Beschreiben Sie
die gewünschte Transformation in einfacher Sprache, zum Beispiel „behalte nur die
Bestellungen dieses Jahres und summiere den Umsatz pro Kunde", und **Vera** schreibt
die Abfrage für Sie. Vera ist der No-Code-Weg; diese Seite erläutert den Knoten für
den Fall, dass Sie lesen oder anpassen möchten, was Vera erzeugt hat. Siehe
[Mit Vera erstellen](../build-with-vera.mdx).

## Arbeiten in einem SQL-Knoten [#arbeiten-in-einem-sql-knoten]

Wenn Sie doch direkt mit der Abfrage arbeiten möchten:

1. Öffnen Sie im Editor den SQL-Knoten.
2. Schreiben oder passen Sie die Abfrage an. Sie liest aus den Knoten, die mit
   diesem verbunden sind.
3. Führen Sie die Abfrage aus, um ihre Ausgabe und die von ihr erzeugten Spalten zu
   sehen.

Die Ergebnisse eines SQL-Knotens speisen alle nachgeschalteten Knoten sowie Ihre
Visualisierungs-Widgets. Da nachgelagerte Schritte von der Ausgabe dieses Knotens
abhängen, verfügen sie erst dann über frische Daten, wenn die Pipeline erfolgreich
ausgeführt wurde. Wenn die Abfrage noch nicht ausgeführt wurde, haben Knoten, die
auf sie angewiesen sind, keine Daten zum Arbeiten, bis Sie auf **Ausführen**
klicken.

Eine Abfrage in einem SQL-Knoten auszuführen ist eine eigene Berechtigung, getrennt
vom Lesen der App. Sie gehört zu den Rollen **Mitwirkender**, **Analyst**, **App-Ersteller** und **Admin** für den
gesamten Workspace - eine Rolle für einen einzelnen Bereich oder eine App gibt sie nicht -, und in
Ihrem eigenen persönlichen Bereich haben Sie sie immer. Ohne sie zeigt der
Knoten seine Abfrage ohne Schaltfläche **Ausführen** und mit einem kurzen Hinweis,
warum. Konnte die App nicht prüfen, ob Sie sie haben, sagt der Hinweis das
stattdessen; laden Sie die Seite neu, um es erneut zu versuchen.

### Was die Schaltfläche Ausführen lesen kann [#was-die-schaltflaeche-ausfuehren-lesen-kann]

Eine Abfrage, die Sie im Editor ausführen, liest **nur die eigenen Knoten dieser App**,
direkt über ihre ID benannt - dieselbe Regel, die auch der SQL-Editor und das
SQL-Widget befolgen. Eine Abfrage darf einen Knoten benennen oder eine `WITH`-Klausel,
die sie selbst definiert, und sonst nichts.

Ein [Indikatordaten](./indicator-data.mdx)- oder [Analyse-App-Daten](./analytic-data.mdx)-Knoten
kann gelesen werden, sobald die Pipeline gelaufen ist: Die Abfrage liest die Kopie seiner
Zeilen, die dieser Lauf angelegt hat. Bevor die App einen Lauf hat, gibt es diese Kopie
nicht, und der Name wird abgelehnt wie jeder andere Name, hinter dem nichts steht. Eine
lokale Entwicklungsumgebung bietet diese beiden Knotentypen einer Abfrage nie an und lehnt
ihre Namen ab; lesen Sie einen solchen Knoten dort über einen SQL-Knoten, der aus ihm liest.

Folgendes wird abgelehnt, bevor etwas ausgeführt wird, mit einer Meldung, was zu ändern
ist:

* ein Name mit Präfix, etwa `other_app.orders` oder `main.orders` - schreiben Sie
  `orders`;
* ein Name, der kein Knoten dieser App ist, etwa die Tabelle einer anderen App, eine
  Systemtabelle wie `duckdb_tables` oder ein Dateipfad;
* ein Knoten, dessen ID zugleich der Name einer Katalogtabelle der Datenbank ist, etwa
  `duckdb_tables`, `pg_class` oder `sqlite_master` - benennen Sie den Knoten um, um ihn zu lesen;
* eine Tabellenfunktion in einer `FROM`-Klausel, etwa `read_parquet(...)`,
  `range(...)` oder `unnest(...)` - `unnest(...)` in der `SELECT`-Liste ist erlaubt;
* `DESCRIBE`, `SHOW` oder `SUMMARIZE` als Unterabfrage, `PIVOT` und `UNPIVOT`, das
  Lesen einer früheren Version mit `AT (VERSION => ...)`, eine
  `WITH ... AS MATERIALIZED`-Klausel und der interne Zustand eines Aggregats mit
  `EXPORT_STATE`;
* eine Funktion, die Einstellungen, Sitzungsangaben oder den Datenbankkatalog liest, als
  Text übergebenes SQL ausführt oder etwas verändert - zum Beispiel
  `current_setting(...)`, `current_database()`, `json_serialize_plan(...)` oder
  `nextval(...)`. Die üblichen Funktionen für Text, Zahlen, Datumswerte, Listen und JSON,
  Aggregate und Fensterfunktionen funktionieren alle. Eine Funktion, die hinter einem Wert
  steht, wie in `name.upper()`, wird ebenfalls abgelehnt - schreiben Sie `upper(name)`;
* ein Typ, der zu einem Schema gehört, etwa `CAST(x AS other_app.mood)`, oder der kein
  eingebauter DuckDB-Typ ist;
* eine Zahl, die zu groß ist, als dass die Datenbank sie darstellen könnte, etwa `1e400` -
  die Abfrage kann nicht geprüft werden und wird daher nicht ausgeführt.

Die SQL-Schlüsselwörter, die ohne Klammern geschrieben werden - `current_user`,
`current_schema`, `current_date` und ähnliche - funktionieren weiterhin, auch als
Spaltennamen. Sie melden nur die eigene Verbindung dieser Abfrage, nie eine andere App.

Ein Pipeline-Lauf und die Live-Vorschau eines Knotens wenden dieselbe Regel auf seine
gespeicherte Abfrage an. Eine Abfrage mit einer dieser Formen lässt sich speichern, doch
beim Lauf der Pipeline schlägt dieser Knoten mit derselben Meldung fehl, und die Knoten,
die aus ihm lesen, werden übersprungen. Schreiben Sie sie ohne diese Formen um - etwa
mit einem bedingten `sum(CASE WHEN ...)` statt eines `PIVOT` oder mit
`SELECT unnest(range(10)) AS n` statt `FROM range(10)`. Um Daten einer anderen App zu
verwenden, fügen Sie einen [Analyse-App-Daten](./analytic-data.mdx)-Knoten hinzu und lesen
diesen Knoten über seine ID.

### Wie viel eine Ergebnisseite enthalten kann [#wie-viel-eine-ergebnisseite-enthalten-kann]

Die Ergebnisse einer Abfrage werden Seite für Seite angezeigt, zusammen mit der Anzahl
aller Zeilen, die die Abfrage geliefert hat. Eine Seite darf höchstens **4 MB** Daten und
höchstens **262.144 Werte** enthalten. Ein Wert wird so gemessen, wie er als Text angezeigt
würde; ein langer Text, eine große Liste oder ein in einen anderen Wert verschachtelter Wert
zählt also vollständig. Und jedes Element einer Liste, jedes Feld eines Structs sowie jeder
Schlüssel und jeder Wert einer Map zählt als eigener Wert.

Eine Abfrage, deren Seite über einer der beiden Grenzen liegt, wird mit einer
entsprechenden Meldung abgelehnt. Nichts wird gekürzt: Sie sehen nie einen Teil eines Werts
oder nur einige der Zeilen, dargestellt, als wäre es das ganze Ergebnis. So bringen Sie die
Seite unter die Grenzen:

* wählen Sie weniger oder kürzere Spalten aus - für einen langen Text liefert
  `left(text, 1000)` seine ersten 1.000 Zeichen und `length(text)` seine Länge, und
  `len(liste)` die Länge einer langen Liste;
* filtern Sie mit einer `WHERE`-Klausel auf weniger Zeilen.

Einige Spaltentypen können überhaupt nicht als Abfrageergebnis angezeigt werden: eine
`UNION`, eine `VARIANT` und ein `ARRAY` fester Größe, allein oder in einer Liste, einem
Struct oder einer Map. Eine Abfrage, die eine solche Spalte liefert, wird mit einer Meldung
abgelehnt, die die Spalte nennt. Wandeln Sie sie in der Abfrage um - `CAST(... AS VARCHAR)`
zeigt ihren Wert als Text, und `CAST(... AS INTEGER[])` macht aus einem Array fester Größe
eine Liste.

Die Grenzen gelten überall, wo die Ergebnisse einer Abfrage sofort angezeigt werden: bei
der Schaltfläche **Ausführen**, im SQL-Editor, in einem SQL-Widget, bei den KI-Werkzeugen,
die eine App abfragen, und in der unten beschriebenen Vorschau eines SQL-Knotens. Sie
begrenzen, was eine Seite enthält, nicht, wie viele Zeilen eine Abfrage liefern darf.

## Sehen, was eine Abfrage liefert, bevor Sie ausführen [#sehen-was-eine-abfrage-liefert-bevor-sie-ausführen]

Sie müssen die Pipeline nicht ausführen, um zu sehen, ob eine Abfrage stimmt. Öffnen Sie den
Tab **Daten** eines SQL-Knotens, wenn es keine Ausführung zu zeigen gibt, und er zeigt eine
Vorschau der AKTUELLEN Abfrage des Knotens über den AKTUELLEN Inhalt der Datasets der App -
sofort. Ein Streifen über den Zeilen sagt das ausdrücklich, denn dies sind keine
Ausführungsergebnisse: niemand sonst sieht sie, Ihre Visualisierung verwendet sie nicht, und
sie ändern sich, sobald Sie die Abfrage oder die Daten bearbeiten.

Das macht die gewöhnliche Schleife kurz. Abfrage bearbeiten, Zeilen ansehen, korrigieren,
wieder ansehen - und erst auf **Ausführen** klicken, wenn es stimmt. Tippen Sie einen Wert in
die Tabelle eines Datasets, spiegelt die nächste Vorschau ihn bereits wider.

Einiges dazu sollten Sie wissen:

* **Sie ist für Personen, die die App bearbeiten dürfen.** Wer nur liest, sieht wie bisher die
  Ausführungsergebnisse.
* **Sie zeigt die erste Seite, in der Reihenfolge der Abfrage selbst.** Sortieren, Filtern und
  das Suchfeld werden hier nicht angeboten - eine Vorschau, die eine Sortierung stillschweigend
  ignoriert, wäre schlechter als eine, die sie gar nicht anbietet. Führen Sie die Pipeline aus,
  um die vollständige Tabelle zu erhalten.
* **Die Spalten stammen aus dem, was die Abfrage tatsächlich liefert**, nicht aus der Liste der
  Ausgabespalten - eine gerade umgeschriebene Abfrage zeigt ihre neuen Spalten also sofort.
* **Wenn die Abfrage nicht laufen kann, sagt sie warum.** Die Meldung nennt die Relation, die
  sich nicht auflösen ließ; das ist meist ein Tippfehler oder ein fehlender Eintrag in
  `manifest.yml` (siehe unten).

### Was eine Vorschau lesen kann [#was-eine-vorschau-lesen-kann]

Eine Vorschau bindet **jeden Dataset-Knoten der App**, genau wie eine Ausführung - eine Abfrage,
die ein Dataset liest, funktioniert also unabhängig davon, ob `manifest.yml` es erwähnt.

Die **SQL-Knoten**, die sie bindet, sind die, die Ihre `manifest.yml` deklariert, und deren
Eingaben wiederum. Eine Abfrage, die die Ausgabe eines ANDEREN SQL-Knotens liest, ohne diesen
Knoten in `manifest.yml` aufzuführen, lässt sich daher nicht in der Vorschau anzeigen, und die
Meldung nennt ihn. Nehmen Sie ihn in `input_tables` auf, und die Vorschau funktioniert - was
ohnehin sinnvoll ist, denn dieser Eintrag zeichnet auch den Pfeil auf der Arbeitsfläche und
sagt der Pipeline, in welcher Reihenfolge die beiden Schritte laufen.

Zwei Arten von Eingaben lassen sich überhaupt nicht in der Vorschau anzeigen, und die Meldung
sagt das, statt wie eine kaputte Abfrage auszusehen: ein
[Analytics-Daten-Import](./analytic-data.mdx) und eine
[Indikatordaten](./indicator-data.mdx)-Brücke. Ihre Zeilen werden beim Ausführen der Pipeline
geholt, es gibt also nichts Aktuelles zu lesen. Führen Sie die Pipeline aus, um einen Knoten zu
sehen, der von einer solchen Eingabe abhängt.

## `manifest.yml` muss zur Abfrage passen [#manifestyml-muss-zur-abfrage-passen]

In `manifest.yml` deklariert ein SQL-Knoten, welche anderen Knoten er liest. Diese Liste ist
keine Formalität: Sie ist das Einzige, was die Pfeile auf der Arbeitsfläche zeichnet, und das
Einzige, was einer Ausführung sagt, welcher Schritt vor diesem fertig sein muss. Eine Abfrage,
die einen Knoten liest, den die Liste nicht nennt, läuft zwar - aber das Bild, das die App von
sich selbst hat, ist dann falsch, und zwei Schritte, die in einer bestimmten Reihenfolge laufen
müssen, dürfen in der falschen laufen.

Beim Speichern eines SQL-Knotens werden die beiden daher gegeneinander geprüft. Stimmen sie
nicht überein, wird das Speichern abgelehnt, und die Meldung nennt den Knoten und die Tabelle:

* **Die Abfrage liest einen Knoten, den `input_tables` nicht auflistet.** Nehmen Sie ihn auf.
* **`input_tables` nennt einen Knoten, den die Abfrage nie liest.** Entfernen Sie ihn, oder
  lesen Sie ihn in der Abfrage.
* **`input_tables` nennt etwas, das kein Knoten dieser App ist.** Meist ein Tippfehler in der ID.

Ein Knoten, der keinen anderen Knoten liest, braucht keine Liste; eine leere `manifest.yml` ist
für ihn richtig.

Wenn Sie Apps über Vera oder einen KI-Connector bauen, ist das bereits erledigt: Die Werkzeuge
verlangen die Liste und kennen dieselbe Regel, sodass die Pfeile von der ersten Version an da
sind und nicht erst, nachdem Sie danach fragen.

## Die Zeilen-ID eines Datasets lesen [#die-zeilen-id-eines-datasets-lesen]

Die Tabelle jedes Dataset-Knotens führt hinter Ihren eigenen Spalten drei weitere:

| Spalte        | Bedeutung                                                                |
| ------------- | ------------------------------------------------------------------------ |
| `_row_id`     | Die stabile ID der Zeile - dieselbe, die auch das Datenraster verwendet. |
| `_created_at` | Wann die Zeile angelegt wurde.                                           |
| `_updated_at` | Wann die Zeile zuletzt geändert wurde.                                   |

Sie stehen NACH jeder vom Dataset deklarierten Spalte, in der von Ihnen deklarierten
Reihenfolge, und sie können niemals mit einer Ihrer eigenen Spalten kollidieren: ein
von Ihnen vergebener Spaltenname beginnt immer mit einem Buchstaben.

`SELECT * FROM orders` liefert sie neben Ihren Spalten mit. Zu Ausgabespalten des
Knotens werden sie aber nicht - die Liste **Ausgabespalten** eines SQL-Knotens
übergeht sie, eine Abfrage mit `_row_id` speichert und läuft also genau wie eine ohne.

Die Zeilen-ID erlaubt es, eine Zeile mit einer Aussage ÜBER diese Zeile zu verbinden - am
nützlichsten mit den [Validierungsergebnissen](./validation.mdx). Der Validierungsknoten
heißt normalerweise `validation_errors`; in einer App, in der einer Ihrer eigenen Knoten
diesen Namen bereits hält, erhält er stattdessen eine nummerierte Variante - verwenden
Sie also den Namen, den Ihre App tatsächlich anzeigt:

```sql title="orders_with_findings.sql"
SELECT o.*, e.validation_error
  FROM orders o
  LEFT JOIN validation_errors e
    ON e.dataset_technical_id = 'orders'
   AND e.row_id = o._row_id
```

Sie stehen überall zur Verfügung, wo Sie SQL gegen die App schreiben - im Skript eines
SQL-Knotens und im Ad-hoc-Abfragefeld -, dieselbe Abfrage funktioniert also an beiden
Stellen.

Ein Dataset ohne Zeilen besitzt die Spalten trotzdem, eine Abfrage darauf liefert also
keine Zeilen statt zu scheitern. Zeilen, die vor der Einführung der Zeilen-ID
hochgeladen wurden, lesen sich als leer: eine erfundene ID, die stabil aussieht, wäre
schlechter als gar keine.

## Jede von der Abfrage gelieferte Spalte braucht einen brauchbaren Namen [#jede-von-der-abfrage-gelieferte-spalte-braucht-einen-brauchbaren-namen]

Der Bezeichner einer Spalte stammt direkt aus der Abfrage, daher muss die Abfrage jeder
Spalte einen Namen geben, der als Bezeichner taugt: Kleinbuchstaben, Ziffern und
Unterstriche, beginnend mit einem Buchstaben, maximal 32 Zeichen. `order_id`, `revenue` und
`region_2024` sind alle in Ordnung.

Die meisten Abfragen erfüllen das bereits, denn eine ausgewählte Spalte behält ihren Namen.
Was das nicht tut, ist ein Ausdruck ohne eigenen Namen. `SELECT count(*)` liefert eine
Spalte, die wörtlich `count_star()` heißt, und `SELECT a + b` eine namens `(a + b)`.
Vergeben Sie dafür einen Alias:

```sql
SELECT count(*) AS order_count
```

Das Speichern eines Knotens, dessen Abfrage einen unbrauchbaren Namen liefert, wird
abgelehnt, und die Meldung nennt die betroffene Spalte. Meist sehen Sie es schon früher:
Sobald Sie die Abfrage ausführen, nennt eine Zeile über den Ergebnissen die Spalten, die
einen Alias brauchen.

Der Alias lohnt sich ohnehin, nicht nur wegen der Regel. Nachgelagerte Knoten und Ihre
Visualisierungs-Widgets sprechen diese Spalte über den NAMEN an - `order_count` können Sie
lesen und referenzieren, `count_star()` nicht. Ihn zu vergeben kostet nichts: Sie benennen
damit die Spalte, die Sie ohnehin gemeint haben.
