Formateur SQL PostgreSQL

Collez une requête Postgres et obtenez du SQL propre, indenté de façon cohérente. Les marqueurs numérotés $1 issus des requêtes préparées sont détectés pour que vous puissiez les remplir, et la syntaxe propre à Postgres — opérateurs JSONB, casts et corps de fonction entre dollars — est préservée.

Une requête PostgreSQL, avant et après

La requête non formatée ci-dessous est l'exemple chargé dans l'éditeur plus haut, et la sortie est exactement ce que ce formateur en renvoie avec les options par défaut. Rien n'a été retouché à la main.

Collé
WITH recent AS (SELECT user_id, count(*) AS n, max(created_at) AS last_seen FROM events WHERE created_at >= $1 AND payload->>'type' = $2 GROUP BY user_id) SELECT u.id, u.email, r.n, row_number() OVER (ORDER BY r.n DESC) AS rank FROM users u JOIN recent r ON r.user_id = u.id WHERE u.status = 'active' AND u.created_at::date BETWEEN $3 AND $4 ORDER BY r.n DESC LIMIT 50
Sortie formatée
WITH
  recent AS (
    SELECT
      user_id,
      count(*) AS n,
      max(created_at) AS last_seen
    FROM
      events
    WHERE
      created_at >= $1
      AND payload ->> 'type' = $2
    GROUP BY
      user_id
  )
SELECT
  u.id,
  u.email,
  r.n,
  row_number() OVER (
    ORDER BY
      r.n DESC
  ) AS rank
FROM
  users u
  JOIN recent r ON r.user_id = u.id
WHERE
  u.status = 'active'
  AND u.created_at::date BETWEEN $3 AND $4
ORDER BY
  r.n DESC
LIMIT
  50

La syntaxe PostgreSQL qu'il gère

Un formateur générique massacre la syntaxe propre au dialecte ou la refuse tout net. Voici les constructions PostgreSQL contre lesquelles ce formateur est testé.

$1, $2

Les marqueurs numérotés des requêtes préparées sont détectés et peuvent être remplis pour produire une requête exécutable.

payload->>'key'

Les opérateurs JSON et JSONB sont laissés exactement tels qu'écrits.

value::type

La syntaxe de cast n'est jamais confondue avec un paramètre :name.

$$ ... $$

Les corps de fonction entre dollars sont traités comme des littéraux, si bien que les mots-clés à l'intérieur ne sont pas reformatés.

WITH ... AS

La clause WHERE de chaque CTE est listée séparément et peut être modifiée indépendamment.

OVER (PARTITION BY ...)

Les fonctions de fenêtrage et leurs frames sont formatées sans casser la clause.

FAQ du formateur PostgreSQL

Gère-t-il les marqueurs $1 des requêtes préparées ?

Oui. Les marqueurs numérotés de Postgres sont détectés et listés dans le panneau Paramètres. Remplissez-les puis basculez la sortie en SQL rempli pour obtenir une requête à coller directement dans psql.

Va-t-il casser mes ::casts ou mes opérateurs JSONB ?

Non. Les casts sont distingués des paramètres :name, et les opérateurs JSON/JSONB comme -> et ->> passent sans modification.

Peut-il formater une requête à plusieurs CTE — et n'en modifier qu'une ?

Oui. Chaque clause WHERE est listée sous la CTE à laquelle elle appartient, si bien qu'une requête faite d'une chaîne de blocs WITH donne une entrée par bloc. Vous en choisissez un, l'éditez comme arbre ET/OU ou comme graphe de nœuds, et la modification est réinjectée exactement dans cette clause tandis que le reste de la requête reste intact octet pour octet.

Formate-t-il une requête incomplète, ou une simple clause WHERE ?

Oui. Rien ici ne dépend d'une analyse complète et valide : vous pouvez coller un fragment tiré d'une ligne de log ou d'une trace de débogage d'ORM — même un simple WHERE created_at >= $1 AND status = $2 — et il sera tout de même formaté et modifiable visuellement.

Conserve-t-il intacts les corps PL/pgSQL entre dollars ?

Oui. Un corps entre dollars est traité comme un littéral unique : les mots-clés qu'il contient ne sont pas réindentés comme s'ils appartenaient à l'instruction englobante, et une balise ouvrante n'est appariée qu'à sa propre balise fermante, pas au premier signe dollar venu.

Peut-il minifier une requête Postgres sur une seule ligne ?

Oui — embellir et minifier sont tous deux disponibles. La minification tient compte des espaces réels au lieu d'appliquer une expression régulière aveugle : l'espacement à l'intérieur des littéraux de chaîne est préservé et la requête minifiée renvoie exactement les mêmes lignes qu'au départ.