# The jOOQ User Manual, version 3.22

> [!NOTE]
> This is the complete jOOQ 3.22 manual in a single Markdown document, generated from the manual sources. Sections are numbered as in the online manual. Each section heading is preceded by an anchor named after the section ID. Links to other sections point to these anchors (e.g. `#select-statement`). The online version of this manual is available at https://www.jooq.org/doc/3.22/manual/
>
> This documentation is for the unreleased development version of jOOQ.

## Overview

This manual is divided into these main sections:

- [Getting started with jOOQ](#getting-started)

  This section will get you started with jOOQ quickly. It contains simple explanations about what jOOQ is, what jOOQ isn't and how to set it up for the first time

- [SQL building](#sql-building)

  This section explains all about the jOOQ syntax used for building queries through the query DSL and the query model API. It explains the central factories, the supported SQL statements and various other syntax elements

- [Code generation](#code-generation)

  This section explains how to configure and use the built-in source code generator

- [SQL execution](#sql-execution)

  This section will get you through the specifics of what can be done with jOOQ at runtime, in order to execute queries, perform CRUD operations, import and export data, and hook into the jOOQ execution lifecycle for debugging

- [What's new in version 3.22.0](#whats-new)

  This section shows what's new in version 3.22.0 of jOOQ.

- [Reference](#reference)

  This section is a reference for elements in this manual

<a id="toc"></a>
## Table of contents

- [1. Copyright, License, and Trademarks](#copyright)
- [2. Getting started with jOOQ](#getting-started)
  - [2.1. How to read this manual](#the-manual)
  - [2.2. The sample database used in this manual](#sample-database)
  - [2.3. Different use cases for jOOQ](#use-cases)
    - [2.3.1. jOOQ as a SQL builder without code generation](#jooq-as-a-sql-builder-without-codegeneration)
    - [2.3.2. jOOQ as a SQL builder with code generation](#jooq-as-a-sql-builder-with-code-generation)
    - [2.3.3. jOOQ as a SQL executor](#jooq-as-a-sql-executor)
    - [2.3.4. jOOQ for CRUD](#jooq-for-crud)
    - [2.3.5. jOOQ for PROs](#jooq-for-pros)
  - [2.4. Downloading jOOQ](#getting-jooq)
  - [2.5. Tutorials](#tutorials)
    - [2.5.1. jOOQ in 7 easy steps](#jooq-in-7-steps)
      - [2.5.1.1. Step 1: Preparation](#jooq-in-7-steps-step1)
      - [2.5.1.2. Step 2: Your database](#jooq-in-7-steps-step2)
      - [2.5.1.3. Step 3: Code generation](#jooq-in-7-steps-step3)
      - [2.5.1.4. Step 4: Connect to your database](#jooq-in-7-steps-step4)
      - [2.5.1.5. Step 5: Querying](#jooq-in-7-steps-step5)
      - [2.5.1.6. Step 6: Iterating](#jooq-in-7-steps-step6)
      - [2.5.1.7. Step 7: Explore!](#jooq-in-7-steps-step7)
    - [2.5.2. Using jOOQ with Flyway](#jooq-with-flyway)
    - [2.5.3. Using jOOQ with jbang](#jooq-with-jbang)
  - [2.6. jOOQ and Java 8](#jooq-and-java-8)
  - [2.7. jOOQ and Scala](#jooq-and-scala)
  - [2.8. jOOQ and Groovy](#jooq-and-groovy)
  - [2.9. jOOQ and Kotlin](#jooq-and-kotlin)
  - [2.10. jOOQ and NoSQL](#jooq-and-nosql)
  - [2.11. jOOQ and JPA](#jooq-and-jpa)
  - [2.12. Build your own](#build-your-own)
  - [2.13. jOOQ and backwards-compatibility](#semantic-versioning)
- [3. SQL building](#sql-building)
  - [3.1. The query DSL type](#dsl)
  - [3.2. The DSLContext API](#dsl-context)
    - [3.2.1. SQL Dialect](#sql-dialects)
    - [3.2.2. SQL Dialect Family](#sql-dialect-family)
    - [3.2.3. SQL Dialect Category](#sql-dialect-category)
    - [3.2.4. Connection vs. DataSource](#connection-vs-datasource)
    - [3.2.5. Custom data](#custom-data)
    - [3.2.6. Custom ExecuteListeners](#custom-execute-listeners)
    - [3.2.7. Custom Unwrappers](#custom-unwrappers)
    - [3.2.8. Custom Settings](#custom-settings)
      - [3.2.8.1. Auto-attach Records](#settings-attach-records)
      - [3.2.8.2. Auto-inline bind values](#settings-auto-inline-bind-values)
      - [3.2.8.3. Backslash Escaping](#settings-backslash-escaping)
      - [3.2.8.4. Batch size](#settings-batch-size)
      - [3.2.8.5. Bind value casting](#settings-param-cast-mode)
      - [3.2.8.6. Computed column activation](#settings-computed-column-activation)
      - [3.2.8.7. Computed column emulation](#settings-computed-column-emulation)
      - [3.2.8.8. Constructor parameter mapping](#settings-constructor-parameter-names)
      - [3.2.8.9. Diagnostics Connection](#settings-diagnostics-connection)
      - [3.2.8.10. Diagnostics Logging](#settings-diagnostics-logging)
      - [3.2.8.11. Dialect compatibility](#settings-dialect-compatibility)
      - [3.2.8.12. Dirty tracking](#settings-dirty-tracking)
      - [3.2.8.13. Dollar quoted string token](#settings-dollar-quoted-string-token)
      - [3.2.8.14. Execute Logging](#settings-execute-logging)
      - [3.2.8.15. Execute Logging SQL Exceptions](#settings-execute-logging-sql-exceptions)
      - [3.2.8.16. Fetching trimmed CHAR types](#settings-fetching-trimmed-strings)
      - [3.2.8.17. Fetch server output](#settings-fetch-server-output)
      - [3.2.8.18. Fetch Warnings](#settings-fetch-warnings)
      - [3.2.8.19. GROUP_CONCAT Configuration](#settings-group-concat)
      - [3.2.8.20. Identifier length](#settings-name-max-length)
      - [3.2.8.21. Identifier style](#settings-name-style)
      - [3.2.8.22. Implicit join type](#settings-implicit-join-type)
      - [3.2.8.23. Inline Threshold](#settings-inline-threshold)
      - [3.2.8.24. IN-list Padding](#settings-in-list-padding)
      - [3.2.8.25. Interpreter Configuration](#settings-interpreter)
      - [3.2.8.26. JDBC Flags](#settings-jdbc-flags)
      - [3.2.8.27. JSR 310 type binding](#settings-jsr310-binding)
      - [3.2.8.28. Keyword style](#settings-keyword-style)
      - [3.2.8.29. Listener Invocation Order](#settings-listener-invocation-order)
      - [3.2.8.30. Locales](#settings-locale)
      - [3.2.8.31. Map JPA Annotations](#settings-map-jpa)
      - [3.2.8.32. Meta SQL on error](#settings-meta-sql-on-error)
      - [3.2.8.33. Meta system objects](#settings-meta-system-objects)
      - [3.2.8.34. Object qualification](#setting-qualification)
      - [3.2.8.35. Object qualification for columns](#setting-table-qualification)
      - [3.2.8.36. Optimistic Locking](#settings-optimistic-locking)
      - [3.2.8.37. Parameter name prefix](#settings-named-parameter-prefix)
      - [3.2.8.38. Parameter types](#settings-parameter-type)
      - [3.2.8.39. Parser Configuration](#settings-parser)
      - [3.2.8.40. Readonly column behaviour](#settings-readonly-columns)
      - [3.2.8.41. Redacted column behaviour](#settings-redacted-columns)
      - [3.2.8.42. Reflection caching](#settings-reflection-caching)
      - [3.2.8.43. Rendering Configuration](#settings-rendering)
      - [3.2.8.44. Return all columns on store](#settings-return-all-on-store)
      - [3.2.8.45. Return computed columns on store](#settings-return-computed-on-store)
      - [3.2.8.46. Return DEFAULT columns on store](#settings-return-default-on-store)
      - [3.2.8.47. Return Identity Value On Store](#settings-return-identity-on-store)
      - [3.2.8.48. Runtime catalog, schema and table mapping](#settings-render-mapping)
      - [3.2.8.49. Scalar subqueries for stored functions](#settings-scalar-subqueries)
      - [3.2.8.50. SEEK clause implementation](#settings-seek-clause)
      - [3.2.8.51. Statement Type](#settings-statement-type)
      - [3.2.8.52. Storing unchanged records](#settings-unchanged-records)
      - [3.2.8.53. Throw exceptions](#settings-throw-exceptions)
      - [3.2.8.54. Updatable Primary Keys](#settings-updatable-primary-keys)
      - [3.2.8.55. UPDATE and DELETE without WHERE](#settings-execute-without-where)
    - [3.2.9. Thread safety](#thread-safety)
  - [3.3. The DSL API](#dsl-api)
    - [3.3.1. Mutability (historic)](#mutability-historic)
  - [3.4. The model API](#model-api)
    - [3.4.1. Design](#model-api-design)
    - [3.4.2. Traversal](#model-api-traversal)
    - [3.4.3. Replacement](#model-api-replacement)
      - [3.4.3.1. Pattern transformation Replacer](#replacement-transform-patterns)
      - [3.4.3.2. Table mapping Replacer](#replacement-table-mapping)
      - [3.4.3.3. Listening Replacer](#replacement-listening)
      - [3.4.3.4. Decomposing Replacer](#replacement-decomposing)
    - [3.4.4. The historic model API](#model-api-historic)
  - [3.5. SQL Statements (DML)](#sql-statements)
    - [3.5.1. The WITH clause](#with-clause)
    - [3.5.2. The WITH RECURSIVE clause](#with-recursive-clause)
    - [3.5.3. The SELECT statement](#select-statement)
      - [3.5.3.1. SELECT clause](#select-clause)
        - [3.5.3.1.1. Projection type safety](#select-clause-type-safety)
        - [3.5.3.1.2. SelectField](#select-clause-selectfield)
        - [3.5.3.1.3. Tables as SelectField](#select-clause-table)
        - [3.5.3.1.4. SELECT *](#select-clause-asterisk)
        - [3.5.3.1.5. SELECT * EXCEPT (...)](#select-clause-asterisk-except)
        - [3.5.3.1.6. SELECT DISTINCT](#select-clause-distinct)
        - [3.5.3.1.7. SELECT DISTINCT ON](#select-clause-distinct-on)
        - [3.5.3.1.8. Convenience methods](#select-clause-convenience)
      - [3.5.3.2. FROM clause](#from-clause)
        - [3.5.3.2.1. JOIN operator](#join-clause)
        - [3.5.3.2.2. Implicit path JOIN](#implicit-join)
        - [3.5.3.2.3. Implicit to-many path JOIN](#implicit-to-many-join)
        - [3.5.3.2.4. Explicit path JOIN](#explicit-path-join)
        - [3.5.3.2.5. Implicit path correlation](#implicit-path-correlation)
      - [3.5.3.3. WHERE clause](#where-clause)
      - [3.5.3.4. CONNECT BY clause](#connect-by-clause)
      - [3.5.3.5. GROUP BY clause](#group-by-clause)
        - [3.5.3.5.1. GROUP BY columns](#group-by-columns)
        - [3.5.3.5.2. GROUP BY column index](#group-by-column-index)
        - [3.5.3.5.3. GROUP BY tables](#group-by-tables)
        - [3.5.3.5.4. GROUP BY ROLLUP](#group-by-rollup)
        - [3.5.3.5.5. GROUP BY CUBE](#group-by-cube)
        - [3.5.3.5.6. GROUP BY GROUPING SETS](#group-by-grouping-sets)
        - [3.5.3.5.7. GROUP BY empty grouping set](#group-by-empty-grouping-set)
      - [3.5.3.6. HAVING clause](#having-clause)
      - [3.5.3.7. WINDOW clause](#window-clause)
      - [3.5.3.8. QUALIFY clause](#qualify-clause)
      - [3.5.3.9. ORDER BY clause](#order-by-clause)
        - [3.5.3.9.1. Ordering by field index](#order-by-field-index)
        - [3.5.3.9.2. Ordering and NULLS](#order-by-nulls-ordering)
        - [3.5.3.9.3. Ordering using CASE expressions](#order-by-case)
        - [3.5.3.9.4. Oracle's ORDER SIBLINGS BY clause](#order-siblings-by)
      - [3.5.3.10. LIMIT .. OFFSET clause](#limit-clause)
      - [3.5.3.11. WITH TIES clause](#with-ties-clause)
      - [3.5.3.12. SEEK clause](#seek-clause)
      - [3.5.3.13. FOR XML clause](#for-xml-clause)
        - [3.5.3.13.1. AUTO mode](#for-xml-auto-mode)
        - [3.5.3.13.2. PATH mode](#for-xml-path-mode)
        - [3.5.3.13.3. EXPLICIT mode](#for-xml-explicit-mode)
        - [3.5.3.13.4. RAW mode](#for-xml-raw-mode)
        - [3.5.3.13.5. ROOT directive](#for-xml-root-directive)
        - [3.5.3.13.6. ELEMENTS directive](#for-xml-elements-directive)
      - [3.5.3.14. FOR JSON clause](#for-json-clause)
        - [3.5.3.14.1. AUTO mode](#for-json-auto-mode)
        - [3.5.3.14.2. PATH mode](#for-json-path-mode)
        - [3.5.3.14.3. ROOT directive](#for-json-root-directive)
        - [3.5.3.14.4. INCLUDE_NULL_VALUES directive](#for-json-include-null-values-directive)
        - [3.5.3.14.5. WITHOUT_ARRAY_WRAPPER directive](#for-json-without-array-wrapper-directive)
      - [3.5.3.15. FOR UPDATE clause](#for-update-clause)
      - [3.5.3.16. Set operations](#set-operations)
        - [3.5.3.16.1. Type safety](#set-operation-typesafety)
        - [3.5.3.16.2. Projection rowtype](#set-operation-rowtype)
        - [3.5.3.16.3. Differences to standard SQL](#set-operation-and-standard)
        - [3.5.3.16.4. UNION](#set-operation-union)
        - [3.5.3.16.5. UNION ALL](#set-operation-union-all)
        - [3.5.3.16.6. INTERSECT](#set-operation-intersect)
        - [3.5.3.16.7. INTERSECT ALL](#set-operation-intersect-all)
        - [3.5.3.16.8. EXCEPT](#set-operation-except)
        - [3.5.3.16.9. EXCEPT ALL](#set-operation-except-all)
      - [3.5.3.17. Lexical and logical SELECT clause order](#select-lexical-vs-logical-order)
    - [3.5.4. The INSERT statement](#insert-statement)
      - [3.5.4.1. INSERT .. VALUES](#insert-values)
      - [3.5.4.2. INSERT .. DEFAULT VALUES](#insert-default-values)
      - [3.5.4.3. INSERT .. SET](#insert-set)
      - [3.5.4.4. INSERT .. SELECT](#insert-select)
      - [3.5.4.5. INSERT .. ON DUPLICATE KEY UPDATE](#insert-on-duplicate-key)
      - [3.5.4.6. INSERT .. ON DUPLICATE KEY UPDATE .. EXCLUDED](#insert-on-duplicate-key-excluded)
      - [3.5.4.7. INSERT .. ON DUPLICATE KEY UPDATE .. SET ALL TO EXCLUDED](#insert-on-duplicate-key-all-excluded)
      - [3.5.4.8. INSERT .. ON DUPLICATE KEY IGNORE](#insert-on-duplicate-key-ignore)
      - [3.5.4.9. INSERT .. ON CONFLICT](#insert-on-conflict)
      - [3.5.4.10. INSERT .. ON CONFLICT .. EXCLUDED](#insert-on-conflict-excluded)
      - [3.5.4.11. INSERT .. ON CONFLICT .. SET ALL TO EXCLUDED](#insert-on-conflict-all-excluded)
      - [3.5.4.12. INSERT .. RETURNING](#insert-returning)
    - [3.5.5. The UPDATE statement](#update-statement)
      - [3.5.5.1. UPDATE .. SET](#update-set)
      - [3.5.5.2. UPDATE .. SET ROW](#update-set-rows)
      - [3.5.5.3. UPDATE .. FROM](#update-from)
      - [3.5.5.4. UPDATE .. WHERE](#update-where)
      - [3.5.5.5. UPDATE .. ORDER BY .. LIMIT](#update-order-by-limit)
      - [3.5.5.6. UPDATE .. RETURNING](#update-returning)
    - [3.5.6. The DELETE statement](#delete-statement)
      - [3.5.6.1. DELETE .. USING](#delete-using)
      - [3.5.6.2. DELETE .. WHERE](#delete-where)
      - [3.5.6.3. DELETE .. ORDER BY .. LIMIT](#delete-order-by-limit)
      - [3.5.6.4. DELETE .. RETURNING](#delete-returning)
    - [3.5.7. The MERGE statement](#merge-statement)
      - [3.5.7.1. USING .. ON](#merge-using)
      - [3.5.7.2. WHEN MATCHED THEN UPDATE](#merge-when-matched-then-update)
      - [3.5.7.3. WHEN MATCHED THEN DELETE](#merge-when-matched-then-delete)
      - [3.5.7.4. WHEN MATCHED AND ..](#merge-when-matched-and)
      - [3.5.7.5. WHEN NOT MATCHED THEN INSERT](#merge-when-not-matched-then-insert)
      - [3.5.7.6. WHEN NOT MATCHED AND ..](#merge-when-not-matched-and)
      - [3.5.7.7. WHEN NOT MATCHED BY SOURCE](#merge-when-not-matched-by-source)
  - [3.6. SQL Statements (DDL)](#ddl-statements)
    - [3.6.1. The ALTER statement](#alter-statement)
      - [3.6.1.1. ALTER DATABASE](#alter-database-statement)
        - [3.6.1.1.1. ALTER DATABASE .. RENAME](#alter-database-rename)
        - [3.6.1.1.2. ALTER DATABASE IF EXISTS](#alter-database-if-exists)
      - [3.6.1.2. ALTER DOMAIN](#alter-domain-statement)
        - [3.6.1.2.1. ALTER DOMAIN .. RENAME](#alter-domain-rename)
        - [3.6.1.2.2. ALTER DOMAIN .. SET DEFAULT](#alter-domain-set-default)
        - [3.6.1.2.3. ALTER DOMAIN .. DROP DEFAULT](#alter-domain-drop-default)
        - [3.6.1.2.4. ALTER DOMAIN .. SET NOT NULL](#alter-domain-set-not-null)
        - [3.6.1.2.5. ALTER DOMAIN .. DROP NOT NULL](#alter-domain-drop-not-null)
        - [3.6.1.2.6. ALTER DOMAIN .. ADD CONSTRAINT](#alter-domain-add-constraint)
        - [3.6.1.2.7. ALTER DOMAIN .. RENAME CONSTRAINT](#alter-domain-rename-constraint)
        - [3.6.1.2.8. ALTER DOMAIN .. RENAME CONSTRAINT IF EXISTS](#alter-domain-rename-constraint-if-exists)
        - [3.6.1.2.9. ALTER DOMAIN .. DROP CONSTRAINT](#alter-domain-drop-constraint)
        - [3.6.1.2.10. ALTER DOMAIN .. DROP CONSTRAINT IF EXISTS](#alter-domain-drop-constraint-if-exists)
        - [3.6.1.2.11. ALTER DOMAIN IF EXISTS](#alter-domain-if-exists)
      - [3.6.1.3. ALTER INDEX](#alter-index-statement)
        - [3.6.1.3.1. ALTER INDEX .. RENAME](#alter-index-rename)
        - [3.6.1.3.2. ALTER INDEX IF EXISTS](#alter-index-if-exists)
      - [3.6.1.4. ALTER SCHEMA](#alter-schema-statement)
        - [3.6.1.4.1. ALTER SCHEMA .. RENAME](#alter-schema-rename)
        - [3.6.1.4.2. ALTER SCHEMA IF EXISTS](#alter-schema-if-exists)
      - [3.6.1.5. ALTER SEQUENCE](#alter-sequence-statement)
        - [3.6.1.5.1. ALTER SEQUENCE .. RENAME](#alter-sequence-rename)
        - [3.6.1.5.2. ALTER SEQUENCE .. CACHE](#alter-sequence-cache)
        - [3.6.1.5.3. ALTER SEQUENCE .. CYCLE](#alter-sequence-cycle)
        - [3.6.1.5.4. ALTER SEQUENCE .. MINVALUE](#alter-sequence-minvalue)
        - [3.6.1.5.5. ALTER SEQUENCE .. MAXVALUE](#alter-sequence-maxvalue)
        - [3.6.1.5.6. ALTER SEQUENCE .. INCREMENT BY](#alter-sequence-increment-by)
        - [3.6.1.5.7. ALTER SEQUENCE .. START WITH](#alter-sequence-start-with)
        - [3.6.1.5.8. ALTER SEQUENCE .. RESTART](#alter-sequence-restart)
        - [3.6.1.5.9. ALTER SEQUENCE IF EXISTS](#alter-sequence-if-exists)
      - [3.6.1.6. ALTER TABLE](#alter-table-statement)
        - [3.6.1.6.1. ALTER TABLE .. ADD COLUMN](#alter-table-add-column)
        - [3.6.1.6.2. ALTER TABLE .. ADD COLUMN .. FIRST, BEFORE, AFTER](#alter-table-add-column-position)
        - [3.6.1.6.3. ALTER TABLE .. ADD COLUMNS](#alter-table-add-multiple)
        - [3.6.1.6.4. ALTER TABLE .. ADD COLUMN IF NOT EXISTS](#alter-table-add-column-if-not-exists)
        - [3.6.1.6.5. ALTER TABLE .. ADD PRIMARY KEY](#alter-table-add-primary-key)
        - [3.6.1.6.6. ALTER TABLE .. ADD UNIQUE](#alter-table-add-unique)
        - [3.6.1.6.7. ALTER TABLE .. ADD FOREIGN KEY](#alter-table-add-foreign-key)
        - [3.6.1.6.8. ALTER TABLE .. ADD CHECK](#alter-table-add-check)
        - [3.6.1.6.9. ALTER TABLE .. RENAME](#alter-table-rename)
        - [3.6.1.6.10. ALTER TABLE .. COMMENT](#alter-table-comment)
        - [3.6.1.6.11. ALTER TABLE .. ALTER COLUMN .. SET DEFAULT](#alter-table-alter-column-set-default)
        - [3.6.1.6.12. ALTER TABLE .. ALTER COLUMN .. DROP DEFAULT](#alter-table-alter-column-drop-default)
        - [3.6.1.6.13. ALTER TABLE .. ALTER COLUMN .. SET GENERATED BY DEFAULT AS IDENTITY](#alter-table-alter-column-set-identity)
        - [3.6.1.6.14. ALTER TABLE .. ALTER COLUMN .. DROP IDENTITY](#alter-table-alter-column-drop-identity)
        - [3.6.1.6.15. ALTER TABLE .. ALTER COLUMN .. SET GENERATED](#alter-table-alter-column-set-generated)
        - [3.6.1.6.16. ALTER TABLE .. ALTER COLUMN .. DROP GENERATED](#alter-table-alter-column-drop-generated)
        - [3.6.1.6.17. ALTER TABLE .. ALTER COLUMN .. SET NOT NULL](#alter-table-alter-column-set-not-null)
        - [3.6.1.6.18. ALTER TABLE .. ALTER COLUMN .. DROP NOT NULL](#alter-table-alter-column-drop-not-null)
        - [3.6.1.6.19. ALTER TABLE .. ALTER COLUMN .. SET TYPE](#alter-table-alter-column-set-type)
        - [3.6.1.6.20. ALTER TABLE .. ALTER CONSTRAINT .. ENFORCED](#alter-table-alter-constraint-enforced)
        - [3.6.1.6.21. ALTER TABLE .. ALTER CONSTRAINT .. NOT ENFORCED](#alter-table-alter-constraint-not-enforced)
        - [3.6.1.6.22. ALTER TABLE .. CHANGE COLUMN](#alter-table-change-column)
        - [3.6.1.6.23. ALTER TABLE .. RENAME COLUMN](#alter-table-rename-column)
        - [3.6.1.6.24. ALTER TABLE .. RENAME CONSTRAINT](#alter-table-rename-constraint)
        - [3.6.1.6.25. ALTER TABLE .. RENAME INDEX](#alter-table-rename-index)
        - [3.6.1.6.26. ALTER TABLE .. DROP COLUMN](#alter-table-drop-column)
        - [3.6.1.6.27. ALTER TABLE .. DROP COLUMN RESTRICT](#alter-table-drop-column-restrict)
        - [3.6.1.6.28. ALTER TABLE .. DROP COLUMN CASCADE](#alter-table-drop-column-cascade)
        - [3.6.1.6.29. ALTER TABLE .. DROP COLUMNS](#alter-table-drop-multiple)
        - [3.6.1.6.30. ALTER TABLE .. DROP COLUMN IF EXISTS](#alter-table-drop-column-if-exists)
        - [3.6.1.6.31. ALTER TABLE .. DROP CONSTRAINT](#alter-table-drop-constraint)
        - [3.6.1.6.32. ALTER TABLE .. DROP PRIMARY KEY](#alter-table-drop-primary-key)
        - [3.6.1.6.33. ALTER TABLE .. DROP UNIQUE](#alter-table-drop-unique)
        - [3.6.1.6.34. ALTER TABLE .. DROP FOREIGN KEY](#alter-table-drop-foreign-key)
        - [3.6.1.6.35. ALTER TABLE .. DROP CONSTRAINT IF EXISTS](#alter-table-drop-constraint-if-exists)
        - [3.6.1.6.36. ALTER TABLE IF EXISTS](#alter-table-if-exists)
      - [3.6.1.7. ALTER TYPE](#alter-type-statement)
        - [3.6.1.7.1. ALTER TYPE .. RENAME](#alter-type-rename)
        - [3.6.1.7.2. ALTER TYPE .. for enum alterations](#alter-type-enum)
        - [3.6.1.7.3. ALTER TYPE IF EXISTS](#alter-type-if-exists)
      - [3.6.1.8. ALTER VIEW](#alter-view-statement)
        - [3.6.1.8.1. ALTER VIEW .. AS](#alter-view-as)
        - [3.6.1.8.2. ALTER VIEW .. COMMENT](#alter-view-comment)
        - [3.6.1.8.3. ALTER VIEW .. RENAME](#alter-view-rename)
        - [3.6.1.8.4. ALTER VIEW IF EXISTS](#alter-view-if-exists)
    - [3.6.2. The COMMENT statement](#comment-statement)
      - [3.6.2.1. COMMENT ON COLUMN](#comment-on-column)
      - [3.6.2.2. COMMENT ON FUNCTION](#comment-on-function)
      - [3.6.2.3. COMMENT ON MATERIALIZED VIEW](#comment-on-materialized-view)
      - [3.6.2.4. COMMENT ON PROCEDURE](#comment-on-procedure)
      - [3.6.2.5. COMMENT ON TABLE](#comment-on-table)
      - [3.6.2.6. COMMENT ON VIEW](#comment-on-view)
    - [3.6.3. The CREATE statement](#create-statement)
      - [3.6.3.1. CREATE DATABASE](#create-database-statement)
      - [3.6.3.2. CREATE DOMAIN](#create-domain-statement)
      - [3.6.3.3. CREATE FUNCTION](#create-function-statement)
        - [3.6.3.3.1. Scalar functions](#create-scalar-function-statement)
        - [3.6.3.3.2. CREATE OR REPLACE FUNCTION](#create-or-replace-function)
        - [3.6.3.3.3. SQL data access characteristics](#create-function-characteristics-sql-data-access)
        - [3.6.3.3.4. DETERMINISTIC characteristic](#create-function-characteristics-deterministic)
        - [3.6.3.3.5. ON NULL INPUT characteristic](#create-function-characteristics-on-null-input)
        - [3.6.3.3.6. COMMENT characteristic](#create-function-characteristics-comment)
      - [3.6.3.4. CREATE INDEX](#create-index-statement)
      - [3.6.3.5. CREATE PROCEDURE](#create-procedure-statement)
        - [3.6.3.5.1. CREATE OR REPLACE PROCEDURE](#create-or-replace-procedure)
        - [3.6.3.5.2. SQL data access characteristics](#create-procedure-characteristics-sql-data-access)
        - [3.6.3.5.3. COMMENT characteristic](#create-procedure-characteristics-comment)
      - [3.6.3.6. CREATE SCHEMA](#create-schema-statement)
      - [3.6.3.7. CREATE SEQUENCE](#create-sequence-statement)
        - [3.6.3.7.1. CREATE SEQUENCE IF NOT EXISTS](#create-sequence-if-not-exists)
        - [3.6.3.7.2. CREATE SEQUENCE .. AS](#create-sequence-as)
        - [3.6.3.7.3. CREATE SEQUENCE .. CACHE](#create-sequence-cache)
        - [3.6.3.7.4. CREATE SEQUENCE .. CYCLE](#create-sequence-cycle)
        - [3.6.3.7.5. CREATE SEQUENCE .. MINVALUE](#create-sequence-minvalue)
        - [3.6.3.7.6. CREATE SEQUENCE .. MAXVALUE](#create-sequence-maxvalue)
        - [3.6.3.7.7. CREATE SEQUENCE .. INCREMENT BY](#create-sequence-increment-by)
        - [3.6.3.7.8. CREATE SEQUENCE .. START WITH](#create-sequence-start-with)
      - [3.6.3.8. CREATE SYNONYM](#create-synonym-statement)
        - [3.6.3.8.1. CREATE OR REPLACE SYNONYM](#create-or-replace-synonym)
      - [3.6.3.9. CREATE TABLE](#create-table-statement)
        - [3.6.3.9.1. Columns](#create-table-columns)
        - [3.6.3.9.2. Nullability](#create-table-nullability)
        - [3.6.3.9.3. Defaults](#create-table-default)
        - [3.6.3.9.4. Identities](#create-table-identity)
        - [3.6.3.9.5. Computed columns](#create-table-computed-columns)
        - [3.6.3.9.6. Primary key](#create-table-primary-key)
        - [3.6.3.9.7. Unique constraints](#create-table-unique)
        - [3.6.3.9.8. Foreign keys](#create-table-foreign-key)
        - [3.6.3.9.9. Check constraints](#create-table-check)
        - [3.6.3.9.10. Constraint enforcement](#create-table-constraint-enforcement)
        - [3.6.3.9.11. Constraint deferrability](#create-table-constraint-deferrability)
        - [3.6.3.9.12. From a SELECT](#create-table-as-select)
        - [3.6.3.9.13. Global temporary tables](#create-table-global-temporary)
        - [3.6.3.9.14. Local temporary tables](#create-table-local-temporary)
      - [3.6.3.10. CREATE TRIGGER](#create-trigger-statement)
        - [3.6.3.10.1. Events](#create-trigger-statement-events)
        - [3.6.3.10.2. REFERENCING clause](#create-trigger-statement-referencing)
        - [3.6.3.10.3. STATEMENT vs ROW triggers](#create-trigger-statement-statement-vs-row)
        - [3.6.3.10.4. WHEN clause](#create-trigger-statement-when)
      - [3.6.3.11. CREATE TYPE .. AS ENUM](#create-type-statement)
      - [3.6.3.12. CREATE TYPE .. AS OBJECT](#create-composite-type-statement)
      - [3.6.3.13. CREATE VIEW](#create-view-statement)
        - [3.6.3.13.1. CREATE OR REPLACE VIEW](#create-or-replace-view)
        - [3.6.3.13.2. WITH CHECK OPTION](#create-view-with-check-option)
        - [3.6.3.13.3. WITH READ ONLY](#create-view-with-read-only)
        - [3.6.3.13.4. MATERIALIZED](#create-materialized-view)
    - [3.6.4. The DROP statement](#drop-statement)
      - [3.6.4.1. DROP DATABASE](#drop-database-statement)
        - [3.6.4.1.1. IF EXISTS](#drop-database-if-exists)
      - [3.6.4.2. DROP DOMAIN](#drop-domain-statement)
        - [3.6.4.2.1. IF EXISTS](#drop-domain-if-exists)
      - [3.6.4.3. DROP FUNCTION](#drop-function-statement)
        - [3.6.4.3.1. IF EXISTS](#drop-function-if-exists)
        - [3.6.4.3.2. DROP FUNCTION with signature](#drop-function-specific-signature)
      - [3.6.4.4. DROP INDEX](#drop-index-statement)
        - [3.6.4.4.1. IF EXISTS](#drop-index-if-exists)
      - [3.6.4.5. DROP PROCEDURE](#drop-procedure-statement)
        - [3.6.4.5.1. IF EXISTS](#drop-procedure-if-exists)
        - [3.6.4.5.2. DROP PROCEDURE with signature](#drop-procedure-specific-signature)
      - [3.6.4.6. DROP SCHEMA](#drop-schema-statement)
        - [3.6.4.6.1. IF EXISTS](#drop-schema-if-exists)
      - [3.6.4.7. DROP SEQUENCE](#drop-sequence-statement)
        - [3.6.4.7.1. IF EXISTS](#drop-sequence-if-exists)
      - [3.6.4.8. DROP SYNONYM](#drop-synonym-statement)
        - [3.6.4.8.1. IF EXISTS](#drop-synonym-if-exists)
      - [3.6.4.9. DROP TABLE](#drop-table-statement)
        - [3.6.4.9.1. CASCADE](#drop-table-cascade)
        - [3.6.4.9.2. IF EXISTS](#drop-table-if-exists)
      - [3.6.4.10. DROP TRIGGER](#drop-trigger-statement)
        - [3.6.4.10.1. IF EXISTS](#drop-trigger-if-exists)
      - [3.6.4.11. DROP TYPE](#drop-type-statement)
        - [3.6.4.11.1. IF EXISTS](#drop-type-if-exists)
      - [3.6.4.12. DROP VIEW](#drop-view-statement)
        - [3.6.4.12.1. CASCADE](#drop-view-cascade)
        - [3.6.4.12.2. IF EXISTS](#drop-view-if-exists)
    - [3.6.5. The GRANT statement](#grant-statement)
    - [3.6.6. The REVOKE statement](#revoke-statement)
    - [3.6.7. The SET statement](#set-statement)
      - [3.6.7.1. SET CATALOG](#set-catalog-statement)
      - [3.6.7.2. SET CONSTRAINTS](#set-constraints-statement)
      - [3.6.7.3. SET SCHEMA](#set-schema-statement)
    - [3.6.8. The TRUNCATE statement](#truncate-statement)
    - [3.6.9. Generating DDL from objects](#generating-ddl)
  - [3.7. Transactional statements](#transactional-statements)
    - [3.7.1. START TRANSACTION statement](#start-transaction-statement)
    - [3.7.2. COMMIT statement](#commit-statement)
    - [3.7.3. ROLLBACK statement](#rollback-statement)
    - [3.7.4. SAVEPOINT statement](#savepoint-statement)
    - [3.7.5. RELEASE SAVEPOINT statement](#release-savepoint-statement)
  - [3.8. Procedural statements](#procedural-statements)
    - [3.8.1. Block statement](#procedural-block)
    - [3.8.2. CALL statement](#procedural-call)
    - [3.8.3. CONTINUE statement](#procedural-continue)
    - [3.8.4. EXECUTE statement](#procedural-execute)
    - [3.8.5. EXIT statement](#procedural-exit)
    - [3.8.6. FOR statement](#procedural-for)
    - [3.8.7. GOTO statement](#procedural-goto)
    - [3.8.8. IF statement](#procedural-if)
    - [3.8.9. Labels](#procedural-label)
    - [3.8.10. LOOP statement](#procedural-loop)
    - [3.8.11. REPEAT statement](#procedural-repeat)
    - [3.8.12. SIGNAL](#procedural-signal)
    - [3.8.13. Variables](#procedural-variables)
    - [3.8.14. WHILE statement](#procedural-while)
  - [3.9. Catalog and schema expressions](#catalog-and-schema-expressions)
  - [3.10. Table expressions](#table-expressions)
    - [3.10.1. Generated Tables](#generated-tables)
    - [3.10.2. Aliased Tables](#aliased-tables)
      - [3.10.2.1. Aliased generated tables](#aliased-generated-tables)
      - [3.10.2.2. Aliased table expressions](#aliased-table-expressions)
      - [3.10.2.3. Aliased joined tables](#aliased-join-tables)
      - [3.10.2.4. Derived column lists](#derived-column-lists)
      - [3.10.2.5. Unnamed derived tables](#unnamed-derived-tables)
      - [3.10.2.6. Client-side aliased tables](#client-side-aliased-tables)
    - [3.10.3. Joined tables](#joined-tables)
      - [3.10.3.1. CROSS JOIN](#join-type-cross)
      - [3.10.3.2. INNER JOIN](#join-type-inner)
      - [3.10.3.3. OUTER JOIN](#join-type-outer)
      - [3.10.3.4. SEMI JOIN](#join-type-semi)
      - [3.10.3.5. ANTI JOIN](#join-type-anti)
      - [3.10.3.6. ON clause](#join-predicate-on)
      - [3.10.3.7. ON KEY clause](#join-predicate-on-key)
      - [3.10.3.8. USING clause](#join-predicate-using)
      - [3.10.3.9. NATURAL clause](#join-predicate-natural)
      - [3.10.3.10. LATERAL](#join-mode-lateral)
      - [3.10.3.11. APPLY](#join-mode-apply)
      - [3.10.3.12. PARTITION BY](#join-mode-partition-by)
      - [3.10.3.13. JOIN hints](#join-hints)
        - [3.10.3.13.1. HASH JOIN](#join-hint-hash)
        - [3.10.3.13.2. LOOP JOIN](#join-hint-loop)
        - [3.10.3.13.3. MERGE JOIN](#join-hint-merge)
    - [3.10.4. The VALUES() table constructor](#values)
    - [3.10.5. Derived tables](#derived-tables)
    - [3.10.6. Inline derived tables](#inline-derived-tables)
    - [3.10.7. Common table expressions (CTE)](#common-table-expressions)
    - [3.10.8. The Oracle PIVOT clause](#pivot-tables)
    - [3.10.9. Relational division](#relational-division)
    - [3.10.10. Array and cursor unnesting](#array-and-cursor-unnesting)
    - [3.10.11. Table-valued functions](#table-valued-functions)
    - [3.10.12. GENERATE_SERIES](#generate-series)
    - [3.10.13. WITH ORDINALITY](#with-ordinality)
    - [3.10.14. JSON_TABLE](#json-table-function)
    - [3.10.15. XMLTABLE](#xml-table-function)
    - [3.10.16. The DUAL table](#dual)
    - [3.10.17. Temporal tables](#temporal-tables)
    - [3.10.18. TABLESAMPLE](#tablesample-tables)
    - [3.10.19. Data change delta tables](#data-change-delta-tables)
  - [3.11. Column expressions](#column-expressions)
    - [3.11.1. Table columns](#table-columns)
      - [3.11.1.1. Generated table columns](#generated-table-columns)
      - [3.11.1.2. Dereferenced table columns](#dereferenced-table-columns)
      - [3.11.1.3. Named table columns](#named-table-columns)
      - [3.11.1.4. System table columns: ROWID](#system-table-columns)
    - [3.11.2. Aliased columns](#aliased-columns)
    - [3.11.3. Cast expressions](#cast-expressions)
    - [3.11.4. Cast expressions (with TRY_CAST)](#try-cast-expressions)
    - [3.11.5. Datatype coercions](#datatype-coercions)
    - [3.11.6. Hidden columns](#hidden-columns)
    - [3.11.7. Redacted columns](#redacted-columns)
    - [3.11.8. Readonly columns](#readonly-columns)
    - [3.11.9. Computed columns](#computed-columns)
    - [3.11.10. Collations](#collations)
    - [3.11.11. Arithmetic expressions](#arithmetic-expressions)
    - [3.11.12. String concatenation](#string-concatenation)
    - [3.11.13. Case sensitivity with strings](#case-sensitivity)
    - [3.11.14. General functions](#general-functions)
      - [3.11.14.1. CHOOSE](#choose-function)
      - [3.11.14.2. COALESCE](#coalesce-function)
      - [3.11.14.3. DECODE](#decode-function)
      - [3.11.14.4. IIF](#iif-function)
      - [3.11.14.5. NULLIF](#nullif-function)
      - [3.11.14.6. NVL](#nvl-function)
      - [3.11.14.7. NVL2](#nvl2-function)
    - [3.11.15. Numeric functions](#numeric-functions)
      - [3.11.15.1. ABS](#abs-function)
      - [3.11.15.2. ACOS](#acos-function)
      - [3.11.15.3. ACOSH](#acosh-function)
      - [3.11.15.4. ACOT](#acot-function)
      - [3.11.15.5. ACOTH](#acoth-function)
      - [3.11.15.6. ASIN](#asin-function)
      - [3.11.15.7. ASINH](#asinh-function)
      - [3.11.15.8. ATAN](#atan-function)
      - [3.11.15.9. ATAN2](#atan2-function)
      - [3.11.15.10. ATANH](#atanh-function)
      - [3.11.15.11. CEIL](#ceil-function)
      - [3.11.15.12. COS](#cos-function)
      - [3.11.15.13. COSH](#cosh-function)
      - [3.11.15.14. COT](#cot-function)
      - [3.11.15.15. COTH](#coth-function)
      - [3.11.15.16. DEG](#deg-function)
      - [3.11.15.17. E](#e-function)
      - [3.11.15.18. EXP](#exp-function)
      - [3.11.15.19. FLOOR](#floor-function)
      - [3.11.15.20. GREATEST](#greatest-function)
      - [3.11.15.21. LEAST](#least-function)
      - [3.11.15.22. LN](#ln-function)
      - [3.11.15.23. LOG](#log-function)
      - [3.11.15.24. LOG10](#log10-function)
      - [3.11.15.25. NEG](#neg-function)
      - [3.11.15.26. PI](#pi-function)
      - [3.11.15.27. POWER](#power-function)
      - [3.11.15.28. RAD](#rad-function)
      - [3.11.15.29. RAND](#rand-function)
      - [3.11.15.30. ROUND](#round-function)
      - [3.11.15.31. SIGN](#sign-function)
      - [3.11.15.32. SIN](#sin-function)
      - [3.11.15.33. SINH](#sinh-function)
      - [3.11.15.34. SQRT](#sqrt-function)
      - [3.11.15.35. SQUARE](#square-function)
      - [3.11.15.36. TAN](#tan-function)
      - [3.11.15.37. TANH](#tanh-function)
      - [3.11.15.38. TRUNC](#trunc-function)
      - [3.11.15.39. WIDTH_BUCKET](#width-bucket-function)
    - [3.11.16. Bitwise functions](#bitwise-functions)
      - [3.11.16.1. BIT_AND](#bit-and-function)
      - [3.11.16.2. BIT_COUNT](#bit-count-function)
      - [3.11.16.3. BIT_GET](#bit-get-function)
      - [3.11.16.4. BIT_NAND](#bit-nand-function)
      - [3.11.16.5. BIT_NOR](#bit-nor-function)
      - [3.11.16.6. BIT_NOT](#bit-not-function)
      - [3.11.16.7. BIT_OR](#bit-or-function)
      - [3.11.16.8. BIT_SET](#bit-set-function)
      - [3.11.16.9. BIT_XNOR](#bit-xnor-function)
      - [3.11.16.10. BIT_XOR](#bit-xor-function)
      - [3.11.16.11. SHL](#bit-shl-function)
      - [3.11.16.12. SHR](#bit-shr-function)
    - [3.11.17. String functions](#string-functions)
      - [3.11.17.1. ASCII](#ascii-function)
      - [3.11.17.2. BIN_TO_UUID](#bin-to-uuid-function)
      - [3.11.17.3. BIT_LENGTH](#bit-length-function)
      - [3.11.17.4. CHR](#chr-function)
      - [3.11.17.5. CONCAT_WS](#concat-ws-function)
      - [3.11.17.6. CONCAT (|| operator)](#concat-function)
      - [3.11.17.7. DIGITS](#digits-function)
      - [3.11.17.8. LEFT](#left-function)
      - [3.11.17.9. LENGTH](#length-function)
      - [3.11.17.10. LOWER](#lower-function)
      - [3.11.17.11. LPAD](#lpad-function)
      - [3.11.17.12. LTRIM](#ltrim-function)
      - [3.11.17.13. MD5](#md5-function)
      - [3.11.17.14. MID](#mid-function)
      - [3.11.17.15. OCTET_LENGTH](#octet-length-function)
      - [3.11.17.16. OVERLAY](#overlay-function)
      - [3.11.17.17. POSITION](#position-function)
      - [3.11.17.18. REGEXP_REPLACE](#regexp-replace-function)
      - [3.11.17.19. REPEAT](#repeat-function)
      - [3.11.17.20. REPLACE](#replace-function)
      - [3.11.17.21. REVERSE](#reverse-function)
      - [3.11.17.22. RIGHT](#right-function)
      - [3.11.17.23. RPAD](#rpad-function)
      - [3.11.17.24. RTRIM](#rtrim-function)
      - [3.11.17.25. SPACE](#space-function)
      - [3.11.17.26. SPLIT_PART](#split-part-function)
      - [3.11.17.27. SUBSTRING](#substring-function)
      - [3.11.17.28. SUBSTRING_INDEX](#substring-index-function)
      - [3.11.17.29. TO_CHAR](#to-char-function)
      - [3.11.17.30. TO_HEX](#to-hex-function)
      - [3.11.17.31. TRANSLATE](#translate-function)
      - [3.11.17.32. TRIM](#trim-function)
      - [3.11.17.33. UPPER](#upper-function)
      - [3.11.17.34. UUID](#uuid-function)
      - [3.11.17.35. UUID_TO_BIN](#uuid-to-bin-function)
    - [3.11.18. Binary functions](#binary-functions)
      - [3.11.18.1. BIT_LENGTH (binary)](#binary-bit-length-function)
      - [3.11.18.2. CONCAT (binary, || operator)](#binary-concat-function)
      - [3.11.18.3. LENGTH (binary)](#binary-length-function)
      - [3.11.18.4. LTRIM (binary)](#binary-ltrim-function)
      - [3.11.18.5. MD5 (binary)](#binary-md5-function)
      - [3.11.18.6. OCTET_LENGTH (binary)](#binary-octet-length-function)
      - [3.11.18.7. OVERLAY (binary)](#binary-overlay-function)
      - [3.11.18.8. POSITION (binary)](#binary-position-function)
      - [3.11.18.9. RTRIM (binary)](#binary-rtrim-function)
      - [3.11.18.10. SUBSTRING (binary)](#binary-substring-function)
      - [3.11.18.11. TRIM (binary)](#binary-trim-function)
    - [3.11.19. Datetime functions](#datetime-functions)
      - [3.11.19.1. CENTURY](#century-function)
      - [3.11.19.2. CURRENT_DATE](#current-date-function)
      - [3.11.19.3. CURRENT_LOCALDATE](#current-localdate-function)
      - [3.11.19.4. CURRENT_LOCALDATETIME](#current-localdatetime-function)
      - [3.11.19.5. CURRENT_LOCALTIME](#current-localtime-function)
      - [3.11.19.6. CURRENT_OFFSETDATETIME](#current-offsetdatetime-function)
      - [3.11.19.7. CURRENT_OFFSETTIME](#current-offsettime-function)
      - [3.11.19.8. CURRENT_TIME](#current-time-function)
      - [3.11.19.9. CURRENT_TIMESTAMP](#current-timestamp-function)
      - [3.11.19.10. DATE](#date-function)
      - [3.11.19.11. DATEADD](#dateadd-function)
      - [3.11.19.12. DATEDIFF](#datediff-function)
      - [3.11.19.13. DATESUB](#datesub-function)
      - [3.11.19.14. DAY](#day-function)
      - [3.11.19.15. DAY_OF_YEAR](#day-of-year-function)
      - [3.11.19.16. DECADE](#decade-function)
      - [3.11.19.17. EPOCH](#epoch-function)
      - [3.11.19.18. EXTRACT](#extract-function)
      - [3.11.19.19. HOUR](#hour-function)
      - [3.11.19.20. ISO_DAY_OF_WEEK](#iso-day-of-week-function)
      - [3.11.19.21. LOCALDATE](#localdate-function)
      - [3.11.19.22. LOCALDATEADD](#localdateadd-function)
      - [3.11.19.23. LOCALDATESUB](#localdatesub-function)
      - [3.11.19.24. LOCALDATETIME](#localdatetime-function)
      - [3.11.19.25. LOCALDATETIMEADD](#localdatetimeadd-function)
      - [3.11.19.26. LOCALDATETIMESUB](#localdatetimesub-function)
      - [3.11.19.27. LOCALTIME](#localtime-function)
      - [3.11.19.28. MILLENNIUM](#millennium-function)
      - [3.11.19.29. MINUTE](#minute-function)
      - [3.11.19.30. MONTH](#month-function)
      - [3.11.19.31. QUARTER](#quarter-function)
      - [3.11.19.32. SECOND](#second-function)
      - [3.11.19.33. TIME](#time-function)
      - [3.11.19.34. TIMESTAMP](#timestamp-function)
      - [3.11.19.35. TIMESTAMPADD](#timestampadd-function)
      - [3.11.19.36. TIMESTAMPSUB](#timestampsub-function)
      - [3.11.19.37. TO_DATE](#to-date-function)
      - [3.11.19.38. TO_LOCALDATE](#to-localdate-function)
      - [3.11.19.39. TO_LOCALDATETIME](#to-localdatetime-function)
      - [3.11.19.40. TO_TIMESTAMP](#to-timestamp-function)
      - [3.11.19.41. TRUNC](#date-trunc-function)
      - [3.11.19.42. YEAR](#year-function)
    - [3.11.20. ARRAY functions](#array-functions)
      - [3.11.20.1. ARRAY_ALL_MATCH](#array-all-match-function)
      - [3.11.20.2. ARRAY_ANY_MATCH](#array-any-match-function)
      - [3.11.20.3. ARRAY_APPEND (|| operator)](#array-append-function)
      - [3.11.20.4. ARRAY_CONCAT (|| operator)](#array-concat-function)
      - [3.11.20.5. ARRAY_CONTAINS](#array-contains-function)
      - [3.11.20.6. ARRAY_FILTER](#array-filter-function)
      - [3.11.20.7. ARRAY_GET](#array-get-function)
      - [3.11.20.8. ARRAY_MAP](#array-map-function)
      - [3.11.20.9. ARRAY_NONE_MATCH](#array-none-match-function)
      - [3.11.20.10. ARRAY_OVERLAP](#array-overlap-function)
      - [3.11.20.11. ARRAY_PREPEND (|| operator)](#array-prepend-function)
      - [3.11.20.12. ARRAY_REMOVE](#array-remove-function)
      - [3.11.20.13. ARRAY_REPLACE](#array-replace-function)
      - [3.11.20.14. ARRAY_REVERSE](#array-reverse-function)
      - [3.11.20.15. ARRAY constructor](#array-constructor)
      - [3.11.20.16. ARRAY constructor from subquery](#array-constructor-subquery)
      - [3.11.20.17. CARDINALITY](#cardinality-function)
    - [3.11.21. JSON functions](#json-functions)
      - [3.11.21.1. JSON_ARRAY](#json-array-function)
        - [3.11.21.1.1. ABSENT ON NULL](#json-array-function-absent-on-null)
        - [3.11.21.1.2. NULL ON NULL](#json-array-function-null-on-null)
      - [3.11.21.2. JSON_ARRAY_LENGTH](#json-array-length-function)
      - [3.11.21.3. JSON_ARRAY from query](#json-array-query-function)
        - [3.11.21.3.1. ABSENT ON NULL](#json-array-query-function-absent-on-null)
        - [3.11.21.3.2. NULL ON NULL](#json-array-query-function-null-on-null)
      - [3.11.21.4. JSON_GET_ATTRIBUTE](#json-attribute-access)
      - [3.11.21.5. JSON_GET_ATTRIBUTE_AS_TEXT](#json-attribute-access-as-text)
      - [3.11.21.6. JSON_GET_ELEMENT](#json-element-access)
      - [3.11.21.7. JSON_GET_ELEMENT_AS_TEXT](#json-element-access-as-text)
      - [3.11.21.8. JSON_INSERT](#json-insert-function)
      - [3.11.21.9. JSON_KEY_EXISTS](#json-key-exists-function)
      - [3.11.21.10. JSON_KEYS](#json-keys-function)
      - [3.11.21.11. JSON_OBJECT](#json-object-function)
        - [3.11.21.11.1. ABSENT ON NULL](#json-object-function-absent-on-null)
        - [3.11.21.11.2. NULL ON NULL](#json-object-function-null-on-null)
      - [3.11.21.12. JSON_QUERY](#json-query-function)
      - [3.11.21.13. JSON_REMOVE](#json-remove-function)
      - [3.11.21.14. JSON_REPLACE](#json-replace-function)
      - [3.11.21.15. JSON_SET](#json-set-function)
      - [3.11.21.16. JSON_VALUE](#json-value-function)
    - [3.11.22. XML functions](#xml-functions)
      - [3.11.22.1. XMLATTRIBUTES](#xml-attributes-function)
      - [3.11.22.2. XMLCOMMENT](#xml-comment-function)
      - [3.11.22.3. XMLCONCAT](#xml-concat-function)
      - [3.11.22.4. XMLDOCUMENT](#xml-document-function)
      - [3.11.22.5. XMLELEMENT](#xml-element-function)
      - [3.11.22.6. XMLFOREST](#xml-forest-function)
      - [3.11.22.7. XMLPARSE](#xml-parse-function)
      - [3.11.22.8. XMLPI](#xml-pi-function)
      - [3.11.22.9. XMLQUERY](#xml-query-function)
      - [3.11.22.10. XMLSERIALIZE](#xml-serialize-function)
    - [3.11.23. CONNECT BY functions](#connect-by-functions)
      - [3.11.23.1. CONNECT_BY_ISCYCLE](#connect-by-iscycle-function)
      - [3.11.23.2. CONNECT_BY_ISLEAF](#connect-by-isleaf-function)
      - [3.11.23.3. CONNECT_BY_ROOT](#connect-by-root-operator)
      - [3.11.23.4. LEVEL](#level-function)
      - [3.11.23.5. PRIOR](#prior-operator)
      - [3.11.23.6. SYS_CONNECT_BY_PATH](#sys-connect-by-path-function)
    - [3.11.24. System functions](#system-functions)
      - [3.11.24.1. CURRENT_CATALOG](#current-catalog-function)
      - [3.11.24.2. CURRENT_SCHEMA](#current-schema-function)
      - [3.11.24.3. CURRENT_USER](#current-user-function)
    - [3.11.25. Spatial functions](#spatial-functions)
      - [3.11.25.1. ST_Area](#st-area-function)
      - [3.11.25.2. ST_AsText](#st-astext-function)
      - [3.11.25.3. ST_Boundary](#st-boundary-function)
      - [3.11.25.4. ST_Centroid](#st-centroid-function)
      - [3.11.25.5. ST_Difference](#st-difference-function)
      - [3.11.25.6. ST_Dimension](#st-dimension-function)
      - [3.11.25.7. ST_Distance](#st-distance-function)
      - [3.11.25.8. ST_EndPoint](#st-endpoint-function)
      - [3.11.25.9. ST_ExteriorRing](#st-exteriorring-function)
      - [3.11.25.10. ST_GeometryN](#st-geometryn-function)
      - [3.11.25.11. ST_GeometryType](#st-geometrytype-function)
      - [3.11.25.12. ST_GeomFromText](#st-geomfromtext-function)
      - [3.11.25.13. ST_InteriorRingN](#st-interiorringn-function)
      - [3.11.25.14. ST_Intersection](#st-intersection-function)
      - [3.11.25.15. ST_Length](#st-length-function)
      - [3.11.25.16. ST_NumGeometries](#st-numgeometries-function)
      - [3.11.25.17. ST_NumInteriorRings](#st-numinteriorrings-function)
      - [3.11.25.18. ST_NumPoints](#st-numpoints-function)
      - [3.11.25.19. ST_Perimeter](#st-perimeter-function)
      - [3.11.25.20. ST_PointN](#st-pointn-function)
      - [3.11.25.21. ST_SRID](#st-srid-function)
      - [3.11.25.22. ST_StartPoint](#st-startpoint-function)
      - [3.11.25.23. ST_Transform](#st-transform-function)
      - [3.11.25.24. ST_Union](#st-union-function)
      - [3.11.25.25. ST_X](#st-x-function)
      - [3.11.25.26. ST_XMax](#st-xmax-function)
      - [3.11.25.27. ST_XMin](#st-xmin-function)
      - [3.11.25.28. ST_Y](#st-y-function)
      - [3.11.25.29. ST_YMax](#st-ymax-function)
      - [3.11.25.30. ST_YMin](#st-ymin-function)
      - [3.11.25.31. ST_Z](#st-z-function)
      - [3.11.25.32. ST_ZMax](#st-zmax-function)
      - [3.11.25.33. ST_ZMin](#st-zmin-function)
    - [3.11.26. Aggregate functions](#aggregate-functions)
      - [3.11.26.1. Grouping](#aggregate-grouping)
      - [3.11.26.2. Distinctness](#aggregate-distinct)
      - [3.11.26.3. Filtering](#aggregate-filter)
      - [3.11.26.4. Ordering](#aggregate-order-by)
      - [3.11.26.5. Ordering WITHIN GROUP](#aggregate-within-group)
      - [3.11.26.6. Keeping](#aggregate-keep)
      - [3.11.26.7. ANY_VALUE](#any-value-function)
      - [3.11.26.8. APPROX_COUNT_DISTINCT](#approx-count-distinct-function)
      - [3.11.26.9. APPROX_PERCENTILE_CONT](#approx-percentile-cont-function)
      - [3.11.26.10. APPROX_PERCENTILE_DISC](#approx-percentile-disc-function)
      - [3.11.26.11. ARRAY_AGG](#array-agg-function)
      - [3.11.26.12. AVG](#avg-function)
      - [3.11.26.13. LISTAGG (binary)](#binary-listagg-function)
      - [3.11.26.14. BIT_AND_AGG](#bit-and-agg-function)
      - [3.11.26.15. BIT_NAND_AGG](#bit-nand-agg-function)
      - [3.11.26.16. BIT_NOR_AGG](#bit-nor-agg-function)
      - [3.11.26.17. BIT_OR_AGG](#bit-or-agg-function)
      - [3.11.26.18. BIT_XOR_AGG](#bit-xor-agg-function)
      - [3.11.26.19. BIT_XNOR_AGG](#bit-xnor-agg-function)
      - [3.11.26.20. BOOL_AND](#bool-and-function)
      - [3.11.26.21. BOOL_OR](#bool-or-function)
      - [3.11.26.22. COLLECT](#collect-function)
      - [3.11.26.23. COUNT](#count-function)
      - [3.11.26.24. CUME_DIST](#cume-dist-function)
      - [3.11.26.25. DENSE_RANK](#dense-rank-function)
      - [3.11.26.26. EVERY](#every-function)
      - [3.11.26.27. GROUP_CONCAT](#group-concat-function)
      - [3.11.26.28. JSON_ARRAYAGG](#json-arrayagg-function)
        - [3.11.26.28.1. ABSENT ON NULL](#json-arrayagg-function-absent-on-null)
        - [3.11.26.28.2. NULL ON NULL](#json-arrayagg-function-null-on-null)
      - [3.11.26.29. JSON_OBJECTAGG](#json-objectagg-function)
        - [3.11.26.29.1. ABSENT ON NULL](#json-objectagg-function-absent-on-null)
        - [3.11.26.29.2. NULL ON NULL](#json-objectagg-function-null-on-null)
      - [3.11.26.30. LISTAGG](#listagg-function)
      - [3.11.26.31. MAX](#max-function)
      - [3.11.26.32. MAX_BY](#max-by-function)
      - [3.11.26.33. MEDIAN](#median-function)
      - [3.11.26.34. MIN](#min-function)
      - [3.11.26.35. MIN_BY](#min-by-function)
      - [3.11.26.36. MODE (ordered)](#mode-function)
      - [3.11.26.37. MODE (unordered)](#mode-function-unordered)
      - [3.11.26.38. MULTISET_AGG](#multiset-agg-function)
      - [3.11.26.39. PERCENT_RANK](#percent-rank-function)
      - [3.11.26.40. PERCENTILE_CONT](#percentile-cont-function)
      - [3.11.26.41. PERCENTILE_DISC](#percentile-disc-function)
      - [3.11.26.42. PRODUCT](#product-function)
      - [3.11.26.43. RANK](#rank-function)
      - [3.11.26.44. SUM](#sum-function)
      - [3.11.26.45. XMLAGG](#xml-agg-function)
    - [3.11.27. Window functions](#window-functions)
      - [3.11.27.1. PARTITION BY](#window-partition)
      - [3.11.27.2. ORDER BY](#window-order)
      - [3.11.27.3. ROWS, RANGE, GROUPS (frame clause)](#window-frame)
      - [3.11.27.4. EXCLUDE](#window-exclude)
      - [3.11.27.5. NULL treatment](#window-nulls)
      - [3.11.27.6. FROM FIRST, FROM LAST](#window-first-last)
      - [3.11.27.7. Nested aggregate functions](#window-nested-aggregate)
      - [3.11.27.8. Window aggregation](#window-aggregate)
      - [3.11.27.9. Window ordered aggregate](#window-ordered-aggregate)
      - [3.11.27.10. ROW_NUMBER](#window-row-number)
      - [3.11.27.11. RANK](#window-rank)
      - [3.11.27.12. DENSE_RANK](#window-dense-rank)
      - [3.11.27.13. PERCENT_RANK](#window-percent-rank)
      - [3.11.27.14. CUME_DIST](#window-cume-dist)
      - [3.11.27.15. IS_FIRST](#window-is-first)
      - [3.11.27.16. NTILE](#window-ntile)
      - [3.11.27.17. LEAD](#window-lead)
      - [3.11.27.18. LAG](#window-lag)
      - [3.11.27.19. FIRST_VALUE](#window-first-value)
      - [3.11.27.20. LAST_VALUE](#window-last-value)
      - [3.11.27.21. NTH_VALUE](#window-nth-value)
      - [3.11.27.22. RATIO_TO_REPORT](#window-ratio-to-report)
    - [3.11.28. User-defined functions](#user-defined-functions)
    - [3.11.29. User-defined aggregate functions](#user-defined-aggregate-functions)
    - [3.11.30. User-defined type constructor expressions](#user-defined-type-constructor-expressions)
    - [3.11.31. User-defined type attribute paths](#user-defined-type-attribute-paths)
    - [3.11.32. The CASE expression](#case-expressions)
    - [3.11.33. Sequences and serials](#sequences-and-serials)
    - [3.11.34. Scalar subqueries](#scalar-subqueries)
    - [3.11.35. ARRAY value constructor](#array-value-constructor)
    - [3.11.36. MULTISET value constructor](#multiset-value-constructor)
    - [3.11.37. Tuples or row value expressions](#row-value-expressions)
    - [3.11.38. Nested records](#nested-records)
  - [3.12. Conditional expressions](#conditional-expressions)
    - [3.12.1. Condition building](#condition-building)
    - [3.12.2. TRUE and FALSE condition](#true-false-no-condition)
    - [3.12.3. BOOLEAN columns](#boolean-column)
    - [3.12.4. AND, OR, NOT boolean operators](#boolean-operators)
    - [3.12.5. Boolean operator precedence](#boolean-operator-precedence)
    - [3.12.6. XOR boolean operator](#xor-operator)
    - [3.12.7. Comparison predicate](#comparison-predicate)
    - [3.12.8. Comparison predicate (degree > 1)](#comparison-predicate-degree-n)
    - [3.12.9. Quantified comparison predicate](#quantified-comparison-predicate)
    - [3.12.10. BETWEEN predicate](#between-predicate)
    - [3.12.11. BETWEEN predicate (degree > 1)](#between-predicate-degree-n)
    - [3.12.12. DISTINCT predicate](#distinct-predicate)
    - [3.12.13. DISTINCT predicate (degree > 1)](#distinct-predicate-degree-n)
    - [3.12.14. DOCUMENT predicate](#document-predicate)
    - [3.12.15. EXISTS predicate](#exists-predicate)
    - [3.12.16. IN predicate](#in-predicate)
    - [3.12.17. IN predicate (degree > 1)](#in-predicate-degree-n)
    - [3.12.18. JSON predicate](#json-predicate)
    - [3.12.19. JSON_EXISTS predicate](#json-exists-predicate)
    - [3.12.20. LIKE predicate](#like-predicate)
    - [3.12.21. LIKE IGNORE CASE predicate](#like-ignore-case-predicate)
    - [3.12.22. LIKE predicate (binary)](#binary-like-predicate)
    - [3.12.23. LIKE REGEX predicate](#like-regex-predicate)
    - [3.12.24. Quantified LIKE predicate](#quantified-like-predicate)
    - [3.12.25. Quantified LIKE predicate (binary)](#quantified-binary-like-predicate)
    - [3.12.26. STARTS_WITH predicate](#starts-with-predicate)
    - [3.12.27. STARTS_WITH IGNORE CASE predicate](#starts-with-ignore-case-predicate)
    - [3.12.28. ENDS_WITH predicate](#ends-with-predicate)
    - [3.12.29. ENDS_WITH IGNORE CASE predicate](#ends-with-ignore-case-predicate)
    - [3.12.30. CONTAINS predicate](#contains-predicate)
    - [3.12.31. CONTAINS IGNORE CASE predicate](#contains-ignore-case-predicate)
    - [3.12.32. NULL predicate](#null-predicate)
    - [3.12.33. NULL predicate (degree > 1)](#null-predicate-degree-n)
    - [3.12.34. OVERLAPS predicate](#overlaps-predicate)
    - [3.12.35. SIMILAR TO predicate](#similar-predicate)
    - [3.12.36. Spatial predicates](#spatial-predicates)
      - [3.12.36.1. ST_Contains](#st-contains-predicate)
      - [3.12.36.2. ST_Crosses](#st-crosses-predicate)
      - [3.12.36.3. ST_Disjoint](#st-disjoint-predicate)
      - [3.12.36.4. ST_Equals](#st-equals-predicate)
      - [3.12.36.5. ST_Intersects](#st-intersects-predicate)
      - [3.12.36.6. ST_IsClosed](#st-isclosed-predicate)
      - [3.12.36.7. ST_IsEmpty](#st-isempty-predicate)
      - [3.12.36.8. ST_IsRing](#st-isring-predicate)
      - [3.12.36.9. ST_IsSimple](#st-issimple-predicate)
      - [3.12.36.10. ST_IsValid](#st-isvalid-predicate)
      - [3.12.36.11. ST_Overlaps](#st-overlaps-predicate)
      - [3.12.36.12. ST_Touches](#st-touches-predicate)
      - [3.12.36.13. ST_Within](#st-within-predicate)
    - [3.12.37. UNIQUE predicate](#unique-predicate)
    - [3.12.38. XMLEXISTS predicate](#xml-exists-predicate)
    - [3.12.39. Query By Example (QBE)](#query-by-example)
  - [3.13. Operator precedence](#operator-precedence)
  - [3.14. Data types](#data-types)
    - [3.14.1. Flags modifying data types](#data-type-flags)
      - [3.14.1.1. Data type length](#data-type-length)
      - [3.14.1.2. Data type precision](#data-type-precision)
      - [3.14.1.3. Data type scale](#data-type-scale)
    - [3.14.2. Built-in data types](#built-in-data-types)
      - [3.14.2.1. BIGINT (Long)](#data-type-bigint)
      - [3.14.2.2. BIGINT UNSIGNED (ULong)](#data-type-bigint-unsigned)
      - [3.14.2.3. BINARY (byte\[\])](#data-type-binary)
      - [3.14.2.4. BIT (Boolean)](#data-type-bit)
      - [3.14.2.5. BLOB (byte\[\])](#data-type-blob)
      - [3.14.2.6. BOOLEAN (Boolean)](#data-type-boolean)
      - [3.14.2.7. CHAR (String)](#data-type-char)
      - [3.14.2.8. CLOB (String)](#data-type-clob)
      - [3.14.2.9. DATE (Date)](#data-type-date)
      - [3.14.2.10. DECFLOAT (Decfloat)](#data-type-decfloat)
      - [3.14.2.11. DECIMAL (BigDecimal)](#data-type-decimal)
      - [3.14.2.12. DECIMAL INTEGER (BigInteger)](#data-type-decimal-integer)
      - [3.14.2.13. DOUBLE (Double)](#data-type-double)
      - [3.14.2.14. FLOAT (Double)](#data-type-float)
      - [3.14.2.15. GEOGRAPHY (Geography)](#data-type-geography)
      - [3.14.2.16. GEOMETRY (Geometry)](#data-type-geometry)
      - [3.14.2.17. INSTANT (Instant)](#data-type-instant)
      - [3.14.2.18. INTEGER (Integer)](#data-type-integer)
      - [3.14.2.19. INTEGER UNSIGNED (UInteger)](#data-type-integer-unsigned)
      - [3.14.2.20. INTERVAL (YearToSecond)](#data-type-interval)
      - [3.14.2.21. INTERVAL DAY TO SECOND (DayToSecond)](#data-type-interval-day-to-second)
      - [3.14.2.22. INTERVAL YEAR TO MONTH (YearToMonth)](#data-type-interval-year-to-month)
      - [3.14.2.23. JSON (JSON)](#data-type-json)
      - [3.14.2.24. JSONB (JSONB)](#data-type-jsonb)
      - [3.14.2.25. LOCALDATE (LocalDate)](#data-type-localdate)
      - [3.14.2.26. LOCALDATETIME (LocalDateTime)](#data-type-localdatetime)
      - [3.14.2.27. LOCALTIME (LocalTime)](#data-type-localtime)
      - [3.14.2.28. LONGNVARCHAR (String)](#data-type-longnvarchar)
      - [3.14.2.29. LONGVARBINARY (byte\[\])](#data-type-longvarbinary)
      - [3.14.2.30. LONGVARCHAR (String)](#data-type-longvarchar)
      - [3.14.2.31. NCHAR (String)](#data-type-nchar)
      - [3.14.2.32. NCLOB (String)](#data-type-nclob)
      - [3.14.2.33. NUMERIC (BigDecimal)](#data-type-numeric)
      - [3.14.2.34. NVARCHAR (String)](#data-type-nvarchar)
      - [3.14.2.35. OFFSETDATETIME (OffsetDateTime)](#data-type-offsetdatetime)
      - [3.14.2.36. OFFSETTIME (OffsetTime)](#data-type-offsettime)
      - [3.14.2.37. OTHER (Object)](#data-type-other)
      - [3.14.2.38. REAL (Float)](#data-type-real)
      - [3.14.2.39. RECORD (Record)](#data-type-record)
      - [3.14.2.40. RESULT (Result)](#data-type-result)
      - [3.14.2.41. ROWID (RowId)](#data-type-rowid)
      - [3.14.2.42. SMALLINT (Short)](#data-type-smallint)
      - [3.14.2.43. SMALLINT UNSIGNED (UShort)](#data-type-smallint-unsigned)
      - [3.14.2.44. TIME (Time)](#data-type-time)
      - [3.14.2.45. TIMESTAMP (Timestamp)](#data-type-timestamp)
      - [3.14.2.46. TIMESTAMP WITH TIME ZONE (OffsetDateTime)](#data-type-timestampwithtimezone)
      - [3.14.2.47. TIME WITH TIME ZONE (OffsetTime)](#data-type-timewithtimezone)
      - [3.14.2.48. TINYINT (Byte)](#data-type-tinyint)
      - [3.14.2.49. TINYINT UNSIGNED (UByte)](#data-type-tinyint-unsigned)
      - [3.14.2.50. UUID (UUID)](#data-type-uuid)
      - [3.14.2.51. VARBINARY (byte\[\])](#data-type-varbinary)
      - [3.14.2.52. VARCHAR (String)](#data-type-varchar)
      - [3.14.2.53. XML (XML)](#data-type-xml)
      - [3.14.2.54. YEAR (Year)](#data-type-year)
    - [3.14.3. Extended data types](#extended-data-types)
      - [3.14.3.1. PostgreSQL CIDR type](#extended-type-pg-cidr)
      - [3.14.3.2. PostgreSQL CITEXT type](#extended-type-pg-citext)
      - [3.14.3.3. PostgreSQL DATERANGE type](#extended-type-pg-daterange)
      - [3.14.3.4. PostgreSQL HSTORE type](#extended-type-pg-hstore)
      - [3.14.3.5. PostgreSQL INET type](#extended-type-pg-inet)
      - [3.14.3.6. PostgreSQL INT4RANGE type](#extended-type-pg-int4range)
      - [3.14.3.7. PostgreSQL INT8RANGE type](#extended-type-pg-int8range)
      - [3.14.3.8. PostgreSQL LTREE type](#extended-type-pg-ltree)
      - [3.14.3.9. PostgreSQL NUMRANGE type](#extended-type-pg-numrange)
      - [3.14.3.10. PostgreSQL TSRANGE type](#extended-type-pg-tsrange)
      - [3.14.3.11. PostgreSQL TSTZRANGE type](#extended-type-pg-tstzrange)
    - [3.14.4. Enum data types](#enum-data-types)
    - [3.14.5. Domain data types](#domain-data-types)
    - [3.14.6. User-defined data types (UDTs)](#user-defined-data-types)
    - [3.14.7. Converted data types](#converted-data-types)
      - [3.14.7.1. Custom data type Converter](#data-type-converter)
      - [3.14.7.2. Custom data type Binding](#data-type-binding)
      - [3.14.7.3. Custom data type Formatter](#data-type-formatter)
  - [3.15. Synthetic SQL clauses](#synthetic-sql-clauses)
  - [3.16. Dynamic SQL](#dynamic-sql)
    - [3.16.1. Optional column expressions](#no-field)
    - [3.16.2. Optional conditional expressions](#no-condition)
    - [3.16.3. Optional tables](#no-table)
    - [3.16.4. Optional join paths](#no-path)
    - [3.16.5. Optional JSON entry expressions](#no-json-entry)
  - [3.17. Plain SQL](#plain-sql)
    - [3.17.1. Plain SQL API](#plain-sql-api)
    - [3.17.2. Plain SQL templating language](#plain-sql-templating-language)
    - [3.17.3. Plain SQL raw templates](#plain-sql-raw-templates)
  - [3.18. Hints](#hints)
    - [3.18.1. MySQL hints](#hints-mysql)
      - [3.18.1.1. Index hints](#hints-mysql-index)
      - [3.18.1.2. STRAIGHT_JOIN](#hints-mysql-join)
      - [3.18.1.3. Oracle style hints in MySQL](#hints-mysql-oracle)
    - [3.18.2. Oracle hints](#hints-oracle)
    - [3.18.3. SQL Server hints](#hints-sql-server)
      - [3.18.3.1. WITH](#hints-sql-server-table)
      - [3.18.3.2. OPTION](#hints-sql-server-option)
  - [3.19. SQL Parser](#sql-parser)
    - [3.19.1. SQL Parser API](#sql-parser-api)
    - [3.19.2. SQL Parser CLI](#sql-parser-cli)
    - [3.19.3. SQL Parser Listener](#sql-parser-listener)
    - [3.19.4. SQL translator](#sql-parser-translator)
    - [3.19.5. SQL Parser Grammar](#sql-parser-grammar)
  - [3.20. SQL interpreter](#sql-interpreter)
  - [3.21. Schema diff](#schema-diff)
  - [3.22. Schema diff CLI](#schema-diff-cli)
  - [3.23. Names and identifiers](#names)
  - [3.24. Bind values and parameters](#bind-values)
    - [3.24.1. Indexed parameters](#indexed-parameters)
    - [3.24.2. Named parameters](#named-parameters)
    - [3.24.3. Inlined parameters](#inlined-parameters)
    - [3.24.4. SQL injection](#sql-injection)
  - [3.25. QueryParts](#queryparts)
    - [3.25.1. SQL rendering](#sql-rendering)
    - [3.25.2. Declaration vs reference](#declaration-vs-reference)
    - [3.25.3. Pretty printing SQL](#pretty-printing)
    - [3.25.4. Variable binding](#variable-binding)
    - [3.25.5. Custom syntax elements](#custom-queryparts)
    - [3.25.6. Plain SQL QueryParts](#plain-sql-queryparts)
    - [3.25.7. Serializability](#serializability)
    - [3.25.8. SQL transformation](#sql-transformation)
      - [3.25.8.1. ANSI JOIN to table lists](#ansi-join-to-table-lists)
      - [3.25.8.2. Table lists to ANSI JOIN](#table-lists-to-ansi-join)
      - [3.25.8.3. ROWNUM to LIMIT](#transform-rownum)
      - [3.25.8.4. QUALIFY to derived table](#transform-qualify)
      - [3.25.8.5. IN condition subquery with LIMIT to derived table](#transform-in-with-limit-to-derived-table)
      - [3.25.8.6. GROUP BY <column index>](#transform-group-by-column-index)
      - [3.25.8.7. Inline CTE](#transform-inline-cte)
      - [3.25.8.8. Unnecessary arithmetic expressions](#transform-unnecessary-arithmetic)
      - [3.25.8.9. Pattern based transformation](#transform-patterns)
        - [3.25.8.9.1. AND to NOT IN](#transform-patterns-and-ne-to-not-in)
        - [3.25.8.9.2. Arithmetic comparisons](#transform-patterns-arithmetic-comparisons)
        - [3.25.8.9.3. Arithmetic expressions](#transform-patterns-arithmetic-expressions)
        - [3.25.8.9.4. BIT_GET function](#transform-patterns-bit-get)
        - [3.25.8.9.5. BIT_SET function](#transform-patterns-bit-set)
        - [3.25.8.9.6. CASE searched to CASE simple](#transform-patterns-case-searched-to-simple)
        - [3.25.8.9.7. CASE to CASE abbreviation](#transform-patterns-case-to-case-abbreviation)
        - [3.25.8.9.8. CASE with DISTINCT FROM to DECODE](#transform-patterns-case-distinct-to-decode)
        - [3.25.8.9.9. CASE with ELSE NULL](#transform-patterns-case-else-null)
        - [3.25.8.9.10. COUNT(*) scalar subquery comparison](#transform-patterns-scalar-subquery-count-asterisk-gt-zero)
        - [3.25.8.9.11. COUNT(const)](#transform-patterns-count-constant)
        - [3.25.8.9.12. COUNT(DISTINCT ..) with redundant args](#transform-patterns-count-distinct-multiple-redundant)
        - [3.25.8.9.13. COUNT(expr) scalar subquery comparison](#transform-patterns-scalar-subquery-count-expression-gt-zero)
        - [3.25.8.9.14. DISTINCT FROM NULL](#transform-patterns-distinct-from-null)
        - [3.25.8.9.15. Empty scalar subquery](#transform-patterns-empty-scalar-subquery)
        - [3.25.8.9.16. Flatten CASE](#transform-patterns-flatten-case)
        - [3.25.8.9.17. Flatten CASE abbreviations](#transform-patterns-flatten-case-abbreviation)
        - [3.25.8.9.18. Flatten DECODE](#transform-patterns-flatten-decode)
        - [3.25.8.9.19. Hyperbolic functions](#transform-patterns-hyperbolic-functions)
        - [3.25.8.9.20. Idempotent function repetition](#transform-patterns-idempotent-function-repetition)
        - [3.25.8.9.21. Inverse hyperbolic functions](#transform-patterns-inverse-hyperbolic-functions)
        - [3.25.8.9.22. Logarithmic functions](#transform-patterns-logarithmic-functions)
        - [3.25.8.9.23. Merge AND predicates](#transform-patterns-merge-and-comparison)
        - [3.25.8.9.24. Merge BIT_NOT with BIT_NAND](#transform-patterns-merge-bit-not-bit-nand)
        - [3.25.8.9.25. Merge BIT_NOT with BIT_NOR](#transform-patterns-merge-bit-not-bit-nor)
        - [3.25.8.9.26. Merge BIT_NOT with BIT_XNOR](#transform-patterns-merge-bit-not-bit-xnor)
        - [3.25.8.9.27. Merge CASE .. WHEN and ELSE clauses](#transform-patterns-case-merge-when-else)
        - [3.25.8.9.28. Merge CASE .. WHEN clauses](#transform-patterns-case-merge-when-when)
        - [3.25.8.9.29. Merge IN predicates](#transform-patterns-merge-in-predicates)
        - [3.25.8.9.30. Merge NOT with comparison predicates](#transform-patterns-merge-not-comparison)
        - [3.25.8.9.31. Merge NOT with DISTINCT predicate](#transform-patterns-merge-not-not-distinct)
        - [3.25.8.9.32. Merge OR predicates](#transform-patterns-merge-or-comparison)
        - [3.25.8.9.33. Merge range predicates](#transform-patterns-merge-range-predicates)
        - [3.25.8.9.34. Normalise associative operations](#transform-patterns-normalise-associative-ops)
        - [3.25.8.9.35. Normalise fields compared to values](#transform-patterns-normalise-field-compare-value)
        - [3.25.8.9.36. Normalise IN list with single element to comparison](#transform-patterns-in-list-single-element-to-comparison)
        - [3.25.8.9.37. NOT AND](#transform-patterns-not-and)
        - [3.25.8.9.38. NOT OR](#transform-patterns-not-or)
        - [3.25.8.9.39. NULL ON NULL INPUT](#transform-patterns-null-on-null-input)
        - [3.25.8.9.40. OR to IN](#transform-patterns-or-eq-to-in)
        - [3.25.8.9.41. Repeated arithmetic negation](#transform-patterns-neg-neg)
        - [3.25.8.9.42. Repeated bitwise negation](#transform-patterns-bit-not-bit-not)
        - [3.25.8.9.43. Repeated NOT](#transform-patterns-not-not)
        - [3.25.8.9.44. Simplify CASE abbreviations](#transform-patterns-simplify-case-abbreviation)
        - [3.25.8.9.45. Trigonometric functions](#transform-patterns-trigonometric-functions)
        - [3.25.8.9.46. Trim](#transform-patterns-trim)
        - [3.25.8.9.47. Trivial bitwise operations](#transform-patterns-trivial-bitwise-operations)
        - [3.25.8.9.48. Trivial CASE abbreviations](#transform-patterns-trivial-case-abbreviations)
        - [3.25.8.9.49. Trivial predicates](#transform-patterns-trivial-predicates)
        - [3.25.8.9.50. Unnecessary DISTINCT](#transform-patterns-unnecessary-distinct)
        - [3.25.8.9.51. Unnecessary EXISTS subquery clauses](#transform-patterns-unnecessary-exists-subquery-clauses)
        - [3.25.8.9.52. Unnecessary GROUP BY expressions](#transform-patterns-unnecessary-group-by-expressions)
        - [3.25.8.9.53. Unnecessary INNER JOIN](#transform-patterns-unnecessary-inner-join)
        - [3.25.8.9.54. Unnecessary ORDER BY expressions](#transform-patterns-unnecessary-order-by-expressions)
        - [3.25.8.9.55. Unnecessary scalar subquery](#transform-patterns-unnecessary-scalar-subquery)
        - [3.25.8.9.56. Unreachable CASE clauses](#transform-patterns-unreachable-case-clauses)
        - [3.25.8.9.57. Unreachable DECODE clauses](#transform-patterns-unreachable-decode-clauses)
    - [3.25.9. Custom SQL transformation with VisitListener](#custom-sql-transformation)
      - [3.25.9.1. Example: Logging abbreviated bind values](#transformation-bind-value-abbreviation)
    - [3.25.10. Policies](#policies)
      - [3.25.10.1. Configuration](#policies-configuration)
      - [3.25.10.2. Implementation](#policies-implementation)
      - [3.25.10.3. Inheritance](#policies-inheritance)
      - [3.25.10.4. Security considerations](#policies-security)
  - [3.26. Zero-based vs one-based APIs](#zero-based-vs-one-based)
  - [3.27. SQL building in Kotlin](#kotlin-sql-building)
    - [3.27.1. Kotlin MULTISET Collectors](#kotlin-multiset-collectors)
    - [3.27.2. Kotlin ResultQuery Collectors](#kotlin-resultquery-collectors)
    - [3.27.3. Kotlin BOOLEAN value expressions](#kotlin-boolean-fields)
    - [3.27.4. Kotlin ARRAY access](#kotlin-array-access)
    - [3.27.5. Kotlin JSON access](#kotlin-json-access)
    - [3.27.6. Kotlin coroutine support](#kotlin-coroutines)
  - [3.28. SQL building in Scala](#scala-sql-building)
  - [3.29. Compile time validation](#checker-framework)
- [4. SQL execution](#sql-execution)
  - [4.1. Comparison between jOOQ and JDBC](#comparison-with-jdbc)
  - [4.2. Query vs. ResultQuery](#query-vs-resultquery)
  - [4.3. Fetching](#fetching)
    - [4.3.1. Record vs. TableRecord](#record-vs-tablerecord)
    - [4.3.2. Record1 to Record22](#record-n)
    - [4.3.3. Arrays, Maps and Lists](#arrays-maps-and-lists)
    - [4.3.4. ResultQuery as Iterable](#iterable-fetching)
    - [4.3.5. RecordMapper](#recordmapper)
    - [4.3.6. POJOs](#pojos)
    - [4.3.7. RecordMapperProvider](#recordmapperprovider)
    - [4.3.8. Ad-hoc Converter](#ad-hoc-converter)
    - [4.3.9. ConverterProvider](#converter-provider)
    - [4.3.10. Lazy fetching](#lazy-fetching)
    - [4.3.11. Lazy fetching with Streams](#lazy-fetching-with-streams)
    - [4.3.12. Many fetching](#many-fetching)
    - [4.3.13. Later fetching](#later-fetching)
    - [4.3.14. Reactive Fetching](#reactive-fetching)
    - [4.3.15. ResultSet fetching](#resultset-fetching)
    - [4.3.16. Auto data type conversion](#auto-type-conversion)
    - [4.3.17. Custom data type conversion](#data-type-conversion)
    - [4.3.18. Data type lookups](#data-type-lookups)
    - [4.3.19. Context Converter](#context-converter)
  - [4.4. Static statements vs. Prepared Statements](#statement-type)
  - [4.5. Reusing a Query's PreparedStatement](#reusing-statements)
  - [4.6. JDBC flags](#jdbc-flags)
  - [4.7. Using JDBC batch operations](#batch-execution)
  - [4.8. Sequence execution](#sequence-execution)
  - [4.9. Stored procedures and functions](#stored-procedures)
    - [4.9.1. Oracle Packages](#oracle-packages)
    - [4.9.2. Oracle member procedures](#oracle-member-procedures)
  - [4.10. Exporting to XML, CSV, JSON, HTML, Text, Charts](#exporting)
    - [4.10.1. Exporting XML](#exporting-xml)
    - [4.10.2. Exporting CSV](#exporting-csv)
    - [4.10.3. Exporting JSON](#exporting-json)
    - [4.10.4. Exporting HTML](#exporting-html)
    - [4.10.5. Exporting Text](#exporting-text)
    - [4.10.6. Exporting Charts](#exporting-charts)
    - [4.10.7. FormattingProvider](#formatting-provider)
  - [4.11. Importing data](#importing)
    - [4.11.1. The Loader API](#importing-api)
    - [4.11.2. Import options](#importing-options)
      - [4.11.2.1. Throttling](#importing-option-throttling)
      - [4.11.2.2. Duplicate handling](#import-option-duplicates)
      - [4.11.2.3. Error handling](#import-option-errors)
    - [4.11.3. Import data sources](#importing-sources)
      - [4.11.3.1. Importing CSV](#importing-source-csv)
      - [4.11.3.2. Importing JSON](#importing-source-json)
      - [4.11.3.3. Importing records](#importing-source-records)
      - [4.11.3.4. Importing arrays](#importing-source-arrays)
      - [4.11.3.5. Importing XML](#importing-source-xml)
    - [4.11.4. Import listeners](#importing-listeners)
    - [4.11.5. Import result and error handling](#importing-results)
  - [4.12. Creating results and records in memory](#in-memory-results)
    - [4.12.1. Creating new results and records](#in-memory-new-result)
    - [4.12.2. Reading CSV](#in-memory-csv)
    - [4.12.3. Reading JSON](#in-memory-json)
    - [4.12.4. Reading XML](#in-memory-xml)
    - [4.12.5. Reading HTML](#in-memory-html)
    - [4.12.6. Reading text](#in-memory-text)
    - [4.12.7. Reading string arrays](#in-memory-string-data)
    - [4.12.8. Working with in-memory results](#in-memory-usage)
  - [4.13. UpdatableRecords](#crud-with-updatablerecords)
    - [4.13.1. Simple CRUD](#simple-crud)
      - [4.13.1.1. CRUD: Store](#crud-store)
      - [4.13.1.2. CRUD: Insert](#crud-insert)
      - [4.13.1.3. CRUD: Update](#crud-update)
      - [4.13.1.4. CRUD: Delete](#crud-delete)
      - [4.13.1.5. CRUD: Merge](#crud-merge)
      - [4.13.1.6. CRUD: Refresh](#crud-refresh)
    - [4.13.2. Record internal flags and dirty tracking](#internal-flags)
    - [4.13.3. IDENTITY values](#identity-values)
    - [4.13.4. Navigation methods](#navigation-methods)
    - [4.13.5. Non-updatable records](#non-updatable-records)
    - [4.13.6. Optimistic locking](#optimistic-locking)
    - [4.13.7. Batch execution](#batch-execution-for-crud)
    - [4.13.8. RecordListener SPI](#crud-record-listener)
  - [4.14. DAOs](#daos)
  - [4.15. Transaction management](#transaction-management)
  - [4.16. Exception handling](#exception-handling)
  - [4.17. ExecuteListeners](#execute-listeners)
  - [4.18. Database meta data](#meta-data)
    - [4.18.1. JDBC meta data](#meta-jdbc)
    - [4.18.2. Interpreted meta data](#meta-interpreter)
    - [4.18.3. XML meta data](#meta-xml)
    - [4.18.4. Generated meta data](#meta-generated)
  - [4.19. JDBC Connection](#jdbc-connection)
  - [4.20. Batched Connection](#batched-connection)
  - [4.21. Mocking Connection](#mocking-connection)
  - [4.22. Mock File Database](#mock-file-database)
  - [4.23. Parsing Connection](#parsing-connection)
  - [4.24. Diagnostics](#diagnostics)
    - [4.24.1. Too Many Rows](#diagnostics-too-many-rows)
    - [4.24.2. Too Many Columns](#diagnostics-too-many-columns)
    - [4.24.3. Duplicate Statements](#diagnostics-duplicate-statements)
    - [4.24.4. Repeated statements](#diagnostics-repeated-statements)
    - [4.24.5. Consecutive aggregation](#diagnostics-consecutive-aggregation)
    - [4.24.6. WasNull calls](#diagnostics-was-null-calls)
    - [4.24.7. Concatenation in predicates](#diagnostics-concatenation-in-predicates)
    - [4.24.8. Possibly wrong expressions](#diagnostics-possibly-wrong-expressions)
    - [4.24.9. Incomplete equi join](#diagnostics-incomplete-equi-join)
    - [4.24.10. Trivial condition](#diagnostics-trivial-condition)
    - [4.24.11. Transform patterns](#diagnostics-transform-patterns)
  - [4.25. Logging with LoggerListener](#logging)
  - [4.26. Logging with SQLExceptionLoggerListener](#logging-sql-exceptions)
  - [4.27. Logging Connection](#logging-connection)
  - [4.28. Logging system properties](#logging-system-properties)
  - [4.29. Performance considerations](#performance-considerations)
  - [4.30. Alternative execution models](#alternative-execution-models)
    - [4.30.1. Using jOOQ with Spring's JdbcTemplate](#using-jooq-with-jdbctemplate)
    - [4.30.2. Using jOOQ with JPA](#using-jooq-with-jpa)
      - [4.30.2.1. Using jOOQ with JPA Native Query](#using-jooq-with-jpa-native)
      - [4.30.2.2. Using jOOQ with JPA entities](#using-jooq-with-jpa-entities)
      - [4.30.2.3. Using jOOQ with JPA EntityResult](#using-jooq-with-jpa-entityresult)
- [5. Code generation](#code-generation)
  - [5.1. Configuration and setup of the generator](#codegen-configuration)
  - [5.2. Advanced generator configuration](#codegen-advanced)
    - [5.2.1. Logging](#codegen-config-logging)
    - [5.2.2. Error handling](#codegen-config-onerror)
    - [5.2.3. Jdbc](#codegen-config-jdbc)
    - [5.2.4. Generator](#codegen-config-generator)
    - [5.2.5. Database](#codegen-config-database)
      - [5.2.5.1. Database name and properties](#codegen-database-name)
      - [5.2.5.2. Inline database implementation](#codegen-database-inline-implementation)
      - [5.2.5.3. RegexFlags](#codegen-database-regex-flags)
      - [5.2.5.4. Includes and Excludes](#codegen-database-includes-excludes)
      - [5.2.5.5. Include object types](#codegen-database-include-object-types)
      - [5.2.5.6. Record Version and Timestamp Fields](#codegen-database-record-version-timestamp-fields)
      - [5.2.5.7. Comments](#codegen-database-comments)
      - [5.2.5.8. Synthetic objects](#codegen-database-synthetic-objects)
        - [5.2.5.8.1. Synthetic columns](#codegen-database-synthetic-columns)
        - [5.2.5.8.2. Synthetic readonly columns](#codegen-database-synthetic-readonly-columns)
        - [5.2.5.8.3. Synthetic readonly ROWIDs](#codegen-database-synthetic-readonly-rowids)
        - [5.2.5.8.4. Synthetic identities](#codegen-database-synthetic-ids)
        - [5.2.5.8.5. Synthetic defaults](#codegen-database-synthetic-defaults)
        - [5.2.5.8.6. Synthetic enums](#codegen-database-synthetic-enums)
        - [5.2.5.8.7. Synthetic primary keys](#codegen-database-synthetic-pks)
        - [5.2.5.8.8. Synthetic unique keys](#codegen-database-synthetic-uks)
        - [5.2.5.8.9. Synthetic foreign keys](#codegen-database-synthetic-fks)
        - [5.2.5.8.10. Synthetic synonyms](#codegen-database-synthetic-synonyms)
      - [5.2.5.9. Date as timestamp](#codegen-database-date-as-timestamp)
      - [5.2.5.10. Ignore procedure return values (deprecated)](#codegen-database-ignore-procedure-return-values)
      - [5.2.5.11. Hidden columns](#codegen-database-hidden-columns)
      - [5.2.5.12. Redacted columns](#codegen-database-redacted-columns)
      - [5.2.5.13. Readonly columns](#codegen-database-readonly-columns)
      - [5.2.5.14. Unsigned types](#codegen-database-unsigned-types)
      - [5.2.5.15. Catalog and schema mapping](#codegen-database-catalog-and-schema-mapping)
      - [5.2.5.16. Catalog and schema version providers](#codegen-database-version-providers)
      - [5.2.5.17. Custom ordering of generated code](#codegen-database-order-provider)
      - [5.2.5.18. Forced types](#codegen-database-forced-types)
        - [5.2.5.18.1. Matching of forced types](#codegen-database-forced-types-matching)
        - [5.2.5.18.2. Data type rewriting](#codegen-database-forced-types-rewrite)
        - [5.2.5.18.3. Qualified converters](#codegen-database-forced-types-converter)
        - [5.2.5.18.4. Inline converters](#codegen-database-forced-types-inline-converter)
        - [5.2.5.18.5. Lambda converters](#codegen-database-forced-types-lambda-converter)
        - [5.2.5.18.6. Auto converters](#codegen-database-forced-types-auto-converter)
        - [5.2.5.18.7. Enum converters](#codegen-database-forced-types-enum-converter)
        - [5.2.5.18.8. Jackson converters](#codegen-database-forced-types-jackson-converter)
        - [5.2.5.18.9. JAXB converters](#codegen-database-forced-types-jaxb-converter)
        - [5.2.5.18.10. Data type bindings](#codegen-database-forced-types-binding)
        - [5.2.5.18.11. Client side computed columns](#codegen-database-forced-types-computed)
        - [5.2.5.18.12. Audit columns](#codegen-database-forced-types-audit)
        - [5.2.5.18.13. Hidden columns](#codegen-database-forced-types-hidden)
        - [5.2.5.18.14. Redacted columns](#codegen-database-forced-types-redacted)
        - [5.2.5.18.15. Visibility Modifier (per forced type)](#codegen-database-forced-types-visibility)
      - [5.2.5.19. Table valued functions](#codegen-database-table-valued-functions)
    - [5.2.6. Generate](#codegen-config-generate)
      - [5.2.6.1. Annotations](#codegen-generate-annotations)
      - [5.2.6.2. Covariant overrides](#codegen-covariant-overrides)
        - [5.2.6.2.1. Overriding as()](#codegen-covariant-overrides-as)
        - [5.2.6.2.2. Overriding rename()](#codegen-covariant-overrides-rename)
        - [5.2.6.2.3. Overriding where()](#codegen-covariant-overrides-where)
      - [5.2.6.3. Default catalog and schema](#codegen-generate-default-catalog-and-schema)
      - [5.2.6.4. Explicit nullability](#codegen-generate-explicit-nullability)
      - [5.2.6.5. Extended types](#codegen-generate-extended-types)
      - [5.2.6.6. Fluent setters](#codegen-generate-fluent-setters)
      - [5.2.6.7. Fully Qualified Types](#codegen-generate-fully-qualified-types)
      - [5.2.6.8. Global Artefacts](#codegen-generate-globals)
      - [5.2.6.9. Global object names](#codegen-generate-global-object-names)
      - [5.2.6.10. Implicit JOIN paths](#codegen-implicit-join-paths)
      - [5.2.6.11. Java Time Types](#codegen-generate-java-time-types)
      - [5.2.6.12. Serial Version UID](#codegen-generate-serial-version-uid)
      - [5.2.6.13. Sources](#codegen-generate-sources)
      - [5.2.6.14. Text blocks](#codegen-textblocks)
      - [5.2.6.15. Visibility Modifier (global)](#codegen-generate-visibility-modifier)
      - [5.2.6.16. Whitespace (newlines and indentation)](#codegen-whitespace)
      - [5.2.6.17. Zero Scale Decimal Types](#codegen-generate-zero-scale-decimals)
    - [5.2.7. Output target configuration](#codegen-config-target)
  - [5.3. Generated object types](#codegen-object-types)
    - [5.3.1. Generated tables](#codegen-tables)
    - [5.3.2. Generated records](#codegen-records)
    - [5.3.3. Generated POJOs](#codegen-pojos)
    - [5.3.4. Generated Interfaces](#codegen-interfaces)
    - [5.3.5. Generated DAOs](#codegen-daos)
    - [5.3.6. Generated sequences](#codegen-sequences)
    - [5.3.7. Generated synonyms](#codegen-synonyms)
    - [5.3.8. Generated procedures](#codegen-procedures)
    - [5.3.9. Generated domains](#codegen-domains)
    - [5.3.10. Generated UDTs](#codegen-udts)
    - [5.3.11. Generated triggers](#codegen-triggers)
    - [5.3.12. Generated global artefacts](#codegen-globals)
  - [5.4. Class names, method names, identifiers](#codegen-object-naming)
    - [5.4.1. Custom generator strategies](#codegen-generatorstrategy)
    - [5.4.2. Matcher strategies](#codegen-matcherstrategy)
      - [5.4.2.1. MatcherRule](#codegen-matcher-rule)
      - [5.4.2.2. Matching catalogs](#codegen-matcher-catalogs)
      - [5.4.2.3. Matching schemas](#codegen-matcher-schemas)
      - [5.4.2.4. Matching tables](#codegen-matcher-tables)
      - [5.4.2.5. Matching fields](#codegen-matcher-fields)
      - [5.4.2.6. Matching indexes](#codegen-matcher-indexes)
      - [5.4.2.7. Matching primary keys](#codegen-matcher-primary-keys)
      - [5.4.2.8. Matching unique keys](#codegen-matcher-unique-keys)
      - [5.4.2.9. Matching foreign keys](#codegen-matcher-foreign-keys)
      - [5.4.2.10. Matching routines](#codegen-matcher-routines)
      - [5.4.2.11. Matching sequences](#codegen-matcher-sequences)
      - [5.4.2.12. Matching enums](#codegen-matcher-enums)
      - [5.4.2.13. Matching embeddables](#codegen-matcher-embeddables)
      - [5.4.2.14. Matching UDTs](#codegen-matcher-udts)
      - [5.4.2.15. Matching attributes](#codegen-matcher-attributes)
      - [5.4.2.16. Matcher examples](#codegen-matcher-examples)
  - [5.5. Custom code sections](#codegen-custom-code)
  - [5.6. Code generation extensions](#codegen-extensions)
    - [5.6.1. PostgreSQL extensions](#codegen-extension-postgres)
  - [5.7. Embeddable types](#codegen-embeddable-types)
    - [5.7.1. Configuration](#codegen-embeddable-types-configuration)
    - [5.7.2. Overlapping embeddable types](#codegen-overlapping-embeddable-types)
    - [5.7.3. Field replacement](#codegen-embeddable-types-replacing-fields)
    - [5.7.4. Embedded keys](#codegen-embedded-keys)
    - [5.7.5. Embedded domains](#codegen-embedded-domains)
    - [5.7.6. Embedded columns (auto configuration)](#codegen-embedded-columns)
  - [5.8. Input catalogs and schemas](#input-schema)
  - [5.9. Alternative meta data sources](#codegen-meta-sources)
    - [5.9.1. JPADatabase: Code generation from entities](#codegen-jpa)
    - [5.9.2. XMLDatabase: Code generation from XML files](#codegen-xml)
    - [5.9.3. DDLDatabase: Code generation from SQL files](#codegen-ddl)
    - [5.9.4. LiquibaseDatabase: Code generation from Liquibase XML, YAML, JSON files](#codegen-liquibase)
  - [5.10. Alternative output languages](#codegen-output-languages)
    - [5.10.1. XMLGenerator: Generating XML](#xmlgenerator)
    - [5.10.2. KotlinGenerator](#kotlingenerator)
    - [5.10.3. ScalaGenerator and Scala3Generator](#scalagenerator)
  - [5.11. Code generation execution](#codegen-execution)
    - [5.11.1. Running the code generator with Maven](#codegen-maven)
    - [5.11.2. Running the code generator with Ant](#codegen-ant)
    - [5.11.3. Running the code generator with Gradle](#codegen-gradle)
      - [5.11.3.1. Multiple executions](#codegen-gradle-executions)
      - [5.11.3.2. Compiler dependency](#codegen-gradle-compiler-dependency)
      - [5.11.3.3. Data change management](#codegen-gradle-data-change-management)
    - [5.11.4. Programmatic configuration and execution](#codegen-programmatic)
  - [5.12. System properties governing code generation](#codegen-system-properties)
  - [5.13. Code generation dependencies](#codegen-dependencies)
  - [5.14. In-memory compilation of programmatic configuration](#codegen-in-memory-compilation)
  - [5.15. Code generation for large schemas](#codegen-large-schemas)
  - [5.16. Reducing the size of generated code](#codegen-reducing-generated-code-size)
  - [5.17. Code generation and version control](#codegen-version-control)
  - [5.18. Features requiring generated code](#codegen-feature-dependencies)
- [6. Coming from JPA](#coming-from-jpa)
  - [6.1. Set based thinking](#from-jpa-set-based-thinking)
  - [6.2. Database first](#from-jpa-database-first)
  - [6.3. Eager or lazy loading](#from-jpa-eager-lazy)
  - [6.4. First level cache and second level cache](#from-jpa-caches)
  - [6.5. StatelessSession](#from-jpa-statelesssession)
  - [6.6. Embeddable](#from-jpa-embeddable)
  - [6.7. AttributeConverter](#from-jpa-converter)
  - [6.8. User types](#from-jpa-user-type)
  - [6.9. Implicit JOIN](#from-jpa-implicit-join)
  - [6.10. @OneToOne or @ManyToOne](#from-jpa-manytoone)
  - [6.11. @OneToMany or @ManyToMany](#from-jpa-onetomany)
- [7. What's new in version 3.22.0](#whats-new)
- [8. Reference](#reference)
  - [8.1. Modules](#modules)
    - [8.1.1. jOOQ module](#module-jooq)
    - [8.1.2. jOOQ-beans-extensions module](#module-jooq-beans-extensions)
    - [8.1.3. jOOQ-bom module](#module-jooq-bom)
    - [8.1.4. jOOQ-checker module](#module-jooq-checker)
    - [8.1.5. jOOQ-codegen module](#module-jooq-codegen)
    - [8.1.6. jOOQ-codegen-gradle module](#module-jooq-codegen-gradle)
    - [8.1.7. jOOQ-codegen-maven module](#module-jooq-codegen-maven)
    - [8.1.8. jOOQ-jackson-extensions module](#module-jooq-jackson-extensions)
    - [8.1.9. jOOQ-jpa-extensions module](#module-jooq-jpa-extensions)
    - [8.1.10. jOOQ-kotlin module](#module-jooq-kotlin)
    - [8.1.11. jOOQ-kotlin-coroutines module](#module-jooq-kotlin-coroutines)
    - [8.1.12. jOOQ-meta module](#module-jooq-meta)
    - [8.1.13. jOOQ-meta-extensions module](#module-jooq-meta-extensions)
    - [8.1.14. jOOQ-meta-extensions-hibernate module](#module-jooq-meta-extensions-hibernate)
    - [8.1.15. jOOQ-meta-extensions-liquibase module](#module-jooq-meta-extensions-liquibase)
    - [8.1.16. jOOQ-meta-kotlin module](#module-jooq-meta-kotlin)
    - [8.1.17. jOOQ-postgres-extensions module](#module-jooq-postgres-extensions)
    - [8.1.18. jOOQ-reactor-extensions module](#module-jooq-reactor-extensions)
    - [8.1.19. jOOQ-scala module](#module-jooq-scala)
    - [8.1.20. jOOQ-xtend module](#module-jooq-xtend)
  - [8.2. Supported RDBMS](#supported-rdbms)
  - [8.3. Commercial only features](#commercial-only-features)
  - [8.4. Experimental features](#experimental-features)
  - [8.5. SQL to DSL mapping rules](#dsl-mapping-rules)
  - [8.6. Quality Assurance](#quality-assurance)
  - [8.7. Security](#security)
    - [8.7.1. SQL Injection](#security-sql-injection)
    - [8.7.2. Debug logging](#security-debug-logging)
    - [8.7.3. Redacted columns](#security-redacted-columns)
    - [8.7.4. Exception message](#security-exception-message)
    - [8.7.5. Contact](#security-contact)
  - [8.8. Migrating to jOOQ 3.0](#migrating-to-3.0)
  - [8.9. Don't do this](#dont-do-this)
    - [8.9.1. jOOQ: Implementing the DSL types](#dont-do-this-jooq-implement-dsl)
    - [8.9.2. jOOQ: Referencing the Step types](#dont-do-this-jooq-step-types)
    - [8.9.3. Schema: NULL columns](#dont-do-this-null-columns)
    - [8.9.4. Schema: Unnamed constraints](#dont-do-this-schema-unnamed-constraints)
    - [8.9.5. Schema: Unnecessary surrogate keys](#dont-do-this-schema-surrogate-keys)
    - [8.9.6. Schema: Wrong data types](#dont-do-this-wrong-datatypes)
    - [8.9.7. SQL: COUNT(*) instead of EXISTS()](#dont-do-this-count-instead-of-exists)
    - [8.9.8. SQL: N+1](#dont-do-this-n-plus-one)
    - [8.9.9. SQL: NATURAL JOIN or JOIN USING](#dont-do-this-natural-join-or-using)
    - [8.9.10. SQL: NOT IN predicate](#dont-do-this-sql-not-in)
    - [8.9.11. SQL: ORDER BY \[column index\]](#dont-do-this-order-by-column-index)
    - [8.9.12. SQL: Rely on implicit ordering](#dont-do-this-rely-on-implicit-ordering)
    - [8.9.13. SQL: SELECT *](#dont-do-this-sql-select-all)
    - [8.9.14. SQL: SELECT DISTINCT](#dont-do-this-sql-select-distinct)
    - [8.9.15. SQL: Unnecessary UNION instead of UNION ALL](#dont-do-this-unnecessary-union)
  - [8.10. The most important jOOQ types](#reference-types)
  - [8.11. Credits](#reference-credits)

<a id="copyright"></a>
## 1. Copyright, License, and Trademarks

This section lists the various licenses that apply to different versions of jOOQ. Prior to version 3.2, jOOQ was shipped for free under the terms of the [Apache Software License 2.0](https://www.apache.org/licenses/LICENSE-2.0). With jOOQ 3.2, jOOQ became dual-licensed: [Apache Software License 2.0](https://www.apache.org/licenses/LICENSE-2.0) (for use with Open Source databases) and [commercial](https://www.jooq.org/licensing) (for use with commercial databases).

This manual itself (as well as the [www.jooq.org](https://www.jooq.org) public website) is licensed to you under the terms of the [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) license.

Please contact [legal@datageekery.com](mailto:legal@datageekery.com), should you have any questions regarding licensing.

### License for jOOQ 3.2 and later

```text
This work is dual-licensed
- under the Apache Software License 2.0 (the "ASL")
- under the jOOQ License and Maintenance Agreement (the "jOOQ License")
=============================================================================
You may choose which license applies to you:

- If you're using this work with Open Source databases, you may choose
  either ASL or jOOQ License.
- If you're using this work with at least one commercial database, you must
  choose jOOQ License

For more information, please visit https://www.jooq.org/licenses

Apache Software License 2.0:
-----------------------------------------------------------------------------
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

jOOQ License and Maintenance Agreement:
-----------------------------------------------------------------------------
Data Geekery grants the Customer the non-exclusive, timely limited and
non-transferable license to install and use the Software under the terms of
the jOOQ License and Maintenance Agreement.

This library is distributed with a LIMITED WARRANTY. See the jOOQ License
and Maintenance Agreement for more details: https://www.jooq.org/licensing
```

### Historic license for jOOQ 1.x, 2.x, 3.0, 3.1

```text
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

### Trademarks owned by Data Geekery™ GmbH

- jOOλ™ is a trademark by Data Geekery™ GmbH
- jOOQ™ is a trademark by Data Geekery™ GmbH
- jOOR™ is a trademark by Data Geekery™ GmbH
- jOOU™ is a trademark by Data Geekery™ GmbH
- jOOX™ is a trademark by Data Geekery™ GmbH

### Trademarks owned by database vendors with no affiliation to Data Geekery™ GmbH

- Access® is a registered trademark of Microsoft® Inc.
- Adaptive Server® Enterprise is a registered trademark of Sybase®, Inc.
- DB2® is a registered trademark of IBM® Corp.
- Derby is a trademark of the Apache™ Software Foundation
- H2 is a trademark of the H2 Group
- HANA is a trademark of SAP SE
- HSQLDB is a trademark of The hsql Development Group
- Ingres is a trademark of Actian™ Corp.
- MariaDB is a trademark of Monty Program Ab
- MySQL® is a registered trademark of Oracle® Corp.
- Firebird® is a registered trademark of Firebird Foundation Inc.
- Oracle® database is a registered trademark of Oracle® Corp.
- PostgreSQL® is a registered trademark of The PostgreSQL Global Development Group
- Postgres Plus® is a registered trademark of EnterpriseDB® software
- SQL Anywhere® is a registered trademark of Sybase®, Inc.
- SQL Server® is a registered trademark of Microsoft® Inc.
- SQLite is a trademark of Hipp, Wyrick & Company, Inc.

### Other trademarks by vendors with no affiliation to Data Geekery™ GmbH

- Java® is a registered trademark by Oracle® Corp. and/or its affiliates
- Liquibase is a trademark by Datical, Inc
- Flyway is a trademark by Red Gate Software Ltd
- Scala is a trademark of EPFL

### Other trademark remarks

Other names may be trademarks of their respective owners.

Throughout the manual, the above trademarks are referenced without a formal ® (R) or ™ (TM) symbol. It is believed that referencing third-party trademarks in this manual or on the jOOQ website constitutes "fair use". Please [contact us](mailto:contact@datageekery.com) if you think that your trademark(s) are not properly attributed.

### Contributions

The following are authors and contributors of jOOQ or parts of jOOQ in alphabetical order:

- Aaron Digulla
- Andreas Franzén
- Anuraag Agrawal
- Arnaud Roger
- Art O Cathain
- Artur Dryomov
- Ben Manes
- Brent Douglas
- Brett Meyer
- Christian Stein
- Christopher Deckers
- Dennis Neufeld
- Ed Schaller
- Eric Peters
- Ernest Mishkin
- Espen Stromsnes
- Eugeny Karpov
- Fabrice Le Roy
- Gonzalo Ortiz Jaureguizar
- Gregory Hlavac
- Henrik Sjöstrand
- Ivan Dugic
- Javier Durante
- Johannes Bühler
- Joseph B Phillips
- Joseph Pachod
- Knut Wannheden
- Laurent Pireyn
- Logan Hauspie
- Luc Marchaud
- Lukas Eder
- Matti Tahvonen
- Michael Doberenz
- Michael Simons
- Michał Kołodziejski
- Miguel Gonzalez Sanchez
- Mustafa Yücel
- Nathaniel Fischer
- Nicholas Chong W.B.
- Octavia Togami
- Oliver Flege
- Per Lundberg
- Peter Ertl
- Richard Bradley
- Robin Stocker
- Roland Weisleder
- Samy Deghou
- Sander Plas
- Sean Wellington
- Sergey Epik
- Sergey Zhuravlev
- Stanislas Nanchen
- Stephan Schroevers
- Sugiharto Lim
- Sven Jacobs
- Szymon Jachim
- Terence Zhang
- Thomas Darimont
- Timothy Wilson
- Timur Shaidullin
- Tsukasa Kitachi
- Victor Bronstein
- Victor Z. Peng
- Vladimir Kulev
- Vladimir Vinogradov
- Vojtech Polivka
- Wang Gaoyuan
- Wyke Oskar
- Xavier Oliver
- Zoltan Tamasi

See the following website for details about contributing to jOOQ:  
[https://www.jooq.org/legal/contributions](https://www.jooq.org/legal/contributions)

<a id="getting-started"></a>
## 2. Getting started with jOOQ

These chapters contain a quick overview of how to get started with this manual and with jOOQ. While the subsequent chapters contain a lot of reference information, this chapter here just wraps up the essentials.

<a id="the-manual"></a>
### 2.1. How to read this manual

This section helps you correctly interpret this manual in the context of jOOQ.

#### Code blocks

The following are code blocks:

```sql
-- A SQL code block
SELECT 1 FROM DUAL
```

```java
// A Java code block
for (int i = 0; i < 10; i++);
```

```xml
<!-- An XML code block -->
<hello what="world"></hello>
```

```
# A config file code block
org.jooq.property=value
```

These are useful to provide examples in code. Often, with jOOQ, it is even more useful to compare SQL code with its corresponding Java/jOOQ code. When this is done, the blocks are aligned side-by-side, with SQL usually being on the left, and an equivalent jOOQ DSL query in Java usually being on the right:

```sql
-- In SQL:
SELECT 1 FROM DUAL
```

```java
// Using jOOQ:
create.selectOne().fetch()
```

#### Code block contents

The contents of code blocks follow conventions, too. If nothing else is mentioned next to any given code block, then the following can be assumed:

```sql
-- SQL assumptions
------------------

-- If nothing else is specified, assume that the Oracle syntax is used
SELECT 1 FROM DUAL
```

```java
// Java assumptions
// ----------------

// Whenever you see "standalone functions", assume they were static imported from org.jooq.impl.DSL
// "DSL" is the entry point of the static query DSL
exists(); max(); min(); val(); inline(); // correspond to DSL.exists(); DSL.max(); DSL.min(); etc...

// Whenever you see BOOK/Book, AUTHOR/Author and similar entities, assume they were (static) imported from the generated schema
BOOK.TITLE, AUTHOR.LAST_NAME // com.example.generated.Tables.BOOK.TITLE, com.example.generated.Tables.AUTHOR.LAST_NAME
FK_BOOK_AUTHOR               // com.example.generated.Keys.FK_BOOK_AUTHOR

// Whenever you see "create" being used in Java code, assume that this is an instance of org.jooq.DSLContext.
// The reason why it is called "create" is the fact, that a jOOQ QueryPart is being created from the DSL object.
// "create" is thus the entry point of the non-static query DSL
DSLContext create = DSL.using(connection, SQLDialect.ORACLE);
```

Your naming may differ, of course. For instance, you could name the "create" instance "db", instead.

#### Execution

When you're coding PL/SQL, T-SQL or some other procedural SQL language, SQL statements are always executed immediately at the semi-colon. This is not the case in jOOQ, because as an internal DSL, jOOQ can never be sure that your statement is complete until you call `fetch()` or `execute()`. The manual tries to apply `fetch()` and `execute()` as thoroughly as possible. If not, it is implied:

```sql
SELECT 1 FROM DUAL
UPDATE t SET v = 1
```

```java
create.selectOne().fetch();
create.update(T).set(T.V, 1).execute();
```

#### Degree (arity)

jOOQ records (and many other API elements) have a degree N between 1 and 22. The variable degree of an API element is denoted as [N], e.g. Row[N] or Record[N]. The term "degree" is preferred over arity, as "degree" is the term used in the SQL standard, whereas "arity" is used more often in mathematics and relational theory.

#### Settings

jOOQ allows to override runtime behaviour using [`org.jooq.conf.Settings`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html). If nothing is specified, the default runtime settings are assumed.

#### Sample database

jOOQ query examples run against the sample database. See the manual's section about [the sample database used in this manual](#sample-database) to learn more about the sample database.

<a id="sample-database"></a>
### 2.2. The sample database used in this manual

For the examples in this manual, the same database will always be referred to. It essentially consists of these entities created using the Oracle dialect

```sql
CREATE TABLE language (
  id              NUMBER(7)     NOT NULL PRIMARY KEY,
  cd              CHAR(2)       NOT NULL,
  description     VARCHAR2(50)
);

CREATE TABLE author (
  id              NUMBER(7)     NOT NULL PRIMARY KEY,
  first_name      VARCHAR2(50),
  last_name       VARCHAR2(50)  NOT NULL,
  date_of_birth   DATE,
  year_of_birth   NUMBER(7),
  distinguished   NUMBER(1)
);

CREATE TABLE book (
  id              NUMBER(7)     NOT NULL PRIMARY KEY,
  author_id       NUMBER(7)     NOT NULL,
  title           VARCHAR2(400) NOT NULL,
  published_in    NUMBER(7)     NOT NULL,
  language_id     NUMBER(7)     NOT NULL,

  CONSTRAINT fk_book_author     FOREIGN KEY (author_id)   REFERENCES author(id),
  CONSTRAINT fk_book_language   FOREIGN KEY (language_id) REFERENCES language(id)
);

CREATE TABLE book_store (
  name            VARCHAR2(400) NOT NULL UNIQUE
);

CREATE TABLE book_to_book_store (
  name            VARCHAR2(400) NOT NULL,
  book_id         INTEGER       NOT NULL,
  stock           INTEGER,

  PRIMARY KEY(name, book_id),
  CONSTRAINT fk_b2bs_book_store FOREIGN KEY (name)        REFERENCES book_store (name) ON DELETE CASCADE,
  CONSTRAINT fk_b2bs_book       FOREIGN KEY (book_id)     REFERENCES book (id)         ON DELETE CASCADE
);
```

More entities, types (e.g. UDT's, ARRAY types, ENUM types, etc), stored procedures and packages are introduced for specific examples

In addition to the above, you may assume the following sample data:

```sql
INSERT INTO language (id, cd, description) VALUES (1, 'en', 'English');
INSERT INTO language (id, cd, description) VALUES (2, 'de', 'Deutsch');
INSERT INTO language (id, cd, description) VALUES (3, 'fr', 'Français');
INSERT INTO language (id, cd, description) VALUES (4, 'pt', 'Português');

INSERT INTO author (id, first_name, last_name, date_of_birth    , year_of_birth)
  VALUES           (1 , 'George'  , 'Orwell' , DATE '1903-06-26', 1903         );
INSERT INTO author (id, first_name, last_name, date_of_birth    , year_of_birth)
  VALUES           (2 , 'Paulo'   , 'Coelho' , DATE '1947-08-24', 1947         );

INSERT INTO book (id, author_id, title         , published_in, language_id)
  VALUES         (1 , 1        , '1984'        , 1948        , 1          );
INSERT INTO book (id, author_id, title         , published_in, language_id)
  VALUES         (2 , 1        , 'Animal Farm' , 1945        , 1          );
INSERT INTO book (id, author_id, title         , published_in, language_id)
  VALUES         (3 , 2        , 'O Alquimista', 1988        , 4          );
INSERT INTO book (id, author_id, title         , published_in, language_id)
  VALUES         (4 , 2        , 'Brida'       , 1990        , 2          );

INSERT INTO book_store VALUES ('Orell Füssli');
INSERT INTO book_store VALUES ('Ex Libris');
INSERT INTO book_store VALUES ('Buchhandlung im Volkshaus');

INSERT INTO book_to_book_store VALUES ('Orell Füssli'             , 1, 10);
INSERT INTO book_to_book_store VALUES ('Orell Füssli'             , 2, 10);
INSERT INTO book_to_book_store VALUES ('Orell Füssli'             , 3, 10);
INSERT INTO book_to_book_store VALUES ('Ex Libris'                , 1, 1 );
INSERT INTO book_to_book_store VALUES ('Ex Libris'                , 3, 2 );
INSERT INTO book_to_book_store VALUES ('Buchhandlung im Volkshaus', 3, 1 );
```

<a id="use-cases"></a>
### 2.3. Different use cases for jOOQ

jOOQ has originally been created as a library for complete abstraction of JDBC and all database interaction. Various best practices that are frequently encountered in pre-existing software products are applied to this library. This includes:

- Typesafe database object referencing through generated schema, table, column, record, procedure, type, dao, pojo artefacts (see the chapter about [code generation](#code-generation))
- Typesafe SQL construction / SQL building through a complete querying DSL API modelling SQL as a domain specific language in Java (see the chapter about [the query DSL API](#dsl-api))
- Convenient query execution through an improved API for result fetching (see the chapters about [the various types of data fetching](#fetching))
- SQL dialect abstraction and SQL clause emulation to improve cross-database compatibility and to enable missing features in simpler databases (see the chapter about [SQL dialects](#sql-dialects))
- SQL logging and debugging using jOOQ as an integral part of your development process (see the chapters about [logging](#logging))

Effectively, jOOQ was originally designed to replace any other database abstraction framework short of the ones handling connection pooling (and more sophisticated [transaction management](#transaction-management))

#### Use jOOQ the way you prefer

... but open source is community-driven. And the community has shown various ways of using jOOQ that diverge from its original intent. Some use cases encountered are:

- Using Hibernate for 70% of the queries (i.e. [CRUD](#crud-with-updatablerecords)) and jOOQ for the remaining 30% where SQL is really needed
- Using jOOQ for SQL building and JDBC for SQL execution
- Using jOOQ for SQL building and Spring Data for SQL execution
- Using jOOQ without the [source code generator](#code-generation) to build the basis of a framework for dynamic SQL execution.

The following sections explain about various use cases for using jOOQ in your application.

<a id="jooq-as-a-sql-builder-without-codegeneration"></a>
#### 2.3.1. jOOQ as a SQL builder without code generation

**We strongly recommend to use jOOQ with its [code generator](#jooq-as-a-sql-builder-with-code-generation) to get the most out of jOOQ!**

However, if you have a dynamic schema, you don't have to use the code generator. This is the most simple of all use cases, allowing for construction of valid SQL for any database. In this use case, you will not use [jOOQ's code generator](#jooq-as-a-sql-builder-with-code-generation) and maybe not even [jOOQ's query execution facilities](#jooq-as-a-sql-executor). Instead, you'll use [jOOQ's query DSL API](#dsl-api) to wrap strings, literals and other user-defined objects into an object-oriented, type-safe AST modelling your SQL statements. An example is given here:

```java
// Fetch a SQL string from a jOOQ Query in order to manually execute it with another tool.
// For simplicity reasons, we're using the API to construct case-insensitive object references, here.
Query query = create.select(field("BOOK.TITLE"), field("AUTHOR.FIRST_NAME"), field("AUTHOR.LAST_NAME"))
                    .from(table("BOOK"))
                    .join(table("AUTHOR"))
                    .on(field("BOOK.AUTHOR_ID").eq(field("AUTHOR.ID")))
                    .where(field("BOOK.PUBLISHED_IN").eq(1948));
String sql = query.getSQL();
List<Object> bindValues = query.getBindValues();
```

The SQL string built with the jOOQ query DSL can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools (note that since jOOQ uses [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html) by default, this will generate a bind variable for "1948". [Read more about bind variables here](#bind-values)).

You can also avoid getting the SQL string and bind values separately:

```java
String sql = query.getSQL(ParamType.INLINED);
```

If you wish to use jOOQ only as a SQL builder, the following sections of the manual will be of interest to you:

- [SQL building](#sql-building): This section contains a lot of information about creating SQL statements using the jOOQ API
- [Plain SQL](#plain-sql): This section contains information useful in particular to those that want to supply [table expressions](#table-expressions), [column expressions](#column-expressions), etc. as plain SQL to jOOQ, rather than through generated artefacts
- [Bind values](#bind-values): This section explains how bind values are managed and/or inlined in jOOQ.

<a id="jooq-as-a-sql-builder-with-code-generation"></a>
#### 2.3.2. jOOQ as a SQL builder with code generation

In addition to using jOOQ as a [standalone SQL builder](#jooq-as-a-sql-builder-without-codegeneration), you can also use jOOQ's code generation features in order to compile your SQL statements using a Java compiler against an actual database schema. This adds a lot of power and expressiveness to just simply constructing SQL using the query DSL and custom strings and literals, as you can be sure that all database artefacts actually exist in the database, and that their type is correct. We strongly recommend using this approach. An example is given here:

```java
// Fetch a SQL string from a jOOQ Query in order to manually execute it with another tool.
Query query = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
                    .from(BOOK)
                    .join(AUTHOR)
                    .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
                    .where(BOOK.PUBLISHED_IN.eq(1948));

String sql = query.getSQL();
List<Object> bindValues = query.getBindValues();
```

The SQL string built with the jOOQ query DSL can then be executed using JDBC directly, using Spring's JdbcTemplate, using Apache DbUtils and many other tools (note that since jOOQ uses [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html) by default, this will generate a bind variable for "1948". [Read more about bind variables here](#bind-values)).

You can also avoid getting the SQL string and bind values separately:

```java
String sql = query.getSQL(ParamType.INLINED);
```

If you wish to use jOOQ only as a SQL builder with code generation, the following sections of the manual will be of interest to you:

- [SQL building](#sql-building): This section contains a lot of information about creating SQL statements using the jOOQ API
- [Code generation](#code-generation): This section contains the necessary information to run jOOQ's code generator against your developer database
- [Bind values](#bind-values): This section explains how bind values are managed and/or inlined in jOOQ.

<a id="jooq-as-a-sql-executor"></a>
#### 2.3.3. jOOQ as a SQL executor

Instead of any tool mentioned in the previous chapters, you can also use jOOQ directly to execute your jOOQ-generated SQL statements. This will add a lot of convenience on top of the previously discussed API for typesafe SQL construction, when you can re-use the information from generated classes to fetch records and custom data types. An example is given here:

```java
// Typesafely execute the SQL statement directly with jOOQ
Result<Record3<String, String, String>> result =
create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .from(BOOK)
      .join(AUTHOR)
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .where(BOOK.PUBLISHED_IN.eq(1948))
      .fetch();
```

By having jOOQ execute your SQL, the jOOQ query DSL becomes truly embedded SQL.

jOOQ doesn't stop here, though! You can execute any SQL with jOOQ. In other words, you can use any other SQL building tool and run the SQL statements with jOOQ. An example is given here:

```java
// Use your favourite tool to construct SQL strings:
String sql = "SELECT title, first_name, last_name FROM book JOIN author ON book.author_id = author.id " +
             "WHERE book.published_in = 1984";

// Fetch results using jOOQ
Result<Record> result = create.fetch(sql);

// Or execute that SQL with JDBC, fetching the ResultSet with jOOQ:
ResultSet rs = connection.createStatement().executeQuery(sql);
Result<Record> result = create.fetch(rs);
```

If you wish to use jOOQ as a SQL executor with (or without) code generation, the following sections of the manual will be of interest to you:

- [SQL building](#sql-building): This section contains a lot of information about creating SQL statements using the jOOQ API
- [Code generation](#code-generation): This section contains the necessary information to run jOOQ's code generator against your developer database
- [SQL execution](#sql-execution): This section contains a lot of information about executing SQL statements using the jOOQ API
- [Fetching](#fetching): This section contains some useful information about the various ways of fetching data with jOOQ

<a id="jooq-for-crud"></a>
#### 2.3.4. jOOQ for CRUD

Apart from jOOQ's fluent API for query construction, jOOQ can also help you execute everyday CRUD operations. An example is given here:

```java
// Fetch an author
AuthorRecord author = create.fetchOne(AUTHOR, AUTHOR.ID.eq(1));

// Create a new author, if it doesn't exist yet
if (author == null) {
    author = create.newRecord(AUTHOR);
    author.setId(1);
    author.setFirstName("Dan");
    author.setLastName("Brown");
}

// Mark the author as a "distinguished" author and store it
author.setDistinguished(1);

// Executes an update on existing authors, or insert on new ones
author.store();
```

If you wish to use all of jOOQ's features, the following sections of the manual will be of interest to you (including all sub-sections):

- [SQL building](#sql-building): This section contains a lot of information about creating SQL statements using the jOOQ API
- [Code generation](#code-generation): This section contains the necessary information to run jOOQ's code generator against your developer database
- [SQL execution](#sql-execution): This section contains a lot of information about executing SQL statements using the jOOQ API

<a id="jooq-for-pros"></a>
#### 2.3.5. jOOQ for PROs

jOOQ isn't just a library that helps you [build](#sql-building) and [execute](#sql-execution) SQL against your [generated, compilable schema](#code-generation). jOOQ ships with a lot of tools. Here are some of the most important tools shipped with jOOQ:

- [jOOQ's Execute Listeners](#execute-listeners): jOOQ allows you to hook your custom execute listeners into jOOQ's SQL statement execution lifecycle in order to centrally coordinate any arbitrary operation performed on SQL being executed. Use this for logging, identity generation, SQL tracing, performance measurements, etc.
- [Logging](#logging): jOOQ has a standard DEBUG logger built-in, for logging and tracing all your executed SQL statements and fetched result sets
- [Stored Procedures](#stored-procedures): jOOQ supports stored procedures and functions of your favourite database. All routines and user-defined types are generated and can be included in jOOQ's SQL building API as function references.
- [Batch execution](#batch-execution): Batch execution is important when executing a big load of SQL statements. jOOQ simplifies these operations compared to JDBC
- [Exporting](#exporting) and [Importing](#importing): jOOQ ships with an API to easily export/import data in various formats

If you're a power user of your favourite, feature-rich database, jOOQ will help you access all of your database's vendor-specific features, such as OLAP features, stored procedures, user-defined types, vendor-specific SQL, functions, etc. Examples are given throughout this manual.

<a id="getting-jooq"></a>
### 2.4. Downloading jOOQ

jOOQ is distributed over 3 main channels:

- The website as downloadable ZIP files: [https://www.jooq.org/download/versions](https://www.jooq.org/download/versions)
- The repository for jOOQ's commercial editions only: [https://repo.jooq.org](https://repo.jooq.org)
- Maven Central for jOOQ's open source edition only: [https://repo1.maven.org/maven2/org/jooq](https://repo1.maven.org/maven2/org/jooq)

#### The ZIP file

If you choose to download jOOQ over the website, you will be able to download a ZIP file with the following layout:

- `maven-deploy.bat`: A Windows batch script to deploy artifacts to a maven repository
- `maven-deploy.sh`: A bash script to deploy artifacts to a maven repository
- `maven-install.bat`: A Windows batch script to install artifacts to the local maven repository
- `maven-install.sh`: A bash script to install artifacts to the local maven repository

The website hosts the latest versions of the jOOQ Open Source Edition as well as all the historic versions of the commercial jOOQ editions including snapshot builds of all distributions that are available to paying customers only.

#### The commercial artifact repository

The commercial artifact repository hosts all the historic versions of the commercial jOOQ editions including snapshot builds of all distributions that are available to paying customers only.

Below is information regarding how to include these dependencies in Maven / Gradle:

**Maven:**

#### settings.xml

```xml
<server>
    <id>jooq-pro</id>
    <username>[your licensee email]</username>
    <password>[your license key]</password>
</server>
```

#### pom.xml

```xml
<repositories>
    <repository>
        <id>central</id>
        <url>https://repo1.maven.org/maven2/</url>
    </repository>
    <!-- Other repositories ... -->

    <repository>
        <id>jooq-pro</id>
        <url>https://repo.jooq.org/repo</url>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>central</id>
        <url>https://repo1.maven.org/maven2/</url>
    </pluginRepository>
    <!-- Other repositories ... -->

    <pluginRepository>
        <id>jooq-pro</id>
        <url>https://repo.jooq.org/repo</url>
    </pluginRepository>
</pluginRepositories>
```

**Gradle (Kotlin):**

#### settings.gradle.kts

```kotlin
pluginManagement {
    repositories {
        mavenCentral()
        // Other repositories...

        maven {
            url = uri("https://repo.jooq.org/repo")
            credentials {
                username = "<your licensee email>"
                password = "<your license key>"
            }
            content {
                includeGroupByRegex("org\\.jooq\\..*")
            }
        }
    }
}
```

#### build.gradle.kts

```kotlin
repositories {
    mavenCentral()
    // Other repositories...

    maven {
        url = uri("https://repo.jooq.org/repo")
        credentials {
            username = "<your licensee email>"
            password = "<your license key>"
        }
        content {
            includeGroupByRegex("org\\.jooq\\..*")
        }
    }
}
```

**Gradle (Groovy):**

#### settings.gradle

```groovy
pluginManagement {
    repositories {
        mavenCentral()
        // Other repositories...

        maven {
            url "https://repo.jooq.org/repo"
            credentials {
                username "<your licensee email>"
                password "<your license key>"
            }
        }
        content {
            includeGroupByRegex "org\\.jooq\\..*"
        }
    }
}
```

#### build.gradle

```groovy
repositories {
    mavenCentral()
    // Other repositories...

    maven {
        url "https://repo.jooq.org/repo"
        credentials {
            username "<your licensee email>"
            password "<your license key>"
        }
        content {
            includeGroupByRegex "org\\.jooq\\..*"
        }
    }
}
```

#### Dependencies

Depending on the edition you're using, please declare the following dependencies in Maven or Gradle:

**Maven:**

```xml
<dependency>
                <!-- Use org.jooq                for the Open Source Edition
                         org.jooq.pro            for commercial editions with Java 25 support,
                         org.jooq.pro-java-21    for commercial editions with Java 21 support,
                         org.jooq.pro-java-17    for commercial editions with Java 17 support,
                         org.jooq.pro-java-11    for commercial editions with Java 11 support,
                         org.jooq.pro-java-8     for commercial editions with Java 8 support,
                         org.jooq.trial          for the free trial edition with Java 25 support,
                         org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                         org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                         org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                         org.jooq.trial-java-8   for the free trial edition with Java 8 support
    
                 Note: Only the Open Source Edition is hosted on Maven Central.
                       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

    <groupId>org.jooq</groupId>
    <artifactId>jooq</artifactId>
    <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation("org.jooq:jooq:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation "org.jooq:jooq:3.22.0-SNAPSHOT"
}
```

<a id="tutorials"></a>
### 2.5. Tutorials

Don't have time to read the full manual? Here are a couple of tutorials that will get you into the most essential parts of jOOQ as quick as possible.

<a id="jooq-in-7-steps"></a>
#### 2.5.1. jOOQ in 7 easy steps

This manual section is intended for new users, to help them get a running application with jOOQ, quickly.

<a id="jooq-in-7-steps-step1"></a>
##### 2.5.1.1. Step 1: Preparation

If you haven't already downloaded it, download jOOQ:  
[https://www.jooq.org/download](https://www.jooq.org/download)

Alternatively, you can create a Maven dependency to download jOOQ artefacts:

###### Open Source Edition

```xml
<dependency>
  <groupId>org.jooq</groupId>
  <artifactId>jooq</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- These may not be required, unless you use the GenerationTool manually for code generation -->
<dependency>
  <groupId>org.jooq</groupId>
  <artifactId>jooq-meta</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq</groupId>
  <artifactId>jooq-codegen</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

###### Commercial Editions (Java 17+)

```xml
<!-- Note: These aren't hosted on Maven Central. Import them manually from your distribution -->
<dependency>
  <groupId>org.jooq.pro</groupId>
  <artifactId>jooq</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- These may not be required, unless you use the GenerationTool manually for code generation -->
<dependency>
  <groupId>org.jooq.pro</groupId>
  <artifactId>jooq-meta</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq.pro</groupId>
  <artifactId>jooq-codegen</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

###### Commercial Editions (Java 11+)

```xml
<!-- Note: These aren't hosted on Maven Central. Import them manually from your distribution -->
<dependency>
  <groupId>org.jooq.pro-java-11</groupId>
  <artifactId>jooq</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- These may not be required, unless you use the GenerationTool manually for code generation -->
<dependency>
  <groupId>org.jooq.pro-java-11</groupId>
  <artifactId>jooq-meta</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq.pro-java-11</groupId>
  <artifactId>jooq-codegen</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

###### Commercial Editions (Java 8+)

```xml
<!-- Note: These aren't hosted on Maven Central. Import them manually from your distribution -->
<dependency>
  <groupId>org.jooq.pro-java-8</groupId>
  <artifactId>jooq</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- These may not be required, unless you use the GenerationTool manually for code generation -->
<dependency>
  <groupId>org.jooq.pro-java-8</groupId>
  <artifactId>jooq-meta</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq.pro-java-8</groupId>
  <artifactId>jooq-codegen</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

###### Commercial Editions (Free Trial, Java 17+)

```xml
<!-- Note: These aren't hosted on Maven Central. Import them manually from your distribution -->
<dependency>
  <groupId>org.jooq.trial</groupId>
  <artifactId>jooq</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- These may not be required, unless you use the GenerationTool manually for code generation -->
<dependency>
  <groupId>org.jooq.trial</groupId>
  <artifactId>jooq-meta</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq.trial</groupId>
  <artifactId>jooq-codegen</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

###### Commercial Editions (Free Trial, Java 11+)

```xml
<!-- Note: These aren't hosted on Maven Central. Import them manually from your distribution -->
<dependency>
  <groupId>org.jooq.trial-java-11</groupId>
  <artifactId>jooq</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- These may not be required, unless you use the GenerationTool manually for code generation -->
<dependency>
  <groupId>org.jooq.trial-java-11</groupId>
  <artifactId>jooq-meta</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq.trial-java-11</groupId>
  <artifactId>jooq-codegen</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

###### Commercial Editions (Free Trial, Java 8+)

```xml
<!-- Note: These aren't hosted on Maven Central. Import them manually from your distribution -->
<dependency>
  <groupId>org.jooq.trial-java-8</groupId>
  <artifactId>jooq</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- These may not be required, unless you use the GenerationTool manually for code generation -->
<dependency>
  <groupId>org.jooq.trial-java-8</groupId>
  <artifactId>jooq-meta</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq.trial-java-8</groupId>
  <artifactId>jooq-codegen</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

###### Commercial Editions (Java 6+)

```xml
<!-- Note: These aren't hosted on Maven Central. Import them manually from your distribution -->
<dependency>
  <groupId>org.jooq.pro-java-6</groupId>
  <artifactId>jooq</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- These may not be required, unless you use the GenerationTool manually for code generation -->
<dependency>
  <groupId>org.jooq.pro-java-6</groupId>
  <artifactId>jooq-meta</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq.pro-java-6</groupId>
  <artifactId>jooq-codegen</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

Note that only the jOOQ Open Source Edition is available from Maven Central. If you're using the jOOQ Professional Edition or the jOOQ Enterprise Edition, you will have to manually install jOOQ in your local Nexus, or in your local Maven cache. For more information, please refer to the [licensing pages](https://www.jooq.org/licensing).

Please refer to the manual's section about [Code generation configuration](#codegen-configuration) to learn how to use jOOQ's code generator with Maven.

For this example, we'll be using MySQL. If you haven't already downloaded MySQL Connector/J, download it here:  
[https://dev.mysql.com/downloads/connector/j/](https://dev.mysql.com/downloads/connector/j/)

If you don't have a MySQL instance up and running yet, get it from [https://www.mysql.com](https://www.mysql.com/) or [https://hub.docker.com/_/mysql](https://hub.docker.com/_/mysql) now!

<a id="jooq-in-7-steps-step2"></a>
##### 2.5.1.2. Step 2: Your database

We're going to create a database called "library" and a corresponding "author" table. Connect to MySQL via your command line client and type the following:

```sql
CREATE DATABASE `library`;

USE `library`;

CREATE TABLE `author` (
  `id` int NOT NULL,
  `first_name` varchar(255) DEFAULT NULL,
  `last_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);
```

<a id="jooq-in-7-steps-step3"></a>
##### 2.5.1.3. Step 3: Code generation

In this step, we're going to use jOOQ's command line tools to generate classes that map to the Author table we just created. More detailed information about how to set up the jOOQ code generator can be found here:  
[jOOQ manual pages about setting up the code generator](#code-generation)

The easiest way to generate a schema is to copy the jOOQ jar files (there should be 3) and the MySQL Connector jar file to a temporary directory. Then, create a library.xml that looks like this:

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration>
  <!-- Configure the database connection here -->
  <jdbc>
    <driver>com.mysql.cj.jdbc.Driver</driver>
    <url>jdbc:mysql://localhost:3306/library</url>
    <user>root</user>
    <password></password>
  </jdbc>

  <generator>
    <!-- The default code generator. You can override this one, to generate your own code style.
         Supported generators:
         - org.jooq.codegen.JavaGenerator
         - org.jooq.codegen.KotlinGenerator
         - org.jooq.codegen.ScalaGenerator
         - org.jooq.codegen.Scala3Generator
         Defaults to org.jooq.codegen.JavaGenerator -->
    <name>org.jooq.codegen.JavaGenerator</name>

    <database>
      <!-- The database type. The format here is:
           org.jooq.meta.[database].[database]Database -->
      <name>org.jooq.meta.mysql.MySQLDatabase</name>

      <!-- The database schema (or in the absence of schema support, in your RDBMS this
           can be the owner, user, database name) to be generated -->
      <inputSchema>library</inputSchema>

      <!-- All elements that are generated from your schema
           (A Java regular expression. Use the pipe to separate several expressions)
           Watch out for case-sensitivity. Depending on your database, this might be important! -->
      <includes>.*</includes>

      <!-- All elements that are excluded from your schema
           (A Java regular expression. Use the pipe to separate several expressions).
           Excludes match before includes, i.e. excludes have a higher priority -->
      <excludes></excludes>
    </database>

    <target>
      <!-- The destination package of your generated classes (within the destination directory) -->
      <packageName>test.generated</packageName>

      <!-- The destination directory of your generated classes. Using Maven directory layout here -->
      <directory>C:/workspace/MySQLTest/src/main/java</directory>
    </target>
  </generator>
</configuration>
```

Replace the username (`<username/>` or `<user/>`) with whatever user has the appropriate privileges to query the database meta data. You'll also want to look at the other values and replace as necessary. Here are the two interesting properties:

`<packageName/>` - set this to the parent package you want to create for the generated classes. Setting the value to `test.generated` will cause the `test.generated.tables.Author` and `test.generated.tables.records.AuthorRecord` classes to be created

`<directory/>` - the directory to output the generated classes to.

Once you have the JAR files and library.xml in your temp directory, type this on a Windows machine:

```text
java -classpath jooq-3.22.0-SNAPSHOT.jar;^
jooq-meta-3.22.0-SNAPSHOT.jar;^
jooq-codegen-3.22.0-SNAPSHOT.jar;^
reactive-streams-1.0.3.jar;^
r2dbc-spi-1.0.0.RELEASE.jar;^
jakarta.xml.bind-api-3.0.0.jar;^
mysql-connector-java.jar;. ^
org.jooq.codegen.GenerationTool library.xml
```

... or type this on a UNIX / Linux / Mac system (colons instead of semi-colons):

```text
java -classpath jooq-3.22.0-SNAPSHOT.jar:\
jooq-meta-3.22.0-SNAPSHOT.jar:\
jooq-codegen-3.22.0-SNAPSHOT.jar:\
reactive-streams-1.0.3.jar:\
r2dbc-spi-1.0.0.RELEASE.jar:\
jakarta.xml.bind-api-3.0.0.jar:\
mysql-connector-java.jar:. \
org.jooq.codegen.GenerationTool library.xml
```

> [!TIP]
> - jOOQ will try loading the **library.xml** from your classpath. This is also why there is a trailing period (`.`) on the classpath. If the file cannot be found on the classpath, jOOQ will look on the file system from the current working directory.
> - Replace the filenames with your actual filenames. In this example, jOOQ 3.22.0-SNAPSHOT is being used.
> - If you're using a linux style shell on Windows, but a Windows JDK/JRE, you still need to use semi-colons in your classpath! (`;`) In git-bash, you might have to quote your classpath (`"jooq-3.22.0-SNAPSHOT.jar;jooq-meta-3.22.0-SNAPSHOT.jar;..."`)

If everything has worked, you should see this in your console output:

```text
Nov 1, 2011 7:25:06 PM org.jooq.impl.JooqLogger info
INFO: Initialising properties  : /library.xml
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Database parameters
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: ----------------------------------------------------------
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO:   dialect                : MYSQL
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO:   schema                 : library
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO:   target dir             : C:/workspace/MySQLTest/src
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO:   target package         : test.generated
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: ----------------------------------------------------------
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Emptying                 : C:/workspace/MySQLTest/src/test/generated
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Generating classes in    : C:/workspace/MySQLTest/src/test/generated
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Generating schema        : Library.java
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Schema generated         : Total: 122.18ms
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Sequences fetched        : 0 (0 included, 0 excluded)
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Tables fetched           : 5 (5 included, 0 excluded)
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Generating tables        : C:/workspace/MySQLTest/src/test/generated/tables
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: ARRAYs fetched           : 0 (0 included, 0 excluded)
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Enums fetched            : 0 (0 included, 0 excluded)
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: UDTs fetched             : 0 (0 included, 0 excluded)
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Generating table         : Author.java
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Tables generated         : Total: 680.464ms, +558.284ms
Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info
INFO: Generating Keys          : C:/workspace/MySQLTest/src/test/generated/tables
Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info
INFO: Keys generated           : Total: 718.621ms, +38.157ms
Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info
INFO: Generating records       : C:/workspace/MySQLTest/src/test/generated/tables/records
Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info
INFO: Generating record        : AuthorRecord.java
Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info
INFO: Table records generated  : Total: 782.545ms, +63.924ms
Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info
INFO: Routines fetched         : 0 (0 included, 0 excluded)
Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info
INFO: Packages fetched         : 0 (0 included, 0 excluded)
Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info
INFO: GENERATION FINISHED!     : Total: 791.688ms, +9.143ms
```

<a id="jooq-in-7-steps-step4"></a>
##### 2.5.1.4. Step 4: Connect to your database

Let's just write a vanilla main class in the project containing the generated classes:

```java
// For convenience, always static import your generated tables and jOOQ functions to decrease verbosity:
import static test.generated.Tables.*;
import static org.jooq.impl.DSL.*;

import java.sql.*;

public class Main {
    public static void main(String[] args) {
        String userName = "root";
        String password = "";
        String url = "jdbc:mysql://localhost:3306/library";

        // Connection is the only JDBC resource that we need
        // PreparedStatement and ResultSet are handled by jOOQ, internally
        try (Connection conn = DriverManager.getConnection(url, userName, password)) {
            // ...
        }

        // For the sake of this tutorial, let's keep exception handling simple
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

This is pretty standard code for establishing a MySQL connection.

<a id="jooq-in-7-steps-step5"></a>
##### 2.5.1.5. Step 5: Querying

Let's add a simple query constructed with jOOQ's query DSL:

```java
DSLContext create = DSL.using(conn, SQLDialect.MYSQL);
Result<Record> result = create.select().from(AUTHOR).fetch();
```

First get an instance of `DSLContext` so we can write a simple `SELECT` query. We pass an instance of the MySQL connection to `DSL`. Note that the DSLContext doesn't close the connection. We'll have to do that ourselves.

We then use jOOQ's query DSL to return an instance of Result. We'll be using this result in the next step.

<a id="jooq-in-7-steps-step6"></a>
##### 2.5.1.6. Step 6: Iterating

After the line where we retrieve the results, let's iterate over the results and print out the data:

```java
for (Record r : result) {
    Integer id = r.getValue(AUTHOR.ID);
    String firstName = r.getValue(AUTHOR.FIRST_NAME);
    String lastName = r.getValue(AUTHOR.LAST_NAME);

    System.out.println("ID: " + id + " first name: " + firstName + " last name: " + lastName);
}
```

The full program should now look like this:

```java
package test;

// For convenience, always static import your generated tables and
// jOOQ functions to decrease verbosity:
import static test.generated.Tables.*;
import static org.jooq.impl.DSL.*;

import java.sql.*;

import org.jooq.*;
import org.jooq.impl.*;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        String userName = "root";
        String password = "";
        String url = "jdbc:mysql://localhost:3306/library";

        // Connection is the only JDBC resource that we need
        // PreparedStatement and ResultSet are handled by jOOQ, internally
        try (Connection conn = DriverManager.getConnection(url, userName, password)) {
            DSLContext create = DSL.using(conn, SQLDialect.MYSQL);
            Result<Record> result = create.select().from(AUTHOR).fetch();

            for (Record r : result) {
                Integer id = r.getValue(AUTHOR.ID);
                String firstName = r.getValue(AUTHOR.FIRST_NAME);
                String lastName = r.getValue(AUTHOR.LAST_NAME);

                System.out.println("ID: " + id + " first name: " + firstName + " last name: " + lastName);
            }
        }

        // For the sake of this tutorial, let's keep exception handling simple
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

<a id="jooq-in-7-steps-step7"></a>
##### 2.5.1.7. Step 7: Explore!

jOOQ has grown to be a comprehensive SQL library. For more information, please consider the documentation:  
[https://www.jooq.org/learn](https://www.jooq.org/learn)

... explore the Javadoc:  
[https://www.jooq.org/javadoc/latest/](https://www.jooq.org/javadoc/latest/)

... or join the news group:  
[https://groups.google.com/forum/#!forum/jooq-user](https://groups.google.com/forum/#!forum/jooq-user)

This tutorial is the courtesy of Ikai Lan. See the original source here:  
[https://ikaisays.com/2011/11/01/getting-started-with-jooq-a-tutorial/](https://ikaisays.com/2011/11/01/getting-started-with-jooq-a-tutorial/)

<a id="jooq-with-flyway"></a>
#### 2.5.2. Using jOOQ with Flyway

[![Flyway - Database Migrations Made Easy](https://www.jooq.org/img/partner/flyway-logo-transparent-300.png)](https://flywaydb.org/)When performing database migrations, we at Data Geekery recommend using jOOQ with Flyway - Database Migrations Made Easy. In this chapter, we're going to look into a simple way to get started with the two frameworks.

##### Philosophy

There are a variety of ways how jOOQ and Flyway could interact with each other in various development setups. In this tutorial we're going to show just one variant of such framework team play - a variant that we find particularly compelling for most use cases.

The general philosophy behind the following approach can be summarised as this:

- **1. Database increment**
- **2. Database migration**
- **3. Code re-generation**
- **4. Development**

The four steps above can be repeated time and again, every time you need to modify something in your database. More concretely, let's consider:

- **1. Database increment** - You need a new column in your database, so you write the necessary DDL in a Flyway script
- **2. Database migration** - This Flyway script is now part of your deliverable, which you can share with all developers who can migrate their databases with it, the next time they check out your change
- **3. Code re-generation** - Once the database is migrated, you regenerate all jOOQ artefacts (see [code generation](#code-generation)), locally
- **4. Development** - You continue developing your business logic, writing code against the updated, generated database schema

##### Maven Project Configuration - Properties

The following properties are defined in our pom.xml, to be able to reuse them between plugin configurations:

```xml
<properties>
    <db.url>jdbc:h2:~/flyway-test</db.url>
    <db.username>sa</db.username>
</properties>
```

##### 0. Maven Project Configuration - Dependencies

While jOOQ and Flyway could be used in standalone migration scripts, in this tutorial, we'll be using Maven for the standard project setup.

These are the dependencies that we're using in our Maven configuration:

```xml
<!-- We'll add the latest version of jOOQ and our JDBC driver - in this case H2 -->
<dependency>
                <!-- Use org.jooq                for the Open Source Edition
                         org.jooq.pro            for commercial editions with Java 25 support,
                         org.jooq.pro-java-21    for commercial editions with Java 21 support,
                         org.jooq.pro-java-17    for commercial editions with Java 17 support,
                         org.jooq.pro-java-11    for commercial editions with Java 11 support,
                         org.jooq.pro-java-8     for commercial editions with Java 8 support,
                         org.jooq.trial          for the free trial edition with Java 25 support,
                         org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                         org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                         org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                         org.jooq.trial-java-8   for the free trial edition with Java 8 support
    
                 Note: Only the Open Source Edition is hosted on Maven Central.
                       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

    <groupId>org.jooq</groupId>
    <artifactId>jooq</artifactId>
    <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.197</version>
</dependency>

<!-- For improved logging, we'll be using log4j via slf4j to see what's going on during migration and code generation -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.11.0</version>
</dependency>

<!-- To ensure our code is working, we're using JUnit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
```

##### 0. Maven Project Configuration - Plugins

After the dependencies, let's simply add the Flyway and jOOQ Maven plugins like so. The Flyway plugin:

```xml
<plugin>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-maven-plugin</artifactId>
    <version>3.0</version>

    <!-- Note that we're executing the Flyway plugin in the "generate-sources" phase -->
    <executions>
        <execution>
            <phase>generate-sources</phase>
            <goals>
                <goal>migrate</goal>
            </goals>
        </execution>
    </executions>

    <!-- Note that we need to prefix the db/migration path with filesystem: to prevent Flyway
         from looking for our migration scripts only on the classpath -->
    <configuration>
        <url>${db.url}</url>
        <user>${db.username}</user>
        <locations>
            <location>filesystem:src/main/resources/db/migration</location>
        </locations>
    </configuration>
</plugin>
```

The above Flyway Maven plugin configuration will read and execute all database migration scripts from `src/main/resources/db/migration` prior to compiling Java source code. While the official Flyway documentation may suggest that migrations be done in the `compile` phase, the jOOQ code generator relies on such migrations having been done *prior* to code generation.

After the Flyway plugin, we'll add the jOOQ Maven Plugin. For more details, please refer to the [manual's section about the code generation configuration](#codegen-configuration).

```xml
<plugin>
                <!-- Use org.jooq                for the Open Source Edition
                         org.jooq.pro            for commercial editions with Java 25 support,
                         org.jooq.pro-java-21    for commercial editions with Java 21 support,
                         org.jooq.pro-java-17    for commercial editions with Java 17 support,
                         org.jooq.pro-java-11    for commercial editions with Java 11 support,
                         org.jooq.pro-java-8     for commercial editions with Java 8 support,
                         org.jooq.trial          for the free trial edition with Java 25 support,
                         org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                         org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                         org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                         org.jooq.trial-java-8   for the free trial edition with Java 8 support
    
                 Note: Only the Open Source Edition is hosted on Maven Central.
                       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

    <groupId>org.jooq</groupId>
    <artifactId>jooq-codegen-maven</artifactId>
    <version>${org.jooq.version}</version>

    <!-- The jOOQ code generation plugin is also executed in the generate-sources phase, prior to compilation -->
    <executions>
        <execution>
            <phase>generate-sources</phase>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>

    <!-- This is a minimal working configuration. See the manual's section about the code generator for more details -->
    <configuration>
        <jdbc>
            <url>${db.url}</url>
            <user>${db.username}</user>
        </jdbc>
        <generator>
            <database>
                <includes>.*</includes>
                <inputSchema>FLYWAY_TEST</inputSchema>
            </database>
            <target>
                <packageName>org.jooq.example.flyway.db.h2</packageName>
                <directory>target/generated-sources/jooq-h2</directory>
            </target>
        </generator>
    </configuration>
</plugin>
```

This configuration will now read the `FLYWAY_TEST` schema and reverse-engineer it into the `target/generated-sources/jooq-h2` directory, and within that, into the `org.jooq.example.flyway.db.h2` package.

##### 1. Database increments

Now, when we start developing our database. For that, we'll create database increment scripts, which we put into the `src/main/resources/db/migration` directory, as previously configured for the Flyway plugin. We'll add these files:

- V1__initialise_database.sql
- V2__create_author_table.sql
- V3__create_book_table_and_records.sql

These three scripts model our schema versions 1-3 (note the capital V!). Here are the scripts' contents

```sql
-- V1__initialise_database.sql
DROP SCHEMA flyway_test IF EXISTS;

CREATE SCHEMA flyway_test;
```

```sql
-- V2__create_author_table.sql
CREATE SEQUENCE flyway_test.s_author_id START WITH 1;

CREATE TABLE flyway_test.author (
  id INT NOT NULL,
  first_name VARCHAR(50),
  last_name VARCHAR(50) NOT NULL,
  date_of_birth DATE,
  year_of_birth INT,
  address VARCHAR(50),

  CONSTRAINT pk_author PRIMARY KEY (ID)
);
```

```sql
-- V3__create_book_table_and_records.sql
CREATE TABLE flyway_test.book (
  id INT NOT NULL,
  author_id INT NOT NULL,
  title VARCHAR(400) NOT NULL,

  CONSTRAINT pk_book PRIMARY KEY (id),
  CONSTRAINT fk_book_author_id FOREIGN KEY (author_id) REFERENCES flyway_test.author(id)
);


INSERT INTO flyway_test.author VALUES (next value for flyway_test.s_author_id, 'George', 'Orwell', '1903-06-25', 1903, null);
INSERT INTO flyway_test.author VALUES (next value for flyway_test.s_author_id, 'Paulo', 'Coelho', '1947-08-24', 1947, null);

INSERT INTO flyway_test.book VALUES (1, 1, '1984');
INSERT INTO flyway_test.book VALUES (2, 1, 'Animal Farm');
INSERT INTO flyway_test.book VALUES (3, 2, 'O Alquimista');
INSERT INTO flyway_test.book VALUES (4, 2, 'Brida');
```

##### 2. Database migration and 3. Code regeneration

The above three scripts are picked up by Flyway and executed in the order of the versions. This can be seen very simply by executing:

```text
mvn clean install
```

And then observing the log output from Flyway...

```text
[INFO] --- flyway-maven-plugin:3.0:migrate (default) @ jooq-flyway-example ---
[INFO] Database: jdbc:h2:~/flyway-test (H2 1.4)
[INFO] Validated 3 migrations (execution time 00:00.004s)
[INFO] Creating Metadata table: "PUBLIC"."schema_version"
[INFO] Current version of schema "PUBLIC": << Empty Schema >>
[INFO] Migrating schema "PUBLIC" to version 1
[INFO] Migrating schema "PUBLIC" to version 2
[INFO] Migrating schema "PUBLIC" to version 3
[INFO] Successfully applied 3 migrations to schema "PUBLIC" (execution time 00:00.073s).
```

... and from jOOQ on the console:

```text
[INFO] --- jooq-codegen-maven:3.22.0-SNAPSHOT:generate (default) @ jooq-flyway-example ---
[INFO] --- jooq-codegen-maven:3.22.0-SNAPSHOT:generate (default) @ jooq-flyway-example ---
[INFO] Using this configuration:
...
[INFO] Generating schemata      : Total: 1
[INFO] Generating schema        : FlywayTest.java
[INFO] ----------------------------------------------------------
[....]
[INFO] GENERATION FINISHED!     : Total: 337.576ms, +4.299ms
```

##### 4. Development

Note that all of the previous steps are executed automatically, every time someone adds new migration scripts to the Maven module. For instance, a team member might have committed a new migration script, you check it out, rebuild and get the latest jOOQ-generated sources for your own development or integration-test database.

Now, that these steps are done, you can proceed writing your database queries. Imagine the following test case

```java
import org.jooq.Result;
import org.jooq.impl.DSL;
import org.junit.Test;

import java.sql.DriverManager;

import static java.util.Arrays.asList;
import static org.jooq.example.flyway.db.h2.Tables.*;
import static org.junit.Assert.assertEquals;

public class AfterMigrationTest {

    @Test
    public void testQueryingAfterMigration() throws Exception {
        try (Connection c = DriverManager.getConnection("jdbc:h2:~/flyway-test", "sa", "")) {
            Result<?> result =
            DSL.using(c)
               .select(
                   AUTHOR.FIRST_NAME,
                   AUTHOR.LAST_NAME,
                   BOOK.ID,
                   BOOK.TITLE
               )
               .from(AUTHOR)
               .join(BOOK)
               .on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
               .orderBy(BOOK.ID.asc())
               .fetch();

            assertEquals(4, result.size());
            assertEquals(asList(1, 2, 3, 4), result.getValues(BOOK.ID));
        }
    }
}
```

##### Reiterate

The power of this approach becomes clear once you start performing database modifications this way. Let's assume that the French guy on our team prefers to have things his way:

```sql
-- V4__le_french.sql
ALTER TABLE flyway_test.book ALTER COLUMN title RENAME TO le_titre;
```

They check it in, you check out the new database migration script, run

```text
mvn clean install
```

And then observing the log output:

```text
[INFO] --- flyway-maven-plugin:3.0:migrate (default) @ jooq-flyway-example ---
[INFO] --- flyway-maven-plugin:3.0:migrate (default) @ jooq-flyway-example ---
[INFO] Database: jdbc:h2:~/flyway-test (H2 1.4)
[INFO] Validated 4 migrations (execution time 00:00.005s)
[INFO] Current version of schema "PUBLIC": 3
[INFO] Migrating schema "PUBLIC" to version 4
[INFO] Successfully applied 1 migration to schema "PUBLIC" (execution time 00:00.016s).
```

So far so good, but later on:

```text
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] C:\...\jOOQ-flyway-example\src\test\java\AfterMigrationTest.java:[24,19] error: cannot find symbol
[INFO] 1 error
```

When we go back to our Java integration test, we can immediately see that the TITLE column is still being referenced, but it no longer exists:

```java
public class AfterMigrationTest {

    @Test
    public void testQueryingAfterMigration() throws Exception {
        try (Connection c = DriverManager.getConnection("jdbc:h2:~/flyway-test", "sa", "")) {
            Result<?> result =
            DSL.using(c)
                .select(
                    AUTHOR.FIRST_NAME,
                    AUTHOR.LAST_NAME,
                    BOOK.ID,
                    BOOK.TITLE
                    //   ^^^^^ This column no longer exists. We'll have to rename it to LE_TITRE
                )
                .from(AUTHOR)
                .join(BOOK)
                .on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
                .orderBy(BOOK.ID.asc())
                .fetch();

            assertEquals(4, result.size());
            assertEquals(asList(1, 2, 3, 4), result.getValues(BOOK.ID));
        }
    }
}
```

##### Automation

The above steps can be automated in your build using another third party called [testcontainers](https://www.testcontainers.org). Please look at this article here for examples on how to do that: [https://blog.jooq.org/using-testcontainers-to-generate-jooq-code/](https://blog.jooq.org/using-testcontainers-to-generate-jooq-code/)

##### Conclusion

This tutorial shows very easily how you can build a rock-solid development process using Flyway and jOOQ to prevent SQL-related errors very early in your development lifecycle - immediately at compile time, rather than in production!

Please, visit the [Flyway website](https://flywaydb.org/) for more information about Flyway.

<a id="jooq-with-jbang"></a>
#### 2.5.3. Using jOOQ with jbang

[jbang](https://www.jbang.dev) allows for quickly working with all sorts of Java libraries without the hassle of setting up environments, dependencies, etc. This catalog allows for using jOOQ's code generator right away on an existing database.

For more information on jbang, see:

- [Installation](https://www.jbang.dev/documentation/guide/latest/installation.html)
- [Usage](https://www.jbang.dev/documentation/guide/latest/usage.html)

##### An example

In a shell, type

```text
git clone https://github.com/jOOQ/jbang-example
cd jbang-example
jbang Example.java
```

In order to re-generate the example code, e.g. when your schema changes, just type:

```text
jbang codegen@jooq db.xml
```

If you prefer working with a pre-existing database, just edit the `db.xml` file and point it to your database. Add the JDBC driver dependency like this:

```text
jbang --deps org.postgresql:postgresql:RELEASE codegen@jooq db.xml
```

To override the jOOQ version from the default `RELEASE` to a specific version, use

```text
jbang -Djooq.version=<version> codegen@jooq db.xml
```

<a id="jooq-and-java-8"></a>
### 2.6. jOOQ and Java 8

Java 8 has introduced a great set of enhancements, among which lambda expressions and the new [`java.util.stream.Stream`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Stream.html). These new constructs align very well with jOOQ's fluent API as can be seen in the following examples:

#### jOOQ and lambda expressions

jOOQ's [RecordMapper](#recordmapper) API is fully Java-8-ready, which basically means that it is a SAM (Single Abstract Method) type, which can be instantiated using a lambda expression. Consider this example:

```java
try (Connection c = getConnection()) {
    String sql = "select schema_name, is_default " +
                 "from information_schema.schemata " +
                 "order by schema_name";

    DSL.using(c)
       .fetch(sql)

       // We can use lambda expressions to map jOOQ Records
       .map(rs -> new Schema(
           rs.getValue("SCHEMA_NAME", String.class),
           rs.getValue("IS_DEFAULT", boolean.class)
       ))

       // ... and then profit from the new Collection methods
       .forEach(System.out::println);
}
```

The above example shows how jOOQ's [`Result.map()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html#map()) method can receive a lambda expression that implements [RecordMapper](#recordmapper) to map from jOOQ [`Records`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) to your custom types.

#### jOOQ and the Streams API

jOOQ's [`Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) type extends [`java.util.List`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html), which opens up access to a variety of new Java features in Java 8. The following example shows how easy it is to transform a jOOQ `Result` containing `INFORMATION_SCHEMA` meta data to produce DDL statements:

```java
DSL.using(c)
   .select(
       COLUMNS.TABLE_NAME,
       COLUMNS.COLUMN_NAME,
       COLUMNS.TYPE_NAME
   )
   .from(COLUMNS)
   .orderBy(
       COLUMNS.TABLE_CATALOG,
       COLUMNS.TABLE_SCHEMA,
       COLUMNS.TABLE_NAME,
       COLUMNS.ORDINAL_POSITION
   )
   .fetch()  // jOOQ ends here
   .stream() // JDK 8 Streams start here
   .collect(groupingBy(
       r -> r.getValue(COLUMNS.TABLE_NAME),
       LinkedHashMap::new,
       mapping(
           r -> new Column(
               r.getValue(COLUMNS.COLUMN_NAME),
               r.getValue(COLUMNS.TYPE_NAME)
           ),
           toList()
       )
   ))
   .forEach(
       (table, columns) -> {
            // Just emit a CREATE TABLE statement
            System.out.println(
                "CREATE TABLE " + table + " (");

            // Map each "Column" type into a String
            // containing the column specification,
            // and join them using comma and
            // newline. Done!
            System.out.println(
                columns.stream()
                       .map(col -> "  " + col.name +
                                    " " + col.type)
                       .collect(Collectors.joining(",\n"))
            );

           System.out.println(");");
       }
   );
```

<a id="jooq-and-scala"></a>
### 2.7. jOOQ and Scala

As any other library, jOOQ can be easily used in Scala, taking advantage of the many Scala language features such as for example:

- Optional "." to dereference methods from expressions
- Optional "(" and ")" to delimit method argument lists
- Optional ";" at the end of a Scala statement
- Type inference using "var" and "val" keywords
- Lambda expressions and for-comprehension syntax for record iteration and data type conversion

But jOOQ also leverages other useful Scala features, such as

- implicit defs for operator overloading
- Scala Macros (soon to come)

All of the above heavily improve jOOQ's querying DSL API experience for Scala developers.

A short example jOOQ application in Scala might look like this:

```scala
import collection.JavaConversions._                                  // Import implicit defs for iteration over org.jooq.Result
                                                                     //
import java.sql.DriverManager                                        //
                                                                     //
import org.jooq._                                                    //
import org.jooq.impl._                                               //
import org.jooq.impl.DSL._                                           //
import org.jooq.examples.scala.h2.Tables._                           //
import org.jooq.scalaextensions.Conversions._                        // Import implicit defs for overloaded jOOQ/SQL operators
                                                                     //
object Test {                                                        //
  def main(args: Array[String]): Unit = {                            //
    val c = DriverManager.getConnection("jdbc:h2:~/test", "sa", ""); // Standard JDBC connection
    val e = DSL.using(c, SQLDialect.H2);                             //
    val x = AUTHOR as "x"                                            // SQL-esque table aliasing
                                                                     //
    for (r <- e                                                      // Iteration over Result. "r" is an org.jooq.Record3
        select (                                                     //
          BOOK.ID * BOOK.AUTHOR_ID,                                  // Using the overloaded "*" operator
          BOOK.ID + BOOK.AUTHOR_ID * 3 + 4,                          // Using the overloaded "+" operator
          BOOK.TITLE || " abc" || " xy"                              // Using the overloaded "||" operator
        )                                                            //
        from BOOK                                                    // No need to use parentheses or "." here
        leftOuterJoin (                                              //
          select (x.ID, x.YEAR_OF_BIRTH)                             // Dereference fields from aliased table
          from x                                                     //
          limit 1                                                    //
          asTable x.getName()                                        //
        )                                                            //
        on BOOK.AUTHOR_ID === x.ID                                   // Using the overloaded "===" operator
        where (BOOK.ID <> 2)                                         // Using the olerloaded "<>" operator
        or (BOOK.TITLE in ("O Alquimista", "Brida"))                 // Neat IN predicate expression
        fetch                                                        //
    ) {                                                              //
      println(r)                                                     //
    }                                                                //
  }                                                                  //
}
```

For more details about jOOQ's Scala integration, please refer to the manual's section about [SQL building with Scala](#scala-sql-building).

<a id="jooq-and-groovy"></a>
### 2.8. jOOQ and Groovy

As any other library, jOOQ can be easily used in Groovy, taking advantage of the many Groovy language features such as for example:

- Optional ";" at the end of a Groovy statement
- Type inference for local variables

A short example jOOQ application in Groovy might look like this:

```groovy
package org.jooq.groovy

import static org.jooq.impl.DSL.*
import static org.jooq.groovy.example.h2.Tables.*

import groovy.sql.Sql
import org.jooq.*
import org.jooq.impl.DSL

sql = Sql.newInstance('jdbc:h2:~/groovy-test', 'sa', '', 'org.h2.Driver');

a = AUTHOR.as("a");
b = BOOK.as("b")

DSL.using(sql.connection)
   .select(a.FIRST_NAME, a.LAST_NAME, b.TITLE)
   .from(a)
   .join(b).on(a.ID.eq(b.AUTHOR_ID))
   .fetchInto ({
       r -> println(
           "${r.getValue(a.FIRST_NAME)} " +
           "${r.getValue(a.LAST_NAME)} " +
           "has written ${r.getValue(b.TITLE)}"
       )
   } as RecordHandler)
```

Note that while Groovy supports [some means of operator overloading](https://groovy-lang.org/operators.html#Operator-Overloading), we think that these means should be avoided in a jOOQ integration. For instance, `a + b` in Groovy maps to a formal `a.plus(b)` method invocation, and jOOQ provides the required synonyms in its API to help you write such expressions. Nonetheless, Groovy only offers little typesafety, and as such, operator overloading can lead to many runtime issues.

Another caveat of Groovy operator overloading is the fact that operators such as `==` or `>=` map to `a.equals(b)`, `a.compareTo(b) == 0`, `a.compareTo(b) >= 0` respectively. This behaviour does not make sense in a fluent API such as jOOQ.

<a id="jooq-and-kotlin"></a>
### 2.9. jOOQ and Kotlin

As any other library, jOOQ can be easily used in Kotlin, taking advantage of the many Kotlin language features such as for example:

- Optional ";" at the end of a Kotlin statement
- Type inference for local variables

A short example jOOQ application in Kotlin might look like this:

```groovy
package org.jooq.example.kotlin

import java.util.Properties

import org.jooq.*
import org.jooq.impl.DSL
import org.jooq.impl.DSL.*

import org.jooq.example.db.h2.Tables.*

fun main(args: Array<String>) {

    val properties = Properties();
    properties.load(Properties::class.java.getResourceAsStream("/config.properties"));

    DSL.using(
        properties.getProperty("db.url"),
        properties.getProperty("db.username"),
        properties.getProperty("db.password")
    ).use { ctx ->
        val a = AUTHOR
        val b = BOOK

        ctx.select(a.FIRST_NAME, a.LAST_NAME, b.TITLE)
           .from(a)
           .join(b).on(a.ID.eq(b.AUTHOR_ID))
           .orderBy(1, 2, 3)
           .forEach {
               println("${it[b.TITLE]} by ${it[a.FIRST_NAME]} ${it[a.LAST_NAME]}")
           }
    }
}
```

Note that Kotlin supports [some means of operator overloading](https://kotlinlang.org/docs/reference/operator-overloading.html). For instance, `a + b` in Kotlin maps to a formal `a.plus(b)` method invocation, and jOOQ provides the required synonyms in its API to help you write such expressions.

One particularly nice language feature is the fact that [square brackets] allow for accessing any object's contents via `get()` and `set()` methods. Instead of using the above `value1()`, `value2()`, and `value3()` methods, we could also iterate as such:

```groovy
        ctx.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, BOOK.TITLE)
           .from(AUTHOR)
           .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
           .orderBy(1, 2, 3)
           .forEach {
               println("${it[BOOK.TITLE]} by ${it[AUTHOR.FIRST_NAME]} ${it[AUTHOR.LAST_NAME]}")
               // Notice:   ^^^^^^^^^^^^         ^^^^^^^^^^^^^^^^^^^      ^^^^^^^^^^^^^^^^^^
           }
```

A caveat of Kotlin operator overloading is the fact that operators such as `==` or `>=` map to `a.equals(b)`, `a.compareTo(b) == 0`, `a.compareTo(b) >= 0` respectively. This behaviour does not make sense in a fluent API such as jOOQ.

<a id="jooq-and-nosql"></a>
### 2.10. jOOQ and NoSQL

jOOQ users often get excited about jOOQ's intuitive API and would then wish for NoSQL support.

There are a variety of NoSQL databases that implement some sort of proprietary query language. Some of these query languages even look like SQL. Examples are [JCR-SQL2](https://www.h2database.com/jcr/grammar.html), [CQL (Cassandra Query Language)](https://cassandra.apache.org/doc/cql/CQL.html), [Cypher (Neo4j's Query Language)](https://neo4j.com/docs/cypher-manual/current/), and many more.

Mapping the jOOQ API onto these alternative query languages would be a very poor fit and a leaky abstraction. We believe in the power and expressivity of the SQL standard and its various dialects. Databases that extend this standard too much, or implement it not thoroughly enough are often not suitable targets for jOOQ. It would be better to build a new, dedicated API for just that one particular query language. E.g. for Cypher, there's [Cypher-DSL](https://github.com/neo4j/cypher-dsl), which is a much better fit.

jOOQ is about SQL, and about SQL alone.

<a id="jooq-and-jpa"></a>
### 2.11. jOOQ and JPA

Just because you're using jOOQ doesn't mean you have to use it for everything!

When introducing jOOQ into an existing application that uses JPA, the common question is always: "Should we replace JPA by jOOQ?" and "How do we proceed doing that?"

Beware that jOOQ is not a replacement for JPA. Think of jOOQ as a complement. JPA (and ORMs in general) try to solve the *object graph persistence* problem. In short, this problem is about

- Loading an entity graph into client memory from a database
- Manipulating that graph in the client
- Storing the modification back to the database

As the above graph gets more complex, a lot of tricky questions arise like:

- What's the optimal order of SQL DML operations for loading and storing entities?
- How can we batch the commands more efficiently?
- How can we keep the transaction footprint as low as possible without compromising on ACID?
- How can we implement optimistic locking?

#### jOOQ only has *some* of the answers.

While jOOQ does offer [updatable records that help running simple CRUD](#crud-with-updatablerecords), [a batch API](#batch-execution), [optimistic locking capabilities](#optimistic-locking), jOOQ mainly focuses on executing actual SQL statements.

SQL is the preferred language of database interaction, when any of the following are given:

- You run reports and analytics on large data sets directly in the database
- You import / export data using ETL
- You run complex business logic as SQL queries

Whenever SQL is a good fit, jOOQ is a good fit. Whenever you're *persisting an object graph*, JPA is a good fit. Though note that starting with jOOQ 3.15 you can also load trees with the [MULTISET_AGG function](#multiset-agg-function) and the [MULTISET value constructor](#multiset-value-constructor) very easily.

And sometimes, [it's best to combine both](#using-jooq-with-jpa)

<a id="build-your-own"></a>
### 2.12. Build your own

In order to build jOOQ (Open Source Edition) yourself, please download the sources from [https://github.com/jOOQ/jOOQ](https://github.com/jOOQ/jOOQ) and use Maven to build jOOQ, preferably in Eclipse. The jOOQ Open Source Edition requires Java 8+ to compile and run. The commercial jOOQ Editions require Java 8+ or Java 6+ to compile and run, depending on the distribution.

Some useful hints to build jOOQ yourself:

- Get the latest version of [Git](https://git-scm.com) or [EGit](https://www.eclipse.org/egit)
- Get the latest version of [Maven](https://maven.apache.org) or [M2E](https://eclipse.org/m2e)
- Check out the jOOQ sources from [https://github.com/jOOQ/jOOQ](https://github.com/jOOQ/jOOQ)
- Optionally, import Maven artefacts into an Eclipse workspace using the following command (see the [maven-eclipse-plugin](https://maven.apache.org/plugins/maven-eclipse-plugin/) documentation for details):
  - `mvn eclipse:eclipse`

- Build the `jooq-parent` artefact by using any of these commands:
  - `mvn clean package`  
    create .jar files in `${project.build.directory}`
  - `mvn clean install`  
    install the .jar files in your local repository (e.g. `~/.m2`)
  - `mvn clean {goal} -Dmaven.test.skip=true`  
    don't run unit tests when building artefacts

<a id="semantic-versioning"></a>
### 2.13. jOOQ and backwards-compatibility

#### Semantic versioning

jOOQ's understanding of backwards compatibility is inspired by the rules of semantic versioning according to [https://semver.org](https://semver.org). Those rules impose a versioning scheme [X].[Y].[Z] that can be summarised as follows:

- If a patch release includes bugfixes, performance improvements and API-irrelevant new features, [Z] is incremented by one.
- If a minor release includes backwards-compatible, API-relevant new features, [Y] is incremented by one and [Z] is reset to zero.
- If a major release includes backwards-incompatible, API-relevant new features, [X] is incremented by one and [Y], [Z] are reset to zero.

#### jOOQ's understanding of backwards-compatibility

Backwards-compatibility is important to jOOQ. You've chosen jOOQ as a strategic SQL engine and you don't want your SQL to break.

However, there are some elements of API evolution that would be considered backwards-incompatible in other APIs, but not in jOOQ. As discussed later on in the section about [jOOQ's query DSL API](#dsl-api), much of jOOQ's API is indeed an internal domain-specific language implemented mostly using Java interfaces. Adding language elements to these interfaces means any of these actions:

- Adding methods to the interface
- Overloading methods for convenience
- Changing the type hierarchy of interfaces (including raw type or binary compatibility implications)

It becomes obvious that it would be impossible to add new language elements (e.g. new [SQL functions](#column-expressions), new [SELECT clauses](#select-statement)) to the API without breaking any client code that actually implements those interfaces. Hence, the following rules should be observed:

- jOOQ's DSL interfaces should not be implemented by client code! Extend only those extension points that are explicitly documented as "extendable" (e.g. [custom QueryParts](#custom-queryparts)).
- Generated code implements such interfaces and extends internal classes, and as such is recommended to be re-generated with a matching code generator version every time the runtime library is upgraded.
- Binary compatibility can be expected from patch releases, but not from minor releases as it is not practical to maintain binary compatibility in an internal DSL.
- Source compatibility can be expected from patch and minor releases, the exception being raw type compatibility (see [#11879](https://github.com/jOOQ/jOOQ/issues/11879)), and rare exceptions where API design is clearly lacking.
- Behavioural compatibility can be expected from patch and minor releases.
- Any jOOQ SPI `XYZ` that is meant to be implemented ships with a `DefaultXYZ` or `AbstractXYZ`, which can be used safely as a default implementation.

#### jOOQ-codegen and jOOQ-meta

While a reasonable amount of care is spent to maintain these two modules under the rules of semantic versioning, it may well be that minor releases introduce backwards-incompatible changes. This will be announced in the respective release notes and should be the exception.

<a id="sql-building"></a>
## 3. SQL building

SQL is a declarative language that is hard to integrate into procedural, object-oriented, functional or any other type of programming languages. jOOQ's philosophy is to give SQL the credit it deserves and integrate SQL itself as an ["internal domain specific language"](https://en.wikipedia.org/wiki/Domain_Specific_Language) directly into Java.

With this philosophy in mind, SQL building is the main feature of jOOQ. All other features (such as [SQL execution](#sql-execution) and [code generation](#code-generation)) are mere convenience built on top of jOOQ's SQL building capabilities.

This section explains all about the various syntax elements involved with jOOQ's SQL building capabilities. For a complete overview of all syntax elements, please refer to the manual's sections about [SQL to DSL mapping rules](#dsl-mapping-rules).

<a id="dsl"></a>
### 3.1. The query DSL type

jOOQ exposes a lot of interfaces and hides most implementation facts from client code. The reasons for this are:

- Interface-driven design. This allows for modelling queries in a fluent API most efficiently
- Reduction of complexity for client code.
- API guarantee. You only depend on the exposed interfaces, not concrete (potentially dialect-specific) implementations.

The [`org.jooq.impl.DSL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html) class is the main class from where you will create all jOOQ objects. It serves as a static factory for [table expressions](#table-expressions), [column expressions](#column-expressions) (or "fields"), [conditional expressions](#conditional-expressions) and many other [QueryParts](#queryparts).

#### The static query DSL API

With jOOQ 2.0, static factory methods have been introduced in order to make client code look more like SQL. Ideally, when working with jOOQ, you will simply static import all methods from the DSL class:

```java
import static org.jooq.impl.DSL.*;
```

Note, that when working with Eclipse, you could also add the DSL to your favourites. This will allow to access functions even more fluently:

```java
concat(trim(FIRST_NAME), trim(LAST_NAME));

// ... which is in fact the same as:
DSL.concat(DSL.trim(FIRST_NAME), DSL.trim(LAST_NAME));
```

<a id="dsl-context"></a>
### 3.2. The DSLContext API

DSLContext references a [`org.jooq.Configuration`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Configuration.html), an object that configures jOOQ's behaviour when executing queries (see [SQL execution](#sql-execution) for more details). Unlike the static DSL, the DSLContext allow for creating [SQL statements](#sql-statements) that are already "configured" and ready for execution.

#### Fluent creation of a DSLContext object

The DSLContext object can be created fluently from the [DSL type](#dsl):

```java
// Create it from a pre-existing configuration
DSLContext create = DSL.using(configuration);

// Create it from ad-hoc arguments
DSLContext create = DSL.using(connection, dialect);
```

If you do not have a reference to a pre-existing Configuration object (e.g. created from [`org.jooq.impl.DefaultConfiguration`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultConfiguration.html)), the various overloaded `DSL.using()` methods will create one for you.

#### Contents of a Configuration object

A Configuration can be supplied with these objects:

- [`org.jooq.SQLDialect`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html) : The dialect of your database. This may be any of the currently supported database types (see [SQL Dialect](#sql-dialects) for more details)
- [`org.jooq.conf.Settings`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html) : An optional runtime configuration (see [Custom Settings](#custom-settings) for more details)
- [`org.jooq.ExecuteListenerProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ExecuteListenerProvider.html) : To provide execution lifecycle listeners (see [ExecuteListeners](#execute-listeners) for more details)
- [`org.jooq.ParseListenerProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ParseListenerProvider.html) : To provide custom parser extensions (see [SQL Parser Listener](#sql-parser-listener) for more details)
- [`org.jooq.RecordListenerProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RecordListenerProvider.html) : To provide record listeners for your CRUD operations (see [RecordListener SPI](#crud-record-listener) for more details)
- [`org.jooq.RecordMapperProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RecordMapperProvider.html) : To provide an alternative default record mapper implementation (see [RecordMapperProvider](#recordmapperprovider) for more details)
- [`org.jooq.FormattingProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/FormattingProvider.html) : To provide custom default data export formats (see [FormattingProvider](#formatting-provider) for more details)
- [`org.jooq.PolicyProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/PolicyProvider.html): To provide custom policies (see [Policies](#policies) for more details)
- JDBC access:
  - [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html) : An optional JDBC Connection that will be re-used for the whole lifecycle of your Configuration (see [Connection vs. DataSource](#connection-vs-datasource) for more details). For simplicity, this is the use-case referenced from this manual, most of the time.
  - [`java.sql.DataSource`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/DataSource.html) : An optional JDBC DataSource that will be re-used for the whole lifecycle of your Configuration. If you prefer using DataSources over Connections, jOOQ will internally fetch new Connections from your DataSource, conveniently closing them again after query execution. This is particularly useful in Java EE or Spring contexts (see [Connection vs. DataSource](#connection-vs-datasource) for more details)
  - [`org.jooq.ConnectionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ConnectionProvider.html) : A custom abstraction that is used by jOOQ to "acquire" and "release" connections. jOOQ will internally "acquire" new Connections from your ConnectionProvider, conveniently "releasing" them again after query execution. (see [Connection vs. DataSource](#connection-vs-datasource) for more details)

- R2DBC access:
  - [`io.r2dbc.spi.Connection`](https://r2dbc.io/spec/0.9.0.M2/api/io/r2dbc.spi/Connection.html) : An optional R2DBC Connection that will be re-used for the whole lifecycle of your Configuration (see [Connection vs. DataSource](#connection-vs-datasource) for more details). For simplicity, this is the use-case referenced from this manual, most of the time.
  - [`io.r2dbc.spi.ConnectionFactory`](https://r2dbc.io/spec/0.9.0.M2/api/io/r2dbc.spi/ConnectionFactory.html) : An optional R2DBC ConnectionFactory that will be re-used for the whole lifecycle of your Configuration. If you prefer using ConnectionFactories over Connections, jOOQ will internally fetch new Connections from your ConnectionFactory, conveniently closing them again after query execution. This is particularly useful in Spring contexts (see [Connection vs. DataSource](#connection-vs-datasource) for more details)

#### Usage of DSLContext

Wrapping a Configuration object, a DSLContext can construct [statements](#sql-statements), for later [execution](#sql-execution). An example is given here:

```java
// The DSLContext is "configured" with a Connection and a SQLDialect
DSLContext create = DSL.using(connection, dialect);

// This select statement contains an internal reference to the DSLContext's Configuration:
Select<?> select = create.selectOne();

// Using the internally referenced Configuration, the select statement can now be executed:
Result<?> result = select.fetch();
```

Note that you do not need to keep a reference to a DSLContext. You may as well inline your local variable, and fluently execute a SQL statement as such:

```java
// Execute a statement from a single execution chain:
Result<?> result =
DSL.using(connection, dialect)
   .select()
   .from(BOOK)
   .where(BOOK.TITLE.like("Animal%"))
   .fetch();
```

<a id="sql-dialects"></a>
#### 3.2.1. SQL Dialect

While jOOQ tries to represent the SQL standard as much as possible, many features are vendor-specific to a given database and to its "SQL dialect". jOOQ models this using the [`org.jooq.SQLDialect`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html) enum type.

The SQL dialect is one of the main attributes of a [Configuration](#dsl-context). Queries created from DSLContexts will assume dialect-specific behaviour when [rendering SQL](#sql-rendering) and [binding bind values](#variable-binding).

Some parts of the jOOQ API are officially supported only by a given subset of the supported SQL dialects. For instance, the [Oracle CONNECT BY clause](#connect-by-clause), which is supported by the Oracle and Informix databases, is annotated with a [`org.jooq.Support`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Support.html) annotation, as such:

```java
/**
 * Add an Oracle-specific <code>CONNECT BY</code> clause to the query
 */
@Support({ SQLDialect.INFORMIX, SQLDialect.ORACLE })
SelectConnectByConditionStep<R> connectBy(Condition condition);
```

jOOQ API methods which are not annotated with the [`org.jooq.Support`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Support.html) annotation, or which are annotated with the Support annotation, but without any SQL dialects can be safely used in all SQL dialects. An example for this is the [SELECT statement](#select-statement) factory method:

```java
/**
 * Create a new DSL select statement.
 */
@Support
SelectSelectStep<R> select(Field<?>... fields);
```

##### jOOQ's SQL clause emulation capabilities

The aforementioned Support annotation does not only designate, which databases natively support a feature. It also indicates that a feature is emulated by jOOQ for some databases lacking this feature. An example of this is the [DISTINCT predicate](#distinct-predicate), a predicate syntax defined by SQL:1999 and implemented only by H2, HSQLDB, and Postgres:

```sql
A IS DISTINCT FROM B
```

Nevertheless, the `IS DISTINCT FROM` predicate is supported by jOOQ in all dialects, as its semantics can be expressed with an equivalent [CASE expression](#case-expressions). For more details, see the manual's section about the [DISTINCT predicate](#distinct-predicate).

##### jOOQ and the Oracle SQL dialect

Oracle SQL is much more expressive than many other SQL dialects. It features many unique keywords, clauses and functions that are out of scope for the SQL standard. Some examples for this are

- The [CONNECT BY clause](#connect-by-clause), for hierarchical queries
- The [PIVOT](#pivot-tables) keyword for creating PIVOT tables
- [Packages](#oracle-packages), [object-oriented user-defined types, member procedures](#oracle-member-procedures) as described in the section about [stored procedures and functions](#stored-procedures)
- Advanced analytical functions as described in the section about [window functions](#window-functions)

jOOQ has a historic affinity to Oracle's SQL extensions. If something is supported in Oracle SQL, it has a high probability of making it into the jOOQ API

<a id="sql-dialect-family"></a>
#### 3.2.2. SQL Dialect Family

In jOOQ 3.1, the notion of a `SQLDialect.family()` was introduced, in order to group several similar [SQL dialects](#sql-dialects) into a common family. An example for this is SQL Server, which is supported by jOOQ in various versions:

- [`SQL Server`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html#SQLSERVER): The "version-less" SQL Server version. This always maps to the latest supported version of SQL Server
- [`SQL Server 2012`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html#SQLSERVER2012): The SQL Server version 2012
- [`SQL Server 2008`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html#SQLSERVER2008): The SQL Server version 2008

In the above list, `SQLSERVER` is both a dialect and a family of three dialects. This distinction is used internally by jOOQ to distinguish whether to use the [OFFSET .. FETCH](#limit-clause) clause (SQL Server 2012), or whether to emulate it using `ROW_NUMBER() OVER()` (SQL Server 2008).

<a id="sql-dialect-category"></a>
#### 3.2.3. SQL Dialect Category

In jOOQ 3.18, the notion of a `SQLDialect.category()` was introduced, in order to group several similar [SQL dialect families](#sql-dialect-family) into a common category. An example for this is T-SQL, which is supported by jOOQ in various versions:

- [`SQL Data Warehouse`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html#SQLDATAWAREHOUSE)
- [`SQL Server`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html#SQLSERVER)
- [`Sybase ASE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html#ASE)
- [`Sybase SQL Anywhere`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html#SYBASE)

Categories are sets of families that often expose similar syntax, due to a common ancestor. Categories include:

- `MYSQL`
- `POSTGRES`
- `TSQL`

<a id="connection-vs-datasource"></a>
#### 3.2.4. Connection vs. DataSource

##### Interact with JDBC Connections

While you can use jOOQ for [SQL building](#sql-building) only, you can also run queries against a JDBC [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html). Internally, jOOQ creates [`java.sql.Statement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html) or [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html) objects from such a Connection, in order to execute statements. The normal operation mode is to provide a [Configuration](#dsl-context) with a JDBC Connection, whose lifecycle you will control yourself. This means that jOOQ will not actively close connections, rollback or commit transactions.

Note, in this case, jOOQ will internally use a [`org.jooq.impl.DefaultConnectionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultConnectionProvider.html), which you can reference directly if you prefer that. The DefaultConnectionProvider exposes various transaction-control methods, such as commit(), rollback(), etc.

##### Interact with JDBC DataSources

If you're in a Java EE or Spring context, however, you may wish to use a [`javax.sql.DataSource`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/javax/sql/DataSource.html) instead. Connections obtained from such a DataSource will be closed after query execution by jOOQ. The semantics of such a close operation should be the returning of the connection into a connection pool, not the actual closing of the underlying connection. Typically, this makes sense in an environment using distributed JTA transactions.

Note, in this case, jOOQ will internally use a [`org.jooq.impl.DataSourceConnectionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DataSourceConnectionProvider.html), which you can reference directly if you prefer that.

##### Inject custom behaviour

If your specific environment works differently from any of the above approaches, you can inject your own custom implementation of a ConnectionProvider into jOOQ. This is the API contract you have to fulfil:

```java
public interface ConnectionProvider {

    // Provide jOOQ with a connection
    Connection acquire() throws DataAccessException;

    // Get a connection back from jOOQ
    void release(Connection connection) throws DataAccessException;
}
```

##### Reactive querying

If you wish to use an [R2DBC](https://r2dbc.io) driver, you do not have to supply a [`org.jooq.ConnectionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ConnectionProvider.html) to your [Configuration](#dsl-context). Instead, jOOQ can work with a [`io.r2dbc.spi.Connection`](https://r2dbc.io/spec/0.9.0.M2/api/io/r2dbc.spi/Connection.html) (jOOQ will never close it) or [`io.r2dbc.spi.ConnectionFactory`](https://r2dbc.io/spec/0.9.0.M2/api/io/r2dbc.spi/ConnectionFactory.html) (jOOQ will close all R2DBC Connections that it creates).

<a id="custom-data"></a>
#### 3.2.5. Custom data

In advanced use cases of integrating your application with jOOQ, you may want to put custom data into your [Configuration](#dsl-context), which you can then access from your...

- [Custom ExecuteListeners](#custom-execute-listeners)
- [Custom QueryParts](#custom-queryparts)

Here is an example of how to use the custom data API. Let's assume that you have written an [ExecuteListener](#execute-listeners), that prevents `INSERT` statements, when a given flag is set to `true`:

```java
public class NoInsertListener implements ExecuteListener {

    @Override
    public void start(ExecuteContext ctx) {

        // This listener is active only, when your custom flag is set to true
        if (Boolean.TRUE.equals(ctx.configuration().data("com.example.my-namespace.no-inserts"))) {

            // If active, fail this execution, if an INSERT statement is being executed
            if (ctx.query() instanceof Insert) {
                throw new DataAccessException("No INSERT statements allowed");
            }
        }
    }
}
```

See the manual's section about [ExecuteListeners](#execute-listeners) to learn more about how to implement an `ExecuteListener`.

Now, the above listener can be added to your [Configuration](#dsl-context), but you will also need to pass the flag to the `Configuration`, in order for the listener to work:

```java
// Create your Configuration
Configuration configuration = new DefaultConfiguration().set(connection).set(dialect);

// Set a new execute listener provider onto the configuration:
configuration.set(new DefaultExecuteListenerProvider(new NoInsertListener()));

// Use any String literal to identify your custom data
configuration.data("com.example.my-namespace.no-inserts", true);

// Try to execute an INSERT statement
try {
    DSL.using(configuration)
       .insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
       .values(1, "Orwell")
       .execute();

    // You shouldn't get here
    Assert.fail();
}

// Your NoInsertListener should be throwing this exception here:
catch (DataAccessException expected) {
    Assert.assertEquals("No INSERT statements allowed", expected.getMessage());
}
```

Using the `data()` methods, you can store and retrieve custom data in your `Configurations`.

<a id="custom-execute-listeners"></a>
#### 3.2.6. Custom ExecuteListeners

`ExecuteListeners` are a useful tool to...

- implement custom logging
- apply triggers written in Java
- collect query execution statistics

ExecuteListeners are hooked into your [Configuration](#dsl-context) by returning them from an [`org.jooq.ExecuteListenerProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ExecuteListenerProvider.html):

```java
// Create your Configuration
Configuration configuration = new DefaultConfiguration().set(connection).set(dialect);

// Hook your listener providers into the configuration:
configuration.set(
    new DefaultExecuteListenerProvider(new MyFirstListener()),
    new DefaultExecuteListenerProvider(new PerformanceLoggingListener()),
    new DefaultExecuteListenerProvider(new NoInsertListener())
);
```

See the manual's section about [ExecuteListeners](#execute-listeners) to see examples of such listener implementations.

<a id="custom-unwrappers"></a>
#### 3.2.7. Custom Unwrappers

JDBC knows the [`java.sql.Wrapper`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Wrapper.html) API, which is implemented by all JDBC types in order to be able to "unwrap" a native driver implementation for any given type. For example:

```java
// This may be some proxy from a connection pool
Connection c = getConnection();

// Sometimes, we want the native driver connection instance
OracleConnection oc = c.unwrap(OracleConnection.class);
Array array = oc.createARRAY("ARRAY_TYPE", new Object[] { "a", "b" });
```

jOOQ internally makes similar calls occasionally. For this, it needs to unwrap the native [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html) or [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html) instance. Unfortunately, not all third party libraries correctly implement the `Wrapper` API contract, so this unwrapping might not work. The [`org.jooq.Unwrapper`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Unwrapper.html) SPI is designed to allow for custom implementations to be injected into jOOQ configurations:

```java
// Your jOOQ configuration
Configuration c1 = getConfiguration();
Configuration c2 = c.derive(new Unwrapper() {
    @Override
    public <T> T unwrap(Wrapper wrapper, Class<T> iface) {
        try {
            if (wrapper instanceof Connection)
                // ...
            else if (wrapper instanceof Statement)
                // ...
            else
                wrapper.unwrap(iface);
        }
        catch (SQLException e) {
            // ...
        }
    }
});

// Work with the derived configuration, where needed
DSL.using(c2).fetch("...");
```

<a id="custom-settings"></a>
#### 3.2.8. Custom Settings

The jOOQ Configuration allows for some optional configuration elements to be used by advanced users. The [`org.jooq.conf.Settings`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html) class is a JAXB-annotated type, that can be provided to a Configuration in several ways:

- In the DSLContext constructor (`DSL.using()`). This will override default settings below
- in the [`org.jooq.impl.DefaultConfiguration`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultConfiguration.html) constructor. This will override default settings below
- From a location specified by a JVM parameter: -Dorg.jooq.settings
- From the classpath at /jooq-settings.xml
- From the settings defaults, as specified in [https://www.jooq.org/xsd/jooq-runtime-3.22.0.xsd](https://www.jooq.org/xsd/jooq-runtime-3.22.0.xsd)

The most specific settings for a given context will apply.

If you wish to configure your settings through XML, but explicitly load them for a given `Configuration`, you can do so as well, using JAXB:

```java
Settings settings = JAXB.unmarshal(new File("/path/to/settings.xml"), Settings.class);
```

##### Example

For example, if you want to indicate to jOOQ, that it should inline all bind variables, and execute static [`java.sql.Statement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html) instead of binding its variables to [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html), you can do so by creating the following DSLContext:

```java
Settings settings = new Settings();
settings.setStatementType(StatementType.STATIC_STATEMENT);
DSLContext create = DSL.using(connection, dialect, settings);
```

##### More details

Please refer to the jOOQ runtime configuration XSD for more details:  
[https://www.jooq.org/xsd/jooq-runtime-3.22.0.xsd](https://www.jooq.org/xsd/jooq-runtime-3.22.0.xsd)

<a id="settings-attach-records"></a>
##### 3.2.8.1. Auto-attach Records

By default, all records fetched through jOOQ are "attached" to the [configuration](#dsl-context) that created them. This allows for features like [updatable records](#crud-with-updatablerecords) as can be seen here:

```java
AuthorRecord author =
DSL.using(configuration) // This configuration will be attached to any record produced by the below query.
   .selectFrom(AUTHOR)
   .where(AUTHOR.ID.eq(1))
   .fetchOne();

author.setLastName("Smith");
author.store(); // This store call operates on the "attached" configuration.
```

In some cases (e.g. when serialising records), it may be desirable not to attach the `Configuration` that created a record to the record. This can be achieved with the `attachRecords` setting:

**Example configuration**

```java
Settings settings = new Settings()
    .withAttachRecords(false); // Defaults to true
```

<a id="settings-auto-inline-bind-values"></a>
##### 3.2.8.2. Auto-inline bind values

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

[Bind values](#bind-values) are an important concept in SQL, for performance reasons, as they simplify caching of prepared statements in some RDBMS. jOOQ always creates bind values by default, when you write this:

```sql
-- Normally, a bind parameter marker is generated
AUTHOR.ID = ?
```

```java
// This is the same as AUTHOR.ID.eq(val(1, AUTHOR.ID))
AUTHOR.ID.eq(1);
```

In some cases, however, it is better not to use a bind variable, but to create [inline values](#inlined-parameters), instead, so the optimiser can better apply its statistics. This is useful mainly when:

- The column is a constant discriminator column in a view, for example
- The column has very skewed statistics and only few possible values (e.g. a `BOOLEAN`, an `ENUM` type or a `CHECK COL IN (1, 2, 3)`) constraint.

In those cases, it can be useful to enable `Settings.transformInlineBindValuesForFieldComparisons` and implement a [`org.jooq.TransformProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TransformProvider.html) as follows:

```java
Configuration configuration = ...
configuration.settings().setTransformInlineBindValuesForFieldComparisons(true);
configuration.set(new TransformProvider() {
    @Override
    public boolean inlineBindValuesForFieldComparisons(Field<?> field) {
        return field.getType() == Boolean.class
            || field.getDataType().isEnum(); // Or, perhaps, limit this only to certain enums
    }
});
```

Now, all queries whose predicates match the above `TransformProvider` content will have their relevant bind values inlined. For example:

```sql
-- Inlining applies to some columns now, not all
AUTHOR.ID = ? AND AUTHOR.STATUS = 'ACTIVE'
```

```java
AUTHOR.ID.eq(1).and(
    AUTHOR.STATUS.eq(Status.ACTIVE));
```

Related settings include:

- [Inline Threshold](#settings-inline-threshold)
- [Statement Type](#settings-statement-type)

<a id="settings-backslash-escaping"></a>
##### 3.2.8.3. Backslash Escaping

Some databases (mainly MySQL and MariaDB) unfortunately chose to go an alternative, non-SQL-standard route when escaping string literals. Here's an example of how to escape a string containing apostrophes in different dialects:

```sql
SELECT 'I''m sure this is OK' AS val             -- Standard SQL escaping of apostrophe by doubling it.
SELECT 'I\'m certain this causes trouble' AS val -- Vendor-specific escaping of apostrophe by using a backslash.
```

As most databases don't support backslash escaping (and MySQL also allows for turning it off!), jOOQ by default also doesn't support it when [inlining bind variables](#inlined-parameters). However, this can lead to SQL injection vulnerabilities and syntax errors when not dealing with it carefully!

This feature is turned on by default and for historic reasons for MySQL and MariaDB.

- `DEFAULT` (the - surprise! - default): Turns the feature `ON` for MySQL and MariaDB and `OFF` for all other dialects
- `ON`: Turn the feature on.
- `OFF`: Turn the feature off.

**Example configuration**

```java
Settings settings = new Settings()
    .withBackslashEscaping(BackslashEscaping.OFF); // Default to DEFAULT
```

<a id="settings-batch-size"></a>
##### 3.2.8.4. Batch size

jOOQ offers a [transparent batching API](#batched-connection), which can buffer all statements generated by jOOQ and other JDBC backed APIs transparently in order to batch them:

```java
// Everything in the below lambda will be buffered and batched
DSL.using(configuration).batched(c -> {
    module1.insertSomething(c);
    module2.insertSomethingElse(c);
});
```

Use the `Settings.batchSize` flag to govern the maximum batch statement size of this API:

```java
Settings settings = new Settings()
    .withBatchSize(100); // Default Integer.MAX_VALUE
```

Starting from jOOQ 3.19, this `Settings.batchSize` flag also applies to most other batch API.

<a id="settings-param-cast-mode"></a>
##### 3.2.8.5. Bind value casting

Most databases can infer the data type of a [bind value](#bind-values) from the context in which it is used. Some databases, however, cannot delay the type inference until the statement is executed, and either reject a bind value of unknown type, or assume a possibly inappropriate type. In those cases, jOOQ wraps the bind value in an explicit `CAST(? AS datatype)` expression to help the database's SQL parser. The `paramCastMode` setting governs this behaviour. The possible values of [`org.jooq.conf.ParamCastMode`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/ParamCastMode.html) are:

- `DEFAULT` (the default): Bind values are cast to their data types only when jOOQ thinks it is needed. The exact behaviour of this mode depends on the dialect, and is subject to change.
- `ALWAYS`: Bind values are always cast to their data types.
- `NEVER`: Bind values are never cast to their data types. You may still add explicit casts yourself using [the CAST() function](#cast-expressions).

The setting applies both to bind variable placeholders and to [inline values](#inlined-parameters).

**Example configuration**

```java
Settings settings = new Settings()
    .withParamCastMode(ParamCastMode.NEVER); // Defaults to DEFAULT
```

<a id="settings-computed-column-activation"></a>
##### 3.2.8.6. Computed column activation

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

[Client side computed columns](#codegen-database-forced-types-computed) including [audit columns](#codegen-database-forced-types-audit) are a useful feature to replace [server side computed columns](#computed-columns) where the computational expression is dynamic, or uses some advanced jOOQ feature like [implicit JOIN](#implicit-join), or if the RDBMS does not support the feature.

In some cases, users may wish to deactivate the feature for the scope of a few individual queries, e.g. to load data into a table where computed values have already been provided.

**Example configuration**

```java
Settings settings = new Settings()
    .withComputedOnClientVirtual(false) // Defaults to true
    .withComputedOnClientStored(false); // Defaults to true
```

> [!TIP]
> In a lot of cases, it doesn't suffice to turn off the [client side computed columns](#codegen-database-forced-types-computed), but if data needs to be inserted / updated into these columns, then the [readonly column feature](#settings-readonly-columns) may also have to be deactivated!

**Example configuration, including readonly column feature**

```java
Settings settings = new Settings()
    .withComputedOnClientStored(false)         // Defaults to true
    .withReadonlyInsert(WRITE)                 // Defaults to IGNORE
    .withReadonlyUpdate(WRITE)                 // Defaults to IGNORE
    .withReadonlyTableRecordInsert(WRITE)      // Defaults to IGNORE
    .withReadonlyUpdatableRecordUpdate(WRITE); // Defaults to IGNORE
```

<a id="settings-computed-column-emulation"></a>
##### 3.2.8.7. Computed column emulation

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Server side [computed columns](#computed-columns) are a useful feature of many RDBMS, where a synthetic column expression is always computed based on other columns of the same row, either on read (`VIRTUAL`) or on write (`STORED`). Recent versions of jOOQ have added support for [client side computed columns](#codegen-database-forced-types-computed), i.e. columns that are computed by jOOQ in the client rather than by the RDBMS on the server side. This can be especially useful if the computational expression is dynamic, or uses some advanced jOOQ feature like [implicit JOIN](#implicit-join), or if the RDBMS does not support the feature.

In the latter case, if the RDBMS does not support the feature, jOOQ can emulate it for you based on a schema generated from an RDBMS that does support the feature. E.g. when the schema is generated with `H2` but the query is run on `TRINO`, jOOQ can run the computation directly in generated SQL, for both (`VIRTUAL`) or (`STORED`) cases:

**Example configuration**

```java
Settings settings = new Settings()
    .withEmulateComputedColumns(true); // Defaults to false
```

<a id="settings-constructor-parameter-names"></a>
##### 3.2.8.8. Constructor parameter mapping

When [mapping records into immutable classes](#pojos), the [DefaultRecordMapper](#recordmapper) calls a constructor. If it cannot discover the constructor's parameter names, it has to match record values to constructor parameters by position. A set of settings governs where parameter names are looked up, so that values can be matched by name instead:

- `mapConstructorPropertiesParameterNames` (defaults to `true`): Whether to use the names declared by the [`java.beans.ConstructorProperties`](https://docs.oracle.com/en/java/javase/25/docs/api/java.desktop/java/beans/ConstructorProperties.html) annotation.The annotation is looked up through the [`org.jooq.ConstructorPropertiesProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ConstructorPropertiesProvider.html) SPI, whose default implementation is in the [jOOQ-beans-extensions module](#module-jooq-beans-extensions).
- `mapRecordComponentParameterNames` (defaults to `false`): Whether to use the component names of a Java [`java.lang.Record`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Record.html) class.
- `mapConstructorParameterNamesInKotlin` (defaults to `true`): Whether to use the parameter names of a Kotlin class's primary constructor, which requires `kotlin-reflect` on the classpath. This has no effect on Java classes.
- `mapConstructorParameterDefaultsInKotlin` (defaults to `true`): Whether to apply Kotlin constructor parameter default values to parameters that cannot be mapped from any column of the record, instead of `null`.
- `mapNullToConstructorParameterDefaultsInKotlin` (defaults to `false`): Whether to also apply Kotlin constructor parameter default values to non-nullable parameters whose column value is `NULL`. Nullable parameters always receive `NULL` values, as an explicit `NULL` is semantically different from an absent value. This has no effect if `mapConstructorParameterDefaultsInKotlin` is turned off.
- `mapConstructorParameterNames` (defaults to `false`): Whether to use parameter names obtained through Java reflection, using [`Executable.getParameters()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/reflect/Executable.html#getParameters()). Parameter names are only available if the class was compiled with the `javac -parameters` flag.

For example, with `mapRecordComponentParameterNames` turned on, the following projection is mapped by name, even though the order of columns differs from the order of record components:

```java
record BookInfo(String title, int id) {}

List<BookInfo> books = create
    .select(BOOK.ID, BOOK.TITLE)
    .from(BOOK)
    .fetchInto(BookInfo.class);
```

In Kotlin, parameters with default values may be omitted from the projection:

```kotlin
data class BookInfo(val id: Int, val title: String, val language: String = "en")

// There is no LANGUAGE column in the projection, so the default value "en" is applied
val books = ctx
    .select(BOOK.ID, BOOK.TITLE)
    .from(BOOK)
    .fetchInto(BookInfo::class.java)
```

**Example configuration**

```java
Settings settings = new Settings()
    .withMapConstructorParameterNames(true)      // Defaults to false
    .withMapRecordComponentParameterNames(true); // Defaults to false
```

<a id="settings-diagnostics-connection"></a>
##### 3.2.8.9. Diagnostics Connection

The `diagnosticsConnection` setting allows for turning on/off the [diagnostics](#diagnostics) functionality within jOOQ.

There are 3 possible values:

- `DEFAULT`: By default, the diagnostics functionality is turned off, but can be used explicitly via [`DSLContext.diagnosticsConnection()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#diagnosticsConnection()) or [`DSLContext.diagnosticsDataSource()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#diagnosticsDataSource()). This is ideal when building custom diagnostics utilities on top of jOOQ's SPIs.
- `ON`: The diagnostics connection is activated implicitly on any JDBC [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html) that jOOQ works with. This is ideal when quickly turning on diagnostics on a development or integration test environment.
- `OFF`: The diagnostics connection is deactivated even when used explicitly.

**Example configuration**

```java
Settings settings = new Settings()
    .withDiagnosticsConnection(DiagnosticsConnection.ON); // Defaults to DEFAULT
```

<a id="settings-diagnostics-logging"></a>
##### 3.2.8.10. Diagnostics Logging

The `diagnosticsLogging` setting turns off the default [diagnostics](#diagnostics) logging implemented through [`org.jooq.impl.LoggingDiagnosticsListener`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/LoggingDiagnosticsListener.html)

**Example configuration**

```java
Settings settings = new Settings()
    .withDiagnosticsLogging(false); // Defaults to true
```

<a id="settings-dialect-compatibility"></a>
##### 3.2.8.11. Dialect compatibility

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

When supporting multiple dialects, there are some dialect specific behaviours that are inconsistent between dialects. This is especially true for `NULL` values in Oracle.

The following settings govern dialect compatibility behaviour:

- `Settings.renderCoalesceToEmptyStringInConcat`: This flag will use [COALESCE](#coalesce-function) on all operands of a [String concatenation expression](#concat-function) in order to turn `NULL` values to `''`, which is Oracle's more useful, but not standards compliant behaviour.
- `Settings.renderNullifEmptyStringForBindValues`: This flag wraps [string typed bind values](#bind-values) in a [NULLIF(?, '') expression](#nullif-function) in order to turn `""` input values back into `NULL`, which is what Oracle does for the `VARCHAR2` and `CLOB` data types, which don't have an empty string representation.

<a id="settings-dirty-tracking"></a>
##### 3.2.8.12. Dirty tracking

A [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) has a set of [internal flags used for dirty tracking](#internal-flags). The dirty tracking settings allow for specifying whether [`Record#touched()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#touched()) or [`Record#modified()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#modified()) flags should be used.

- [`TOUCHED`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/RecordDirtyTracking.html#TOUCHED): The default is to track any "touching" of a record value, i.e. any call to a `Record.set()` method, assuming that even if a value hasn't changed, the fact that it was set at all is relevant for triggers, default values, etc. This is a useful default whenever e.g. [audit columns](#codegen-database-forced-types-audit), [optimistic locking (version columns)](#optimistic-locking) or some other auto-updated value is involved.
- [`MODIFIED`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/RecordDirtyTracking.html#MODIFIED): An alternative is to track only actual value changes, to help minimise database interactions and locking when not necessary in the absence of triggers, default values, locking behaviour, etc.

**Example configuration**

```java
Settings settings = new Settings()
    .withRecordDirtyTracking(MODIFIED) // Defaults to TOUCHED
```

<a id="settings-dollar-quoted-string-token"></a>
##### 3.2.8.13. Dollar quoted string token

Occasionally, when using the [`SQLDialect.POSTGRES`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQLDialect.html#POSTGRES) dialect, jOOQ renders dollar quoted string literals, in particular for [anonymous blocks](#procedural-block):

```sql
DO $$
BEGIN
  ..
END;
$$
```

The point of these string literals is to avoid having to escape all `'` characters in procedural content, or elsewhere.

Sometimes, the `$$` token may conflict with string contents, however, such as an identifier. In that case, users can override the delimiter token between the `$$` and provide their own, e.g. `$token$`.

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderDollarQuotedStringToken("token");
```

<a id="settings-execute-logging"></a>
##### 3.2.8.14. Execute Logging

The `executeLogging` setting turns off the default [logging](#logging) implemented through [`org.jooq.tools.LoggerListener`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/LoggerListener.html)

**Example configuration**

```java
Settings settings = new Settings()
    .withExecuteLogging(false); // Defaults to true
```

<a id="settings-execute-logging-sql-exceptions"></a>
##### 3.2.8.15. Execute Logging SQL Exceptions

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `executeLoggingSQLExceptions` setting turns off the default [logging of SQLExceptions](#logging-sql-exceptions).

**Example configuration**

```java
Settings settings = new Settings()
    .withExecuteLoggingSQLExceptions(false); // Defaults to true
```

<a id="settings-fetching-trimmed-strings"></a>
##### 3.2.8.16. Fetching trimmed CHAR types

Historically, fixed-length `CHAR` types used to be more present in schemas than the more useful variable length `VARCHAR` or even `TEXT` / `CLOB` types. To support variable length strings inside of `CHAR` types, strings were typically right-padded with whitespace. This can be annoying in Java based client applications, where the strings have to be trimmed manually, or using SQL [RTRIM function calls](#rtrim-function). Specifically, dictionary views of these RDBMS still use `CHAR` typed strings very often:

- Db2
- Firebird
- Informix
- Teradata

To avoid having to manually right-trim these strings, the following `Settings` can be specified to do this automatically in jOOQ at the JDBC level:

```java
Settings settings = new Settings()
    .withFetchTrimmedCharValues(true); // Default to false
```

<a id="settings-fetch-server-output"></a>
##### 3.2.8.17. Fetch server output

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Some databases allow procedural code to produce server output, such as Oracle's `DBMS_OUTPUT.PUT_LINE()`. Such output is buffered on the server and is not returned to JDBC clients unless it is explicitly enabled and fetched. If the `fetchServerOutputSize` setting is greater than `0`, jOOQ enables the server output prior to executing each statement, and fetches up to that many lines of output afterwards, in dialects that support it.

The fetched lines are written to the [log](#logging), and are also made available to [ExecuteListeners](#execute-listeners) through [`ExecuteContext.serverOutput()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ExecuteContext.html#serverOutput()):

```java
DSLContext ctx = DSL.using(connection, SQLDialect.ORACLE, new Settings()
    .withFetchServerOutputSize(10));

ctx.configuration().set(new DefaultExecuteListener() {
    @Override
    public void end(ExecuteContext c) {
        for (String line : c.serverOutput())
            System.out.println(line);
    }
});

ctx.execute("begin dbms_output.put_line('Hello world'); end;");
```

**Example configuration**

```java
Settings settings = new Settings()
    .withFetchServerOutputSize(10); // Defaults to 0, i.e. server output isn't fetched
```

<a id="settings-fetch-warnings"></a>
##### 3.2.8.18. Fetch Warnings

Apart from JDBC exceptions, there is also the possibility to handle [`java.sql.SQLWarning`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/SQLWarning.html), which are made available to jOOQ users through the [`java.sql.ExecuteListener`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ExecuteListener.html) SPI and the [log](#logging). Users who do not wish to get these notifications (e.g. for performance reasons), may turn off fetching of warnings through the `fetchWarnings` setting:

**Example configuration**

```java
Settings settings = new Settings()
    .withFetchWarnings(false); // Defaults to true
```

<a id="settings-group-concat"></a>
##### 3.2.8.19. GROUP_CONCAT Configuration

The MySQL [GROUP_CONCAT function](#group-concat-function) suffers from a controversial design decision where results are truncated after a certain length, the `@@group_concat_max_len`.

Whenever jOOQ generates a `GROUP_CONCAT` function, by default, that MySQL system variable is increased to the maximum value for the scope of a single statement, e.g.

```sql
SET @T = @@GROUP_CONCAT_MAX_LEN;
SET @@GROUP_CONCAT_MAX_LEN = 4294967295;
SELECT GROUP_CONCAT(TITLE SEPARATOR ', ')
FROM BOOK;
SET @@GROUP_CONCAT_MAX_LEN = @T;
```

[More details here](https://blog.jooq.org/mysqls-allowmultiqueries-flag-with-jdbc-and-jooq/). While this is a reasonable default behaviour (as opposed to the random truncation), it may occasionally be undesired, e.g. if statement batches (`;` separated statements) aren't possible in a single JDBC statement. The feature can be turned off with

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderGroupConcatMaxLenSessionVariable(false); // Defaults to true
```

<a id="settings-name-max-length"></a>
##### 3.2.8.20. Identifier length

Most databases limit the length of identifiers, e.g. to 63 characters in PostgreSQL. jOOQ sometimes generates identifiers itself, e.g. when deriving an alias from an expression, and those may exceed such a limit. Long user-defined aliases can, too. When the `nameAutoAliasingIfMaxLengthExceeded` setting is active, jOOQ replaces any unqualified, quoted identifier that exceeds the maximum length with a generated `alias_[hash]` identifier, where `[hash]` is a hash of the original identifier.

- `nameAutoAliasingIfMaxLengthExceeded`: Whether to replace identifiers that are too long. The default is `true`.
- `nameMaxLength`: An override for the maximum identifier length. If this isn't set, jOOQ uses the dialect's maximum identifier length. This setting has no effect if `nameAutoAliasingIfMaxLengthExceeded` is turned off.

Identifiers are only replaced if they are quoted, see the [identifier style settings](#settings-name-style).

**Example configuration**

```java
Settings settings = new Settings()
    .withNameAutoAliasingIfMaxLengthExceeded(true) // Defaults to true
    .withNameMaxLength(30);                        // Defaults to the dialect's limit
```

<a id="settings-name-style"></a>
##### 3.2.8.21. Identifier style

By default, jOOQ will always generate quoted names for all identifiers (even if this manual omits this for readability).

For instance:

```sql
SELECT "TABLE"."COLUMN" FROM "TABLE" -- SQL standard style
SELECT `TABLE`.`COLUMN` FROM `TABLE` -- MySQL style
SELECT [TABLE].[COLUMN] FROM [TABLE] -- SQL Server style
```

Quoting has the following effect on identifiers in most (but not all) databases:

- It allows for using reserved names as object names, e.g. a table called `"FROM"` is usually possible only when quoted.
- It allows for using special characters in object names, e.g. a column called `"FIRST NAME"` can be achieved only with quoting.
- It turns what are mostly case-insensitive identifiers into case-sensitive ones, e.g. `"name"` and `"NAME"` are different identifiers, whereas `name` and `NAME` are not. Please consider your database manual to learn what the proper default case and default case sensitivity is.

The `renderQuotedNames` and `renderNameCase` settings allow for overriding the name of all identifiers in jOOQ to a consistent style. The two flags are independent of one another. Possible options are:

###### RenderQuotedNames

- `ALWAYS`: This will quote all identifiers.
- `EXPLICIT_DEFAULT_QUOTED`: This will quote all identifiers, which are not explicitly unquoted using [`DSL.unquotedName()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#unquotedName(String)).
- `EXPLICIT_DEFAULT_UNQUOTED`: This will not quote any identifiers, unless they are explicitly quoted using [`DSL.quotedName()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#quotedName(String)).
- `NEVER`: This will not quote any identifiers.

###### RenderNameCase

- `AS_IS`: This will generate all names in their proper case.
- `LOWER`: This will transform all names to lower case.
- `LOWER_IF_UNQUOTED`: This will transform all names to lower case if the name is unquoted.
- `UPPER`: This will transform all names to upper case.
- `UPPER_IF_UNQUOTED`: This will transform all names to upper case if the name is unquoted.

> [!TIP]
> In some database products, quoted identifiers only enable special characters. Other database products use quotes also to make identifiers case sensitive. Keep this in mind when working with the above flags.

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderQuotedNames(RenderQuotedNames.EXPLICIT_DEFAULT_UNQUOTED) // Defaults to EXPLICIT_DEFAULT_QUOTED
    .withRenderNameCase(RenderNameCase.LOWER_IF_UNQUOTED);              // Defaults to AS_IS
```

The behaviour of this setting is influenced by the [renderLocale setting](#settings-locale).

<a id="settings-implicit-join-type"></a>
##### 3.2.8.22. Implicit join type

jOOQ's very useful [implicit JOIN](#implicit-join) feature can be used to use a path notation to join tables on their actual, or [synthetic](#codegen-database-synthetic-fks) foreign keys. For example:

```java
// Get all books, their authors, and their respective language
create.select(
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.TITLE,
          BOOK.language().CD.as("language"))
      .from(BOOK)
      .fetch();
```

By default, this produces:

- An `INNER_JOIN` if all columns of the foreign key are `NOT NULL`
- A `LEFT_JOIN` if the foreign key is nullable / optional
- A `SCALAR_SUBQUERY` if the implicit join path is in a DML statement
- An exception if the path follows a `to-many` relationship

The above defaults are important to prevent implicit joins from filtering results when placed in clauses that are not meant to filter, such as the [SELECT clause](#select-clause) or the [ORDER BY clause](#order-by-clause), as well as to prevent them from generating rows in such cases (in the case of `to-many` joins).

Users may prefer to enforce a different behaviour, including:

- Always produce a `LEFT_JOIN`, e.g. because this was the behaviour before jOOQ 3.14
- Always produce an `INNER_JOIN`, e.g. because they're migrating off Hibernate / JPA, and depend on Hibernate's implicit joins producing inner joins
- Always produce a `SCALAR_SUBQUERY`, to keep scoping of a path local (producing duplicates for shared path segments). This is also what's being done when an implicit join path is rendered in a DML statement.
- Always `THROW` an exception.

This change of behaviour can be achieved with the following setting:

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderImplicitJoinType(RenderImplicitJoinType.INNER_JOIN)
    .withRenderImplicitJoinToManyType(RenderImplicitJoinType.LEFT_JOIN);
```

<a id="settings-inline-threshold"></a>
##### 3.2.8.23. Inline Threshold

Previous sections showed how the SQL generation of [bind values](#bind-values) can be controlled, e.g. by forcing them to be inlined, or by running a static JDBC statement.

Sometimes, inlining needs to be enforced dynamically, depending on the query content. This is the case when there are a great number of bind variables. Known vendor-specific limits are:

- Access : 768
- Ingres : 1024
- Oracle : 32767
- PostgreSQL : 65535 (32767 in older versions)
- SQLite : 999
- SQL Server : 2100
- Sybase ASE : 2000
- Teradata : 2536

By default, jOOQ will automatically inline all bind variables in any SQL statement, once these thresholds have been reached. However, it is possible to override this default and provide a setting to re-define a global threshold for all dialects.

**Example configuration**

```java
Settings settings = new Settings()
    .withInlineThreshold(100); // Defaults to 0, which means the default thresholds are applied
```

<a id="settings-in-list-padding"></a>
##### 3.2.8.24. IN-list Padding

Databases that feature a cursor cache / statement cache (e.g. Oracle, SQL Server, DB2, etc.) are highly optimised for prepared statement re-use. When a client sends a prepared statement to the server, the server will go to the cache and look up whether there already exists a previously calculated execution plan for the statement (i.e. the SQL string). This is called a "soft-parse" (in Oracle). If not, the execution plan is calculated on the fly. This is called a "hard-parse" (in Oracle).

Preventing hard-parses is extremely important in high throughput OLTP systems where queries are usually not very complex but are run millions of times in a short amount of time. Using bind variables, this is usually not a problem, with the exception of the [IN predicate](#in-predicate), which generates different SQL strings even when using bind variables:

```sql
-- All of these are different SQL statements:
SELECT * FROM AUTHOR WHERE ID IN (?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?)
```

This problem may not be obvious to Java / jOOQ developers, as they are always produced from the same jOOQ statement:

```java
// All of these are the same jOOQ statement
DSL.using(configuration)
   .select()
   .from(AUTHOR)
   .where(AUTHOR.ID.in(collection))
   .fetch();
```

Depending on the possible sizes of the collection, it may be worth exploring using arrays or temporary tables as a workaround, or to reuse the original query that produced the set of IDs in the first place (through a semi-join). But sometimes, this is not possible. In this case, users can opt in to a third workaround: enabling the `inListPadding` setting. If enabled, jOOQ will "pad" the `IN` list to a length that is a power of two (configurable with `Settings.inListPadBase`). So, the original queries would look like this instead:

```sql
-- Original
SELECT * FROM AUTHOR WHERE ID IN (?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?)
```

```sql
-- Padded
SELECT * FROM AUTHOR WHERE ID IN (?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)
```

This technique will drastically reduce the number of possible SQL strings without impairing too much the usual cases where the `IN` list is small. When padding, the last bind variable will simply be repeated many times.

Usually, there is a better way - use this as a last resort!

**Example configuration**

```java
Settings settings = new Settings()
    .withInListPadding(true) // Default to false
    .withInListPadBase(4);   // Default to 2
```

<a id="settings-interpreter"></a>
##### 3.2.8.25. Interpreter Configuration

The [SQL Interpreter API](#sql-interpreter) ships with a variety of settings that govern its behaviour. These settings include:

- `interpreterDialect`: The interpreter input dialect. This dialect is used to decide whether DDL interpretation should be done on an actual in-memory database of a specific type, or using jOOQ's built in DDL interpretation.
- `interpreterDelayForeignKeyDeclarations`: Whether the interpreter should delay the application of foreign key declarations (in case of which forward references are possible).
- `interpreterLocale`: The locale to use for things like case insensitive comparisons.
- `interpreterNameLookupCaseSensitivity`: The identifier case sensitivity that should be applied when interpreting SQL, depending on whether identifiers are quoted or not.
- `interpreterQuotedNames`: Specify how the interpreter handles quoting of interpreted identifiers.
- `interpreterSearchPath`: The search path for unqualified schema objects used by the interpreter.
- `interpreterWithMetaLookups`: Whether the interpreter should perform meta lookups in already interpreted meta data. Setting this to `IGNORE_ON_FAILURES` effectively adds `IF EXISTS` or `IF NOT EXISTS` clauses to all statements and subclauses.

**Example configuration**

```java
Settings settings = new Settings()
    .withInterpreterDialect(H2)                           // Defaults to DEFAULT
    .withInterpreterDelayForeignKeyDeclarations(true)     // Defaults to false
    .withInterpreterLocale(Locale.forLanguageTag("de"))   // Defaults to Locale.getDefault()
    .withInterpreterQuotedNames(ALWAYS)                   // Defaults to EXPLICIT_DEFAULT_QUOTED
    .withInterpreterNameLookupCaseSensitivity(NEVER)      // Defaults to WHEN_QUOTED
    .withInterpreterSearchPath(...)                       // Defaults to an empty list
    .withInterpreterWithMetaLookups(IGNORE_ON_FAILURE);   // Defaults to THROW_ON_FAILURE
```

<a id="settings-jdbc-flags"></a>
##### 3.2.8.26. JDBC Flags

JDBC statements feature a couple of flags that influence the execution of such a statement. Each of these flags can be configured through jOOQ's [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html) and [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) on a statement-per-statement basis, but there's also the possibility to centrally specify a value for these flags. These are the three flags:

- `queryTimeout`: The JDBC statement timeout in seconds. Corresponds to [`Query.queryTimeout()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html#queryTimeout(int)) or [`Statement.setQueryTimeout()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#setQueryTimeout(int))
- `maxRows`: The maximum number of rows returned by the JDBC statement. Corresponds to [`ResultQuery.maxRows()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html#maxRows(int)) or [`Statement.setMaxRows()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#setMaxRows(int))
- `largeMaxRows`: The maximum number of rows returned by the JDBC statement, as a `long`. Corresponds to [`ResultQuery.largeMaxRows()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html#largeMaxRows(long)) or [`Statement.setLargeMaxRows()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#setLargeMaxRows(long))
- `fetchSize`: The number of rows to be buffered by the JDBC ResultSet. Corresponds to [`ResultQuery.fetchSize()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html#fetchSize(int)) or [`Statement.setFetchSize()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#setFetchSize(int))

All of these flags are JDBC-only features with no direct effect on jOOQ. jOOQ only passes them through to the underlying statement.

**Example configuration**

```java
Settings settings = new Settings()
    .withQueryTimeout(5)
    .withQueryPoolable(DEFAULT)
    .withMaxRows(1000)
    .withFetchSize(20);
```

<a id="settings-jsr310-binding"></a>
##### 3.2.8.27. JSR 310 type binding

Historically, JDBC drivers had poor support for the `java.time` (JSR 310) types, which is why jOOQ encodes some of them in a more compatible way when binding them to JDBC statements. Most modern drivers support these types natively, and binding them natively may perform better both on the client and on the server. The following settings govern this behaviour:

- `bindOffsetDateTimeType`: Whether [`java.time.OffsetDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetDateTime.html) values are bound natively using `PreparedStatement.setObject()`. The default is `false`, in case of which jOOQ binds them as formatted strings in many dialects.
- `bindOffsetTimeType`: Whether [`java.time.OffsetTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetTime.html) values are bound natively using `PreparedStatement.setObject()`. The default is `false`, in case of which jOOQ binds them as formatted strings in many dialects.
- `bindLocalTimeType`: Whether [`java.time.LocalTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalTime.html) values are bound natively. The default is `true`. If set to `false`, jOOQ reverts to the behaviour prior to jOOQ 3.21, binding [`java.sql.Time`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Time.html) values instead, which truncates fractional seconds. Dialects that don't support binding `LocalTime` natively always use the legacy behaviour.

See also the manual's sections about the [OffsetDateTime](#data-type-offsetdatetime) and [OffsetTime](#data-type-offsettime) data types.

**Example configuration**

```java
Settings settings = new Settings()
    .withBindOffsetDateTimeType(true) // Defaults to false
    .withBindOffsetTimeType(true)     // Defaults to false
    .withBindLocalTimeType(false);    // Defaults to true
```

<a id="settings-keyword-style"></a>
##### 3.2.8.28. Keyword style

In all SQL dialects, keywords are case insensitive, and this is also the default in jOOQ, which mostly generates lower-case keywords. Users may wish to adapt this and they have these options for the `renderKeywordCase` setting:

- `AS_IS` (the default): Generate keywords as they are defined in the codebase (mostly lower case).
- `LOWER`: Generate keywords in lower case.
- `UPPER`: Generate keywords in upper case.
- `PASCAL`: Generate keywords in pascal case.

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderKeywordCase(RenderKeywordCase.UPPER); // Defaults to AS_IS
```

<a id="settings-listener-invocation-order"></a>
##### 3.2.8.29. Listener Invocation Order

jOOQ offers a variety of SPIs in the [Configuration](#dsl-context) object. Some of those SPIs are event listeners, that can listen to "start" and "end" events, such as for example the [ExecuteListener](#execute-listeners) that listens to the query execution lifecycle.

When registering multiple listeners of a type, the invocation order may be relevant as custom listeners might communicate with each other. In such a case, the following settings allow for overriding the invocation order of "start" and "end" events for each type of listener:

**Example configuration**

```java
Settings settings = new Settings()
    .withTransactionListenerStartInvocationOrder(DEFAULT) // Defaults to DEFAULT
    .withTransactionListenerEndInvocationOrder(REVERSE)   // Defaults to DEFAULT
    .withVisitListenerStartInvocationOrder(DEFAULT)       // Defaults to DEFAULT
    .withVisitListenerEndInvocationOrder(REVERSE)         // Defaults to DEFAULT
    .withRecordListenerStartInvocationOrder(DEFAULT)      // Defaults to DEFAULT
    .withRecordListenerEndInvocationOrder(REVERSE)        // Defaults to DEFAULT
    .withExecuteListenerStartInvocationOrder(DEFAULT)     // Defaults to DEFAULT
    .withExecuteListenerEndInvocationOrder(REVERSE);      // Defaults to DEFAULT
```

<a id="settings-locale"></a>
##### 3.2.8.30. Locales

When doing locale sensitive operations, such as upper casing or lower casing a name (see [Name styles](#settings-name-style)), then it may be important in some areas to be able to specify the [`java.util.Locale`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Locale.html) for the operation.

**Example configuration**

```java
// All of these default to Locale.getDefault(), if not specified explicitly
Settings settings = new Settings()
    .withLocale(Locale.forLanguageTag("de"))             // The default locale if no more specific locales are specified
    .withRenderLocale(Locale.forLanguageTag("de"))       // The locale used when rendering SQL
    .withParseLocale(Locale.forLanguageTag("de"))        // The locale used when parsing SQL
    .withInterpreterLocale(Locale.forLanguageTag("de")); // The locale used when interpreting SQL
```

<a id="settings-map-jpa"></a>
##### 3.2.8.31. Map JPA Annotations

The [`org.jooq.impl.DefaultRecordMapper`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultRecordMapper.html) supports basic JPA mapping (mostly `@Table` and `@Column` annotations). Looking up these annotations costs a slight extra overhead (mostly taken care of through [reflection caching](#settings-reflection-caching)). It can be turned off using the `mapJPAAnnotations` setting:

**Example configuration**

```java
Settings settings = new Settings()
    .withMapJPAAnnotations(false); // Defaults to true
```

<a id="settings-meta-sql-on-error"></a>
##### 3.2.8.32. Meta SQL on error

The JDBC [`java.sql.DatabaseMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/DatabaseMetaData.html) backed [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) implementation runs a few auxiliary queries to fetch objects and meta information that JDBC cannot provide reliably. These include:

- Constraint meta data (e.g. constraint enforcement, deferrability)
- Check constraint meta data
- Comments
- Computed column meta data
- Identity meta data (e.g. additional sequence flags, `DEFAULT` or `ALWAYS` semantics, etc.)
- Object source code
- Sequence meta data
- Trigger meta data
- UDT attribute meta data

Some of these queries may fail due to missing grants, RDBMS version incompatibilities, etc. Using this setting, it is possible to handle failures related to these queries, including failure, logging, ignoring.

**Example configuration**

```java
Settings settings = new Settings()
    .withMetaSqlOnError(OnError.SILENT); // Defaults to OnError.FAIL
```

<a id="settings-meta-system-objects"></a>
##### 3.2.8.33. Meta system objects

The JDBC [`java.sql.DatabaseMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/DatabaseMetaData.html) backed [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) implementation attempts to exclude producing system generated auxiliary objects from its results, as they are rarely interesting for users. Such object types include:

- System indexes, i.e. indexes that are generated automatically to back constraints.
- System sequences, i.e. sequences that are generated automatically to back identity columns.

**Example configuration**

```java
Settings settings = new Settings()
    .withMetaIncludeSystemIndexes(true)    // Defaults to false
    .withMetaIncludeSystemSequences(true); // Defaults to false
```

<a id="setting-qualification"></a>
##### 3.2.8.34. Object qualification

By default, jOOQ fully qualifies all objects with their catalog and schema names, if such qualification is made available by the [code generator](#code-generation).

For instance, the following SQL statement containing full qualification may be produced by jOOQ code with seemingly no qualification:

```sql
-- Full qualification on columns and tables
SELECT catalog.schema.table.column
FROM catalog.schema.table
```

```java
DSL.using(configuration)
   .select(TABLE.COLUMN) // Column only qualified with table
   .from(TABLE)          // No qualification on table
```

While the jOOQ code is also implicitly fully qualified ([see implied imports](#the-manual)), it may not be desireable to use fully qualified object names in SQL. The `renderCatalog` and `renderSchema` settings are used for this.

**Example configuration**

```java
new Settings()
  .withRenderCatalog(false)  // Defaults to true
  .withRenderSchema(false);  // Defaults to true
```

More sophisticated multitenancy approaches are available through the [render mapping feature](#settings-render-mapping).

<a id="setting-table-qualification"></a>
##### 3.2.8.35. Object qualification for columns

By default, jOOQ fully qualifies all columns with their table names ([and the tables might themselves be qualified](#setting-qualification)). This is a reasonable default, as any [JOIN operation](#join-clause) may produce ambiguous column names, such as the ubiquitous names `ID` or `CREATED_AT`.

```sql
-- Columns always qualified with table name.
SELECT table.column
FROM table
```

```java
DSL.using(configuration)
   .select(TABLE.COLUMN)
   .from(TABLE);
```

In rare cases, it may be desirable to drop this qualification, keeping it only either:

- `ALWAYS`: This is the default. Columns are always qualified with their table.
- `WHEN_MULTIPLE_TABLES`: When the [FROM clause](#from-clause) has multiple tables.
- `WHEN_AMBIGUOUS_COLUMNS`: When the [FROM clause](#from-clause) produces ambiguous columns.
- `NEVER`: Qualification is always dropped. This may produce semantically wrong SQL and is intended only to be used on a query by query basis, if any of the above does not implement requirements as desired.

**Example configuration**

```java
new Settings()
  .withRenderTable(RenderTable.WHEN_MULTIPLE_TABLES) // Defaults to ALWAYS
```

<a id="settings-optimistic-locking"></a>
##### 3.2.8.36. Optimistic Locking

There are two settings governing the behaviour of the jOOQ [optimistic locking feature](#optimistic-locking):

- `updateRecordVersion`: Whether [`UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) instances should modify the record version prior to storing the record. This feature is independent of, but related to optimistic locking.
- `updateRecordTimestamp`: Whether [`UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) instances should modify the record timestamp prior to storing the record. This feature is independent of, but related to optimistic locking.
- `executeWithOptimisticLocking`: This allows for turning off the feature entirely.
- `executeWithOptimisticLockingExcludeUnversioned`: This allows for turning off the feature for [updatable records](#crud-with-updatablerecords) who are not explicitly versioned.

**Example configuration**

```java
Settings settings = new Settings()
    .withUpdateRecordVersion(true)                              // Defaults to true
    .withUpdateRecordTimestamp(true)                            // Defaults to true
    .withExecuteWithOptimisticLocking(true)                     // Defaults to false
    .withExecuteWithOptimisticLockingExcludeUnversioned(false); // Defaults to false
```

For more details, please refer to the [manual's section about the optimistic locking feature](#optimistic-locking).

<a id="settings-named-parameter-prefix"></a>
##### 3.2.8.37. Parameter name prefix

When choosing a [ParameterType.NAMED](#settings-parameter-type) to produce named parameters, the default is to use a colon as a prefix to the parameter name.

For example:

```sql
-- NAMED
SELECT FIRST_NAME || :1 FROM AUTHOR WHERE ID = :x
```

Depending on how the named parameters are interpreted, this default is not optimal. A better character might be the `$` sign, e.g. in PostgreSQL or R2DBC. For this, the `renderNamedParamPrefix` setting can be used:

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderNamedParamPrefix("$"); // Defaults to ":"
```

<a id="settings-parameter-type"></a>
##### 3.2.8.38. Parameter types

Bind values or bind parameters come in different flavours in different SQL databases. JDBC standardises on their syntax by allowing only `?` (question mark) characters as placeholders for bind variables. Thus, jOOQ, by default, generates `?` placeholders for JDBC consumptions. Users who wish to use jOOQ with a different backend than JDBC can specify that all jOOQ [bind values](#bind-values), including [indexed parameters](#indexed-parameters) and [named parameters](#named-parameters) generate alternative strings, other than `?`.

These are the current options:

- `INDEXED` (the default): Generates indexed parameter placeholders using `?`.
- `NAMED`: Generates named parameter placeholders, such as `:param` for parameters that are named explicitly or `:1` for unnamed, indexed parameters.
- `NAMED_OR_INLINED:` Generates named parameter placeholders for parameters that are named explicitly and inlines all unnamed parameters.
- `INLINED`: Inlines all parameters.

An example:

```sql
-- INDEXED
SELECT FIRST_NAME || ? FROM AUTHOR WHERE ID = ?
-- NAMED
SELECT FIRST_NAME || :1 FROM AUTHOR WHERE ID = :x
-- NAMED_OR_INLINED
SELECT FIRST_NAME || 'x' FROM AUTHOR WHERE ID = :x
-- INLINED
SELECT FIRST_NAME || 'x' FROM AUTHOR WHERE ID = 42
```

```java
Param<String> x = val("x");
Param<Integer> i = param("x", 42);

DSL.using(configuration)
   .select(FIRST_NAME.concat(x))
   .from(AUTHOR)
   .where(ID.eq(i))
   .fetch();
```

**Example configuration**

```java
Settings settings = new Settings()
    .withParamType(ParamType.NAMED); // Defaults to INDEXED
```

The following setting [statementType](#settings-statement-type) may override this setting.

<a id="settings-parser"></a>
##### 3.2.8.39. Parser Configuration

The [SQL Parser API](#sql-parser) ships with a variety of settings that govern its behaviour. These settings include:

- `parseAppendMissingTableReferences`: Support Teradata style implicit joins when projected table references aren't listed explicitly in `FROM` clause.
- `parseDateFormat`: The date format that is applied automatically when parsing date formatting functions without an explicit format.
- `parseDialect`: The parser input dialect. This dialect is used to decide what vendor specific grammar should be applied in case of ambiguities that cannot be resolved from the context.
- `parseIgnoreComments`: Using this flag, the parser can ignore certain sections that would otherwise be executed by RDBMS. Everything between an `parseIgnoreCommentStart` and the `parseIgnoreCommentStop` token will be ignored.
- `parseIgnoreCommentStart`: The token that delimits the beginning of a section to be ignored by jOOQ. Ideally, this token is placed inside of a SQL comment.
- `parseIgnoreCommentStop`: The token that delimits the end of a section to be ignored by jOOQ. Ideally, this token is placed inside of a SQL comment.
- `parseIgnoreCommercialOnlyFeatures`: Ignore commercial only features when parsing, to avoid unnecessary exceptions.
- `parseMetaDefaultExpressions`: Specify whether [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) implementations should attempt to parse `DEFAULT` expressions, or leave them as raw SQL strings.
- `parseMetaViewSources`: Specify whether [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) implementations should attempt to parse view source code, or leave them as raw SQL strings.
- `parseNameCase`: Specify the name case behaviour, depending on whether names are quoted or not.
- `parseNamedParamPrefix`: The prefix used for named parameters, defaulting to `:`, e.g. for `:param` style names.
- `parsePlainSQLTemplateComments`: Using this flag, the parser can parse certain sections as plain SQL templates using [`DSL.sql(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#sql(java.lang.String)) semantics, ignoring their vendor-specific syntax. Everything between an `parsePlainSQLTemplateCommentStart` and the `parsePlainSQLTemplateCommentStop` token will be ignored.
- `parsePlainSQLTemplateCommentStart`: The token that delimits the beginning of a section to be parsed as a plain SQL template by jOOQ. Ideally, this token is placed inside of a SQL comment.
- `parsePlainSQLTemplateCommentStop`: The token that delimits the end of a section to be parsed as a plain SQL template by jOOQ. Ideally, this token is placed inside of a SQL comment.
- `parseRawComments`: Using this flag, the parser can parse certain sections as raw SQL using [`DSL.raw(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#raw(java.lang.String)) semantics, ignoring their vendor-specific syntax. Everything between an `parsePlainSQLTemplateCommentStart` and the `parsePlainSQLTemplateCommentStop` token will be ignored.
- `parseRawCommentStart`: The token that delimits the beginning of a section to be parsed as a raw SQL by jOOQ. Ideally, this token is placed inside of a SQL comment.
- `parseRawCommentStop`: The token that delimits the end of a section to be parsed as a raw SQL by jOOQ. Ideally, this token is placed inside of a SQL comment.
- `parseRetainCommentsBetweenQueries`: Whether comments in between statements from [`Parser.parse()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parse--) are retained and parsed as ignored queries. Comments inside of statements (including procedural statements) currently aren't supported by jOOQ.
- `parseSearchPath`: The search path to look up unqualified identifiers to be used when using `parseWithMetaLookups`. Most dialects support a single schema on their search path (the `CURRENT_SCHEMA`). PostgreSQL supports a `'search_path'`, which allows for listing multiple schemata to use to look up unqualified tables, procedures, etc. in.
- `parseSetCommands`: Whether [SET commands](#set-statement) should be parsed or ignored.
- `parseTimestampFormat`: The timestamp format that is applied automatically when parsing timestamp formatting functions without an explicit format.
- `parseUnsupportedSyntax`: The parser can parse some syntax that jOOQ does not support. By default, such syntax is ignored. Use this flag if you want to fail in such cases.
- `parseUnknownFunctions`: The parser only parses "known" (to jOOQ) built in functions, and fails otherwise. This flag allows for parsing any built in function using a standard `func_name(arg1, arg2, ...)` syntax.
- `parseWithMetaLookups`: Whether [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) should be used to look up meta information such as schemas, tables, columns, column types, etc.

An example of using the `parseIgnoreComments` feature:

```sql
-- What you execute
/* [jooq ignore start] */
CREATE SCHEMA s1;
SET SCHEMA s1;
/* [jooq ignore stop] */

/* [jooq ignore start] */ -- /* [jooq ignore stop] */ CREATE SCHEMA s2;
/* [jooq ignore start] */ -- /* [jooq ignore stop] */ SET SCHEMA s2;

CREATE TABLE t (i INTEGER);
```

```sql
-- What the jOOQ parser sees
/*


                      */

/*                                                 */ CREATE SCHEMA s2;
/*                                                 */ SET SCHEMA s2;

CREATE TABLE t (i INTEGER);
```

**Example configuration**

```java
Settings settings = new Settings()
    .withParseDialect(SQLSERVER)                         // Defaults to DEFAULT
    .withParseWithMetaLookups(THROW_ON_FAILURE)          // Defaults to OFF
    .withParseSearchPath(
        new ParseSearchSchemata().withSchema("PUBLIC"),
        new ParseSearchSchemata().withSchema("TEST"))
    .withParseUnsupportedSyntax(FAIL)                    // Defaults to IGNORE
    .withParseUnknownFunctions(IGNORE)                   // Defaults to FAIL
    .withParseIgnoreComments(true)                       // Defaults to false
    .withParseIgnoreCommentStart("<ignore>")             // Defaults to "[jooq ignore start]"
    .withParseIgnoreCommentStop("</ignore>")             // Defaults to "[jooq ignore stop]"
```

In addition to the above settings, there is also a powerful [parser listener SPI](#sql-parser-listener) called the [`org.jooq.ParseListener`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ParseListener.html).

<a id="settings-readonly-columns"></a>
##### 3.2.8.40. Readonly column behaviour

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

When using is [readonly columns](#readonly-columns), by default, any values that are attempted to be [inserted](#insert-statement) or [updated](#update-statement) are ignored. The following [`Settings`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html) allow for overriding and the default behaviour of readonly columns:

- [`Settings.readonlyInsert`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyInsert): In an [INSERT statement](#insert-statement), or in the `INSERT` clause of a [MERGE statement](#merge-statement).
- [`Settings.readonlyUpdate`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyUpdate): In an [UPDATE statement](#update-statement), or in the `UPDATE` clause of a [MERGE statement](#merge-statement).
- [`Settings.readonlyTableRecordInsert`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyTableRecordInsert): In a [`TableRecord.insert()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html#insert()) operation, or the `INSERT` part or execution of [`TableRecord.store()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#store()) or [`UpdatableRecord.merge()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#merge()). If this is deactivated, [`Settings.readonlyInsert`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyInsert) still applies
- [`Settings.readonlyUpdatableRecordUpdate`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyUpdatableRecordUpdate): In a [`UpdatableRecord.update()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#update()) operation, or the `UPDATE` part or execution of [`TableRecord.store()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#store()) or [`UpdatableRecord.merge()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#merge()). If this is deactivated, [`Settings.readonlyUpdate`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyUpdate) still applies

Each one of these flags is of type [`org.jooq.conf.WriteIfReadonly`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/WriteIfReadonly.html) with these permitted states:

- `WRITE`: Write to the column as if it weren't readonly. This effectively turns off the feature.
- `IGNORE`: Ignore the column in a relevant statement. This is the default.
- `THROW`: Throw an exception if the column is included in a relevant DML statement.

The default behaviour `IGNORE` is particularly useful when loading POJO data into [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) and storing it, while ignoring `IDENTITY` columns, computed columns, synthetic columns (such as the [synthetic ROWIDs](#codegen-database-synthetic-readonly-rowids)), and more.

**Example configuration**

```java
Settings settings = new Settings()
    .withReadonlyInsert(WriteIfReadonly.THROW)                 // Defaults to IGNORE
    .withReadonlyUpdate(WriteIfReadonly.THROW)                 // Defaults to IGNORE
    .withReadonlyTableRecordInsert(WriteIfReadonly.THROW)      // Defaults to IGNORE
    .withReadonlyUpdatableRecordUpdate(WriteIfReadonly.THROW); // Defaults to IGNORE
```

<a id="settings-redacted-columns"></a>
##### 3.2.8.41. Redacted column behaviour

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

When using is [redacted columns](#redacted-columns), the [`Settings.redact`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#redact) flag specifies whether columns whose [`DataType.redacted()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html#redacted()) flag is set to `true` will be redacted in which context:

- [`Redact.TEXT_ONLY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Redact.html#TEXT_ONLY) (the default) redacts content in [text output](#exporting-text) and [HTML output](#exporting-html).
- [`Redact.ALL_FORMATS`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Redact.html#ALL_FORMATS) redacts content also in [CSV output](#exporting-csv), [JSON output](#exporting-json), and [XML output](#exporting-xml).
- [`Redact.NONE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Redact.html#NONE) turns the feature off.

**Example configuration**

```java
Settings settings = new Settings()
    .redact(Redact.ALL_FORMATS); // Defaults to TEXT_ONLY
```

<a id="settings-reflection-caching"></a>
##### 3.2.8.42. Reflection caching

All operations of the [DefaultRecordMapper](#recordmapper) are cached in the `Configuration` by default for improved mapping and reflection speed. Users who prefer to override this cache, or work with [their own custom record mapper provider](#recordmapperprovider) may wish to turn off the out-of-the-box caching feature.

**Example configuration**

```java
Settings settings = new Settings()
    .withReflectionCaching(false); // Defaults to true
```

<a id="settings-rendering"></a>
##### 3.2.8.43. Rendering Configuration

Rendering SQL from an expression tree is jOOQ's core feature. The following set of settings govern various functional and cosmetic rendering features:

###### Functional rendering settings

- `renderAutoAliasedDerivedTableExpressions`: Whether derived table projection expressions should receive auto aliases if an alias is absent.
- `renderDefaultNullability`: Whether non-explicit nullability should be rendered in DDL exports.
- `renderImplicitWindowRange`: Whether any implicit [window range](#window-frame) clause should be rendered to help standardise SQL behaviour across dialects.
- `renderOrderByRownumberForEmulatedPagination`: Whether [ROW_NUMBER](#window-row-number) based [LIMIT](#limit-clause) emulation should apply an explicit [ORDER BY clause](#order-by-clause) for row number ordering.
- `renderOutputForSQLServerReturningClause`: Whether to use `OUTPUT` in SQL Server to emulate [RETURNING](#insert-returning) clauses.
- `renderParenthesisAroundSetOperationQueries`: Whether to render parentheses around [set operations](#set-operations).
- `renderPlainSQLTemplatesAsRaw`: Whether to process plain SQL templates are render them as raw templates.
- `renderVariablesInDerivedTablesForEmulations`: Whether variables and expressions should be rendered in derived tables in order to prevent repetition of expressions in certain situations.

###### Cosmetic rendering settings

- `renderFormatted`: Whether rendered SQL should be formatted (e.g. for debugging) or rendered on a single line (e.g. to send to the JDBC driver).
- `renderFormatting`: A set of formatting related values, such as the newline character, the indentation string, the print margin width.
- `renderOptionalAsKeywordForFieldAliases`: Whether the optional `AS` keyword should be rendered for [field aliases](#aliased-columns).
- `renderOptionalAsKeywordForTableAliases`: Whether the optional `AS` keyword should be rendered for [table aliases](#aliased-tables).
- `renderOptionalAssociativityParentheses`: Whether optional parentheses around associative operators should be maintained.
- `renderOptionalInnerKeyword`: Whether the optional `INNER` keyword should be rendered for [INNER JOIN](#join-type-inner) operators.
- `renderOptionalOuterKeyword`: Whether the optional `OUTER` keyword should be rendered for [INNER JOIN](#join-type-outer) operators.

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderFormatted(true)                           // Defaults to false
    .withRenderFormatting(new RenderFormatting()
        .withNewline("\\r\\n")                           // Defaults to \n
        .withIndentation("\\t"))                         // Defaults to "  "
```

<a id="settings-return-all-on-store"></a>
##### 3.2.8.44. Return all columns on store

When using the [updatable records feature](#crud-with-updatablerecords), jOOQ always fetches the generated [identity value](#identity-values), if such a value is availableand if [the return identity on store](#settings-return-identity-on-store) feature is enabled (it is, by default).

The identity value is not the only value that is generated by default. Specifically, there may be triggers that are used for auditing or other reasons, which generate `LAST_UPDATE` or `LAST_UPDATE_BY` values in a record. Users who wish to also automatically fetch these values after all `store()`, `insert()`, or `update()` calls may do so by specifying the `returnAllOnUpdatableRecord` setting. This setting depends on the availability of [INSERT .. RETURNING](#insert-returning), `UPDATE .. RETURNING`, and `DELETE .. RETURNING` statements, which are not available from all databases, in case of which a `refresh()` call may be issued, creating a separate round trip to the server.

**Example configuration**

```java
Settings settings = new Settings()
    .withReturnAllOnUpdatableRecord(true); // Defaults to false
```

<a id="settings-return-computed-on-store"></a>
##### 3.2.8.45. Return computed columns on store

When using the [updatable records feature](#crud-with-updatablerecords), jOOQ always fetches the generated [identity value](#identity-values), if such a value is availableand if [the return identity on store](#settings-return-identity-on-store) feature is enabled (it is, by default).

The identity value is not the only value that is generated by default. Specifically, there may be different types of [computed columns](#computed-columns). Users who wish to also automatically fetch these values after all `store()`, `insert()`, or `update()` calls may do so by specifying the `returnDefaultOnUpdatableRecord` setting. This setting depends on the availability of [INSERT .. RETURNING](#insert-returning), `UPDATE .. RETURNING`, and `DELETE .. RETURNING` statements, which are not available from all databases, in case of which a `refresh()` call may be issued, creating a separate round trip to the server.

**Example configuration**

```java
Settings settings = new Settings()
    .withReturnComputedOnUpdatableRecord(true); // Defaults to false
```

<a id="settings-return-default-on-store"></a>
##### 3.2.8.46. Return DEFAULT columns on store

When using the [updatable records feature](#crud-with-updatablerecords), jOOQ always fetches the generated [identity value](#identity-values), if such a value is availableand if [the return identity on store](#settings-return-identity-on-store) feature is enabled (it is, by default).

The identity value is not the only value that is generated by default. Specifically, there may be other defaulted values, such as creation timestamps and users. Users who wish to also automatically fetch these values after all `store()`, `insert()`, or `update()` calls may do so by specifying the `returnDefaultOnUpdatableRecord` setting. This setting depends on the availability of [INSERT .. RETURNING](#insert-returning), `UPDATE .. RETURNING`, and `DELETE .. RETURNING` statements, which are not available from all databases, in case of which a `refresh()` call may be issued, creating a separate round trip to the server.

**Example configuration**

```java
Settings settings = new Settings()
    .withReturnDefaultOnUpdatableRecord(true); // Defaults to false
```

<a id="settings-return-identity-on-store"></a>
##### 3.2.8.47. Return Identity Value On Store

When using the [updatable records feature](#crud-with-updatablerecords), jOOQ by default fetches the generated [identity value](#identity-values). In some situations, it is desirable for this feature to be turned off using the following flag:

**Example configuration**

```java
Settings settings = new Settings()
    .withReturnIdentityOnUpdatableRecord(false); // Defaults to true
```

<a id="settings-render-mapping"></a>
##### 3.2.8.48. Runtime catalog, schema and table mapping

Most SQL object types are qualified with a [`org.jooq.Catalog`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Catalog.html) and [`org.jooq.Schema`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Schema.html). In multi-tenant application, users may want to map these identifier namespaces to something other than the default.

###### Mapping your DEV schema to a productive environment

You may wish to design your database in a way that you have several instances of your schema. This is useful when you want to cleanly separate data belonging to several customers / organisation units / branches / users and put each of those entities' data in a separate database or schema.

In our AUTHOR example this would mean that you provide a book reference database to several companies, such as My Book World and Books R Us. In that case, you'll probably have a schema setup like this:

- DEV: Your development schema. This will be the schema that you base code generation upon, with jOOQ
- MY_BOOK_WORLD: The schema instance for My Book World
- BOOKS_R_US: The schema instance for Books R Us

###### Mapping DEV to MY_BOOK_WORLD with jOOQ

When a user from My Book World logs in, you want them to access the MY_BOOK_WORLD schema using classes generated from DEV. This can be achieved with the [`org.jooq.conf.RenderMapping`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/RenderMapping.html) class, that you can equip your Configuration's [settings](#custom-settings) with. Take the following example:

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderMapping(new RenderMapping()
    .withSchemata(
        new MappedSchema().withInput("DEV")
                          .withOutput("MY_BOOK_WORLD"),
        new MappedSchema().withInput("LOG")
                          .withOutput("MY_BOOK_WORLD_LOG")));
```

The query executed with a Configuration equipped with the above mapping will in fact produce this SQL statement:

```sql
SELECT *
FROM MY_BOOK_WORLD.AUTHOR
```

```java
DSL.using(connection, dialect, settings)
   .selectFrom(DEV.AUTHOR)
```

This works because `AUTHOR` was generated from the `DEV` schema, which is mapped to the `MY_BOOK_WORLD` schema by the above settings.

###### Mapping of tables

Not only schemata can be mapped, but also tables. If you are not the owner of the database your application connects to, you might need to install your schema with some sort of prefix to every table. In our examples, this might mean that you will have to map DEV.AUTHOR to something MY_BOOK_WORLD.MY_APP__AUTHOR, where MY_APP__ is a prefix applied to all of your tables. This can be achieved by creating the following mapping:

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderMapping(new RenderMapping()
    .withSchemata(
        new MappedSchema().withInput("DEV")
                          .withTables(
         new MappedTable().withInput("AUTHOR")
                          .withOutput("MY_APP__AUTHOR"))));
```

The query executed with a Configuration equipped with the above mapping will in fact produce this SQL statement:

```sql
SELECT * FROM DEV.MY_APP__AUTHOR
```

Table mapping and schema mapping can be applied independently, by specifying several MappedSchema entries in the above configuration. jOOQ will process them in order of appearance and map at first match. Note that you can always omit a MappedSchema's output value, in case of which, only the table mapping is applied.

###### Mapping of UDTs

Not only schemata can be mapped, but also UDTs. If you are not the owner of the database your application connects to, you might need to install your schema with some sort of prefix to every UDT. In our examples, this might mean that you will have to map DEV.AUTHOR_TYPE to something MY_BOOK_WORLD.MY_APP__AUTHOR_TYPE, where MY_APP__ is a prefix applied to all of your UDTs. This can be achieved by creating the following mapping:

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderMapping(new RenderMapping()
    .withSchemata(
        new MappedSchema().withInput("DEV")
                          .withUdts(
         new MappedUDT().withInput("AUTHOR_TYPE")
                          .withOutput("MY_APP__AUTHOR_TYPE"))));
```

The query executed with a Configuration equipped with the above mapping will in fact produce this SQL statement:

```sql
SELECT CAST(ROW('John', 'Doe') AS DEV.MY_APP__AUTHOR_TYPE)
```

UDT mapping and schema mapping can be applied independently, by specifying several MappedSchema entries in the above configuration. jOOQ will process them in order of appearance and map at first match. Note that you can always omit a MappedSchema's output value, in case of which, only the UDT mapping is applied.

###### Mapping of catalogs

For databases like SQL Server, it is also possible to map catalogs in addition to schemata. The mechanism is exactly the same. So let's assume that we generated code for a table [dev].[dbo].[author] and want to map it to [my_book_world].[dbo].[author] at runtime. This can be achieved as follows:

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderMapping(new RenderMapping()
    .withCatalogs(
        new MappedCatalog().withInput("DEV")
                           .withOutput("MY_BOOK_WORLD")));
```

To give you full control of how each and every table gets mapped, a MappedCatalog object can contain MappedSchema (and thus also MappedTable) definitions.

###### Using regular expressions

All of the above examples were using 1:1 constant name mappings where the input and output schema or table names are fixed by the configuration. With jOOQ 3.8, regular expression can be used as well for mapping, for example:

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderMapping(new RenderMapping()
    .withSchemata(
        new MappedSchema().withInputExpression(Pattern.compile("DEV_(.*)"))
                          .withOutput("PROD_$1")
                          .withTables(
         new MappedTable().withInputExpression(Pattern.compile("DEV_(.*)"))
                          .withOutput("PROD_$1"))));
```

The only difference to the constant version is that the `input` field is replaced by the `inputExpression` field of type [`java.util.regex.Pattern`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/regex/Pattern.html), in case of which the meaning of the `output` field is a pattern replacement, not a constant replacement.

###### Hard-wiring mappings at code-generation time

Note that the manual's section about [code generation schema mapping](#codegen-database-catalog-and-schema-mapping) explains how you can hard-wire your catalog, schema and table mappings at code generation time.

###### Limitations

Mapped objects need to be known to the jOOQ [`org.jooq.RenderContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RenderContext.html), which means that for example [plain SQL templates](#plain-sql-templating-language) and their contents cannot be mapped. See also [features requiring code generation](#codegen-feature-dependencies) for more details.

<a id="settings-scalar-subqueries"></a>
##### 3.2.8.49. Scalar subqueries for stored functions

This setting is useful mostly for the Oracle database, which implements a feature called [scalar subquery caching](https://blog.jooq.org/oracle-scalar-subquery-caching/), which is a good tool to avoid the expensive PL/SQL-to-SQL context switch when predicates make use of stored function calls.

With this setting in place, all stored function calls embedded in SQL statements will be wrapped in a scalar subquery:

```sql
SELECT
  (SELECT my_package.format(LANGUAGE_ID) FROM dual)
FROM BOOK
```

```java
DSL.using(configuration)
   .select(MyPackage.format(BOOK.LANGUAGE_ID))
   .from(BOOK)
```

If our table contains thousands of books, but only a dozen of `LANGUAGE_ID` values, then with scalar subquery caching, we can avoid most of the function calls and cache the result per `LANGUAGE_ID`.

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderScalarSubqueriesForStoredFunctions(true);
```

<a id="settings-seek-clause"></a>
##### 3.2.8.50. SEEK clause implementation

The [SEEK clause](#seek-clause) is a powerful alternative to the [OFFSET clause](#limit-clause) for pagination. By default, the `SEEK` clause is transformed into an equivalent [ROW predicate](#comparison-predicate-degree-n) as follows:

```sql
SELECT id, value
FROM t
WHERE (value, id) > (2, 533)
ORDER BY value, id
LIMIT 5
 
```

```java
create.select(T.ID, T.VALUE)
      .from(T)
      .orderBy(T.VALUE, T.ID)
      .seek(lastValue, lastId)
      .limit(5)
      .fetch();
```

That `ROW` predicate is optimal, syntactically, but may not be optimised optimally by a dialect's underlying optimiser. As such, there are two ways to influence the generation of this predicate in away to possibly help the optimiser choose the right index:

```sql
-- Settings.renderRowConditionForSeekClause = false to turn off using the ROW syntax
WHERE value > 2 OR value = 2 AND id > 533

-- Settings.renderRedundantConditionForSeekClause = true to add an additional redundant predicate
WHERE value >= 2 AND (value, id) > (2, 533)
WHERE value >= 2 AND (value > 2 OR value = 2 AND id > 533)
```

The default in jOOQ is to not do the above, but users can opt into the manual expansion of syntax to benefit performance.

Note that if the `ROW` syntax isn't supported natively, then jOOQ will expand that to the equivalent [OR predicate](#boolean-operators) anyway.

**Example configuration**

```java
Settings settings = new Settings()
    .withRenderRowConditionForSeekClause(false)       // Default to true
    .withRenderRedundantConditionForSeekClause(true); // Default to false
```

<a id="settings-statement-type"></a>
##### 3.2.8.51. Statement Type

JDBC knows two types of statements:

- [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html): This allows for sending bind variables to the server. jOOQ uses prepared statements by default.
- [`java.sql.Statement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html): Also "static statement". These do not support bind variables and may be useful for one-shot commands like [DDL statements](#ddl-statements).

The `statementType` setting allows for overriding the default of using prepared statements internally. There are two possible options for this setting:

- `PREPARED_STATEMENT` (the default): Use prepared statements.
- `STATIC_STATEMENT`: Use static statements. This enforces the `paramType == INLINED`. See [parameter types](#settings-parameter-type)

**Example configuration**

```java
Settings settings = new Settings()
    .withStatementType(StatementType.STATIC_STATEMENT); // Defaults to PREPARED_STATEMENT
```

<a id="settings-unchanged-records"></a>
##### 3.2.8.52. Storing unchanged records

When [storing records](#crud-with-updatablerecords), jOOQ only includes values in an `INSERT` or `UPDATE` statement that have been changed by client code. This raises the question of what should happen if no value has been changed at all:

```java
BookRecord book = create.fetchOne(BOOK, BOOK.ID.eq(1));

// No value was changed. Should this execute an UPDATE statement?
book.update();

BookRecord newBook = create.newRecord(BOOK);

// No value was set. Should this execute an INSERT statement?
newBook.insert();
```

The `insertUnchangedRecords` setting governs the behaviour of [`TableRecord.insert()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html#insert()), as well as the `INSERT` part of [`UpdatableRecord.store()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#store()) and [`UpdatableRecord.merge()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#merge()):

- `true` (the default): An `INSERT INTO .. DEFAULT VALUES` statement is executed, producing a row with only default values.
- `false`: No statement is executed, and `0` is returned.

The `updateUnchangedRecords` setting governs the behaviour of [`UpdatableRecord.update()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#update()), as well as the `UPDATE` part of `store()` and `merge()`. Executing an `UPDATE` for an unchanged record can be useful, for example, to fire triggers, to increment [record version or timestamp columns](#optimistic-locking), or to check that the row still exists. The possible values of [`org.jooq.conf.UpdateUnchangedRecords`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/UpdateUnchangedRecords.html) are:

- `NEVER` (the default): No statement is executed, and `0` is returned.
- `SET_PRIMARY_KEY_TO_ITSELF`: The primary key columns are set to themselves, e.g. `UPDATE book SET id = id WHERE id = ?`
- `SET_NON_PRIMARY_KEY_TO_THEMSELVES`: All other columns are set to themselves, e.g. `UPDATE book SET title = title, author_id = author_id WHERE id = ?`
- `SET_NON_PRIMARY_KEY_TO_RECORD_VALUES`: All other columns are set to the record's values, e.g. `UPDATE book SET title = ?, author_id = ? WHERE id = ?`. This is the same as calling `record.changed(true)` prior to updating.

Whether a record counts as unchanged depends on the [dirty tracking setting](#settings-dirty-tracking).

**Example configuration**

```java
Settings settings = new Settings()
    .withInsertUnchangedRecords(false) // Defaults to true
    .withUpdateUnchangedRecords(UpdateUnchangedRecords.SET_PRIMARY_KEY_TO_ITSELF); // Defaults to NEVER
```

<a id="settings-throw-exceptions"></a>
##### 3.2.8.53. Throw exceptions

Some databases, such as SQL Server or Sybase, can raise several errors from a single statement or batch, for example when executing procedural logic that interleaves result sets, update counts, and errors. JDBC exposes these errors through [`Statement.getMoreResults()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#getMoreResults()) and chained [`java.sql.SQLException`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/SQLException.html) instances. The `throwExceptions` setting governs how jOOQ propagates them. The possible values of [`org.jooq.conf.ThrowExceptions`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/ThrowExceptions.html) are:

- `THROW_ALL` (the default): All exceptions are consumed, chained using [`SQLException.setNextException()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/SQLException.html#setNextException(java.sql.SQLException)), and thrown together, wrapped in a [`org.jooq.exception.DataAccessException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataAccessException.html).
- `THROW_FIRST`: Only the first exception is thrown. Any further exceptions are not consumed.
- `THROW_NONE`: No exception is thrown. When [fetching many results](#many-fetching), the exceptions are collected in the resulting [`org.jooq.Results`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Results.html) instead, alongside the results and update counts.

With `THROW_NONE`, each exception is available from its [`org.jooq.ResultOrRows`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultOrRows.html) element:

```java
Results results = DSL.using(connection, dialect, new Settings().withThrowExceptions(THROW_NONE))
    .fetchMany("...");

for (ResultOrRows r : results.resultsOrRows()) {
    if (r.exception() != null)
        System.out.println("Exception: " + r.exception().getMessage());
    else if (r.result() != null)
        System.out.println("Result:\n" + r.result());
    else
        System.out.println("Update count: " + r.rows());
}
```

**Example configuration**

```java
Settings settings = new Settings()
    .withThrowExceptions(ThrowExceptions.THROW_FIRST); // Defaults to THROW_ALL
```

<a id="settings-updatable-primary-keys"></a>
##### 3.2.8.54. Updatable Primary Keys

In most database design guidelines, primary key values are expected to never change - an assumption that is essential to a normalised database.

As always, there are exceptions to these rules, and users may wish to allow for updatable primary key values in the [updatable records feature](#crud-with-updatablerecords) (note: any value can always be updated through ordinary [update statements](#update-statement)). An example:

```java
AuthorRecord author =
DSL.using(configuration) // This configuration will be attached to any record produced by the below query.
   .selectFrom(AUTHOR)
   .where(AUTHOR.ID.eq(1))
   .fetchOne();

author.setId(2);
author.store(); // The behaviour of this store call is governed by the updatablePrimaryKeys flag
```

The above store call depends on the value of the `updatablePrimaryKeys` flag:

- `false` (the default): Since immutability of primary keys is assumed, the store call will create a new record (a copy) with the new primary key value.
- `true`: Since mutablity of primary keys is allowed, the store call will change the primary key value from `1` to `2`.

**Example configuration**

```java
Settings settings = new Settings()
    .withUpdatablePrimaryKeys(true); // Defaults to false
```

<a id="settings-execute-without-where"></a>
##### 3.2.8.55. UPDATE and DELETE without WHERE

Forgetting the [WHERE clause](#where-clause) of an [UPDATE](#update-statement) or [DELETE](#delete-statement) statement is one of the most costly mistakes in SQL, as the statement affects all rows of the table. jOOQ checks every `UPDATE` and `DELETE` statement for the presence of a `WHERE` clause prior to executing it, and takes an action according to the `executeUpdateWithoutWhere` and `executeDeleteWithoutWhere` settings, respectively. The possible values of [`org.jooq.conf.ExecuteWithoutWhere`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/ExecuteWithoutWhere.html) are:

- `IGNORE`: The statement is executed without any further action.
- `LOG_DEBUG` (the default): The statement is executed, and a `DEBUG` level message is [logged](#logging).
- `LOG_INFO`: The statement is executed, and an `INFO` level message is logged.
- `LOG_WARN`: The statement is executed, and a `WARN` level message is logged.
- `THROW`: The statement is not executed. Instead, a [`org.jooq.exception.DataAccessException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataAccessException.html) is thrown.

The check happens only when the statement is executed by jOOQ. It has no effect on rendering the SQL string. A statement is considered to have a `WHERE` clause if any condition other than [`noCondition()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#noCondition()) was supplied, so in order to deliberately update or delete all rows of a table when `THROW` is active, use [`trueCondition()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#trueCondition()):

```java
// Throws a DataAccessException when executeUpdateWithoutWhere = THROW
create.update(BOOK)
      .set(BOOK.TITLE, "Untitled")
      .execute();

// Explicitly updates all rows
create.update(BOOK)
      .set(BOOK.TITLE, "Untitled")
      .where(trueCondition())
      .execute();
```

**Example configuration**

```java
Settings settings = new Settings()
    .withExecuteUpdateWithoutWhere(ExecuteWithoutWhere.THROW)  // Defaults to LOG_DEBUG
    .withExecuteDeleteWithoutWhere(ExecuteWithoutWhere.THROW); // Defaults to LOG_DEBUG
```

<a id="thread-safety"></a>
#### 3.2.9. Thread safety

[`org.jooq.Configuration`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Configuration.html), and by consequence [`org.jooq.DSLContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html), make no thread safety guarantees, but by carefully observing a few rules, they can be shared in a thread safe way. We encourage sharing `Configuration` instances, because they contain caches for work not worth repeating, such as reflection field and method lookups for [`org.jooq.impl.DefaultRecordMapper`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultRecordMapper.html). If you're using Spring or CDI for dependency injection, you will want to be able to inject a `DSLContext` instance everywhere you use it.

The following needs to be considered when attempting to share `Configuration` and `DSLContext` among threads:

- `Configuration` is mutable for historic reasons. Calls to various `Configuration.set()` methods must be avoided after initialisation, should a `Configuration` (and by consequence `DSLContext`) instance be shared among threads. If you wish to modify some elements of a `Configuration` for single use, use the `Configuration.derive()` methods instead, which create a copy.
- `Configuration` components, such as [`org.jooq.conf.Settings`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html) are mutable as well. The same rules for modification apply here.
- `Configuration` allows for supplying user-defined SPI implementations (see above for examples). All of these must be thread safe as well, for their wrapping `Configuration` to be thread safe. If you are using a [`org.jooq.impl.DataSourceConnectionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DataSourceConnectionProvider.html), for instance, you must make sure that your [`javax.sql.DataSource`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/javax/sql/DataSource.html) is thread safe as well. This is usually the case when you use a third party connection pool.

As can be seen above, `Configuration` was designed to work in a thread safe way, despite it not making any such guarantee.

<a id="dsl-api"></a>
### 3.3. The DSL API

The DSL API is the primary way to construct queries or query parts in jOOQ. See the [model API](#model-api) for an alternative way to interact with the jOOQ query object model.

jOOQ ships with its own DSL (or [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language)) that emulates SQL in Java. This means, that you can write SQL statements almost as if Java natively supported it, just like .NET's C# does with [LINQ to SQL.](https://msdn.microsoft.com/en-us/library/bb425822.aspx)

Here is an example to illustrate what that means:

```sql
-- Select all books by authors born after 1920,
-- named "Paulo" from a catalogue:
SELECT *
  FROM author a
  JOIN book b ON a.id = b.author_id
 WHERE a.year_of_birth > 1920
   AND a.first_name = 'Paulo'
 ORDER BY b.title
```

```java
Result<Record> result =
create.select()
      .from(AUTHOR.as("a"))
      .join(BOOK.as("b")).on(a.ID.eq(b.AUTHOR_ID))
      .where(a.YEAR_OF_BIRTH.gt(1920)
      .and(a.FIRST_NAME.eq("Paulo")))
      .orderBy(b.TITLE)
      .fetch();
```

We'll see how the aliasing works later in the section about [aliased tables](#aliased-tables)

Many other frameworks have similar APIs with similar feature sets. Yet, what makes jOOQ special is its informal [BNF notation](https://blog.jooq.org/the-java-fluent-api-designer-crash-course/) modelling a unified SQL dialect suitable for many vendor-specific dialects, and implementing that BNF notation as a hierarchy of interfaces in Java. This concept is extremely powerful, when [using jOOQ with IDE syntax auto completion](https://blog.jooq.org/why-you-should-use-jooq-with-code-generation/). Not only can you code much faster, your SQL code will be compile-checked to a certain extent. An example of a DSL query equivalent to the previous one is given here:

```java
DSLContext create = DSL.using(connection, dialect);
Result<?> result = create.select()
                         .from(AUTHOR)
                         .join(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
                         .fetch();
```

Unlike other, simpler frameworks that use ["fluent APIs"](https://en.wikipedia.org/wiki/Fluent_interface) or ["method chaining"](https://en.wikipedia.org/wiki/Method_chaining), jOOQ's BNF-based interface hierarchy will not allow bad query syntax. The following will not compile, for instance:

```java
DSLContext create = DSL.using(connection, dialect);
Result<?> result = create.select()
                         .join(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
                      //  ^^^^ "join" is not possible here
                         .from(AUTHOR)
                         .fetch();

Result<?> result = create.select()
                         .from(AUTHOR)
                         .join(BOOK)
                         .fetch();
                      //  ^^^^^ "on" is missing here

Result<?> result = create.select(rowNumber())
                      //         ^^^^^^^^^ "over()" is missing here
                         .from(AUTHOR)
                         .fetch();

Result<?> result = create.select()
                         .from(AUTHOR)
                         .where(AUTHOR.ID.in(select(BOOK.TITLE).from(BOOK)))
                      //                     ^^^^^^^^^^^^^^^^^^
                      // AUTHOR.ID is of type Field<Integer> but subselect returns Record1<String>
                         .fetch();

Result<?> result = create.select()
                         .from(AUTHOR)
                         .where(AUTHOR.ID.in(select(BOOK.AUTHOR_ID, BOOK.ID).from(BOOK)))
                      //                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                      // AUTHOR.ID is of degree 1 but subselect returns Record2<Integer, Integer>
                         .fetch();
```

<a id="mutability-historic"></a>
#### 3.3.1. Mutability (historic)

For historic reasons, the DSL API mixes mutable and immutable behaviour with respect to the internal representation of the [QueryPart](#queryparts) being constructed. While creating [conditional expressions](#conditional-expressions), [column expressions](#column-expressions) (such as functions) assumes immutable behaviour, creating [SQL statements](#sql-statements) does not. In other words, the following can be said:

```java
// Conditional expressions (immutable)
// -----------------------------------
Condition a = BOOK.TITLE.eq("1984");
Condition b = BOOK.TITLE.eq("Animal Farm");

// The following can be said
a       != a.or(b); // or() does not modify a
a.or(b) != a.or(b); // or() always creates new objects

// Statements (mutable)
// --------------------
SelectFromStep<?> s1 = select();
SelectJoinStep<?> s2 = s1.from(BOOK);
SelectJoinStep<?> s3 = s1.from(AUTHOR);

// The following can be said
s1 == s2; // The internal object is always the same
s2 == s3; // The internal object is always the same
```

On the other hand, beware that you can always extract and modify [bind values](#bind-values) from any `QueryPart`.

<a id="model-api"></a>
### 3.4. The model API

The model API is the secondary way to interact with queries or query parts in jOOQ. See the [DSL API](#dsl-api) for the main way to interact with the jOOQ query object model.

<a id="model-api-design"></a>
#### 3.4.1. Design

Experimental: this functionality is subject to change

The model API (Query Object Model or [`org.jooq.impl.QOM`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/QOM.html)) is an auxiliary API implemented by each and every [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) allowing for users to get public access to jOOQ's internal query object model structure. For example:

```java
// Create an expression using the DSL API:
Field<String> field = substring(BOOK.TITLE, 2, 4);

// Access the expression's internals using the model API
if (field instanceof QOM.Substring substring) {
    Field<String> string = substring.$string();
    Field<? extends Number> startingPosition = substring.$startingPosition();
    Field<? extends Number> length = substring.$length();
}
```

Every argument passed to the DSL API has a `$` prefixed accessor method on the model API, exposing the wrapped argument. Using these accessor methods, users can traverse the expression tree manually or via the [model API traversal API](#model-api-traversal). More recent Java language features like pattern matching can be very helpful for such operations, especially as we're planning to seal the entire query object model API.

All of the model API is immutable, but new expressions can still be created using equivalent `$` prefixed setter methods, which don't mutate the original expression but return a copy:

```java
// Produces a substring(BOOK.TITLE, 2, 4) column expression
QOM.Substring substring = (QOM.Substring) substring(BOOK.TITLE, 2, 4);

// Produces a substring(BOOK.TITLE, 3, 5) column expression
substring.$startingPosition(val(3)).$length(val(5));
```

These basic operations allow for powerful [SQL transformations](#sql-transformation) on expression trees created with the [DSL API](#dsl-api) but also with the [SQL parser](#sql-parser).

<a id="model-api-traversal"></a>
#### 3.4.2. Traversal

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition) · Experimental: this functionality is subject to change

While the [accessor methods](#model-api-design) from the model API allow for traversing the expression tree manually, a more generic way to traverse the expression tree is using the [`org.jooq.Traverser`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Traverser.html) API, which can traverse a [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) in a similar fashion as a [`java.util.stream.Collector`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collector.html) can iterate a [`java.util.stream.Stream`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Stream.html), collecting and aggregating data about the expression tree. A `Traverser consists of this API`:

```java
public interface Traverser<A, R> {

    /**
     * A supplier for a temporary data structure to accumulate {@link QueryPart}
     * objects into during traversal.
     */
    Supplier<A> supplier();

    /**
     * An optional traversal abort condition to short circuit traversal e.g.
     * when the searched object has been found.
     */
    Predicate<A> abort();

    /**
     * An optional recursion condition to prevent entering a specific
     * {@link QueryPart}, e.g. when it is undesired to enter any subqueries.
     */
    Predicate<QueryPart> recurse();

    /**
     * An optional recursion condition to prevent entering a specific
     * {@link QueryPart}'s children, e.g. when it is desired to traverse only
     * into certain operators.
     */
    Predicate<QueryPart> recurseChildren();

    /**
     * A callback that is invoked before recursing into a subtree.
     */
    BiFunction<A, QueryPart, A> before();

    /**
     * A callback that is invoked after recursing into a subtree.
     */
    BiFunction<A, QueryPart, A> after();

    /**
     * An optional transformation function to turn the temporary data structure
     * supplied by {@link #supplier()} into the final data structure.
     */
    Function<A, R> finisher();
}
```

Some elements are similar to that of a [`java.util.stream.Collector`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collector.html), others are specific to tree traversal.

A simple illustration shows what can be done:

```java
// Any ordinary QueryPart:
Condition condition = BOOK.ID.eq(1);
int count = condition.$traverse(

    // Supplier of the initial data structure: an int
    () -> 0,

    // Print all traversed QueryParts and increment the counter
    (r, q) -> {
        System.out.println("Part " + r + ": " + q);
        return r + 1;
    }
);
System.out.println("Count : " + count);
```

The above will print:

```text
Part 0: "BOOK"."ID" = 1
Part 1: "BOOK"."ID"
Part 2: 1
Count : 3
```

Using the same traverser on a slightly more complex `QueryPart`

```java
Condition condition = BOOK.ID.eq(1).or(BOOK.ID.eq(2));
// ...
```

```text
Part 0: ("BOOK"."ID" = 1 or "BOOK"."ID" = 2)
Part 1: "BOOK"."ID" = 1
Part 2: "BOOK"."ID"
Part 3: 1
Part 4: "BOOK"."ID" = 2
Part 5: "BOOK"."ID"
Part 6: 2
Count : 7
```

##### Re-using your JDK collectors

Any `Collector` can be turned into a `Traverser` using [`Traversers.collecting(Collector)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Traversers.html#collecting(java.util.stream.Collector)). For example, if you want to count all `QueryPart` items in an expression, instead of the above hand-written traverser, just use the JDK [`Collectors.counting()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collectors.html#counting()):

```java
// Contains 3 query parts
long count1 = BOOK.ID.eq(1)
    .$traverse(Traversers.collecting(Collectors.counting());

// Contains 7 query parts
long count2 = BOOK.ID.eq(1).or(BOOK.ID.eq(2))
    .$traverse(Traversers.collecting(Collectors.counting());
```

##### Limitations

Just like [model API replacement](#model-api-replacement), traversers cannot traverse into "opaque" [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) instances, including [custom QueryParts](#custom-queryparts) or [plain SQL templates](#plain-sql-templating-language). See also [features requiring code generation](#codegen-feature-dependencies) for more details.

<a id="model-api-replacement"></a>
#### 3.4.3. Replacement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition) · Experimental: this functionality is subject to change

A very powerful way to transform your SQL is to replace specific [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) elements in any expression tree by something else using the [`QueryPart.replace()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html#replace(org.jooq.Function1)) API. This API treats the expression tree as a [persistent data structure](https://en.wikipedia.org/wiki/Persistent_data_structure), i.e. the resulting tree may consist of parts of the existing tree, but the existing tree is not modified.

Let's assume you wish to implement an optimisation engine that removes redundant SQL clauses. For example, an expression `NOT(NOT(p))` can be replaced by `p` in standard SQL (it may not be the exact same thing in some "clever" dialects without standard `BOOLEAN` type support):

```java
// Contains redundant operators
Condition c = not(not(BOOK.ID.eq(1)));
System.out.println(c);
System.out.println(c.$replace(q ->
    q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Not n2
        ? n2.$arg1()
        : q
));
```

The above prints:

```text
not (not ("BOOK"."ID" = 1))
"BOOK"."ID" = 1
```

The replacement algorithm will attempt to run the replacement function recursively on your tree until it no longer affects the tree. This means two things:

- You can implement all of your replacement logic in a single function, for various rules. The order of application of the rules is the one you define in your function.
- The algorithm stops only when no more rules apply. If two rules turn `A > B` and `B > A`, then the algorithm may never stop.

Here's a more complex example that logs the replacements with `println()` calls:

```java
// Contains redundant operators
Condition c = not(not(not(BOOK.ID.ne(1))));
QueryPart result = c.$replace(q -> {
    if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Not n2) {
        System.out.println("Replacing NOT(NOT(p)) by NOT(p): " + q);
        return n2.$arg1();
    }
    else if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Ne<?> n2) {
        System.out.println("Replacing NOT(x != y) by x = y: " + q);
        return n2.$arg1().eq((Field) n2.$arg2());
    }

    return q;
}));
System.out.println("Result: " + result);
```

The output is:

```text
Replacing NOT(x != y) by x = y: not ("BOOK"."ID" <> 1)
Replacing NOT(NOT(p)) by NOT(p): not (not ("BOOK"."ID" = 1))
Result: "BOOK"."ID" = 1
```

As you can see:

- The replacement function is invoked several times.
- The second invocation can work on the result of the first invocation, where the `NOT (x != y)` predicate has already been improved.
- The replacement works recursively, depth first, and bottom up.
- It stops when no more replacements take place.

This obviously also works when you use jOOQ's [parser](#sql-parser), and is extremely useful when used via the [parsing connection](#parsing-connection), e.g. to optimise any type of JDBC or R2DBC based application!

```java
// Contains redundant operators
Condition c = create.parser().parseCondition("not not not book.id != 1");
QueryPart result = c.$replace(q -> {
    if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Not n2) {
        System.out.println("Replacing NOT(NOT(p)) by NOT(p): " + q);
        return n2.$arg1();
    }
    else if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Ne<?> n2) {
        System.out.println("Replacing NOT(x != y) by x = y: " + q);
        return n2.$arg1().eq((Field) n2.$arg2());
    }

    return q;
}));
System.out.println("Result: " + result);
```

The result is exactly the same:

```text
Replacing NOT(x != y) by x = y: not (book.id <> 1)
Replacing NOT(NOT(p)) by NOT(p): not (not (book.id = 1))
Result: book.id = 1
```

> [!TIP]
> Starting from jOOQ 3.17, this logging can also be achieved using a [listening replacer](#replacement-listening).

##### Built-in replacers

The following sections show a few examples of built-in replacers.

##### Limitations

Just like [model API traversal](#model-api-traversal), replacers cannot traverse into "opaque" [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) instances, including [custom QueryParts](#custom-queryparts) or [plain SQL templates](#plain-sql-templating-language). See also [features requiring code generation](#codegen-feature-dependencies) for more details.

<a id="replacement-transform-patterns"></a>
##### 3.4.3.1. Pattern transformation Replacer

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition) · Experimental: this functionality is subject to change

jOOQ offers a lot of out-of-the-box pattern based replacements like the above examples from the [previous section](#model-api-replacement). Please look at the sections about [pattern based transformation](#transform-patterns) for more details about individual patterns.

In order to apply pattern transformation explicitly to a [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html), just call:

```java
Condition input = BOOK.ID.eq(1).or(BOOK.ID.eq(2));
Condition output = (Condition) input.$replace(Replacers.transformPatterns(configuration));
```

By default, this will apply the [OR to IN](#transform-patterns-or-eq-to-in) transformation, and produce the following output:

```sql
BOOK.ID IN (1, 2)
```

```java
BOOK.ID.in(1, 2)
```

<a id="replacement-table-mapping"></a>
##### 3.4.3.2. Table mapping Replacer

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition) · Experimental: this functionality is subject to change

jOOQ has a powerful [runtime catalog, schema, and table mapping feature](#settings-render-mapping), which can be used to implement multi tenancy use-cases, etc. This mapping functionality is meant as a global configuration for the entirety of your application. Very often, however, you need to map just a single table, or a small set of tables for a specific purpose, for example:

```sql
-- Input
SELECT t.id, t.value FROM t

-- Output
SELECT u.id, u.value FROM u
```

In order to achieve this, just apply the following replacement:

```java
Select<?> input = select(T.ID, T.VALUE).from(T);
Select<?> output = (Select<?>) input.$replace(Replacers.mappingTable(T, U));
```

Or, if the decision what to map is more elaborate, use a lambda:

```java
Select<?> input = select(T.ID, T.VALUE).from(T);
Select<?> output = (Select<?>) input.$replace(Replacers.mappingTable(t -> T.equals(t) ? U : t));
```

<a id="replacement-listening"></a>
##### 3.4.3.3. Listening Replacer

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition) · Experimental: this functionality is subject to change

This replacer doesn't replace anything on its own, but helps debug things from other replacers. For example, a Replacer that removes redundant `NOT(NOT(x))` expressions:

```java
// The input condition
Condition c = ctx.parser().parseCondition("not not not book.id != 1");

// The replacer doing the replacement
Replacer r = Replacer.of(q -> {
    if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Not n2)
        return n2.$arg1();
    else if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Ne<?> n2)
        return n2.$arg1().eq((Field) n2.$arg2());
    else
        return q;
});

// A proxy to the above replacer, doing some logging
r = Replacers.listening(r, (p1, p2) -> System.out.println("Replacing: " + p1 + " => " + p2));

// The application of the replacement
QueryPart result = c.$replace(r);
System.out.println("Result: " + result);
```

The above now prints each replacement that the depth first replacement algorithm applies to your expression tree, bottom-up:

```text
Replacing: not (book.id <> 1) => book.id = 1
Replacing: not (not (book.id = 1)) => book.id = 1
Result: book.id = 1
```

<a id="replacement-decomposing"></a>
##### 3.4.3.4. Decomposing Replacer

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition) · Experimental: this functionality is subject to change

This replacer decomposes compound queries into their component queries. Some DDL statements are compound statements, such as e.g.

```sql
ALTER TABLE t
  ADD col1 INT,
  ADD col2 INT;
```

The above single compound statement can be decomposed into its component statements:

```sql
ALTER TABLE t ADD col1 INT;
ALTER TABLE t ADD col2 INT;
```

Some use-cases, including DDL interpretation may be better served by component statements rather than the compound version.

As this [`org.jooq.Replacer`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Replacer.html) has to adhere to the contract imposed on replacers, it can only operate on [`org.jooq.Queries`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Queries.html) and other [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html) wrapping elements, such as [`org.jooq.Block`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Block.html) and other procedural scope statements.

<a id="model-api-historic"></a>
#### 3.4.4. The historic model API

Historically, jOOQ started out as an object-oriented SQL builder library like any other. This meant that all queries and their syntactic components were modeled as so-called [QueryParts](#queryparts), which delegate [SQL rendering](#sql-rendering) and [variable binding](#variable-binding) to child components. This part of the API will be referred to as the model API (or non-DSL API), which is still maintained and used internally by jOOQ for incremental query building. An example of incremental query building is given here:

```java
DSLContext create = DSL.using(connection, dialect);
SelectQuery<Record> query = create.selectQuery();
query.addFrom(AUTHOR);

// Join books only under certain circumstances
if (join) {
    query.addJoin(BOOK, BOOK.AUTHOR_ID.eq(AUTHOR.ID));
}

Result<?> result = query.fetch();
```

This query is equivalent to the one shown before using the DSL syntax. In fact, internally, the DSL API constructs precisely this SelectQuery object. Note, that you can always access the SelectQuery object to switch between DSL and model APIs:

```java
DSLContext create = DSL.using(connection, dialect);
SelectFinalStep<?> select = create.select().from(AUTHOR);

// Add the JOIN clause on the internal QueryObject representation
SelectQuery<?> query = select.getQuery();
query.addJoin(BOOK, BOOK.AUTHOR_ID.eq(AUTHOR.ID));
```

This API is completely mutable, and for historic reasons, [early DSL API elements have inherited this mutability](#mutability-historic).

<a id="sql-statements"></a>
### 3.5. SQL Statements (DML)

jOOQ currently supports 5 types of SQL statements. All of these statements are constructed from a DSLContext instance with an optional [JDBC Connection or DataSource](#connection-vs-datasource). If supplied with a Connection or DataSource, they can be executed. Depending on the [query type](#query-vs-resultquery), executed queries can return results.

<a id="with-clause"></a>
#### 3.5.1. The WITH clause

The SQL:1999 standard specifies the `WITH` clause to be an optional clause for the [SELECT statement](#select-statement), in order to specify [common table expressions](#common-table-expressions) (also: CTE). Many other databases (such as PostgreSQL, SQL Server) also allow for using common table expressions also in other DML statements, such as the [INSERT statement](#insert-statement), [UPDATE statement](#update-statement), [DELETE statement](#delete-statement), or [MERGE statement](#merge-statement).

The following example makes use of [names](#names) to construct common table expressions, which can then be supplied to a `WITH` clause or a `FROM` clause of a [SELECT statement](#select-statement):

```sql
-- Pseudo-SQL for a common table expression specification
"t1" ("f1", "f2") AS (SELECT 1, 'a')
```

```java
// Code for creating a CommonTableExpression instance
name("t1").fields("f1", "f2").as(select(val(1), val("a")));
```

The above expression can be assigned to a variable in Java and then be used to create a full [SELECT statement](#select-statement):

```sql
WITH "t1" ("f1", "f2") AS (SELECT 1, 'a'),
     "t2" ("f3", "f4") AS (SELECT 2, 'b')
SELECT
    "t1"."f1" + "t2"."f3" AS "add",
    "t1"."f2" || "t2"."f4" AS "concat"
FROM "t1", "t2"
;
```

```java
CommonTableExpression<Record2<Integer, String>> t1 =
  name("t1").fields("f1", "f2").as(select(val(1), val("a")));
CommonTableExpression<Record2<Integer, String>> t2 =
  name("t2").fields("f3", "f4").as(select(val(2), val("b")));

Result<?> result2 =
create.with(t1)
      .with(t2)
      .select(
          t1.field("f1").add(t2.field("f3")).as("add"),
          t1.field("f2").concat(t2.field("f4")).as("concat"))
      .from(t1, t2)
      .fetch();
```

See also the section about [common table expressions](#common-table-expressions).

<a id="with-recursive-clause"></a>
#### 3.5.2. The WITH RECURSIVE clause

The various SQL dialects do not agree on the use of `RECURSIVE` when writing recursive common table expressions. When using jOOQ, always use the [`DSLContext.withRecursive()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#withRecursive(org.jooq.CommonTableExpression...)) or [`DSL.withRecursive()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#withRecursive(org.jooq.CommonTableExpression...)) methods, and jOOQ will render the `RECURSIVE` keyword, if needed.

Assuming a table like this:

```sql
CREATE TABLE directory (
  id           INT NOT NULL,
  parent_id    INT,

  -- In PostgreSQL, use TEXT instead, to work around https://github.com/jOOQ/jOOQ/issues/12067
  label        VARCHAR(50),

  CONSTRAINT pk_directory PRIMARY KEY (id),
  CONSTRAINT fk_directory FOREIGN KEY (parent_id) REFERENCES directory (id)
);

INSERT INTO directory VALUES ( 1, null, 'C:');
INSERT INTO directory VALUES ( 2,    1, 'eclipse');
INSERT INTO directory VALUES ( 3,    2, 'configuration');
INSERT INTO directory VALUES ( 4,    2, 'dropins');
INSERT INTO directory VALUES ( 5,    2, 'features');
INSERT INTO directory VALUES ( 7,    2, 'plugins');
INSERT INTO directory VALUES ( 8,    2, 'readme');
INSERT INTO directory VALUES ( 9,    8, 'readme_eclipse.html');
INSERT INTO directory VALUES (10,    2, 'src');
INSERT INTO directory VALUES (11,    2, 'eclipse.exe');
```

Using `WITH RECURSIVE`, you can now query the structure of this directory as follows:

```sql
WITH RECURSIVE t (
  id,
  name,
  path
) AS (
  SELECT
    DIRECTORY.ID,
    DIRECTORY.LABEL,
    DIRECTORY.LABEL
  FROM
    DIRECTORY
  WHERE
    DIRECTORY.PARENT_ID IS NULL
  UNION ALL
  SELECT
    DIRECTORY.ID,
    DIRECTORY.LABEL,
    t.path
      || '\'
      || DIRECTORY.LABEL
  FROM
    t
  JOIN
    DIRECTORY
  ON t.id = DIRECTORY.PARENT_ID
)
SELECT *
FROM
  t;
```

```java
CommonTableExpression<?> cte = name("t").fields(
  "id",
  "name",
  "path"
).as(
  select(
    DIRECTORY.ID,
    DIRECTORY.LABEL,
    DIRECTORY.LABEL)
  .from(DIRECTORY)
  .where(DIRECTORY.PARENT_ID.isNull())
  .unionAll(
  select(
    DIRECTORY.ID,
    DIRECTORY.LABEL,
    field(name("t", "path"), VARCHAR)
      .concat("\\")
      .concat(DIRECTORY.LABEL))
  .from(table(name("t")))
  .join(DIRECTORY)
  .on(field(name("t", "id"), INTEGER)
    .eq(DIRECTORY.PARENT_ID)))
);

System.out.println(
    create.withRecursive(cte)
          .selectFrom(cte)
          .fetch()
);
```

The output would look like this:

```text
+----+---------------------+---------------------------------------+
| id | name                | path                                  |
+----+---------------------+---------------------------------------+
| 1  | C:                  | C:                                    |
| 2  | eclipse             | C:\eclipse                            |
| 3  | configuration       | C:\eclipse\configuration              |
| 4  | dropins             | C:\eclipse\dropins                    |
| 11 | eclipse.exe         | C:\eclipse\eclipse.exe                |
| 5  | features            | C:\eclipse\features                   |
| 7  | plugins             | C:\eclipse\plugins                    |
| 8  | readme              | C:\eclipse\readme                     |
| 9  | readme_eclipse.html | C:\eclipse\readme\readme_eclipse.html |
| 10 | src                 | C:\eclipse\src                        |
+----+---------------------+---------------------------------------+
```

##### Caveats

The SQL language expresses the recursion syntactically, meaning the table `t` in the above example is being referenced from within the declaration of `t`. This isn't possible in a language like Java. Hence, we must use the [identifier API](#names) to construct identifier references for [tables](#table-expressions) and [columns](#column-expressions). This technique usually appears a bit more verbose than ordinary jOOQ API usage that is based on generated code for your schema.

<a id="select-statement"></a>
#### 3.5.3. The SELECT statement

When you don't just perform [CRUD](#crud-with-updatablerecords) (i.e. SELECT * FROM your_table WHERE ID = ?), you're usually generating new record types using custom projections. With jOOQ, this is as intuitive, as if using SQL directly. A more or less complete example of the "standard" SQL syntax, plus some extensions, is provided by a query like this:

##### SELECT from a complex table expression

```sql
-- get all authors' first and last names, and the number
-- of books they've written in German, if they have written
-- more than five books in German in the last three years
-- (from 2011), and sort those authors by last names
-- limiting results to the second and third row, locking
-- the rows for a subsequent update... whew!

  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, COUNT(*)
    FROM AUTHOR
    JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID
   WHERE BOOK.LANGUAGE = 'DE'
     AND BOOK.PUBLISHED_IN > 2008
GROUP BY AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  HAVING COUNT(*) > 5
ORDER BY AUTHOR.LAST_NAME ASC NULLS FIRST
   LIMIT 2
  OFFSET 1
     FOR UPDATE
```

```java
// And with jOOQ...



DSLContext create = DSL.using(connection, dialect);

create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())
      .from(AUTHOR)
      .join(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .where(BOOK.LANGUAGE.eq("DE"))
      .and(BOOK.PUBLISHED_IN.gt(2008))
      .groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .having(count().gt(5))
      .orderBy(AUTHOR.LAST_NAME.asc().nullsFirst())
      .limit(2)
      .offset(1)
      .forUpdate()
      .fetch();
```

Details about the various clauses of this query will be provided in subsequent sections.

##### SELECT from single tables

A very similar, but limited API is available, if you want to select from single tables in order to retrieve [TableRecords or even UpdatableRecords](#crud-with-updatablerecords). The decision, which type of select to create is already made at the very first step, when you create the `SELECT` statement with the DSL or DSLContext types:

```java
public <R extends Record> SelectWhereStep<R> selectFrom(Table<R> table);
```

As you can see, there is no way to further restrict/project the selected fields. This just selects all known TableFields in the supplied Table, and it also binds <R extends Record> to your Table's associated Record. An example of such a Query would then be:

```java
BookRecord book = create.selectFrom(BOOK)
                        .where(BOOK.LANGUAGE.eq("DE"))
                        .orderBy(BOOK.TITLE)
                        .fetchAny();
```

The "reduced" SELECT API is limited in the way that it skips DSL access to any of these clauses:

- [SELECT clause](#select-clause)
- [JOIN operator](#join-clause)

In most parts of this manual, it is assumed that you do not use the "reduced" SELECT API. For more information about the simple SELECT API, see the manual's section about [fetching strongly or weakly typed records](#record-vs-tablerecord).

<a id="select-clause"></a>
##### 3.5.3.1. SELECT clause

The `SELECT` clause lets you project your own record types, referencing table fields, functions, arithmetic expressions, etc. The DSL type provides several methods for expressing a SELECT clause:

```sql
-- The SELECT clause
SELECT BOOK.ID, BOOK.TITLE
SELECT BOOK.ID, TRIM(BOOK.TITLE)
```

```java
// Provide a varargs Fields list to the SELECT clause:
Select<?> s1 = create.select(BOOK.ID, BOOK.TITLE);
Select<?> s2 = create.select(BOOK.ID, trim(BOOK.TITLE));
```

The following sections illustrate various features and subclauses of the `SELECT` clause.

<a id="select-clause-type-safety"></a>
###### 3.5.3.1.1. Projection type safety

Since jOOQ 3.0, [records](#record-n) and [row value expressions](#row-value-expressions) up to degree 22 are now generically typesafe. This is reflected by an overloaded `SELECT` (and `SELECT DISTINCT`) API in both DSL and DSLContext. An extract from the DSL type:

```java
// Non-typesafe select methods:
public static SelectSelectStep<Record> select(Collection<? extends SelectField<?>> fields);
public static SelectSelectStep<Record> select(SelectField<?>... fields);

// Typesafe select methods:
public static <T1>         SelectSelectStep<Record1<T1>>         select(SelectField<T1> field1);
public static <T1, T2>     SelectSelectStep<Record2<T1, T2>>     select(SelectField<T1> field1, SelectField<T2> field2);
// [...]
```

The type that is being projected is the [`org.jooq.SelectField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SelectField.html), see also the [next section about SelectField](#select-clause-selectfield). Since the generic R type is bound to some [Record[N]](#record-n), the associated T type information can be used in various other contexts, e.g. the [IN predicate](#in-predicate). Such a `SELECT` statement can be assigned typesafely:

```java
Select<Record2<Integer, String>> s1 = create.select(BOOK.ID, BOOK.TITLE);
Select<Record2<Integer, String>> s2 = create.select(BOOK.ID, trim(BOOK.TITLE));

// Alternatively, just use var to infer the type:
var s3 = create.select(BOOK.ID, trim(BOOK.TITLE));
```

For more information about typesafe record types with degree up to 22, see the manual's section about [Record1 to Record22](#record-n).

<a id="select-clause-selectfield"></a>
###### 3.5.3.1.2. SelectField

The [`org.jooq.SelectField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SelectField.html) type is used by any projection of the [SELECT clause](#select-clause) and the [INSERT .. RETURNING](#insert-returning) clause. It has numerous subtypes, which are allowed as projections in jOOQ:

- [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html): Every [column expression](#column-expressions) can automatically be projected in `SELECT` as you would expect.
- [`org.jooq.Row`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Row.html): [nested records](#nested-records) can be projected in `SELECT`
- [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html): [tables](#select-clause-table) can be projected as type safe nested records in `SELECT`
- [MULTISET](#multiset-value-constructor) and other means of projecting nested collections can be projected as well

<a id="select-clause-table"></a>
###### 3.5.3.1.3. Tables as SelectField

An [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) expression extends the [`org.jooq.SelectField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SelectField.html) type, and as such, can be used in the [SELECT clause](#select-clause) directly, as well as everywhere else a `SelectField` is accepted, e.g. in [nested records](#nested-records). This is specifically useful for [(generated) table references](#generated-tables). The following shows how to project a nested [`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html):

```java
Result<Record2<AuthorRecord, BookRecord>> result =
create.select(AUTHOR, BOOK)
      .from(AUTHOR)
      .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
      .fetch();
```

This plays very well together with [implicit joins](#implicit-join):

```java
Result<Record2<AuthorRecord, BookRecord>> result =
create.select(BOOK.author(), BOOK)
      .from(BOOK)
      .fetch();
```

Behind the scenes, the implementation may either be native in dialects that support this kind of projection (e.g. PostgreSQL), or emulated using the usual [nested records](#nested-records) emulations.

> [!TIP]
> Nesting tables using this syntax is different from using the [TABLE.asterisk()](#select-clause-asterisk) syntax, which doesn't nest the table but flattens its fields into the surrounding projection.

###### Dialect support

This example using jOOQ:

```java
select(BOOK).from(BOOK)
```

Translates to the following dialect specific expressions:

###### ASE, Access, SQLDataWarehouse, SQLServer, Sybase

```sql
SELECT BOOK.ID [BOOK__ID],
BOOK.AUTHOR_ID [BOOK__AUTHOR_ID],
BOOK.TITLE [BOOK__TITLE],
BOOK.PUBLISHED_IN [BOOK__PUBLISHED_IN],
BOOK.LANGUAGE_ID [BOOK__LANGUAGE_ID]
FROM BOOK
```

###### Aurora MySQL, BigQuery, MariaDB, MemSQL, MySQL, SQLite, Spanner

```sql
SELECT BOOK.ID `BOOK__ID`,
BOOK.AUTHOR_ID `BOOK__AUTHOR_ID`,
BOOK.TITLE `BOOK__TITLE`,
BOOK.PUBLISHED_IN `BOOK__PUBLISHED_IN`,
BOOK.LANGUAGE_ID `BOOK__LANGUAGE_ID`
FROM BOOK
```

###### Aurora Postgres, CockroachDB, DuckDB, H2, Informix, Postgres, YugabyteDB

```sql
SELECT ROW (
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
) BOOK
FROM BOOK
```

###### ClickHouse

```sql
SELECT TUPLE (
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
) BOOK
FROM BOOK
```

###### Databricks

```sql
SELECT STRUCT (
  coalesce(BOOK.ID),
  coalesce(BOOK.AUTHOR_ID),
  coalesce(BOOK.TITLE),
  coalesce(BOOK.PUBLISHED_IN),
  coalesce(BOOK.LANGUAGE_ID)
) BOOK
FROM BOOK
```

###### DB2, Exasol, Firebird, HSQLDB, Hana, Oracle, Redshift, Snowflake, Teradata, Trino, Vertica

```sql
SELECT BOOK.ID "BOOK__ID",
BOOK.AUTHOR_ID "BOOK__AUTHOR_ID",
BOOK.TITLE "BOOK__TITLE",
BOOK.PUBLISHED_IN "BOOK__PUBLISHED_IN",
BOOK.LANGUAGE_ID "BOOK__LANGUAGE_ID"
FROM BOOK
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="select-clause-asterisk"></a>
###### 3.5.3.1.4. SELECT *

jOOQ supports the asterisk operator in projections both as a qualified asterisk (through [`Table.asterisk()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#asterisk())) and as an unqualified asterisk (through [`DSL.asterisk()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#asterisk())). It is also possible to omit the projection entirely, in case of which an asterisk may appear in generated SQL, if not all column names are known to jOOQ.

Whenever jOOQ generates an asterisk (explicitly, or because jOOQ doesn't know the exact projection), the column order, and the column set are defined by the database server, not jOOQ. If you're using generated code, this may lead to problems as there might be a different column order than expected, as well as too many or too few columns might be projected.

```java
// Explicitly selects all columns available from BOOK - No asterisk
create.select().from(BOOK).fetch();

// Explicitly selects all columns available from BOOK and AUTHOR - No asterisk
create.select().from(BOOK, AUTHOR).fetch();
create.select().from(BOOK).crossJoin(AUTHOR).fetch();

// Renders a SELECT * statement, as columns are unknown to jOOQ - Implicit unqualified asterisk
create.select().from(table(name("BOOK"))).fetch();

// Renders a SELECT * statement - Explicit unqualified asterisk
create.select(asterisk()).from(BOOK).fetch();

// Renders a SELECT BOOK.* statement - Explicit qualified asterisk
create.select(BOOK.asterisk()).from(BOOK).fetch();
create.select(BOOK.asterisk(), AUTHOR.asterisk()).from(BOOK, AUTHOR).fetch();
```

With all of the above syntaxes, the row type (as discussed below) is unknown to jOOQ and to the Java compiler.

> [!TIP]
> Unlike the [Nesting tables syntax](#select-clause-table), the asterisk is expanded by the SQL engine (or by jOOQ, if necessary) by flattening the table's fields into the surrounding projection. It does not nest tables.

It is worth mentioning that in many cases, using an asterisk is a sign of an inefficient query because if not all columns are needed, too much data is transferred between client and server, plus some joins that could be eliminated otherwise, cannot. For more information check out [this section](#dont-do-this-sql-select-all).

<a id="select-clause-asterisk-except"></a>
###### 3.5.3.1.5. SELECT * EXCEPT (...)

A useful extension to the previously mentioned standard SQL [SELECT *](#select-clause-asterisk) syntax is the BigQuery inspired `* EXCEPT (columns)` syntax, which takes all of a projection's columns, except *some* columns. Just like the asterisk itself, this is mainly useful for ad-hoc querying, but it can also be useful for an occasional jOOQ query.

```java
// Renders a SELECT * statement - Explicit unqualified asterisk
create.select(asterisk().except(BOOK.ID)).from(BOOK).fetch();

// Renders a SELECT BOOK.* statement - Explicit qualified asterisk
create.select(BOOK.asterisk().except(BOOK.ID))
      .from(BOOK)
      .fetch();

create.select(BOOK.asterisk().except(BOOK.ID), AUTHOR.asterisk().except(AUTHOR.ID))
      .from(BOOK, AUTHOR)
      .fetch();
```

If a dialect doesn't support this syntax natively, jOOQ will just expand the syntax for you, explicitly, given the knowledge about meta data in generated code.

###### Dialect support

This example using jOOQ:

```java
select(asterisk().except(LANGUAGE.ID)).from(LANGUAGE)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, SQLDataWarehouse, SQLServer, SQLite, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT LANGUAGE.CD, LANGUAGE.DESCRIPTION
FROM LANGUAGE
```

###### BigQuery, Spanner

```sql
SELECT * EXCEPT (ID)
FROM LANGUAGE
```

###### Databricks, H2

```sql
SELECT * EXCEPT (LANGUAGE.ID)
FROM LANGUAGE
```

###### Redshift

```sql
SELECT * EXCLUDE (LANGUAGE.ID)
FROM LANGUAGE
```

###### Snowflake

```sql
SELECT * EXCLUDE (ID)
FROM LANGUAGE
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="select-clause-distinct"></a>
###### 3.5.3.1.6. SELECT DISTINCT

The `DISTINCT` keyword can be included in the method name, when constructing a `SELECT` clause, to remove duplicate tuples from the projection.

```sql
SELECT DISTINCT BOOK.TITLE FROM BOOK
```

```java
create.selectDistinct(BOOK.TITLE).from(BOOK).fetch();
```

###### Dialect support

This example using jOOQ:

```java
selectDistinct(BOOK.TITLE).from(BOOK)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
SELECT DISTINCT BOOK.TITLE
FROM BOOK
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="select-clause-distinct-on"></a>
###### 3.5.3.1.7. SELECT DISTINCT ON

A useful, though perhaps a bit esoteric PostgreSQL specific extension to `SELECT DISTINCT` is the `ON` clause. Using this clause, PostgreSQL users can specify a distinctness criteria, but then produce other columns per distinct group from one of the group's tuples. This is normally not possible in SQL, but with `ON`, the first tuple in the group according to the `ORDER BY` clause can be accessed nonetheless. An example:

```sql
SELECT DISTINCT ON (BOOK.LANGUAGE_ID)
  BOOK.LANGUAGE_ID, BOOK.TITLE
FROM BOOK
ORDER BY BOOK.LANGUAGE_ID, BOOK.TITLE
```

```java
Select<?> select1 = create.select(BOOK.LANGUAGE_ID, BOOK.TITLE)
      .distinctOn(BOOK.LANGUAGE_ID)
      .from(BOOK)
      .orderBy(BOOK.LANGUAGE_ID, BOOK.TITLE).fetch();
```

For syntactic reasons, the order of keywords had to be inversed as the PostgreSQL syntax cannot be easily reproduced in jOOQ's internal DSL. Quite likely, you might find jOOQ's syntax a bit more intuitive, though, as it more clearly separates the `SELECT` parts and the `DISTINCT ON` parts. Arguably, the `DISTINCT ON` clause should be positioned after `ORDER BY`, where it [logically belongs](https://blog.jooq.org/a-beginners-guide-to-the-true-order-of-sql-operations/).

###### Standard SQL equivalence

The PostgreSQL extension isn't really necessary as there is a standard SQL equivalence using `ROW_NUMBER` filtering. In the below example, we're using an extension to the standard, the [QUALIFY clause](#qualify-clause), to illustrate:

```sql
SELECT BOOK.LANGUAGE_ID, BOOK.TITLE
FROM BOOK
QUALIFY ROW_NUMBER() OVER (PARTITION BY BOOK.LANGUAGE_ID ORDER BY BOOK.TITLE) = 1
ORDER BY BOOK.LANGUAGE_ID, BOOK.TITLE
```

```java
Select<?> select1 = create.select(BOOK.LANGUAGE_ID, BOOK.TITLE)
      .from(BOOK)
      .qualify(rowNumber().over(partitionBy(BOOK.LANGUAGE_ID).orderBy(BOOK.TITLE)).eq(1))
      .orderBy(BOOK.LANGUAGE_ID, BOOK.TITLE).fetch();
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.LANGUAGE_ID, BOOK.TITLE).distinctOn(BOOK.LANGUAGE_ID).from(BOOK).orderBy(BOOK.LANGUAGE_ID, BOOK.TITLE)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, ClickHouse, CockroachDB, DuckDB, H2, Postgres, YugabyteDB

```sql
SELECT DISTINCT ON (BOOK.LANGUAGE_ID) BOOK.LANGUAGE_ID, BOOK.TITLE
FROM BOOK
ORDER BY BOOK.LANGUAGE_ID, BOOK.TITLE
```

###### BigQuery, DB2, Databricks, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
SELECT t.LANGUAGE_ID, t.TITLE
FROM (
  SELECT
    BOOK.LANGUAGE_ID,
    BOOK.TITLE,
    row_number() OVER (
      PARTITION BY BOOK.LANGUAGE_ID
      ORDER BY BOOK.LANGUAGE_ID, BOOK.TITLE
    ) rn
  FROM BOOK
) t
WHERE rn = 1
ORDER BY LANGUAGE_ID, TITLE
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="select-clause-convenience"></a>
###### 3.5.3.1.8. Convenience methods

Some commonly used projections can be easily created using convenience methods:

```sql
-- Simple SELECTs
SELECT COUNT(*)
SELECT 0 -- Not a bind variable
SELECT 1 -- Not a bind variable
```

```java
// Select commonly used values
Result<?> result1 = create.selectCount().fetch();
Result<?> result2 = create.selectZero().fetch();
Result<?> result3 = create.selectOne().fetch();
```

Which are short forms for creating [Column expressions](#column-expressions) from the [`org.jooq.impl.DSL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html) API

```sql
-- Simple SELECTs
SELECT COUNT(*)
SELECT 0 -- Not a bind variable
SELECT ? -- A bind variable
```

```java
// Select commonly used values
Result<?> result1 = create.select(count()).fetch();
Result<?> result2 = create.select(inline(0)).fetch();
Result<?> result3 = create.select(val(1)).fetch();
```

<a id="from-clause"></a>
##### 3.5.3.2. FROM clause

The SQL FROM clause allows for specifying any number of [table expressions](#table-expressions) to select data from. The following are examples of how to form normal FROM clauses:

```sql
SELECT 1 FROM BOOK
SELECT 1 FROM BOOK, AUTHOR
SELECT 1 FROM BOOK "b", AUTHOR "a"
```

```java
create.selectOne().from(BOOK).fetch();
create.selectOne().from(BOOK, AUTHOR).fetch();
create.selectOne().from(BOOK.as("b"), AUTHOR.as("a")).fetch();
```

Read more about aliasing in the manual's section about [aliased tables](#aliased-tables).

###### More advanced table expressions

Apart from simple tables, you can pass any arbitrary [table expression](#table-expressions) to the jOOQ FROM clause. This may include [unnested cursors](#array-and-cursor-unnesting) in Oracle:

```sql
SELECT *
FROM TABLE(
    DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS')
);
```

```java
create.select()
      .from(table(
          DbmsXplan.displayCursor(null, null, "ALLSTATS")
      ).fetch();
```

Note, in order to access the DbmsXplan package, you can use the [code generator](#code-generation) to generate Oracle's SYS schema.

###### Selecting FROM DUAL with jOOQ

In many SQL dialects, FROM is a mandatory clause, in some it isn't. jOOQ allows you to omit the FROM clause, returning just one record. An example:

```sql
SELECT 1 FROM DUAL
SELECT 1
```

```java
DSL.using(SQLDialect.ORACLE).selectOne().fetch();
DSL.using(SQLDialect.POSTGRES).selectOne().fetch();
```

Read more about dual or dummy tables in the manual's section about [the DUAL table](#dual). The following are examples of how to form normal FROM clauses:

<a id="join-clause"></a>
###### 3.5.3.2.1. JOIN operator

jOOQ supports many different types of standard and non-standard SQL JOIN operations. All of these JOIN methods can be called on [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) types the (more info in [joined tables section](#joined-tables)), or directly after the FROM clause for convenience. The following example joins AUTHOR and BOOK

```java
DSLContext create = DSL.using(connection, dialect);

// Call "join" directly on the AUTHOR table
Result<?> result = create.select()
                         .from(AUTHOR.join(BOOK)
                                     .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
                         .fetch();

// Call "join" on the type returned by "from"
Result<?> result = create.select()
                         .from(AUTHOR)
                         .join(BOOK)
                         .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
                         .fetch();
```

The two syntaxes will produce the same SQL statement. However, calling "join" on [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) objects allows for more powerful, nested JOIN expressions (if you can handle the parentheses):

```sql
SELECT *
FROM AUTHOR
LEFT OUTER JOIN (
  BOOK JOIN BOOK_TO_BOOK_STORE
       ON BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
)
ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
// Nest joins and provide JOIN conditions only at the end
create.select()
      .from(AUTHOR
      .leftOuterJoin(BOOK
        .join(BOOK_TO_BOOK_STORE)
        .on(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK.ID)))
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
      .fetch();
```

- See the section about [conditional expressions](#conditional-expressions) to learn more about the many ways to create [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html) objects in jOOQ.
- See the section about [table expressions](#table-expressions) to learn about the various ways of referencing [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) objects in jOOQ

For more information about the different types of join, please refer to the [joined tables section](#joined-tables).

<a id="implicit-join"></a>
###### 3.5.3.2.2. Implicit path JOIN

In SQL, a lot of [explicit JOIN clauses](#join-clause) are written simply to retrieve a parent table's column from a given child table. For example, we'll write:

```sql
-- Get all books, their authors, and their respective language
SELECT
  a.first_name,
  a.last_name,
  b.title,
  l.cd AS language
FROM book b
JOIN author a ON b.author_id = a.id
JOIN language l ON b.language_id = l.id;

-- Count the number of books by author and language
SELECT
  a.first_name,
  a.last_name,
  l.cd AS language,
  COUNT(*)
FROM book
JOIN author a ON b.author_id = a.id
JOIN language l ON b.language_id = l.id
GROUP BY a.id, a.first_name, a.last_name, l.cd
ORDER BY a.first_name, a.last_name, l.cd
```

There is quite a bit of syntactic ceremony (or we could even call it "noise") to get a relatively simple job done. A much simpler notation would be using implicit joins:

```sql
-- Get all books, their authors, and their respective language
SELECT
  b.author.first_name,
  b.author.last_name,
  b.title,
  b.language.cd AS language
FROM book b;

-- Count the number of books by author and language
SELECT
  b.author.first_name,
  b.author.last_name,
  b.language.cd AS language,
  COUNT(*)
FROM book b
GROUP BY
  b.author_id,
  b.author.first_name,
  b.author.last_name,
  b.language.cd
ORDER BY
  b.author.first_name,
  b.author.last_name,
  b.language.cd
```

Notice how this alternative notation (depending on your taste) may look more tidy and straightforward, as the semantics of accessing a table's parent table (or an entity's parent entity) is straightforward.

From jOOQ 3.11 onwards, this syntax is supported for to-one relationship navigation, and from jOOQ 3.19 also for to-many relationship navigation. The code generator produces relevant navigation methods on generated tables, which can be used in a type safe way. The navigation method names are:

- The parent table name (or child table name, respectively), if there is only one foreign key between child table and parent table
- The foreign key name, if there are more than one foreign keys between child table and parent table

This default behaviour can be overridden by using a [Code Generator Strategy](#codegen-generatorstrategy).

The jOOQ version of the previous queries looks like this:

```java
// Get all books, their authors, and their respective language
create.select(
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.TITLE,
          BOOK.language().CD.as("language"))
      .from(BOOK)
      .fetch();

// Count the number of books by author and language
create.select(
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.language().CD.as("language"),
          count())
      .from(BOOK)
      .groupBy(
          BOOK.AUTHOR_ID,
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.language().CD)
      .orderBy(
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.language().CD)
      .fetch();
```

The generated SQL is almost identical to the original one - there is no performance penalty to this syntax.

###### Default JOIN type

The default type of join that is generated is:

- `INNER JOIN` for `to-one` path segments with non-nullable parent
- `LEFT JOIN` for `to-one` path segments with nullable parent
- An exception for implicit `to-many` path segments, which haven't been declared in the [FROM clause](#from-clause) explicitly, otherwise a `LEFT JOIN` (see also [implicit to-many path joins](#implicit-to-many-join) for details)

These defaults can be overridden with [Settings.renderImplicitJoinType](#settings-implicit-join-type)or [Settings.renderImplicitJoinToManyType](#settings-implicit-join-type), respectively, or by specifying an [explicit path join](#explicit-path-join)

###### How it works

During the SQL generation phase, implicit join paths are replaced by generated aliases for the path's last table. The paths are translated to a join graph, which is always `LEFT JOIN`ed to the path's "root table". If two paths share a common prefix, that prefix is also shared in the join graph.

###### Known limitations

- Implicit JOINs can currently only be used to access columns, not to produce joins. I.e. it is not possible to write things like `FROM book IMPLICIT JOIN book.author`
- Implicit JOINs are added to the SQL string after the entire SQL statement is available, for performance reasons. This means, that [VisitListener](#custom-sql-transformation) SPI implementations cannot observe implicitly joined tables

<a id="implicit-to-many-join"></a>
###### 3.5.3.2.3. Implicit to-many path JOIN

Support for `to-many` paths ([implicit](#implicit-join) or [explicit](#explicit-path-join)) has been added in 3.19. While explicit `to-many` paths are very powerful, users may want the convenience of the implicit `to-many` paths just like the implicit `to-one` paths. However, jOOQ doesn't support these out of the box like other ORMs might do, and as users might expect in case of simple examples. Take the following "obvious" example, for instance:

```java
// Get all authors and count their books
create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count(AUTHOR.book().ID))
      .from(AUTHOR)
      .groupBy(AUTHOR.ID)
      .fetch();
```

It reads nicely: "Get all authors and count their books.". The expected query produced by this is:

```sql
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, COUNT(BOOK.ID)
FROM AUTHOR
LEFT JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
GROUP BY AUTHOR.ID
```

Another cool example is this clever [ANTI JOIN](#join-type-anti):

```java
// Get all authors without any book
create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .from(AUTHOR)
      .where(AUTHOR.book().ID.isNull())
      .fetch();
```

```sql
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
FROM AUTHOR
LEFT JOIN BOOK
  ON BOOK.AUTHOR_ID = AUTHOR.ID
WHERE BOOK.ID IS NULL
```

But if the above is possible, then the following counter example would produce very surprising results! One would expect the inverse of an [ANTI JOIN](#join-type-anti) to produce a [SEMI JOIN](#join-type-semi), but that wouldn't be what happens:

```java
// Get all authors with books
create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .from(AUTHOR)
      .where(AUTHOR.book().ID.isNotNull())
      .fetch();
```

```sql
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
FROM AUTHOR
LEFT JOIN BOOK
  ON BOOK.AUTHOR_ID = AUTHOR.ID
WHERE BOOK.ID IS NOT NULL
```

Now, we get duplicate authors. One per book they've written, due to the cartesian product created by the `LEFT JOIN`.

> [!TIP]
> Accidental duplicate objects isn't the main problem that such implicit `to-many` path joins would cause. The main problem is that an implicit `to-many` path placed in the [SELECT clause](#select-clause) or [WHERE clause](#where-clause) (and other clauses) would be able to *generate rows*, when in fact `SELECT` only transforms rows (like `Stream.map()`) and `WHERE` only filters rows (like `Stream.filter()`). It would be *very* SQL-unidiomatic and confusing for these clauses to be able to effectively *produce* rows.

To prevent this, the *default* behaviour when encountering an *implicit* `to-many` join path expression an exception that is thrown.

To prevent this, users have 2 options:

- Override the default with [Settings.renderImplicitJoinToManyType](#settings-implicit-join-type). This applies to all queries and removes the above scalar subquery protection for power users who know what they're doing.
- Use [explicit path joins](#explicit-path-join) to specify that indeed, a `LEFT JOIN` (or any other type of `JOIN`) is indeed desired, see example below:

```java
// Get all authors with books
create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .from(AUTHOR)
      .leftJoin(AUTHOR.book()) // Now, the LEFT JOIN is explicit and cartesian products aren't accidental.
      .where(AUTHOR.book().ID.isNotNull())
      .fetch();
```

<a id="explicit-path-join"></a>
###### 3.5.3.2.4. Explicit path JOIN

Starting from jOOQ 3.19, it is possible to make path joins (as introduced with [implicit path JOIN](#implicit-join)) explicit in the [FROM clause](#from-clause):

```java
// Path joins are created implicitly:
create.select(
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.TITLE,
          BOOK.language().CD.as("language"))
      .from(BOOK)
      .fetch();

// Path joins are created explicitly (e.g. using table lists):
create.select(
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.TITLE,
          BOOK.language().CD.as("language"))
      .from(BOOK, BOOK.language(), BOOK.author())
      .fetch();

// Path joins are created explicitly (e.g. using inner joins, with optional ON clause):
create.select(
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.TITLE,
          BOOK.language().CD.as("language"))
      .from(BOOK)
      .join(BOOK.language())
      .join(BOOK.author())
      .fetch();
```

This has a few benefits:

- The exact [JOIN type](#joined-tables) can be specified on a per path basis, including more esoteric `JOIN` types, such as for example [SEMI JOIN](#join-type-semi), [ANTI JOIN](#join-type-anti), or [APPLY](#join-mode-apply).
- It may improve the clarity of the query.
- It allows for correlating subqueries based on join paths

A special case of the putting path expressions in the [FROM clause](#from-clause) is the [implicit path correlation](#implicit-path-correlation), where a path establishes a correlation to an outer query, rather than a join to a previous table from the [FROM clause](#from-clause).

<a id="implicit-path-correlation"></a>
###### 3.5.3.2.5. Implicit path correlation

A special case of the putting path expressions in the [FROM clause](#from-clause) is the implicit path correlation, where a path establishes a correlation to an outer query, rather than a join to a previous table from the [FROM clause](#from-clause). This correlated subquery case is very powerful, e.g. to count books per author:

```sql
SELECT
  AUTHOR.ID, (
    SELECT COUNT(*) FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  )
FROM AUTHOR
```

```java
// Count the number of books per author
create.select(
          AUTHOR.ID,
          field(selectCount().from(AUTHOR.book())))
      .from(AUTHOR)
      .fetch();
```

Or as a way to simplify the correlation of an [EXISTS predicate](#exists-predicate):

```java
// For all authors, check if they have any books
create.select(
          AUTHOR.ID,
          exists(AUTHOR.book())
      .from(AUTHOR)
      .fetch();
```

> [!TIP]
> This works well with the [inline derived tables](#inline-derived-tables) feature.

Or as a way to simplify the correlation of a [MULTISET subquery](#multiset-value-constructor):

```java
// Get all books by author
create.select(
          AUTHOR.ID,
          multiset(AUTHOR.book()))
      .from(AUTHOR)
      .fetch();
```

<a id="where-clause"></a>
##### 3.5.3.3. WHERE clause

The WHERE clause can be used for JOIN or filter predicates, in order to restrict the data returned by the [table expressions](#table-expressions) supplied to the previously specified [from clause](#from-clause) and [join clause](#join-clause). Here is an example:

```sql
SELECT *
FROM BOOK
WHERE AUTHOR_ID = 1
AND TITLE = '1984'
 
```

```java
create.select()
      .from(BOOK)
      .where(BOOK.AUTHOR_ID.eq(1))
      .and(BOOK.TITLE.eq("1984"))
      .fetch();
```

The above syntax is convenience provided by jOOQ, allowing you to connect the [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html) supplied in the WHERE clause with another condition using an AND operator. You can of course also create a more complex condition and supply that to the WHERE clause directly (observe the different placing of parentheses). The results will be the same:

```sql
SELECT *
FROM BOOK
WHERE AUTHOR_ID = 1
AND TITLE = '1984'
 
```

```java
create.select()
      .from(BOOK)
      .where(BOOK.AUTHOR_ID.eq(1).and(
             BOOK.TITLE.eq("1984")))
      .fetch();
```

You will find more information about creating [conditional expressions](#conditional-expressions) later in the manual.

<a id="connect-by-clause"></a>
##### 3.5.3.4. CONNECT BY clause

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The Oracle database knows a very succinct syntax for creating hierarchical queries: the CONNECT BY clause, which is fully supported by jOOQ, including all related functions and pseudo-columns. A more or less formal definition of this clause is given here:

```text
--   SELECT ..
--     FROM ..
--    WHERE ..
 CONNECT BY [ NOCYCLE ] condition [ AND condition, ... ] [ START WITH condition ]
-- GROUP BY ..
-- ORDER [ SIBLINGS ] BY ..
```

An example for an iterative query, iterating through values between 1 and 5 is this:

```sql
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= 5
 
```

```java
// Get a table with elements 1, 2, 3, 4, 5
create.select(level())
      .connectBy(level().le(5))
      .fetch();
```

Here's a more complex example where you can recursively fetch directories in your database, and concatenate them to a path:

```sql
SELECT
  SUBSTR(SYS_CONNECT_BY_PATH(DIRECTORY.NAME, '/'), 2)
FROM DIRECTORY
CONNECT BY
  PRIOR DIRECTORY.ID = DIRECTORY.PARENT_ID
START WITH DIRECTORY.PARENT_ID IS NULL
ORDER BY 1
 
```

```java
.select(
   substring(sysConnectByPath(DIRECTORY.NAME, "/"), 2))
.from(DIRECTORY)
.connectBy(
   prior(DIRECTORY.ID).eq(DIRECTORY.PARENT_ID))
.startWith(DIRECTORY.PARENT_ID.isNull())
.orderBy(1)
.fetch();
```

The output might then look like this

```text
+------------------------------------------------+
|substring                                       |
+------------------------------------------------+
|C:                                              |
|C:/eclipse                                      |
|C:/eclipse/configuration                        |
|C:/eclipse/dropins                              |
|C:/eclipse/eclipse.exe                          |
+------------------------------------------------+
|...21 record(s) truncated...
```

Some of the supported functions, operators, and pseudo-columns are these (available from the [DSL](#dsl)):

- [CONNECT_BY_ISCYCLE](#connect-by-iscycle-function) function
- [CONNECT_BY_ISLEAF](#connect-by-isleaf-function) function
- [CONNECT_BY_ROOT](#connect-by-root-operator) operator
- [LEVEL](#level-function) pseudo-column
- [PRIOR](#prior-operator) operator
- [SYS_CONNECT_BY_PATH](#sys-connect-by-path-function) function

###### ORDER SIBLINGS

The Oracle database allows for specifying a SIBLINGS keyword in the [ORDER BY clause](#order-by-clause). Instead of ordering the overall result, this will only order siblings among each other, keeping the hierarchy intact. An example is given here:

```sql
SELECT DIRECTORY.NAME
FROM DIRECTORY
CONNECT BY
  PRIOR DIRECTORY.ID = DIRECTORY.PARENT_ID
START WITH DIRECTORY.PARENT_ID IS NULL
ORDER SIBLINGS BY 1
 
```

```java
.select(DIRECTORY.NAME)
.from(DIRECTORY)
.connectBy(
   prior(DIRECTORY.ID).eq(DIRECTORY.PARENT_ID))
.startWith(DIRECTORY.PARENT_ID.isNull())
.orderSiblingsBy(1)
.fetch();
```

<a id="group-by-clause"></a>
##### 3.5.3.5. GROUP BY clause

`GROUP BY` can be used to create unique groups of data, to form aggregations, to remove duplicates and for other reasons. It will transform your previously defined [set of table expressions](#table-expressions), and return only one record per unique group as specified in this clause.

<a id="group-by-columns"></a>
###### 3.5.3.5.1. GROUP BY columns

The `GROUP BY` columns list specifies the columns whose values are used to form groups. The group columns can then be projected, whereas all the non-group columns can be [aggregated](#aggregate-functions). An example of such a grouped aggregation is this query:

```sql
SELECT AUTHOR_ID, COUNT(*)
FROM BOOK
GROUP BY AUTHOR_ID
 
```

```java
create.select(BOOK.AUTHOR_ID, count())
      .from(BOOK)
      .groupBy(BOOK.AUTHOR_ID)
      .fetch();
```

The above example counts all books per author.

> [!TIP]
> Note: a different and more powerful way of grouping data is to use the [WINDOW clause and window functions](#window-clause).

###### Dialect support

This example using jOOQ:

```java
select(BOOK.AUTHOR_ID, count()).from(BOOK).groupBy(BOOK.AUTHOR_ID)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
SELECT
  BOOK.AUTHOR_ID,
  count(*)
FROM BOOK
GROUP BY BOOK.AUTHOR_ID
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="group-by-column-index"></a>
###### 3.5.3.5.2. GROUP BY column index

To work against some of SQL's verbosity, some SQL dialects support grouping by column index (starting from 1):

> [!TIP]
> It is not recommended to use this feature in jOOQ as indexes tend to shift without developers noticing. The feature is supported mainly so jOOQ's [SQL parser](#sql-parser) can parse and translate it. If you want to avoid redundancy in jOOQ, better resort to using a [dynamic SQL style](#dynamic-sql).

###### Dialect support

This example using jOOQ:

```java
select(BOOK.AUTHOR_ID, count()).from(BOOK).groupBy(inline(1))
```

Translates to the following dialect specific expressions:

###### ASE, Access, DB2, Exasol, H2, HSQLDB, Hana, Oracle, SQLDataWarehouse, SQLServer, Sybase

```sql
SELECT
  BOOK.AUTHOR_ID,
  count(*)
FROM BOOK
GROUP BY BOOK.AUTHOR_ID
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Firebird, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT
  BOOK.AUTHOR_ID,
  count(*)
FROM BOOK
GROUP BY 1
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="group-by-tables"></a>
###### 3.5.3.5.3. GROUP BY tables

An [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) expression extends the [`org.jooq.GroupField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/GroupField.html) type, and as such, can be used in the [GROUP BY clause](#group-by-clause) directly. This is specifically useful for [(generated) table references](#generated-tables). The following two statements are equivalent, although their generated SQL may differ, depending on native support:

```java
// Ordinary grouping
create.select(AUTHOR.ID, count())
  .from(AUTHOR)
  .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
  .groupBy(AUTHOR.ID)
  .fetch();

// Convenient grouping by the entire table
create.select(AUTHOR.ID, count())
  .from(AUTHOR)
  .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
  .groupBy(AUTHOR)
  .fetch();
```

<a id="group-by-rollup"></a>
###### 3.5.3.5.4. GROUP BY ROLLUP

In reports, it may be useful to run multiple aggregations across multiple dimensions of the data in one go. `ROLLUP` is one way to do this.

```sql
SELECT AUTHOR_ID, PUBLISHED_IN, COUNT(*)
FROM BOOK
GROUP BY ROLLUP (AUTHOR_ID, PUBLISHED_IN)
 
```

```java
create.select(BOOK.AUTHOR_ID, BOOK.PUBLISHED_IN, count())
      .from(BOOK)
      .groupBy(rollup(BOOK.AUTHOR_ID, BOOK.PUBLISHED_IN))
      .fetch();
```

The above is a more concise (and possibly more performant) form of writing the following [UNION ALL](#set-operation-union) query:

```sql
SELECT AUTHOR_ID, PUBLISHED_IN, COUNT(*)
FROM BOOK
GROUP BY AUTHOR_ID, PUBLISHED_IN
UNION ALL
SELECT AUTHOR_ID, NULL, COUNT(*)
FROM BOOK
GROUP BY AUTHOR_ID
UNION ALL
SELECT NULL, NULL, COUNT(*)
FROM BOOK
GROUP BY ()
```

The `ROLLUP` function is just syntax sugar for a more complex [GROUPING SETS](#group-by-grouping-sets) specification. In general:

```sql
-- This
ROLLUP (A, B, C)

-- Is just short for this
GROUPING SETS ((A, B, C), (A, B), (A), ())
```

An example result set might look like this:

```text
+-----------+--------------+----------+
| AUTHOR_ID | PUBLISHED_IN | COUNT(*) |
+-----------+--------------+----------+
|         1 |         1945 |        1 | <- GROUP BY (AUTHOR_ID, PUBLISHED_IN)
|         1 |         1948 |        1 | <- GROUP BY (AUTHOR_ID, PUBLISHED_IN)
|         1 |         NULL |        2 | <- GROUP BY (AUTHOR_ID)
|         2 |         1988 |        1 | <- GROUP BY (AUTHOR_ID, PUBLISHED_IN)
|         2 |         1990 |        1 | <- GROUP BY (AUTHOR_ID, PUBLISHED_IN)
|         2 |         NULL |        2 | <- GROUP BY (AUTHOR_ID)
|      NULL |         NULL |        4 | <- GROUP BY ()
+-----------+--------------+----------+
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID, count()).from(BOOK).groupBy(rollup(BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID))
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MySQL

```sql
SELECT
  BOOK.AUTHOR_ID,
  BOOK.LANGUAGE_ID,
  count(*)
FROM BOOK
GROUP BY BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID
WITH ROLLUP
```

###### Aurora Postgres, ClickHouse, DB2, Databricks, DuckDB, Hana, MemSQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
SELECT
  BOOK.AUTHOR_ID,
  BOOK.LANGUAGE_ID,
  count(*)
FROM BOOK
GROUP BY ROLLUP (BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID)
```

###### ASE, Access, BigQuery, CockroachDB, Exasol, Firebird, H2, HSQLDB, Informix, SQLite, Spanner, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="group-by-cube"></a>
###### 3.5.3.5.5. GROUP BY CUBE

In reports, it may be useful to run multiple aggregations across multiple dimensions of the data in one go. `CUBE` is one way to do this.

```sql
SELECT AUTHOR_ID, PUBLISHED_IN, COUNT(*)
FROM BOOK
GROUP BY CUBE (AUTHOR_ID, PUBLISHED_IN)
 
```

```java
create.select(BOOK.AUTHOR_ID, BOOK.PUBLISHED_IN, count())
      .from(BOOK)
      .groupBy(cube(BOOK.AUTHOR_ID, BOOK.PUBLISHED_IN))
      .fetch();
```

The above is a more concise (and possibly more performant) form of writing the following [UNION ALL](#set-operation-union) query:

```sql
SELECT AUTHOR_ID, PUBLISHED_IN, COUNT(*)
FROM BOOK
GROUP BY AUTHOR_ID, PUBLISHED_IN
UNION ALL
SELECT AUTHOR_ID, NULL, COUNT(*)
FROM BOOK
GROUP BY AUTHOR_ID
SELECT NULL, PUBLISHED_IN, COUNT(*)
FROM BOOK
GROUP BY LANGUAGE_ID
UNION ALL
SELECT NULL, NULL, COUNT(*)
FROM BOOK
GROUP BY ()
```

The `CUBE` function is just syntax sugar for a more complex [GROUPING SETS](#group-by-grouping-sets) specification. In general:

```sql
-- This
CUBE (A, B, C)

-- Is just short for this
GROUPING SETS ((A, B, C), (A, B), (A, C), (B, C), (A), (B), (C), ())
```

An example result set might look like this:

```text
+-----------+--------------+----------+
| AUTHOR_ID | PUBLISHED_IN | COUNT(*) |
+-----------+--------------+----------+
|      NULL |         NULL |        4 | <- GROUP BY ()
|      NULL |         1945 |        1 | <- GROUP BY (PUBLISHED_IN)
|      NULL |         1948 |        1 | <- GROUP BY (PUBLISHED_IN)
|      NULL |         1988 |        1 | <- GROUP BY (PUBLISHED_IN)
|      NULL |         1990 |        1 | <- GROUP BY (PUBLISHED_IN)
|         1 |         NULL |        2 | <- GROUP BY (AUTHOR_ID)
|         1 |         1945 |        1 | <- GROUP BY (AUTHOR_ID, PUBLISHED_IN)
|         1 |         1948 |        1 | <- GROUP BY (AUTHOR_ID, PUBLISHED_IN)
|         2 |         NULL |        2 | <- GROUP BY (AUTHOR_ID)
|         2 |         1988 |        1 | <- GROUP BY (AUTHOR_ID, PUBLISHED_IN)
|         2 |         1990 |        1 | <- GROUP BY (AUTHOR_ID, PUBLISHED_IN)
+-----------+--------------+----------+
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID, count()).from(BOOK).groupBy(cube(BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, ClickHouse, DB2, Databricks, DuckDB, Hana, Oracle, Postgres, Redshift, SQLServer, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
SELECT
  BOOK.AUTHOR_ID,
  BOOK.LANGUAGE_ID,
  count(*)
FROM BOOK
GROUP BY CUBE (BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID)
```

###### ASE, Access, Aurora MySQL, BigQuery, CockroachDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="group-by-grouping-sets"></a>
###### 3.5.3.5.6. GROUP BY GROUPING SETS

In reports, it may be useful to run multiple aggregations across multiple dimensions of the data in one go. `GROUPING SETS` is one way to do this.

```sql
SELECT AUTHOR_ID, PUBLISHED_IN, COUNT(*)
FROM BOOK
GROUP BY GROUPING SETS ((AUTHOR_ID), (PUBLISHED_IN))
 
```

```java
create.select(BOOK.AUTHOR_ID, BOOK.PUBLISHED_IN, count())
      .from(BOOK)
      .groupBy(groupingSets(BOOK.AUTHOR_ID, BOOK.PUBLISHED_IN))
      .fetch();
```

The above is a more concise (and possibly more performant) form of writing the following [UNION ALL](#set-operation-union) query:

```sql
SELECT AUTHOR_ID, NULL AS PUBLISHED_IN, COUNT(*)
FROM BOOK
GROUP BY AUTHOR_ID
UNION ALL
SELECT NULL, PUBLISHED_IN, COUNT(*)
FROM BOOK
GROUP BY LANGUAGE_ID
```

An example result set might look like this:

```text
+-----------+--------------+----------+
| AUTHOR_ID | PUBLISHED_IN | COUNT(*) |
+-----------+--------------+----------+
|      NULL |         1945 |        1 | <- GROUP BY (PUBLISHED_IN)
|      NULL |         1948 |        1 | <- GROUP BY (PUBLISHED_IN)
|      NULL |         1988 |        1 | <- GROUP BY (PUBLISHED_IN)
|      NULL |         1990 |        1 | <- GROUP BY (PUBLISHED_IN)
|         1 |         NULL |        2 | <- GROUP BY (AUTHOR_ID)
|         2 |         NULL |        2 | <- GROUP BY (AUTHOR_ID)
+-----------+--------------+----------+
```

Note that the most common `GROUPING SETS` specifications have a dedicated, special syntax:

- [ROLLUP](#group-by-rollup)
- [CUBE](#group-by-cube)

###### Dialect support

This example using jOOQ:

```java
select(BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID, count()).from(BOOK).groupBy(groupingSets(BOOK.AUTHOR_ID, BOOK.LANGUAGE_ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, ClickHouse, DB2, Databricks, DuckDB, Hana, Oracle, Postgres, Redshift, SQLServer, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
SELECT
  BOOK.AUTHOR_ID,
  BOOK.LANGUAGE_ID,
  count(*)
FROM BOOK
GROUP BY GROUPING SETS (
  (BOOK.AUTHOR_ID),
  (BOOK.LANGUAGE_ID)
)
```

###### ASE, Access, Aurora MySQL, BigQuery, CockroachDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="group-by-empty-grouping-set"></a>
###### 3.5.3.5.7. GROUP BY empty grouping set

A special kind of [GROUPING SET](#group-by-grouping-sets) is the empty grouping set, which can be achieved in standard SQL and many SQL dialects using `GROUP BY ()`. It is implicit, whenever an [aggregate function](#aggregate-functions) is present in a query, but not an explicit [GROUP BY clause](#group-by-clause).

```sql
SELECT COUNT(*)
FROM BOOK
GROUP BY ()
 
```

```java
create.selectCount()
      .from(BOOK)
      .groupBy()
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
selectCount().from(BOOK).groupBy()
```

Translates to the following dialect specific expressions:

###### Access

```sql
SELECT count(*)
FROM BOOK, (select count(*) dual from MSysResources) as empty_grouping_dummy_table
GROUP BY empty_grouping_dummy_table.dual
```

###### ASE, SQLDataWarehouse

```sql
SELECT count(*)
FROM BOOK, (select 1 as dual) as empty_grouping_dummy_table
GROUP BY empty_grouping_dummy_table.dual
```

###### Aurora MySQL, MemSQL

```sql
SELECT count(*)
FROM BOOK
GROUP BY (SELECT 1
FROM DUAL)
```

###### Aurora Postgres, BigQuery, DB2, DuckDB, Exasol, H2, Oracle, Postgres, SQLServer, Sybase, Teradata, Trino

```sql
SELECT count(*)
FROM BOOK
GROUP BY ()
```

###### ClickHouse, CockroachDB, MariaDB, MySQL, Redshift, SQLite, Spanner, Vertica, YugabyteDB

```sql
SELECT count(*)
FROM BOOK
GROUP BY (SELECT 1)
```

###### Databricks, Hana, Snowflake

```sql
SELECT count(*)
FROM BOOK
GROUP BY GROUPING SETS (())
```

###### Firebird

```sql
SELECT count(*)
FROM BOOK
GROUP BY (SELECT 1
FROM RDB$DATABASE)
```

###### HSQLDB

```sql
SELECT count(*)
FROM BOOK
GROUP BY 0
```

###### Informix

```sql
SELECT count(*)
FROM BOOK, (select 1 as dual from systables where tabid = 1) as empty_grouping_dummy_table
GROUP BY empty_grouping_dummy_table.dual
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="having-clause"></a>
##### 3.5.3.6. HAVING clause

The HAVING clause is commonly used to further restrict data resulting from a previously issued [GROUP BY clause](#group-by-clause). An example, selecting only those authors that have written at least two books:

```sql
SELECT AUTHOR_ID, COUNT(*)
FROM BOOK
GROUP BY AUTHOR_ID
HAVING COUNT(*) >= 2
 
```

```java
create.select(BOOK.AUTHOR_ID, count())
      .from(BOOK)
      .groupBy(AUTHOR_ID)
      .having(count().ge(2))
      .fetch();
```

According to the SQL standard, you may omit the GROUP BY clause and still issue a HAVING clause. This will implicitly GROUP BY (). jOOQ also supports this syntax. The following example selects one record, only if there are at least 4 books in the books table:

```sql
SELECT COUNT(*)
FROM BOOK
HAVING COUNT(*) >= 4
 
```

```java
create.select(count(*))
      .from(BOOK)
      .having(count().ge(4))
      .fetch();
```

<a id="window-clause"></a>
##### 3.5.3.7. WINDOW clause

The SQL:2003 standard supports a `WINDOW` clause that allows for specifying `WINDOW` frames for reuse in [SELECT clauses](#select-clause) and [ORDER BY clauses](#order-by-clause).

```sql
SELECT
  LAG(first_name, 1) OVER w "prev",
  first_name,
  LEAD(first_name, 1) OVER w "next"
FROM author
WINDOW w AS (ORDER first_name)
ORDER BY first_name DESC
 
```

```java
WindowDefinition w = name("w").as(
  orderBy(AUTHOR.FIRST_NAME));

create.select(
         lag(AUTHOR.FIRST_NAME, 1).over(w).as("prev"),
         AUTHOR.FIRST_NAME,
         lead(AUTHOR.FIRST_NAME, 1).over(w).as("next"))
      .from(AUTHOR)
      .window(w)
      .orderBy(AUTHOR.FIRST_NAME.desc())
      .fetch();
```

Note that in order to create such a window definition, we need to first create a [name reference](#names) using [`DSL.name()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#name(java.lang.String...)).

Even if only PostgreSQL and Sybase SQL Anywhere natively support this great feature, jOOQ can emulate it by expanding any [`org.jooq.WindowDefinition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/WindowDefinition.html) and [`org.jooq.WindowSpecification`](https://www.jooq.org/javadoc/3.22.x/org/jooq/WindowSpecification.html) types that you pass to the `window()` method - if the database supports window functions at all.

Some more information about [window functions](#window-functions) and the `WINDOW` clause can be found on our blog: [https://blog.jooq.org/probably-the-coolest-sql-feature-window-functions/](https://blog.jooq.org/probably-the-coolest-sql-feature-window-functions/)

###### Dialect support

This example using jOOQ:

```java
select(rowNumber().over("w")).from(AUTHOR).window(name("w").as(orderBy(AUTHOR.ID)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, MySQL, Oracle, Postgres, SQLServer, SQLite, Sybase, Trino, YugabyteDB

```sql
SELECT row_number() OVER w
FROM AUTHOR
WINDOW w AS (ORDER BY AUTHOR.ID)
```

###### DB2, Hana, Informix, MariaDB, MemSQL, SQLDataWarehouse, Snowflake, Teradata, Vertica

```sql
SELECT row_number() OVER (ORDER BY AUTHOR.ID)
FROM AUTHOR
```

###### ASE, Access, Aurora MySQL, HSQLDB, Redshift, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="qualify-clause"></a>
##### 3.5.3.8. QUALIFY clause

A select few dialects support a very useful `QUALIFY` clause, which can be used to filter using window functions without having to nest the window function calculation in a derived table.

For example, if you do not have access to the [WITH TIES](#with-ties-clause) clause, you could easily emulate it like this. The following query finds the top 5 author *WITH TIES*, counting their books:

```sql
SELECT AUTHOR_ID, count(*)
FROM BOOK
GROUP BY AUTHOR_ID
QUALIFY rank() OVER (ORDER BY count(*) DESC) <= 5
ORDER BY count(*) DESC
 
```

```java
create.select(BOOK.AUTHOR_ID, count())
      .from(BOOK)
      .groupBy(BOOK.AUTHOR_ID)
      .qualify(rank().over(orderBy(count().desc())).le(5))
      .orderBy(count().desc())
      .fetch();
```

> [!TIP]
> If your dialect does not support `QUALIFY` natively, then jOOQ can apply a [transformation from QUALIFY to derived tables](#transform-qualify).

###### Dialect support

This example using jOOQ:

```java
select(AUTHOR.ID).from(AUTHOR).qualify(rank().over(orderBy(AUTHOR.ID)).le(10))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, MemSQL, Postgres, SQLite, Trino, Vertica, YugabyteDB

```sql
SELECT t.ID ID
FROM (
  SELECT
    *,
    (rank() OVER (ORDER BY AUTHOR.ID) <= 10) w0
  FROM AUTHOR
) t
WHERE w0
```

###### BigQuery

```sql
SELECT AUTHOR.ID
FROM AUTHOR
WHERE TRUE
QUALIFY rank() OVER (ORDER BY AUTHOR.ID) <= 10
```

###### ClickHouse, Databricks, DuckDB, Exasol, H2, Oracle, Snowflake, Teradata

```sql
SELECT AUTHOR.ID
FROM AUTHOR
QUALIFY rank() OVER (ORDER BY AUTHOR.ID) <= 10
```

###### DB2, SQLDataWarehouse, SQLServer, Sybase

```sql
SELECT t.ID ID
FROM (
  SELECT
    *,
    CASE
      WHEN rank() OVER (ORDER BY AUTHOR.ID) <= 10 THEN 1
      WHEN NOT (rank() OVER (ORDER BY AUTHOR.ID) <= 10) THEN 0
    END w0
  FROM AUTHOR
) t
WHERE w0 = 1
```

###### Firebird

```sql
SELECT t.ID ID
FROM (
  SELECT
    AUTHOR.ID,
    AUTHOR.FIRST_NAME,
    AUTHOR.LAST_NAME,
    AUTHOR.DATE_OF_BIRTH,
    AUTHOR.YEAR_OF_BIRTH,
    AUTHOR.DISTINGUISHED,
    (rank() OVER (ORDER BY AUTHOR.ID) <= 10) w0
  FROM AUTHOR
) t
WHERE w0 = TRUE
```

###### Hana

```sql
SELECT t.ID ID
FROM (
  SELECT
    *,
    CASE
      WHEN rank() OVER (ORDER BY AUTHOR.ID) <= 10 THEN TRUE
      WHEN NOT (rank() OVER (ORDER BY AUTHOR.ID) <= 10) THEN FALSE
    END w0
  FROM AUTHOR
) t
WHERE w0 = TRUE
```

###### Informix

```sql
SELECT t.ID ID
FROM (
  SELECT
    *,
    CASE
      WHEN rank() OVER (ORDER BY AUTHOR.ID) <= 10 THEN cast('t' AS boolean)
      WHEN NOT (rank() OVER (ORDER BY AUTHOR.ID) <= 10) THEN cast('f' AS boolean)
    END w0
  FROM AUTHOR
) t
WHERE w0
```

###### MariaDB, MySQL

```sql
SELECT t.ID ID
FROM (
  SELECT
    AUTHOR.ID,
    AUTHOR.FIRST_NAME,
    AUTHOR.LAST_NAME,
    AUTHOR.DATE_OF_BIRTH,
    AUTHOR.YEAR_OF_BIRTH,
    AUTHOR.DISTINGUISHED,
    (rank() OVER (ORDER BY AUTHOR.ID) <= 10) w0
  FROM AUTHOR
) t
WHERE w0
```

###### Redshift

```sql
SELECT AUTHOR.ID
FROM AUTHOR
WHERE 1 = 1
QUALIFY rank() OVER (ORDER BY AUTHOR.ID) <= 10
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="order-by-clause"></a>
##### 3.5.3.9. ORDER BY clause

Databases are allowed to return data in any arbitrary order, unless you explicitly declare that order in the ORDER BY clause.

```sql
SELECT AUTHOR_ID, TITLE
FROM BOOK
ORDER BY AUTHOR_ID ASC, TITLE DESC
 
```

```java
create.select(BOOK.AUTHOR_ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.AUTHOR_ID.asc(), BOOK.TITLE.desc())
      .fetch();
```

Any jOOQ [column expression (or field)](#column-expressions) can be transformed into an [`org.jooq.SortField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SortField.html) by calling the [`asc()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#asc()) and [`desc()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#desc()) methods.

###### jOOQ's understanding of SELECT .. ORDER BY

The SQL standard defines that a "query expression" can be ordered, and that query expressions can contain [UNION, INTERSECT and EXCEPT clauses](#set-operations), whose subqueries cannot be ordered. While this is defined as such in the SQL standard, many databases allowing for the [LIMIT clause](#limit-clause) in one way or another, do not adhere to this part of the SQL standard. Hence, jOOQ allows for ordering all SELECT statements, regardless whether they are constructed as a part of a UNION or not. Corner-cases are handled internally by jOOQ, by introducing synthetic subselects to adhere to the correct syntax, where this is needed.

<a id="order-by-field-index"></a>
###### 3.5.3.9.1. Ordering by field index

The SQL standard allows for specifying integer literals ([literals](#inlined-parameters), not [bind values](#bind-values)!) to reference column indexes from the projection ([SELECT clause](#select-clause)). This may be useful if you do not want to repeat a lengthy expression, by which you want to order - although most databases also allow for referencing [aliased column references](#aliased-columns) in the ORDER BY clause.

An example of this is given here:

```sql
SELECT AUTHOR_ID, TITLE
FROM BOOK
ORDER BY 1 ASC, 2 DESC
 
```

```java
create.select(BOOK.AUTHOR_ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(inline(1).asc(), inline(2).desc())
      .fetch();
```

> [!TIP]
> This practice is generally discouraged as field indexes may shift in the `SELECT` clause, and developers might forget to update the indexes in `ORDER BY`. It is mainly useful for quick-and-dirty ad-hoc SQL. See also [the don't do this section about this topic](#dont-do-this-order-by-column-index).

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(1)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
SELECT BOOK.ID
FROM BOOK
ORDER BY 1
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="order-by-nulls-ordering"></a>
###### 3.5.3.9.2. Ordering and NULLS

A few databases support the SQL standard "null ordering" clause in sort specification lists, to define whether `NULL` values should come first or last in an ordered result.

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME
FROM AUTHOR
ORDER BY LAST_NAME ASC,
         FIRST_NAME ASC NULLS LAST
 
```

```java
create.select(
         AUTHOR.FIRST_NAME,
         AUTHOR.LAST_NAME)
      .from(AUTHOR)
      .orderBy(AUTHOR.LAST_NAME.asc(),
               AUTHOR.FIRST_NAME.asc().nullsLast())
      .fetch();
```

If your database doesn't support this syntax, jOOQ emulates it using a [CASE expression](#case-expressions)

###### Dialect support

This example using jOOQ:

```java
select(AUTHOR.FIRST_NAME).from(AUTHOR).orderBy(AUTHOR.FIRST_NAME.asc().nullsLast())
```

Translates to the following dialect specific expressions:

###### Access, SQLServer

```sql
SELECT AUTHOR.FIRST_NAME
FROM AUTHOR
ORDER BY iif(AUTHOR.FIRST_NAME IS NOT NULL, 0, 1), AUTHOR.FIRST_NAME ASC
```

###### ASE, Aurora MySQL, MemSQL, MySQL, SQLDataWarehouse, Spanner, Sybase

```sql
SELECT AUTHOR.FIRST_NAME
FROM AUTHOR
ORDER BY CASE
  WHEN AUTHOR.FIRST_NAME IS NOT NULL THEN 0
  ELSE 1
END, AUTHOR.FIRST_NAME ASC
```

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, SQLite, Snowflake, Teradata, Trino, YugabyteDB

```sql
SELECT AUTHOR.FIRST_NAME
FROM AUTHOR
ORDER BY AUTHOR.FIRST_NAME ASC NULLS LAST
```

###### DB2, MariaDB, Redshift, Vertica

```sql
SELECT AUTHOR.FIRST_NAME
FROM AUTHOR
ORDER BY nvl2(AUTHOR.FIRST_NAME, 0, 1), AUTHOR.FIRST_NAME ASC
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="order-by-case"></a>
###### 3.5.3.9.3. Ordering using CASE expressions

Using [CASE expressions](#case-expressions) in SQL ORDER BY clauses is a common pattern, if you want to introduce some sort indirection / sort mapping into your queries. As with SQL, you can add any type of [column expression](#column-expressions) into your ORDER BY clause.

For instance, if you have two favourite books that you always want to appear on top, you could write:

```sql
SELECT *
FROM BOOK
ORDER BY CASE TITLE
         WHEN '1984' THEN 0
         WHEN 'Animal Farm' THEN 1
         ELSE 2 END ASC
 
```

```java
create.select()
      .from(BOOK)
      .orderBy(case_(BOOK.TITLE)
               .when("1984", 0)
               .when("Animal Farm", 1)
               .else_(2).asc())
      .fetch();
```

But writing these things can become quite verbose. jOOQ supports a convenient syntax for specifying sort mappings. The same query can be written in jOOQ as such:

```java
create.select()
      .from(BOOK)
      .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm"))
      .fetch();
```

More complex sort indirections can be provided using a Map:

```java
create.select()
      .from(BOOK)
      .orderBy(BOOK.TITLE.sort(Map.of(
          "1984", 1,
          "Animal Farm", 13,
          "The jOOQ book", 10
      )))
      .fetch();
```

Of course, you can combine this feature with the previously discussed [NULLS FIRST / NULLS LAST](#order-by-nulls-ordering) feature. So, if in fact these two books are the ones you like least, you can put all NULLS FIRST (all the other books):

```java
create.select()
      .from(BOOK)
      .orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm").nullsFirst())
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.TITLE.sortAsc("1984", "Animal Farm"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
SELECT BOOK.ID
FROM BOOK
ORDER BY
  SWITCH(BOOK.TITLE = '1984', 0, BOOK.TITLE = 'Animal Farm', 1) ASC
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT BOOK.ID
FROM BOOK
ORDER BY
  CASE BOOK.TITLE
    WHEN '1984' THEN 0
    WHEN 'Animal Farm' THEN 1
  END ASC
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="order-siblings-by"></a>
###### 3.5.3.9.4. Oracle's ORDER SIBLINGS BY clause

jOOQ also supports Oracle's SIBLINGS keyword to be used with ORDER BY clauses for [hierarchical queries using CONNECT BY](#connect-by-clause)

```java
create.select(sysConnectByPath(DIRECTORY.LABEL, "/").as("dir"))
      .from(DIRECTORY)
      .startWith(DIRECTORY.PARENT_ID.isNull())
      .connectBy(prior(DIRECTORY.ID).eq(DIRECTORY.PARENT_ID))
      .orderSiblingsBy(DIRECTORY.LABEL)
      .fetch();
```

<a id="limit-clause"></a>
##### 3.5.3.10. LIMIT .. OFFSET clause

While being extremely useful for every application that does pagination, or just to limit result sets to reasonable sizes, this clause has not been standardised up until SQL:2008. Hence, there exist a variety of possible implementations in various SQL dialects, concerning this limit clause. jOOQ chose to implement the LIMIT .. OFFSET clause as understood and supported by MySQL, H2, HSQLDB, Postgres, and SQLite. Here is an example of how to apply limits with jOOQ:

```java
create.select().from(BOOK).orderBy(BOOK.ID).limit(1).offset(2).fetch();
```

This will limit the result to 1 books skipping the first 2 books (offset 2). limit() is supported in all dialects, offset() in all but Sybase ASE, which has no reasonable means to emulate it. This is how jOOQ trivially emulates the above query in various SQL dialects with native `OFFSET` pagination support:

```sql
-- MySQL, H2, HSQLDB, and SQLite
SELECT * FROM BOOK ORDER BY ID LIMIT 1 OFFSET 2

-- Derby, SQL Server 2012, Oracle 12c, PostgreSQL, the SQL:2008 standard
SELECT * FROM BOOK ORDER BY ID OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY

-- Informix has SKIP .. FIRST support
SELECT SKIP 2 FIRST 1 * FROM BOOK ORDER BY ID

-- Ingres (almost the SQL:2008 standard)
SELECT * FROM BOOK ORDER BY ID OFFSET 2 FETCH FIRST 1 ROWS ONLY

-- Firebird
SELECT * FROM BOOK ORDER BY ID ROWS 2 TO 3

-- Sybase SQL Anywhere
SELECT TOP 1 START AT 3 * FROM BOOK ORDER BY ID

-- DB2 (almost the SQL:2008 standard, without OFFSET)
SELECT * FROM BOOK ORDER BY ID FETCH FIRST 1 ROWS ONLY

-- Sybase ASE, SQL Server 2008 (without OFFSET)
SELECT TOP 1 * FROM BOOK ORDER BY ID
```

Things get a little more tricky in those databases that have no native idiom for `OFFSET` pagination (actual queries may vary):

```sql
-- DB2 (with OFFSET), SQL Server 2008 (with OFFSET)
SELECT * FROM (
  SELECT BOOK.*,
    ROW_NUMBER() OVER (ORDER BY ID ASC) AS RN
  FROM BOOK
) AS X
WHERE RN > 2
AND RN <= 3

-- DB2 (with OFFSET), SQL Server 2008 (with OFFSET)
SELECT * FROM (
  SELECT DISTINCT BOOK.ID, BOOK.TITLE,
    DENSE_RANK() OVER (ORDER BY ID ASC, TITLE ASC) AS RN
  FROM BOOK
) AS X
WHERE RN > 2
AND RN <= 3

-- Oracle 11g and less
SELECT *
FROM (
  SELECT b.*, ROWNUM RN
  FROM (
    SELECT *
    FROM BOOK
    ORDER BY ID ASC
  ) b
  WHERE ROWNUM <= 3
)
WHERE RN > 2
```

As you can see, jOOQ will take care of the incredibly painful ROW_NUMBER() OVER() (or ROWNUM for Oracle) filtering in subselects for you, you'll just have to write limit(1).offset(2) in any dialect.

###### SQL Server's ORDER BY, TOP and subqueries

As can be seen in the above example, writing correct SQL can be quite tricky, depending on the SQL dialect. For instance, with SQL Server, you cannot have an ORDER BY clause in a subquery, unless you also have a TOP clause. This is illustrated by the fact that jOOQ renders a TOP 100 PERCENT clause for you. The same applies to the fact that ROW_NUMBER() OVER() needs an ORDER BY windowing clause, even if you don't provide one to the jOOQ query. By default, jOOQ adds ordering by the first column of your projection.

###### Keyset pagination

Note, the `LIMIT` clause can also be used with the [SEEK clause](#seek-clause) for keyset pagination.

<a id="with-ties-clause"></a>
##### 3.5.3.11. WITH TIES clause

The previous chapter talked about [the LIMIT clause](#limit-clause), which limits the result set to a certain number of rows. The SQL standard specifies the following syntax:

```sql
OFFSET m { ROW | ROWS }
FETCH { FIRST | NEXT } n { ROW | ROWS } { ONLY | WITH TIES }
```

By default, most users will use the semantics of the `ONLY` keyword, meaning a `LIMIT 5` expression (or `FETCH NEXT 5 ROWS ONLY` expression) will result in at most 5 rows. The alternative clause `WITH TIES` will return at most 5 rows, except if the 5th row and the 6th row (and so on) are "tied" according to the `ORDER BY` clause, meaning that the `ORDER BY` clause does not deterministically produce a 5th or 6th row. For example, let's look at our book table:

```sql
SELECT *
FROM book
ORDER BY author_id
FETCH NEXT 1 ROWS WITH TIES
```

```java
DSL.using(configuration)
   .selectFrom(BOOK)
   .orderBy(BOOK.AUTHOR_ID)
   .limit(1).withTies()
   .fetch();
```

Resulting in:

```text
+----+----------+-------------+
| id | actor_id | title       |
+----+----------+-------------+
|  1 |        1 | 1984        |
|  2 |        1 | Animal Farm |
+----+----------+-------------+
```

We're now getting two rows because both rows "tied" when ordering them by `ACTOR_ID`. The database cannot really pick the next 1 row, so they're both returned. If we omit the `WITH TIES` clause, then only a random one of the rows would be returned.

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.AUTHOR_ID).limit(1).withTies()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Firebird, Hana, MySQL, Sybase, Vertica, YugabyteDB

```sql
SELECT v0 ID
FROM (
  SELECT
    BOOK.ID v0,
    rank() OVER (ORDER BY BOOK.AUTHOR_ID) rn
  FROM BOOK
) x
WHERE rn <= (0 + 1)
ORDER BY rn
```

###### BigQuery, Databricks, DuckDB, Exasol, Snowflake

```sql
SELECT BOOK.ID
FROM BOOK
QUALIFY rank() OVER (ORDER BY BOOK.AUTHOR_ID) <= (0 + 1)
```

###### ClickHouse, H2, MariaDB, Oracle, Postgres, Trino

```sql
SELECT BOOK.ID
FROM BOOK
ORDER BY BOOK.AUTHOR_ID
FETCH NEXT 1 ROWS WITH TIES
```

###### Informix

```sql
SELECT v0 ID
FROM (
  SELECT *
  FROM (
    SELECT
      BOOK.ID v0,
      rank() OVER (ORDER BY BOOK.AUTHOR_ID) rn
    FROM BOOK
  ) x
) x
WHERE rn <= (0 + 1)
ORDER BY rn
```

###### Redshift

```sql
SELECT BOOK.ID
FROM BOOK
WHERE 1 = 1
QUALIFY rank() OVER (ORDER BY BOOK.AUTHOR_ID) <= (0 + 1)
```

###### SQLDataWarehouse, SQLServer, Teradata

```sql
SELECT TOP 1 WITH TIES BOOK.ID
FROM BOOK
ORDER BY BOOK.AUTHOR_ID
```

###### ASE, Access, Aurora MySQL, HSQLDB, MemSQL, SQLite, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="seek-clause"></a>
##### 3.5.3.12. SEEK clause

One of the previous chapters talked about [OFFSET pagination](#limit-clause) using `LIMIT .. OFFSET`, or `OFFSET .. FETCH` or some other vendor-specific variant of the same. This can lead to significant performance issues when reaching a high page number, as all unneeded records need to be skipped by the database.

A much faster and more stable way to perform pagination is the so-called *keyset pagination method* also called *seek method*. jOOQ supports a synthetic `seek()` clause, that can be used to perform keyset pagination (learn about [other synthetic sql syntaxes](#synthetic-sql-clauses)). Imagine we have these data:

```text
+------+-------+---------------+
|   ID | VALUE | PAGE_BOUNDARY |
+------+-------+---------------+
|  ... |   ... |           ... |
|  474 |     2 |             0 |
|  533 |     2 |             1 | <-- Before page 6
|  640 |     2 |             0 |
|  776 |     2 |             0 |
|  815 |     2 |             0 |
|  947 |     2 |             0 |
|   37 |     3 |             1 | <-- Last on page 6
|  287 |     3 |             0 |
|  450 |     3 |             0 |
|  ... |   ... |           ... |
+------+-------+---------------+
```

Now, if we want to display page 6 to the user, instead of going to page 6 by using a record `OFFSET`, we could just fetch the record strictly after the last record on page 5, which yields the values `(533, 2)`. This is how you would do it with SQL or with jOOQ:

```sql
SELECT id, value
FROM t
WHERE (value, id) > (2, 533)
ORDER BY value, id
LIMIT 5
 
```

```java
DSL.using(configuration)
   .select(T.ID, T.VALUE)
   .from(T)
   .orderBy(T.VALUE, T.ID)
   .seek(lastValue, lastId) // from last page: value = 2, id = 533
   .limit(5)
   .fetch();
```

As you can see, the jOOQ `SEEK` clause is a synthetic clause that does not really exist in SQL. However, the jOOQ syntax is far more intuitive for a variety of reasons:

- It replaces `OFFSET` where you would expect
- It doesn't force you to mix regular predicates with *"seek"* predicates
- It is typesafe
- It emulates [row value expression predicates](#comparison-predicate-degree-n) for you, in those databases that do not support them

This query now yields:

```text
+-----+-------+
|  ID | VALUE |
+-----+-------+
| 640 |     2 |
| 776 |     2 |
| 815 |     2 |
| 947 |     2 |
|  37 |     3 |
+-----+-------+
```

Note that you cannot combine the `SEEK` clause with the `OFFSET` clause.

More information about this great feature can be found in the jOOQ blog:

- [https://blog.jooq.org/faster-sql-paging-with-jooq-using-the-seek-method/](https://blog.jooq.org/faster-sql-paging-with-jooq-using-the-seek-method/)
- [https://blog.jooq.org/faster-sql-pagination-with-keysets-continued/](https://blog.jooq.org/faster-sql-pagination-with-keysets-continued/)

Further information about offset pagination vs. keyset pagination performance can be found on our [partner page](https://use-the-index-luke.com/no-offset):

[![No more offset](https://www.jooq.org/img/no-offset-banner-728x90.white.png)](https://use-the-index-luke.com/no-offset)

<a id="for-xml-clause"></a>
##### 3.5.3.13. FOR XML clause

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

While both XML and JSON usage in SQL has been standardised in more recent versions of the SQL standard, SQL Server has always had some very convenient utilities at the end of a [SELECT statement](#select-statement), which allow for converting SQL tables into the most common XML or JSON representations.

Starting with jOOQ 3.14, these syntaxes are supported in jOOQ as well, and if possible, emulated in other dialects which have native XML or JSON support.

Consider the following query

```sql
SELECT id, title
FROM book
ORDER BY id
FOR XML PATH ('book'), ROOT ('books')
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forXML().path("book").root("books")
      .fetch();
```

This query produces a document like this:

```xml
<books>
  <book><id>1</id><title>1984</title></book>
  <book><id>2</id><title>Animal Farm</title></book>
  <book><id>3</id><title>O Alquimista</title></book>
  <book><id>4</id><title>Brida</title></book>
</books>
```

<a id="for-xml-auto-mode"></a>
###### 3.5.3.13.1. AUTO mode

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `AUTO` mode generates XML content based on automatically generated elements that model the query structure. This mode doesn't provide much control over the output.

Consider the following query

```sql
SELECT id, title
FROM book
ORDER BY id
FOR XML AUTO
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forXML().auto()
      .fetch();
```

This query produces a document fragment like this:

```xml
<test.dbo.book ID="1" TITLE="1984"/>
<test.dbo.book ID="2" TITLE="Animal Farm"/>
<test.dbo.book ID="3" TITLE="O Alquimista"/>
<test.dbo.book ID="4" TITLE="Brida"/>
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).forXML().auto()
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres

```sql
SELECT xmlagg(xmlelement(
  NAME BOOK,
  xmlattributes(t.ID AS ID)
))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML AUTO
)
```

###### Sybase

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML AUTO
)
FROM SYS.DUMMY
```

###### Teradata

```sql
SELECT xmlagg(xmlelement(
  NAME BOOK,
  xmlattributes(t.ID AS ID)
))
FROM (
  SELECT *
  FROM (
    SELECT TOP 999999999999999999 BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID
  ) x
) t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-xml-path-mode"></a>
###### 3.5.3.13.2. PATH mode

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `PATH` mode generates XML content based on the "path" as specified by column aliases.

Consider the following query

```sql
SELECT 
  id AS [book/id], 
  title AS [book/title]
FROM book
ORDER BY id
FOR XML PATH
 
```

```java
create.select(
         BOOK.ID.as("book/id"), 
         BOOK.TITLE.as("book/title"))
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forXML().path()
      .fetch();
```

This query produces a document fragment like this:

```xml
<row><book><ID>1</ID><TITLE>1984</TITLE></book></row>
<row><book><ID>2</ID><TITLE>Animal Farm</TITLE></book></row>
<row><book><ID>3</ID><TITLE>O Alquimista</TITLE></book></row>
<row><book><ID>4</ID><TITLE>Brida</TITLE></book></row>
```

Alternatively, provide an explicit element name for rows (the default being `row`, as above):

```sql
SELECT id, title
FROM book
ORDER BY id
FOR XML PATH ('book')
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forXML().path("book")
      .fetch();
```

This will produce

```xml
<book><ID>1</ID><TITLE>1984</TITLE></book>
<book><ID>2</ID><TITLE>Animal Farm</TITLE></book>
<book><ID>3</ID><TITLE>O Alquimista</TITLE></book>
<book><ID>4</ID><TITLE>Brida</TITLE></book>
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID.as(quotedName("book/id"))).from(BOOK).orderBy(BOOK.ID).forXML().path()
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlelement(
    NAME book,
    xmlelement(NAME id, "book/id")
  )
))
FROM (
  SELECT BOOK.ID "book/id"
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID [book/id]
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML PATH
)
```

###### Teradata

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlelement(
    NAME book,
    xmlelement(NAME id, "book/id")
  )
))
FROM (
  SELECT *
  FROM (
    SELECT TOP 999999999999999999 BOOK.ID "book/id"
    FROM BOOK
    ORDER BY BOOK.ID
  ) x
) t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-xml-explicit-mode"></a>
###### 3.5.3.13.3. EXPLICIT mode

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `EXPLICIT` mode generates XML content based on the "explicit" instructions on how to nest content, and thus provides the most flexibility in SQL Server's syntax, which even the authors of the syntax have to look up constantly, themselves.

Consider the following query

```sql
SELECT 
  1 [Tag],
  null [Parent],
  book.id [Book!1!BookID]
FROM book
ORDER BY id
FOR XML PATH
 
```

```java
create.select(
            inline(1).as("Tag"), 
            inline((Integer) null).as("Parent"), 
            BOOK.ID.as("Book!1!BookID"))
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forXML().explicit()
      .fetch();
```

This query produces a document fragment like this:

```xml
<Book BookID="1"/>
<Book BookID="2"/>
<Book BookID="3"/>
<Book BookID="4"/>
```

###### Dialect support

This example using jOOQ:

```java
select(
    inline(1).as("Tag"),
    inline((Integer) null).as("Parent"),
    BOOK.ID.as("Book!1!BookID"))
.from(BOOK)
.orderBy(BOOK.ID)
.forXML().path()
```

Translates to the following dialect specific expressions:

###### DB2, Oracle

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlelement(NAME Tag, Tag),
  xmlelement(NAME Parent, Parent),
  xmlelement(NAME Book!1!BookID, Book!1!BookID)
))
FROM (
  SELECT
    1 Tag,
    NULL Parent,
    BOOK.ID Book!1!BookID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### Postgres

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlelement(NAME Tag, Tag),
  xmlelement(NAME Parent, Parent),
  xmlelement(NAME Book!1!BookID, Book!1!BookID)
))
FROM (
  SELECT
    1 Tag,
    cast(NULL AS int) Parent,
    BOOK.ID Book!1!BookID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT
    1 Tag,
    NULL Parent,
    BOOK.ID Book!1!BookID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML PATH
)
```

###### Teradata

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlelement(NAME Tag, Tag),
  xmlelement(NAME Parent, Parent),
  xmlelement(NAME Book!1!BookID, Book!1!BookID)
))
FROM (
  SELECT *
  FROM (
    SELECT TOP 999999999999999999
      1 Tag,
      NULL Parent,
      BOOK.ID Book!1!BookID
    FROM BOOK
    ORDER BY BOOK.ID
  ) x
) t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-xml-raw-mode"></a>
###### 3.5.3.13.4. RAW mode

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `RAW` mode generates XML content based on the structure of the result set without any nesting capabilities. This mode doesn't provide much control over the output.

Consider the following query

```sql
SELECT id, title
FROM book
ORDER BY id
FOR XML RAW
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forXML().raw()
      .fetch();
```

This query produces a document fragment like this:

```xml
<row ID="1" TITLE="1984"/>
<row ID="2" TITLE="Animal Farm"/>
<row ID="3" TITLE="O Alquimista"/>
<row ID="4" TITLE="Brida"/>
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).forXML().raw()
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlattributes(t.ID AS ID)
))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML RAW
)
```

###### Sybase

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML RAW
)
FROM SYS.DUMMY
```

###### Teradata

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlattributes(t.ID AS ID)
))
FROM (
  SELECT *
  FROM (
    SELECT TOP 999999999999999999 BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID
  ) x
) t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-xml-root-directive"></a>
###### 3.5.3.13.5. ROOT directive

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `ROOT` directive allows for wrapping the XML document fragment in a root element.

Consider the following query

```sql
SELECT id, title
FROM book
ORDER BY id
FOR XML RAW, ROOT ('result')
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forXML().raw().root("result")
      .fetch();
```

This query produces a document like this:

```xml
<result>
  <row ID="1" TITLE="1984"/>
  <row ID="2" TITLE="Animal Farm"/>
  <row ID="3" TITLE="O Alquimista"/>
  <row ID="4" TITLE="Brida"/>
</result>
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).forXML().raw().root("result")
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres

```sql
SELECT xmlelement(
  NAME result,
  xmlagg(xmlelement(
    NAME row,
    xmlattributes(t.ID AS ID)
  ))
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML RAW, ROOT ('result')
)
```

###### Teradata

```sql
SELECT xmlelement(
  NAME result,
  xmlagg(xmlelement(
    NAME row,
    xmlattributes(t.ID AS ID)
  ))
)
FROM (
  SELECT *
  FROM (
    SELECT TOP 999999999999999999 BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID
  ) x
) t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-xml-elements-directive"></a>
###### 3.5.3.13.6. ELEMENTS directive

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `ELEMENTS` directive allows for generating XML elements for each column instead of attributes.

Consider the following query

```sql
SELECT id, title
FROM book
ORDER BY id
FOR XML RAW, ELEMENTS
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forXML().raw().elements()
      .fetch();
```

This query produces a document like this:

```xml
<row><ID>1</ID><TITLE>1984</TITLE></row>
<row><ID>2</ID><TITLE>Animal Farm</TITLE></row>
<row><ID>3</ID><TITLE>O Alquimista</TITLE></row>
<row><ID>4</ID><TITLE>Brida</TITLE></row>
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).forXML().raw().elements()
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlelement(NAME ID, ID)
))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML RAW, ELEMENTS
)
```

###### Sybase

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR XML RAW, ELEMENTS
)
FROM SYS.DUMMY
```

###### Teradata

```sql
SELECT xmlagg(xmlelement(
  NAME row,
  xmlelement(NAME ID, ID)
))
FROM (
  SELECT *
  FROM (
    SELECT TOP 999999999999999999 BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID
  ) x
) t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-json-clause"></a>
##### 3.5.3.14. FOR JSON clause

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

While both XML and JSON usage in SQL has been standardised in more recent versions of the SQL standard, SQL Server has always had some very convenient utilities at the end of a [SELECT statement](#select-statement), which allow for converting SQL tables into the most common XML or JSON representations.

Starting with jOOQ 3.14, these syntaxes are supported in jOOQ as well, and if possible, emulated in other dialects which have native XML or JSON support.

JSON is just XML with less syntax and less features. So the `FOR JSON` syntax in SQL Server is almost the same as the above `FOR XML` syntax from the [previous section](#for-xml-clause):

```sql
SELECT id, title
FROM book
ORDER BY id
FOR JSON PATH
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forJSON().path()
      .fetch();
```

This query produces a document like this:

```text
[
  {"id": 1, "title": "1984"},
  {"id": 2, "title": "Animal Farm"},
  {"id": 3, "title": "O Alquimista"},
  {"id": 4, "title": "Brida"}
]
```

<a id="for-json-auto-mode"></a>
###### 3.5.3.14.1. AUTO mode

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `AUTO` mode generates JSON content based on automatically generated object keys that model the query structure.

Consider the following query

```sql
SELECT id, title
FROM book
ORDER BY id
FOR JSON AUTO
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forJSON().auto()
      .fetch();
```

This query produces a document like this:

```text
[
  {"id": 1, "title": "1984"},
  {"id": 2, "title": "Animal Farm"},
  {"id": 3, "title": "O Alquimista"},
  {"id": 4, "title": "Brida"}
]
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).forJSON().auto()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
SELECT json_agg(json_strip_nulls(json_build_object('ID', ID)))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### DB2

```sql
SELECT cast(
  ('[' || listagg(
    json_object(
      KEY 'ID' VALUE ID
      ABSENT ON NULL
    ),
    ','
  ) || ']')
  AS varchar(32672)
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### H2

```sql
SELECT json_arrayagg(json_object(
  KEY 'ID' VALUE ID
  ABSENT ON NULL
))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### MariaDB, MySQL

```sql
SET @t = @@group_concat_max_len;
SET @@group_concat_max_len = 4294967295;
SELECT json_merge_preserve(
  '[]',
  concat(
    '[',
    group_concat(json_object('ID', ID) SEPARATOR ','),
    ']'
  )
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t;
SET @@group_concat_max_len = @t;
```

###### Oracle

```sql
SELECT json_arrayagg(json_object(
  KEY 'ID' VALUE ID
  ABSENT ON NULL
  RETURNING clob
) FORMAT JSON RETURNING clob)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR JSON AUTO
)
```

###### Sybase

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR JSON AUTO
)
FROM SYS.DUMMY
```

###### Trino

```sql
SELECT cast(array_agg(cast(
  map_from_entries(filter(
    ARRAY[row(
      'ID',
      cast(ID AS json)
    )],
    e -> e[2] IS NOT NULL
  ))
  AS json
)) AS json)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-json-path-mode"></a>
###### 3.5.3.14.2. PATH mode

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `PATH` mode generates JSON content based on the "path" as specified by column aliases.

Consider the following query

```sql
SELECT 
  id AS [book.id], 
  title AS [book.title]
FROM book
ORDER BY id
FOR JSON PATH
 
```

```java
create.select(
         BOOK.ID.as("book.id"), 
         BOOK.TITLE.as("book.title"))
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forJSON().path()
      .fetch();
```

This query produces a document like this:

```text
[
  {"book":{"id":1,"title":"1984"}},
  {"book":{"id":2,"title":"Animal Farm"}},
  {"book":{"id":3,"title":"O Alquimista"}},
  {"book":{"id":4,"title":"Brida"}}
]
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID.as(quotedName("book.id"))).from(BOOK).orderBy(BOOK.ID).forJSON().path()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
SELECT json_agg(json_strip_nulls(json_build_object('book', json_strip_nulls(json_build_object('id', "book.id")))))
FROM (
  SELECT BOOK.ID "book.id"
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### DB2

```sql
SELECT cast(
  ('[' || listagg(
    json_object(
      KEY 'book' VALUE json_object(
        KEY 'id' VALUE "book.id"
        ABSENT ON NULL
      ) FORMAT JSON
      ABSENT ON NULL
    ),
    ','
  ) || ']')
  AS varchar(32672)
)
FROM (
  SELECT BOOK.ID "book.id"
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### H2

```sql
SELECT json_arrayagg(json_object(
  KEY 'book' VALUE json_object(
    KEY 'id' VALUE "book.id"
    ABSENT ON NULL
  )
  ABSENT ON NULL
))
FROM (
  SELECT BOOK.ID "book.id"
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### MariaDB, MySQL

```sql
SET @t = @@group_concat_max_len;
SET @@group_concat_max_len = 4294967295;
SELECT json_merge_preserve(
  '[]',
  concat(
    '[',
    group_concat(json_object('book', json_object('id', `book.id`)) SEPARATOR ','),
    ']'
  )
)
FROM (
  SELECT BOOK.ID `book.id`
  FROM BOOK
  ORDER BY BOOK.ID
) t;
SET @@group_concat_max_len = @t;
```

###### Oracle

```sql
SELECT json_arrayagg(json_object(
  KEY 'book' VALUE json_object(
    KEY 'id' VALUE "book.id"
    ABSENT ON NULL
    RETURNING clob
  ) FORMAT JSON
  ABSENT ON NULL
  RETURNING clob
) FORMAT JSON RETURNING clob)
FROM (
  SELECT BOOK.ID "book.id"
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID [book.id]
  FROM BOOK
  ORDER BY BOOK.ID
  FOR JSON PATH
)
```

###### Trino

```sql
SELECT cast(array_agg(cast(
  map_from_entries(filter(
    ARRAY[row(
      'book',
      cast(
        cast(
          map_from_entries(filter(
            ARRAY[row(
              'id',
              cast("book.id" AS json)
            )],
            e -> e[2] IS NOT NULL
          ))
          AS json
        )
        AS json
      )
    )],
    e -> e[2] IS NOT NULL
  ))
  AS json
)) AS json)
FROM (
  SELECT BOOK.ID "book.id"
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-json-root-directive"></a>
###### 3.5.3.14.3. ROOT directive

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `ROOT` directive allows for wrapping the JSON document in a root object.

Consider the following query

```sql
SELECT id, title
FROM book
ORDER BY id
FOR JSON AUTO, ROOT ('result')
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forJSON().auto().root("result")
      .fetch();
```

This query produces a document like this:

```text
{
  "result": [
    {"id": 1, "title": "1984"},
    {"id": 2, "title": "Animal Farm"},
    {"id": 3, "title": "O Alquimista"},
    {"id": 4, "title": "Brida"}
  ]
}
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).forJSON().auto().root("result")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
SELECT json_strip_nulls(json_build_object('result', json_agg(json_strip_nulls(json_build_object('ID', ID)))))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### DB2

```sql
SELECT json_object(
  KEY 'result' VALUE cast(
    ('[' || listagg(
      json_object(
        KEY 'ID' VALUE ID
        ABSENT ON NULL
      ),
      ','
    ) || ']')
    AS varchar(32672)
  ) FORMAT JSON
  ABSENT ON NULL
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### H2

```sql
SELECT json_object(
  KEY 'result' VALUE json_arrayagg(json_object(
    KEY 'ID' VALUE ID
    ABSENT ON NULL
  ))
  ABSENT ON NULL
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### MariaDB

```sql
SET @t = @@group_concat_max_len;
SET @@group_concat_max_len = 4294967295;
SELECT json_object('result', json_merge_preserve(
  '[]',
  json_merge_preserve(
    '[]',
    concat(
      '[',
      group_concat(json_object('ID', ID) SEPARATOR ','),
      ']'
    )
  )
))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t;
SET @@group_concat_max_len = @t;
```

###### MySQL

```sql
SET @t = @@group_concat_max_len;
SET @@group_concat_max_len = 4294967295;
SELECT json_object('result', json_merge_preserve(
  '[]',
  concat(
    '[',
    group_concat(json_object('ID', ID) SEPARATOR ','),
    ']'
  )
))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t;
SET @@group_concat_max_len = @t;
```

###### Oracle

```sql
SELECT json_object(
  KEY 'result' VALUE json_arrayagg(json_object(
    KEY 'ID' VALUE ID
    ABSENT ON NULL
    RETURNING clob
  ) FORMAT JSON RETURNING clob) FORMAT JSON
  ABSENT ON NULL
  RETURNING clob
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR JSON AUTO, ROOT ('result')
)
```

###### Trino

```sql
SELECT cast(
  map_from_entries(filter(
    ARRAY[row(
      'result',
      cast(
        cast(array_agg(cast(
          map_from_entries(filter(
            ARRAY[row(
              'ID',
              cast(ID AS json)
            )],
            e -> e[2] IS NOT NULL
          ))
          AS json
        )) AS json)
        AS json
      )
    )],
    e -> e[2] IS NOT NULL
  ))
  AS json
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-json-include-null-values-directive"></a>
###### 3.5.3.14.4. INCLUDE_NULL_VALUES directive

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `INCLUDE_NULL_VALUES` directive allows for including `NULL` values in the output document.

By default, `NULL` values are omitted from the `FOR JSON` document output. Consider this query:

```sql
SELECT 
  id, 
  nullif(cd, 'en') AS cd
FROM langauge
ORDER BY id
FOR JSON AUTO
 
```

```java
create.select(
            LANGUAGE.ID, 
            nullif(LANGUAGE.CD, "en").as(LANGUAGE.CD))
      .from(LANGUAGE)
      .orderBy(LANGUAGE.ID)
      .forJSON().auto()
      .fetch();
```

This query produces a document like this:

```text
[
  {"id":1},
  {"id":2,"cd":"de"},
  {"id":3,"cd":"fr"},
  {"id":4,"cd":"pt"}
]
```

If you prefer explicit `NULL` values, write:

```sql
SELECT 
  id, 
  nullif(cd, 'en') AS cd
FROM langauge
ORDER BY id
FOR JSON AUTO, INCLUDE_NULL_VALUES
 
```

```java
create.select(
            LANGUAGE.ID, 
            nullif(LANGUAGE.CD, "en").as(LANGUAGE.CD))
      .from(LANGUAGE)
      .orderBy(LANGUAGE.ID)
      .forJSON().auto().includeNullValues()
      .fetch();
```

This query produces a document like this:

```text
[
  {"id":1,"cd":null},
  {"id":2,"cd":"de"},
  {"id":3,"cd":"fr"},
  {"id":4,"cd":"pt"}
]
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).forJSON().auto().includeNullValues()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
SELECT json_agg(json_build_object('ID', ID))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### ClickHouse

```sql
SELECT toJSONString(cast(
  groupArray(toJSONString(map('ID', ID)))
  AS Array(JSON)
))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### DB2

```sql
SELECT cast(
  ('[' || listagg(
    json_object(
      KEY 'ID' VALUE ID
      NULL ON NULL
    ),
    ','
  ) || ']')
  AS varchar(32672)
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### H2

```sql
SELECT json_arrayagg(json_object(
  KEY 'ID' VALUE ID
  NULL ON NULL
))
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### MariaDB, MySQL

```sql
SET @t = @@group_concat_max_len;
SET @@group_concat_max_len = 4294967295;
SELECT json_merge_preserve(
  '[]',
  concat(
    '[',
    group_concat(json_object('ID', ID) SEPARATOR ','),
    ']'
  )
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t;
SET @@group_concat_max_len = @t;
```

###### Oracle

```sql
SELECT json_arrayagg(json_object(
  KEY 'ID' VALUE ID
  NULL ON NULL
  RETURNING clob
) FORMAT JSON RETURNING clob)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR JSON AUTO, INCLUDE_NULL_VALUES
)
```

###### Trino

```sql
SELECT cast(array_agg(cast(
  map_from_entries(ARRAY[row(
    'ID',
    cast(ID AS json)
  )])
  AS json
)) AS json)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### ASE, Access, Aurora MySQL, BigQuery, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-json-without-array-wrapper-directive"></a>
###### 3.5.3.14.5. WITHOUT_ARRAY_WRAPPER directive

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `WITHOUT_ARRAY_WRAPPER` directive allows for avoiding the array wrapper around the resulting JSON document.

Consider the following query

```sql
SELECT id, title
FROM book
ORDER BY id
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .forJSON().auto().withoutArrayWrapper()
      .fetch();
```

This query produces a document like this:

```text
{"id": 1, "title": "1984"},
{"id": 2, "title": "Animal Farm"},
{"id": 3, "title": "O Alquimista"},
{"id": 4, "title": "Brida"}
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).forJSON().auto().withoutArrayWrapper()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
SELECT regexp_replace(cast(
  json_agg(json_strip_nulls(json_build_object('ID', ID)))
  AS varchar
), '^\[(.*)\]$', '\1', 'g')
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### CockroachDB

```sql
SELECT regexp_replace(cast(
  json_agg(json_strip_nulls(json_build_object('ID', ID)))
  AS string
), '^\[(.*)\]$', '\1', 'g')
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### DB2

```sql
SELECT listagg(
  json_object(
    KEY 'ID' VALUE ID
    ABSENT ON NULL
  ),
  ','
)
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### H2

```sql
SELECT regexp_replace(cast(
  json_arrayagg(json_object(
    KEY 'ID' VALUE ID
    ABSENT ON NULL
  ))
  AS varchar
), '^\[(.*)\]$', '$1')
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### MariaDB, MySQL

```sql
SET @t = @@group_concat_max_len;
SET @@group_concat_max_len = 4294967295;
SELECT group_concat(json_object('ID', ID) SEPARATOR ',')
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t;
SET @@group_concat_max_len = @t;
```

###### Oracle

```sql
SELECT regexp_replace(cast(
  json_arrayagg(json_object(
    KEY 'ID' VALUE ID
    ABSENT ON NULL
    RETURNING clob
  ) FORMAT JSON RETURNING clob)
  AS varchar2(4000)
), '^\[(.*)\]$', '\1')
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) t
```

###### SQLServer

```sql
SELECT (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="for-update-clause"></a>
##### 3.5.3.15. FOR UPDATE clause

For inter-process synchronisation and other reasons, you may choose to use the SELECT .. FOR UPDATE clause to indicate to the database, that a set of cells or records should be locked by a given transaction for subsequent updates. With jOOQ, this can be achieved as such:

```sql
SELECT *
FROM BOOK
WHERE ID = 3
FOR UPDATE
 
```

```java
create.select()
      .from(BOOK)
      .where(BOOK.ID.eq(3))
      .forUpdate()
      .fetch();
```

The above example will produce a record-lock, locking the whole record for updates. Some databases also support cell-locks using FOR UPDATE OF ..

```sql
SELECT *
FROM BOOK
WHERE ID = 3
FOR UPDATE OF TITLE
 
```

```java
create.select()
      .from(BOOK)
      .where(BOOK.ID.eq(3))
      .forUpdate().of(BOOK.TITLE)
      .fetch();
```

Oracle goes a bit further and also allows to specify the actual locking behaviour. It features these additional clauses, which are all supported by jOOQ:

- `FOR UPDATE NOWAIT`: This is the default behaviour. If the lock cannot be acquired, the query fails immediately
- `FOR UPDATE WAIT n`: Try to wait for [n] seconds for the lock acquisition. The query will fail only afterwards
- `FOR UPDATE SKIP LOCKED`: This peculiar syntax will skip all locked records. This is particularly useful when implementing queue tables with multiple consumers

With jOOQ, you can use those Oracle extensions as such:

```java
create.select().from(BOOK).where(BOOK.ID.eq(3)).forUpdate().nowait().fetch();
create.select().from(BOOK).where(BOOK.ID.eq(3)).forUpdate().wait(5).fetch();
create.select().from(BOOK).where(BOOK.ID.eq(3)).forUpdate().skipLocked().fetch();
```

###### Pessimistic (shared) locking with the `FOR SHARE` clause

Some databases (MySQL, Postgres) also allow to issue a non-exclusive lock explicitly using a `FOR SHARE` clause. This is also supported by jOOQ

###### Optimistic locking in jOOQ

Note, that jOOQ also supports optimistic locking, if you're doing simple CRUD. This is documented in the section's manual about [optimistic locking](#optimistic-locking).

<a id="set-operations"></a>
##### 3.5.3.16. Set operations

SQL allows to perform set operations as understood in standard set theory on result sets. These operations include unions, intersections, subtractions. For two subselects to be combinable by such a set operator, each subselect must return a [table expression](#table-expressions) of the same degree and type.

All of these set operations come with 2 flavours:

- `DISTINCT` (the default): Removing duplicates after applying the set operation
- `ALL`: Retaining duplicates after applying the set operation

<a id="set-operation-typesafety"></a>
###### 3.5.3.16.1. Type safety

Two subselects of degree less than 22 that are combined by a set operator are required to be of the same degree and, in most databases, also of the same type. jOOQ 3.0's introduction of [Typesafe Record[N] types](#record-n) helps compile-checking these constraints:

```java
// Some sample SELECT statements
Select<Record2<Integer, String>>  s1 = select(BOOK.ID, BOOK.TITLE).from(BOOK);
Select<Record1<Integer>>          s2 = selectOne();
Select<Record2<Integer, Integer>> s3 = select(one(), zero());
Select<Record2<Integer, String>>  s4 = select(one(), inline("abc"));

// Let's try to combine them:
s1.union(s2); // Doesn't compile because of a degree mismatch. Expected: Record2<...>, got: Record1<...>
s1.union(s3); // Doesn't compile because of a type mismatch. Expected: <Integer, String>, got: <Integer, Integer>
s1.union(s4); // OK. The two Record[N] types match
```

<a id="set-operation-rowtype"></a>
###### 3.5.3.16.2. Projection rowtype

Much like most dialects use only the first set operation subquery's column names and types for the resulting row type, so does jOOQ.This is particularly interesting when applying converters, including [ad-hoc converters](#ad-hoc-converter) or [converters attached to generated code](#codegen-database-forced-types-converter).

Since jOOQ does not know which row is produced by which union subquery, it cannot disambiguate these rows in case the projection row type isn't exactly identical. As such, the ad-hoc converter in the following example is ignored:

```java
Result<Record1<Integer>> result =
create.select(BOOK.ID)
   .from(BOOK)
   .union(

    // This has no effect
    select(AUTHOR.ID.convertFrom(i -> -i))
   .from(AUTHOR))
   .fetch();
```

While this can lead to subtle bugs, it makes perfect sense, knowing that a `Converter` is always applied at the client side of the execution.

<a id="set-operation-and-standard"></a>
###### 3.5.3.16.3. Differences to standard SQL

As previously mentioned in the manual's section about the [ORDER BY clause](#order-by-clause), jOOQ has slightly changed the semantics of these set operators. While in SQL, a set operation subselect may not immediately contain any [ORDER BY clause](#order-by-clause) or [LIMIT clause](#limit-clause) (unless you wrap the subselect into a [derived table](#derived-tables)), jOOQ allows you to do so. In order to select both the youngest and the oldest author from the database, you can issue the following statement with jOOQ (rendered to the MySQL dialect):

```sql
  (SELECT * FROM AUTHOR
   ORDER BY DATE_OF_BIRTH ASC LIMIT 1)
UNION
  (SELECT * FROM AUTHOR
   ORDER BY DATE_OF_BIRTH DESC LIMIT 1)
ORDER BY 1
 
```

```java
create.selectFrom(AUTHOR)
      .orderBy(AUTHOR.DATE_OF_BIRTH.asc()).limit(1)
      .union(
       selectFrom(AUTHOR)
      .orderBy(AUTHOR.DATE_OF_BIRTH.desc()).limit(1))
      .orderBy(1)
      .fetch();
```

In case your database doesn't support ordered `UNION` subselects, the subselects are nested in derived tables.

```sql
SELECT * FROM (
  SELECT * FROM AUTHOR
  ORDER BY DATE_OF_BIRTH ASC LIMIT 1
)
UNION
SELECT * FROM (
  SELECT * FROM AUTHOR
  ORDER BY DATE_OF_BIRTH DESC LIMIT 1
)
ORDER BY 1
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).orderBy(BOOK.ID).limit(1).union(select(AUTHOR.ID).from(AUTHOR).orderBy(AUTHOR.ID).limit(1)).orderBy(1)
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse, Sybase

```sql
(
  SELECT TOP 1 BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
)
UNION (
  SELECT TOP 1 AUTHOR.ID
  FROM AUTHOR
  ORDER BY AUTHOR.ID
)
ORDER BY 1
```

###### ASE, SQLServer

```sql
SELECT *
FROM (
  SELECT TOP 1 BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) x
UNION 
SELECT *
FROM (
  SELECT TOP 1 AUTHOR.ID
  FROM AUTHOR
  ORDER BY AUTHOR.ID
) x
ORDER BY 1
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, Exasol, HSQLDB, Hana, MySQL, Redshift, Snowflake, Vertica, YugabyteDB

```sql
(
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  LIMIT 1
)
UNION (
  SELECT AUTHOR.ID
  FROM AUTHOR
  ORDER BY AUTHOR.ID
  LIMIT 1
)
ORDER BY 1
```

###### BigQuery, Spanner

```sql
(
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  LIMIT 1
)
UNION DISTINCT (
  SELECT AUTHOR.ID
  FROM AUTHOR
  ORDER BY AUTHOR.ID
  LIMIT 1
)
ORDER BY 1
```

###### ClickHouse

```sql
SELECT 
  t.*
FROM (
  (
    SELECT BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID
    LIMIT 1
  )
  UNION DISTINCT (
    SELECT AUTHOR.ID
    FROM AUTHOR
    ORDER BY AUTHOR.ID
    LIMIT 1
  )
) t
ORDER BY 1
```

###### Databricks

```sql
(
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  LIMIT cast(1 AS int)
)
UNION (
  SELECT AUTHOR.ID
  FROM AUTHOR
  ORDER BY AUTHOR.ID
  LIMIT cast(1 AS int)
)
ORDER BY 1
```

###### DB2, Oracle

```sql
SELECT *
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FETCH NEXT 1 ROWS ONLY
) x
UNION 
SELECT *
FROM (
  SELECT AUTHOR.ID
  FROM AUTHOR
  ORDER BY AUTHOR.ID
  FETCH NEXT 1 ROWS ONLY
) x
ORDER BY 1
```

###### Firebird, H2, MariaDB, Postgres, Trino

```sql
(
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  FETCH NEXT 1 ROWS ONLY
)
UNION (
  SELECT AUTHOR.ID
  FROM AUTHOR
  ORDER BY AUTHOR.ID
  FETCH NEXT 1 ROWS ONLY
)
ORDER BY 1
```

###### Informix

```sql
SELECT *
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
) x
UNION 
SELECT *
FROM (
  SELECT *
  FROM (
    SELECT FIRST 1 AUTHOR.ID
    FROM AUTHOR
    ORDER BY AUTHOR.ID
  ) x
) x
ORDER BY 1
```

###### MemSQL

```sql
SELECT 
  t.*
FROM (
  (
    SELECT BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID
    LIMIT 1
  )
  UNION (
    SELECT AUTHOR.ID
    FROM AUTHOR
    ORDER BY AUTHOR.ID
    LIMIT 1
  )
) t
ORDER BY 1
```

###### SQLite

```sql
SELECT *
FROM (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
  LIMIT 1
) x
UNION 
SELECT *
FROM (
  SELECT AUTHOR.ID
  FROM AUTHOR
  ORDER BY AUTHOR.ID
  LIMIT 1
) x
ORDER BY 1
```

###### Teradata

```sql
(
  SELECT TOP 1 BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID
)
UNION (
  SELECT *
  FROM (
    SELECT TOP 1 AUTHOR.ID
    FROM AUTHOR
    ORDER BY AUTHOR.ID
  ) x
)
ORDER BY 1
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="set-operation-union"></a>
###### 3.5.3.16.4. UNION

A `UNION` operation combines two subquery results of compatible row type into a single result. `UNION DISTINCT` semantics is implied, i.e. all duplicate records resulting from this combination are removed. Typically, you should prefer `UNION ALL` over `UNION`, if you don't really need to remove duplicates, see also [this section of the manual](#dont-do-this-unnecessary-union). The following example shows how to use such a `UNION` operation in jOOQ.

```sql
SELECT * FROM BOOK WHERE ID = 3
UNION
SELECT * FROM BOOK WHERE ID = 5
 
```

```java
create.selectFrom(BOOK).where(BOOK.ID.eq(3))
      .union(
create.selectFrom(BOOK).where(BOOK.ID.eq(5)))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).union(select(AUTHOR.ID).from(AUTHOR)).orderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT BOOK.ID
FROM BOOK
UNION
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### BigQuery, Spanner

```sql
SELECT BOOK.ID
FROM BOOK
UNION DISTINCT
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### ClickHouse

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  UNION DISTINCT
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

###### Firebird

```sql
SELECT BOOK.ID
FROM BOOK
UNION
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY 1
```

###### MemSQL

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  UNION
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="set-operation-union-all"></a>
###### 3.5.3.16.5. UNION ALL

A `UNION ALL` operation combines two subquery results of compatible row type into a single result without removing duplicates. Typically, you should prefer `UNION ALL` over `UNION`, if you don't really need to remove duplicates, see also [this section of the manual](#dont-do-this-unnecessary-union). The following example shows how to use such a `UNION ALL` operation in jOOQ.

```sql
SELECT * FROM BOOK WHERE ID = 3
UNION ALL
SELECT * FROM BOOK WHERE ID = 5
 
```

```java
create.selectFrom(BOOK).where(BOOK.ID.eq(3))
      .unionAll(
create.selectFrom(BOOK).where(BOOK.ID.eq(5)))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).unionAll(select(AUTHOR.ID).from(AUTHOR)).orderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT BOOK.ID
FROM BOOK
UNION ALL
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### ClickHouse, MemSQL

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  UNION ALL
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

###### Firebird

```sql
SELECT BOOK.ID
FROM BOOK
UNION ALL
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY 1
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="set-operation-intersect"></a>
###### 3.5.3.16.6. INTERSECT

`INTERSECT` is the operation that produces only those values that are returned by both subselects. By default, this removes duplicate rows. Use `INTERSECT ALL` in order to retain them, and require duplicates to appear in both subqueries.

```sql
SELECT ID FROM BOOK
INTERSECT
SELECT ID FROM AUTHOR
 
```

```java
create.select(BOOK.ID).from(BOOK)
      .intersect(
create.select(AUTHOR.ID).from(AUTHOR))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).intersect(select(AUTHOR.ID).from(AUTHOR)).orderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT BOOK.ID
FROM BOOK
INTERSECT
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### BigQuery, Spanner

```sql
SELECT BOOK.ID
FROM BOOK
INTERSECT DISTINCT
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### ClickHouse

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  INTERSECT DISTINCT
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

###### MemSQL

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  INTERSECT
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

###### Access, Aurora MySQL, Firebird, Redshift

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="set-operation-intersect-all"></a>
###### 3.5.3.16.7. INTERSECT ALL

`INTERSECT ALL` is the operation that produces only those values that are returned by both subselects without removing duplicates.

```sql
SELECT ID FROM BOOK
INTERSECT ALL
SELECT ID FROM AUTHOR
 
```

```java
create.select(BOOK.ID).from(BOOK)
      .intersectAll(
create.select(AUTHOR.ID).from(AUTHOR))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).intersectAll(select(AUTHOR.ID).from(AUTHOR)).orderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, HSQLDB, MariaDB, MySQL, Oracle, Postgres, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
SELECT BOOK.ID
FROM BOOK
INTERSECT ALL
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### ClickHouse

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  INTERSECT ALL
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

###### ASE, Access, Aurora MySQL, BigQuery, Exasol, Firebird, H2, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="set-operation-except"></a>
###### 3.5.3.16.8. EXCEPT

`EXCEPT` (or `MINUS` in Oracle) is the operation that returns only those values that are returned exclusively in the first subselect. By default, this removes duplicate rows. Use `EXCEPT ALL` in order to retain them, and require duplicates to appear in both subqueries.

```sql
SELECT ID FROM BOOK
EXCEPT
SELECT ID FROM AUTHOR
 
```

```java
create.select(BOOK.ID).from(BOOK)
      .except(
create.select(AUTHOR.ID).from(AUTHOR))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).except(select(AUTHOR.ID).from(AUTHOR)).orderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MySQL, Postgres, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT BOOK.ID
FROM BOOK
EXCEPT
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### BigQuery, Spanner

```sql
SELECT BOOK.ID
FROM BOOK
EXCEPT DISTINCT
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### ClickHouse

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  EXCEPT DISTINCT
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

###### MemSQL

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  EXCEPT
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

###### Oracle

```sql
SELECT BOOK.ID
FROM BOOK
MINUS
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### Access, Aurora MySQL, Firebird, Redshift

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="set-operation-except-all"></a>
###### 3.5.3.16.9. EXCEPT ALL

`EXCEPT ALL` is the operation that returns only those values that are returned exclusively in the first subselect without removing duplicates.

```sql
SELECT ID FROM BOOK
EXCEPT ALL
SELECT ID FROM AUTHOR
 
```

```java
create.select(BOOK.ID).from(BOOK)
      .exceptAll(
create.select(AUTHOR.ID).from(AUTHOR))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK).exceptAll(select(AUTHOR.ID).from(AUTHOR)).orderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, HSQLDB, MariaDB, MySQL, Oracle, Postgres, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
SELECT BOOK.ID
FROM BOOK
EXCEPT ALL
SELECT AUTHOR.ID
FROM AUTHOR
ORDER BY ID
```

###### ClickHouse

```sql
SELECT 
  t.*
FROM (
  SELECT BOOK.ID
  FROM BOOK
  EXCEPT ALL
  SELECT AUTHOR.ID
  FROM AUTHOR
) t
ORDER BY ID
```

###### ASE, Access, Aurora MySQL, BigQuery, Exasol, Firebird, H2, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="select-lexical-vs-logical-order"></a>
##### 3.5.3.17. Lexical and logical SELECT clause order

SQL has a lexical and a logical order of `SELECT` clauses. The lexical order of `SELECT` clauses is inspired by the English language. As SQL statements are commands for the database, it is natural to express a statement in an imperative tense, such as "SELECT this and that!".

###### Logical SELECT clause order

The logical order of `SELECT` clauses, however, does not correspond to the syntax. In fact, the logical order is this:

- [The FROM clause](#from-clause): First, all data sources are defined and joined
- [The WHERE clause](#where-clause): Then, data is filtered as early as possible
- [The CONNECT BY clause](#connect-by-clause): Then, data is traversed iteratively or recursively, to produce new tuples
- [The GROUP BY clause](#group-by-clause): Then, data is reduced to groups, possibly producing new tuples if [grouping functions like ROLLUP(), CUBE(), GROUPING SETS()](#group-by-grouping-sets) are used
- [The HAVING clause](#having-clause): Then, data is filtered again, based on aggregate functions
- [The WINDOW clause](#window-clause): Then, window specifications and window functions are evaluated
- [The QUALIFY clause](#qualify-clause): Then, data is filtered again, based on window functions
- [The SELECT clause](#select-clause): Only now, the projection is evaluated.
- [The DISTINCT clause](#select-clause-distinct): Duplicate projected rows are removed
- [UNION, INTERSECT and EXCEPT clauses](#set-operations): Optionally, the above is repeated for several `UNION`-connected subqueries. Unless this is a `UNION ALL` clause, data is further reduced to remove duplicates
- [The ORDER BY clause](#order-by-clause): Now, all remaining tuples are ordered
- [The LIMIT clause](#limit-clause): Then, a paginating view is created for the ordered tuples
- The FOR clause: Transformation to XML or JSON
- [The FOR UPDATE clause](#for-update-clause): Finally, pessimistic locking is applied

The [SQL Server documentation](https://msdn.microsoft.com/en-us/library/ms189499.aspx) also explains this, with slightly different clauses:

- `FROM`
- `ON`
- `JOIN`
- `WHERE`
- `GROUP BY`
- `WITH CUBE` or `WITH ROLLUP`
- `HAVING`
- `SELECT`
- `DISTINCT`
- `ORDER BY`
- `TOP`

As can be seen, databases have to logically reorder a SQL statement in order to determine the best execution plan.

###### Alternative syntaxes: LINQ, SLICK

Some "higher-level" abstractions, such as C#'s LINQ or Scala's Slick try to inverse the lexical order of `SELECT` clauses to what appears to be closer to the logical order. The obvious advantage of moving the `SELECT` clause to the end is the fact that the projection type, which is the record type returned by the `SELECT` statement can be re-used more easily in the target environment of the internal domain specific language.

A LINQ example:

```java
// LINQ-to-SQL looks somewhat similar to SQL
// AS clause    // FROM clause
From p          In db.Products

// WHERE clause
Where p.UnitsInStock <= p.ReorderLevel AndAlso Not p.Discontinued

// SELECT clause
Select p
```

A Slick example:

```scala
// "for" is the "entry-point" to the DSL
val q = for {

    // FROM clause   WHERE clause
    c <- Coffees     if c.supID === 101

// SELECT clause and projection to a tuple
} yield (c.name, c.price)
```

While this looks like a good and idiomatic idea at first, jOOQ's take here is that this only complicates translation to more advanced SQL statements while impairing readability for those users that are used to writing SQL. This is specifically true for Slick, which not only changed the `SELECT` clause order, but also heavily "integrated" SQL clauses with the Scala language.

jOOQ is designed to look just like SQL. For these reasons, the jOOQ DSL API is modelled in SQL's lexical order.

<a id="insert-statement"></a>
#### 3.5.4. The INSERT statement

The `INSERT` statement is used to insert new records into a database table. The following sections describe the various operation modes of the jOOQ `INSERT` statement.

<a id="insert-values"></a>
##### 3.5.4.1. INSERT .. VALUES

###### INSERT .. VALUES with a single row

Records can either be supplied using a `VALUES()` constructor, or a `SELECT` statement. jOOQ supports both types of `INSERT` statements. An example of an `INSERT` statement using a `VALUES()` constructor is given here:

```sql
INSERT INTO AUTHOR
       (ID, FIRST_NAME, LAST_NAME)
VALUES (100, 'Hermann', 'Hesse');
 
```

```java
create.insertInto(AUTHOR,
        AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .values(100, "Hermann", "Hesse")
      .execute();
```

Note that for explicit degrees up to 22, the `VALUES()` constructor provides additional typesafety. The following example illustrates this:

```java
InsertValuesStep3<AuthorRecord, Integer, String, String> step =
  create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME);
    step.values("A", "B", "C");
         // ^^^ Doesn't compile, the expected type is Integer
```

###### INSERT .. VALUES with multiple rows

The SQL standard specifies that multiple rows can be supplied to the VALUES() constructor in an INSERT statement. Here's an example of a multi-record INSERT

```sql
INSERT INTO AUTHOR
       (ID, FIRST_NAME, LAST_NAME)
VALUES (100, 'Hermann', 'Hesse'),
       (101, 'Alfred', 'Döblin');
 
```

```java
create.insertInto(AUTHOR,
        AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .values(100, "Hermann", "Hesse")
      .values(101, "Alfred", "Döblin")
      .execute()
```

jOOQ tries to stay close to actual SQL. In detail, however, Java's expressiveness is limited. That's why the values() clause is repeated for every record in multi-record inserts.

Some RDBMS do not support inserting several records in a single statement. In those cases, jOOQ emulates multi-record INSERTs using the following SQL:

```sql
INSERT INTO AUTHOR
    (ID, FIRST_NAME, LAST_NAME)
SELECT 100, 'Hermann', 'Hesse' FROM DUAL UNION ALL
SELECT 101, 'Alfred', 'Döblin' FROM DUAL;
 
```

```java
create.insertInto(AUTHOR,
        AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .values(100, "Hermann", "Hesse")
      .values(101, "Alfred", "Döblin")
      .execute();
```

If your inserted rows or records are dynamic, you can use `valuesOfRows()` or `valuesOfRecords()` instead:

```sql
INSERT INTO AUTHOR
       (ID, FIRST_NAME, LAST_NAME)
VALUES (100, 'Hermann', 'Hesse'),
       (101, 'Alfred', 'Döblin');
 
```

```java
List<Record3<Integer, String, String>> records = ...
create.insertInto(AUTHOR,
        AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .valuesOfRecords(records)
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR).columns(AUTHOR.ID, AUTHOR.LAST_NAME).values(100, "Hesse")
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  100, 
  'Hesse'
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-default-values"></a>
##### 3.5.4.2. INSERT .. DEFAULT VALUES

A lesser-known syntactic feature of SQL is the `INSERT .. DEFAULT VALUES` statement, where a single record is inserted, containing only `DEFAULT` values for every row. It is written as such:

```sql
INSERT INTO AUTHOR
DEFAULT VALUES;
 
```

```java
create.insertInto(AUTHOR)
      .defaultValues()
      .execute();
```

This can make a lot of sense in situations where you want to "reserve" a row in the database for an subsequent [UPDATE statement](#update-statement) within the same transaction. Or if you just want to send an event containing trigger-generated default values, such as IDs or timestamps.

The `DEFAULT VALUES` clause is not supported in all databases, but jOOQ can emulate it using the equivalent statement:

```sql
INSERT INTO AUTHOR
    (ID, FIRST_NAME, LAST_NAME, ...)
VALUES (
	DEFAULT,
	DEFAULT,
	DEFAULT, ...);
 
```

```java
create.insertInto(
        AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, ...)
      .values(
      	defaultValue(AUTHOR.ID),
      	defaultValue(AUTHOR.FIRST_NAME),
      	defaultValue(AUTHOR.LAST_NAME), ...)
      .execute();
```

The `DEFAULT` keyword (or [`DSL#defaultValue()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#defaultValue()) method) can also be used for individual columns only, although that will have the same effect as leaving the column away entirely.

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR).defaultValues()
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, BigQuery, DB2, Databricks, MariaDB, MemSQL, MySQL, Oracle, Snowflake

```sql
INSERT INTO AUTHOR
VALUES (
  DEFAULT,
  DEFAULT,
  DEFAULT,
  DEFAULT,
  DEFAULT,
  DEFAULT
)
```

###### Aurora Postgres, ClickHouse, CockroachDB, DuckDB, Exasol, Firebird, H2, HSQLDB, Postgres, SQLDataWarehouse, SQLServer, Teradata, YugabyteDB

```sql
INSERT INTO AUTHOR
DEFAULT VALUES
```

###### Hana, Informix, Redshift, SQLite, Sybase, Vertica

```sql
INSERT INTO AUTHOR (FIRST_NAME, DATE_OF_BIRTH, YEAR_OF_BIRTH, DISTINGUISHED)
VALUES (
  NULL, 
  NULL, 
  NULL, 
  NULL
)
```

###### Spanner

```sql
INSERT INTO AUTHOR (
  ID,
  FIRST_NAME,
  LAST_NAME,
  DATE_OF_BIRTH,
  YEAR_OF_BIRTH,
  DISTINGUISHED
)
VALUES (
  DEFAULT,
  DEFAULT,
  DEFAULT,
  DEFAULT,
  DEFAULT,
  DEFAULT
)
```

###### Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-set"></a>
##### 3.5.4.3. INSERT .. SET

MySQL (and some other RDBMS) allow for using a non-SQL-standard, UPDATE-like syntax for INSERT statements. This is also supported in jOOQ (and emulated for all databases), should you prefer that syntax. The above INSERT statement can also be expressed as follows:

```java
create.insertInto(AUTHOR)
      .set(AUTHOR.ID, 100)
      .set(AUTHOR.FIRST_NAME, "Hermann")
      .set(AUTHOR.LAST_NAME, "Hesse")
      .execute();
```

Multi row variant:

```java
create.insertInto(AUTHOR)
      .set(AUTHOR.ID, 100)
      .set(AUTHOR.FIRST_NAME, "Hermann")
      .set(AUTHOR.LAST_NAME, "Hesse")
      .newRecord()
      .set(AUTHOR.ID, 101)
      .set(AUTHOR.FIRST_NAME, "Alfred")
      .set(AUTHOR.LAST_NAME, "Döblin")
      .execute();
```

As you can see, this syntax is a bit more verbose, but also more readable, as every field can be matched with its value. Internally, the two syntaxes are strictly equivalent.

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR).set(AUTHOR.ID, 100).set(AUTHOR.LAST_NAME, "Hesse")
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  100, 
  'Hesse'
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-select"></a>
##### 3.5.4.4. INSERT .. SELECT

In some occasions, you may prefer the INSERT SELECT syntax, for instance, when you copy records from one table to another:

```java
create.insertInto(AUTHOR_ARCHIVE)
      .select(selectFrom(AUTHOR).where(AUTHOR.DECEASED.isTrue()))
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR).columns(AUTHOR.ID, AUTHOR.LAST_NAME).select(select(val(100), val("Hesse")))
```

Translates to the following dialect specific expressions:

###### Access

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
FROM (
  SELECT count(*) dual
  FROM MSysResources
) AS dual
```

###### ASE, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
```

###### Aurora MySQL, MemSQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
FROM DUAL
```

###### DB2

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
FROM SYSIBM.DUAL
```

###### Firebird

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
FROM RDB$DATABASE
```

###### Hana, Sybase

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
FROM SYS.DUMMY
```

###### HSQLDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
FROM (VALUES (1)) AS dual (dual)
```

###### Informix

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
FROM (
  SELECT 1 AS dual
  FROM systables
  WHERE (tabid = 1)
) AS dual
```

###### Teradata

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT 100, 'Hesse'
FROM (
  SELECT 1 AS "dual"
) AS "dual"
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-on-duplicate-key"></a>
##### 3.5.4.5. INSERT .. ON DUPLICATE KEY UPDATE

The MySQL database supports a very convenient way to INSERT or UPDATE a record. This is a non-standard extension to the SQL syntax, which is supported by jOOQ and emulated in other RDBMS, where this is possible (e.g. if they support the SQL standard [MERGE statement](#merge-statement)). Here is an example how to use the ON DUPLICATE KEY UPDATE clause:

```java
// Add a new author called "Koontz" with ID 3.
// If that ID is already present, update the author's name
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
      .values(3, "Koontz")
      .onDuplicateKeyUpdate()
      .set(AUTHOR.LAST_NAME, "Koontz")
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME).values(3, "X").onDuplicateKeyUpdate().set(AUTHOR.LAST_NAME, "X")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON DUPLICATE KEY UPDATE
  AUTHOR.LAST_NAME = 'X'
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, YugabyteDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT (ID)
DO UPDATE
SET
  LAST_NAME = 'X'
```

###### DB2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYSIBM.DUAL
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Exasol

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Firebird

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM RDB$DATABASE
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### H2

```sql
MERGE INTO AUTHOR
USING (
  SELECT
    3 ID,
    'X' LAST_NAME
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Hana

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
    FROM SYS.DUMMY
  )
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### HSQLDB

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (VALUES (1)) AS dual (dual)
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### MySQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
AS excluded
ON DUPLICATE KEY UPDATE
  AUTHOR.LAST_NAME = 'X'
```

###### Oracle

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
  )
) t
ON (AUTHOR.ID = t.ID)
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Redshift, Snowflake

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### SQLite

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT 
DO UPDATE
SET
  LAST_NAME = 'X'
```

###### SQLServer

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
);
```

###### Sybase

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYS.DUMMY
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Teradata

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### ASE, Access, BigQuery, ClickHouse, Databricks, Informix, SQLDataWarehouse, Spanner, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-on-duplicate-key-excluded"></a>
##### 3.5.4.6. INSERT .. ON DUPLICATE KEY UPDATE .. EXCLUDED

Starting with MySQL 8, there's support for aliasing the [INSERT .. VALUES](#insert-values) clause in order to reference its columns from the `ON DUPLICATE KEY UPDATE` clause:

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES
  (3, 'Koontz'),
  (4, 'Shakespeare') AS t   -- Declare source data alias
ON DUPLICATE KEY UPDATE
SET last_name = t.last_name -- Reference source data alias
```

jOOQ does not explicitly support this syntax in the DSL API, but the PostgreSQL specific equivalent from [INSERT .. ON CONFLICT .. EXCLUDED](#insert-on-conflict-excluded) can be emulated in MySQL as well, so you can just use the [`DSL.excluded()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#excluded(org.jooq.Field)) pseudo table:

```java
// Add a new author called "Koontz" with ID 3.
// If that ID is already present, update the author's name
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
      .values(3, "Koontz")
      .values(4, "Shakespeare")
      .onDuplicateKeyUpdate()
      .set(AUTHOR.LAST_NAME, excluded(AUTHOR.LAST_NAME))
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME).values(3, "X").onDuplicateKeyUpdate().set(AUTHOR.LAST_NAME, excluded(AUTHOR.LAST_NAME))
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON DUPLICATE KEY UPDATE
  AUTHOR.LAST_NAME = VALUES(LAST_NAME)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, YugabyteDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT (ID)
DO UPDATE
SET
  LAST_NAME = excluded.LAST_NAME
```

###### DB2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYSIBM.DUAL
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Exasol

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Firebird

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM RDB$DATABASE
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### H2

```sql
MERGE INTO AUTHOR
USING (
  SELECT
    3 ID,
    'X' LAST_NAME
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Hana

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
    FROM SYS.DUMMY
  )
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### HSQLDB

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (VALUES (1)) AS dual (dual)
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### MySQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
AS excluded
ON DUPLICATE KEY UPDATE
  AUTHOR.LAST_NAME = excluded.LAST_NAME
```

###### Oracle

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
  )
) t
ON (AUTHOR.ID = t.ID)
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Redshift, Snowflake

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### SQLite

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT 
DO UPDATE
SET
  LAST_NAME = excluded.LAST_NAME
```

###### SQLServer

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
);
```

###### Sybase

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYS.DUMMY
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Teradata

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### ASE, Access, BigQuery, ClickHouse, Databricks, Informix, SQLDataWarehouse, Spanner, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-on-duplicate-key-all-excluded"></a>
##### 3.5.4.7. INSERT .. ON DUPLICATE KEY UPDATE .. SET ALL TO EXCLUDED

A [synthetic SQL clause](#synthetic-sql-clauses) extension of the [INSERT .. ON DUPLICATE KEY UPDATE .. EXCLUDED](#insert-on-duplicate-key-excluded) syntax is a clause that sets all the (known) columns of a table to `EXCLUDED` in the `ON DUPLICATE KEY UPDATE` clause, for convenience.

The clause comes in 3 flavours:

- `setAllToExcluded()`: Take all the columns from the `INSERT` column list and set them to `EXCLUDED`
- `setNonKeyToExcluded()`: Take all the non-unique and non-primary key columns from the `INSERT` column list and set them to `EXCLUDED`
- `setNonPrimaryKeyToExcluded()`: Take all the non-primary key columns from the `INSERT` column list and set them to `EXCLUDED`

```java
// Add a new author called "Koontz" with ID 3.
// If that ID is already present, update the author's name
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
      .values(3, "Koontz")
      .onDuplicateKeyUpdate()
      .setNonPrimaryKeyToExcluded()
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME).values(3, "X").onDuplicateKeyUpdate().setAllToExcluded()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON DUPLICATE KEY UPDATE
  AUTHOR.ID = VALUES(ID),
  AUTHOR.LAST_NAME = VALUES(LAST_NAME)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, YugabyteDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT (ID)
DO UPDATE
SET
  ID = excluded.ID,
  LAST_NAME = excluded.LAST_NAME
```

###### DB2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYSIBM.DUAL
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Exasol

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Firebird

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM RDB$DATABASE
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### H2

```sql
MERGE INTO AUTHOR
USING (
  SELECT
    3 ID,
    'X' LAST_NAME
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Hana

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
    FROM SYS.DUMMY
  )
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### HSQLDB

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (VALUES (1)) AS dual (dual)
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### MySQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
AS excluded
ON DUPLICATE KEY UPDATE
  AUTHOR.ID = excluded.ID,
  AUTHOR.LAST_NAME = excluded.LAST_NAME
```

###### Oracle

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
  )
) t
ON ((
  SELECT AUTHOR.ID
) = t.ID)
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Redshift, Snowflake

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  ID = t.ID,
  LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### SQLite

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT 
DO UPDATE
SET
  ID = excluded.ID,
  LAST_NAME = excluded.LAST_NAME
```

###### SQLServer

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
);
```

###### Sybase

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYS.DUMMY
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Teradata

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  ID = t.ID,
  LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### ASE, Access, BigQuery, ClickHouse, Databricks, Informix, SQLDataWarehouse, Spanner, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-on-duplicate-key-ignore"></a>
##### 3.5.4.8. INSERT .. ON DUPLICATE KEY IGNORE

The MySQL database also supports an INSERT IGNORE INTO clause. This is supported by jOOQ using the more convenient SQL syntax variant of ON DUPLICATE KEY IGNORE:

```java
// Add a new author called "Koontz" with ID 3.
// If that ID is already present, ignore the INSERT statement
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
      .values(3, "Koontz")
      .onDuplicateKeyIgnore()
      .execute();
```

If the underlying database doesn't have any way to "ignore" failing `INSERT` statements, (e.g. MySQL via `INSERT IGNORE`), jOOQ can emulate the statement using a [MERGE statement](#merge-statement), or using `INSERT .. SELECT WHERE NOT EXISTS.`

> [!TIP]
> The MySQL `INSERT IGNORE` statement ignores more constraint violations than just duplicate keys, so the emulation isn't exactly equivalent, see [#5211](https://github.com/jOOQ/jOOQ/issues/5211)

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME).values(3, "X").onDuplicateKeyIgnore()
```

Translates to the following dialect specific expressions:

###### Access

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT t.v0, t.v1
FROM (
  SELECT
    3 v0,
    'X' v1
  FROM (
    SELECT count(*) dual
    FROM MSysResources
  ) AS dual
  WHERE NOT EXISTS (
    SELECT 1
    FROM AUTHOR
    WHERE AUTHOR.ID = 3
  )
) t
```

###### ASE, ClickHouse, SQLDataWarehouse, Trino, Vertica

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT t.v0, t.v1
FROM (
  SELECT
    3 v0,
    'X' v1
  WHERE NOT EXISTS (
    SELECT 1
    FROM AUTHOR
    WHERE AUTHOR.ID = 3
  )
) t
```

###### Aurora MySQL, MariaDB, MySQL

```sql
INSERT IGNORE INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, SQLite, YugabyteDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT
DO NOTHING
```

###### BigQuery

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT t.v0, t.v1
FROM (
  SELECT
    3 v0,
    'X' v1
  FROM UNNEST([STRUCT(1 AS dual)]) AS dual
  WHERE NOT EXISTS (
    SELECT 1
    FROM AUTHOR
    WHERE AUTHOR.ID = 3
  )
) t
```

###### Databricks

```sql
MERGE INTO AUTHOR
USING (
  SELECT t.ID, t.LAST_NAME
  FROM (
    SELECT 3, 'X'
  ) t (ID, LAST_NAME)
) t
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### DB2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYSIBM.DUAL
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Exasol, MemSQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT t.v0, t.v1
FROM (
  SELECT
    3 v0,
    'X' v1
  FROM DUAL
  WHERE NOT EXISTS (
    SELECT 1
    FROM AUTHOR
    WHERE AUTHOR.ID = 3
  )
) t
```

###### Firebird

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM RDB$DATABASE
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### H2

```sql
MERGE INTO AUTHOR
USING (
  SELECT
    3 ID,
    'X' LAST_NAME
) t
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Hana

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
    FROM SYS.DUMMY
  )
) t
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### HSQLDB

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (VALUES (1)) AS dual (dual)
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Informix

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
SELECT t.v0, t.v1
FROM (
  SELECT
    3 v0,
    'X' v1
  FROM (
    SELECT 1 AS dual
    FROM systables
    WHERE (tabid = 1)
  ) AS dual
  WHERE NOT EXISTS (
    SELECT 1
    FROM AUTHOR
    WHERE AUTHOR.ID = 3
  )
) t
```

###### Oracle

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
  )
) t
ON (AUTHOR.ID = t.ID)
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Redshift, Snowflake

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Spanner

```sql
INSERT OR IGNORE INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
```

###### SQLServer

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
);
```

###### Sybase

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYS.DUMMY
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Teradata

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-on-conflict"></a>
##### 3.5.4.9. INSERT .. ON CONFLICT

The PostgreSQL database offers an alternative syntax to MySQL's vendor specific [INSERT .. ON DUPLICATE KEY](#insert-on-duplicate-key) syntax, which allows for specifying an explicit (reference by constraint name) or implicit (reference by column list) unique constraint for conflict resolution.

```java
// Add a new author called "Koontz" with ID 3.
// If that ID is already present, update the author's name
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
      .values(3, "Koontz")
      .onConflict(AUTHOR.ID)
      .doUpdate()
      .set(AUTHOR.LAST_NAME, "Koontz")
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME).values(3, "X").onConflict(AUTHOR.ID).doUpdate().set(AUTHOR.LAST_NAME, "X")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON DUPLICATE KEY UPDATE
  AUTHOR.LAST_NAME = 'X'
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, SQLite, YugabyteDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT (ID)
DO UPDATE
SET
  LAST_NAME = 'X'
```

###### DB2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYSIBM.DUAL
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Exasol

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Firebird

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM RDB$DATABASE
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### H2

```sql
MERGE INTO AUTHOR
USING (
  SELECT
    3 ID,
    'X' LAST_NAME
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Hana

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
    FROM SYS.DUMMY
  )
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### HSQLDB

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (VALUES (1)) AS dual (dual)
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### MySQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
AS excluded
ON DUPLICATE KEY UPDATE
  AUTHOR.LAST_NAME = 'X'
```

###### Oracle

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
  )
) t
ON (AUTHOR.ID = t.ID)
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Redshift, Snowflake

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### SQLServer

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
);
```

###### Sybase

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYS.DUMMY
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Teradata

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  LAST_NAME = 'X'
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### ASE, Access, BigQuery, ClickHouse, Databricks, Informix, SQLDataWarehouse, Spanner, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-on-conflict-excluded"></a>
##### 3.5.4.10. INSERT .. ON CONFLICT .. EXCLUDED

A special use-case for [INSERT .. ON CONFLICT](#insert-on-conflict) is an `UPSERT` statement where all (or most of) the values to be updated are the same values that would have been inserted if there wasn't a conflict - with the exception of primary keys. In PostgreSQL, this is done using the `EXCLUDED` pseudo table. The keyword should be read as "rows that have been excluded from the `INSERT` part of the statement."

```java
// Add a new author called "Koontz" with ID 3.
// If that ID is already present, update the author's name
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
      .values(3, "Koontz")
      .onConflict(AUTHOR.ID)
      .doUpdate()
      .set(AUTHOR.LAST_NAME, excluded(AUTHOR.LAST_NAME))
      .execute();
```

> [!TIP]
> See [SET ALL TO EXCLUDED](#insert-on-conflict-excluded) to automatically set all columns to `EXCLUDED`.

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME).values(3, "X").onConflict(AUTHOR.ID).doUpdate().set(AUTHOR.LAST_NAME, excluded(AUTHOR.LAST_NAME))
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON DUPLICATE KEY UPDATE
  AUTHOR.LAST_NAME = VALUES(LAST_NAME)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, SQLite, YugabyteDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT (ID)
DO UPDATE
SET
  LAST_NAME = excluded.LAST_NAME
```

###### DB2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYSIBM.DUAL
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Exasol

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Firebird

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM RDB$DATABASE
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### H2

```sql
MERGE INTO AUTHOR
USING (
  SELECT
    3 ID,
    'X' LAST_NAME
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Hana

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
    FROM SYS.DUMMY
  )
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### HSQLDB

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (VALUES (1)) AS dual (dual)
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### MySQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
AS excluded
ON DUPLICATE KEY UPDATE
  AUTHOR.LAST_NAME = excluded.LAST_NAME
```

###### Oracle

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
  )
) t
ON (AUTHOR.ID = t.ID)
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Redshift, Snowflake

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### SQLServer

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
);
```

###### Sybase

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYS.DUMMY
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Teradata

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### ASE, Access, BigQuery, ClickHouse, Databricks, Informix, SQLDataWarehouse, Spanner, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-on-conflict-all-excluded"></a>
##### 3.5.4.11. INSERT .. ON CONFLICT .. SET ALL TO EXCLUDED

A [synthetic SQL clause](#synthetic-sql-clauses) extension of the [INSERT .. ON CONFLICT .. EXCLUDED](#insert-on-conflict-excluded) syntax is a clause that sets all the (known) columns of a table to `EXCLUDED` in the `ON CONFLICT .. DO UPDATE` clause, for convenience.

The clause comes in 4 flavours:

- `setAllToExcluded()`: Take all the columns from the `INSERT` column list and set them to `EXCLUDED`
- `setNonKeyToExcluded()`: Take all the non-unique and non-primary key columns from the `INSERT` column list and set them to `EXCLUDED`
- `setNonPrimaryKeyToExcluded()`: Take all the non-primary key columns from the `INSERT` column list and set them to `EXCLUDED`
- `setNonConflictingKeyToExcluded()`: Take all the columns from the `INSERT` column list except those from the `ON CONFLICT` clause and set them to `EXCLUDED`

```java
// Add a new author called "Koontz" with ID 3.
// If that ID is already present, update the author's name
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
      .values(3, "Koontz")
      .onConflict(AUTHOR.ID)
      .doUpdate()
      .setNonConflictingKeyToExcluded()
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME).values(3, "X").onConflict(AUTHOR.ID).doUpdate().setAllToExcluded()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON DUPLICATE KEY UPDATE
  AUTHOR.ID = VALUES(ID),
  AUTHOR.LAST_NAME = VALUES(LAST_NAME)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, SQLite, YugabyteDB

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
ON CONFLICT (ID)
DO UPDATE
SET
  ID = excluded.ID,
  LAST_NAME = excluded.LAST_NAME
```

###### DB2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYSIBM.DUAL
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Exasol

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Firebird

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM RDB$DATABASE
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### H2

```sql
MERGE INTO AUTHOR
USING (
  SELECT
    3 ID,
    'X' LAST_NAME
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Hana

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
    FROM SYS.DUMMY
  )
) t
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### HSQLDB

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (VALUES (1)) AS dual (dual)
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### MySQL

```sql
INSERT INTO AUTHOR (ID, LAST_NAME)
VALUES (
  3, 
  'X'
)
AS excluded
ON DUPLICATE KEY UPDATE
  AUTHOR.ID = excluded.ID,
  AUTHOR.LAST_NAME = excluded.LAST_NAME
```

###### Oracle

```sql
MERGE INTO AUTHOR
USING (
  (
    SELECT
      3 ID,
      'X' LAST_NAME
  )
) t
ON ((
  SELECT AUTHOR.ID
) = t.ID)
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Redshift, Snowflake

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  ID = t.ID,
  LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### SQLServer

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
);
```

###### Sybase

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM SYS.DUMMY
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  AUTHOR.ID = t.ID,
  AUTHOR.LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### Teradata

```sql
MERGE INTO AUTHOR
USING (
  SELECT 3, 'X'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (ID, LAST_NAME)
ON AUTHOR.ID = t.ID
WHEN MATCHED THEN UPDATE SET
  ID = t.ID,
  LAST_NAME = t.LAST_NAME
WHEN NOT MATCHED THEN INSERT (ID, LAST_NAME)
VALUES (
  t.ID, 
  t.LAST_NAME
)
```

###### ASE, Access, BigQuery, ClickHouse, Databricks, Informix, SQLDataWarehouse, Spanner, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="insert-returning"></a>
##### 3.5.4.12. INSERT .. RETURNING

The Postgres database has native support for an INSERT .. RETURNING clause. This is a very powerful concept that is emulated for all other dialects using JDBC's [`getGeneratedKeys()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#getGeneratedKeys()) method. Take this example:

```java
// Add another author, with a generated ID
Record record =
create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .values("Charlotte", "Roche")
      .returningResult(AUTHOR.ID)
      .fetchOne();

System.out.println(record.getValue(AUTHOR.ID));

// For some RDBMS, this also works when inserting several values
// The following should return a 2x2 table
Result<?> result =
create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .values("Johann Wolfgang", "von Goethe")
      .values("Friedrich", "Schiller")
      // You can request any field. Also trigger-generated values
      .returningResult(AUTHOR.ID, AUTHOR.CREATION_DATE)
      .fetch();
```

Some databases have poor support for returning generated keys after INSERTs. In those cases, jOOQ might need to issue another [SELECT statement](#select-statement) in order to fetch an @@identity value. Be aware, that this can lead to race-conditions in those databases that cannot properly return generated ID values. For more information, please consider the jOOQ Javadoc for the returningResult() clause.

###### Dialect support

This example using jOOQ:

```java
insertInto(AUTHOR, AUTHOR.LAST_NAME).values("Doe").returningResult(AUTHOR.ID)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, HSQLDB, Hana, Informix, MemSQL, MySQL, Oracle, Redshift, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
INSERT INTO AUTHOR (LAST_NAME)
VALUES ('Doe')
```

###### Aurora Postgres, CockroachDB, DuckDB, Firebird, Postgres, SQLite, YugabyteDB

```sql
INSERT INTO AUTHOR (LAST_NAME)
VALUES ('Doe')
RETURNING AUTHOR.ID
```

###### DB2, H2

```sql
SELECT ID
FROM FINAL TABLE (
  INSERT INTO AUTHOR (LAST_NAME)
  VALUES ('Doe')
) AUTHOR
```

###### MariaDB

```sql
INSERT INTO AUTHOR (LAST_NAME)
VALUES ('Doe')
RETURNING ID
```

###### Spanner

```sql
INSERT INTO AUTHOR (LAST_NAME)
VALUES ('Doe')
THEN RETURN AUTHOR.ID
```

###### SQLDataWarehouse, SQLServer

```sql
INSERT INTO AUTHOR (LAST_NAME)
OUTPUT inserted.ID
VALUES ('Doe')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="update-statement"></a>
#### 3.5.5. The UPDATE statement

The `UPDATE` statement is used to modify one or several pre-existing records in a database table. `UPDATE` statements are only possible on single tables. Support for multi-table updates might be implemented in the future. An example update query is given here:

```sql
UPDATE AUTHOR
   SET FIRST_NAME = 'Hermann',
       LAST_NAME = 'Hesse'
 WHERE ID = 3;
 
```

```java
create.update(AUTHOR)
      .set(AUTHOR.FIRST_NAME, "Hermann")
      .set(AUTHOR.LAST_NAME, "Hesse")
      .where(AUTHOR.ID.eq(3))
      .execute();
```

The following subsections discuss the various subclauses of the `UPDATE` statement.

<a id="update-set"></a>
##### 3.5.5.1. UPDATE .. SET

The `SET` clause allows for setting new values on updated records in a table.

###### Dialect support

This example using jOOQ:

```java
update(BOOK).set(BOOK.TITLE, "New Title")
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, Sybase, Trino

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
```

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Postgres, Redshift, SQLite, Snowflake, Teradata, Vertica, YugabyteDB

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
```

###### BigQuery, Spanner

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE TRUE
```

###### ClickHouse

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
WHERE TRUE
```

###### Hana

```sql
UPDATE BOOK
FROM BOOK
SET
  BOOK.TITLE = 'New Title'
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="update-set-rows"></a>
##### 3.5.5.2. UPDATE .. SET ROW

The `SET` clause allows for setting [ROW value expressions](#row-value-expressions) on updated records in a table.

```sql
UPDATE AUTHOR
   SET (FIRST_NAME, LAST_NAME) =
       ('Hermann',  'Hesse')
 WHERE ID = 3;
 
```

```java
create.update(AUTHOR)
      .set(row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME),
           row("Herman",          "Hesse"))
      .where(AUTHOR.ID.eq(3))
      .execute();
```

This can be particularly useful when using correlated subqueries in the `SET` clause, in case of which multiple columns can be updated with a single subquery, instead of only 1. See also [UPDATE .. FROM](#update-from) for an alternative syntax for this scenario.

```sql
UPDATE AUTHOR
   SET (FIRST_NAME, LAST_NAME) = (
         SELECT PERSON.FIRST_NAME, PERSON.LAST_NAME
         FROM PERSON
         WHERE PERSON.ID = AUTHOR.ID
       )
 WHERE ID = 3;
 
```

```java
create.update(AUTHOR)
      .set(row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME),
           select(PERSON.FIRST_NAME, PERSON.LAST_NAME)
          .from(PERSON)
          .where(PERSON.ID.eq(AUTHOR.ID))
      )
      .where(AUTHOR.ID.eq(3))
      .execute();
```

The above row value expressions usages are completely typesafe.

###### Dialect support

This example using jOOQ:

```java
update(BOOK).set(row(BOOK.TITLE, BOOK.LANGUAGE_ID), row("New Title", 1))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Exasol, Firebird, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, Sybase

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title',
  BOOK.LANGUAGE_ID = 1
```

###### Aurora Postgres, CockroachDB, DB2, H2, HSQLDB, Trino

```sql
UPDATE BOOK
SET
  (TITLE, LANGUAGE_ID) = ('New Title', 1)
```

###### BigQuery, Spanner

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title',
  BOOK.LANGUAGE_ID = 1
WHERE TRUE
```

###### ClickHouse

```sql
UPDATE BOOK
SET
  TITLE = 'New Title',
  LANGUAGE_ID = 1
WHERE TRUE
```

###### Databricks, DuckDB, Redshift, SQLite, Snowflake, Teradata, Vertica

```sql
UPDATE BOOK
SET
  TITLE = 'New Title',
  LANGUAGE_ID = 1
```

###### Hana

```sql
UPDATE BOOK
FROM BOOK
SET
  (TITLE, LANGUAGE_ID) = ('New Title', 1)
```

###### Oracle

```sql
UPDATE BOOK
SET
  (TITLE, LANGUAGE_ID) = (
    SELECT 'New Title', 1
  )
```

###### Postgres, YugabyteDB

```sql
UPDATE BOOK
SET
  (TITLE, LANGUAGE_ID) = ROW ('New Title', 1)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="update-from"></a>
##### 3.5.5.3. UPDATE .. FROM

Some databases, including for example PostgreSQL and SQL Server, support joining additional tables to an `UPDATE` statement using a vendor-specific `FROM` clause. This is supported as well by jOOQ:

```sql
UPDATE BOOK_ARCHIVE
SET
  BOOK_ARCHIVE.TITLE = BOOK.TITLE
FROM BOOK
WHERE BOOK_ARCHIVE.ID = BOOK.ID
```

```java
create.update(BOOK_ARCHIVE)
      .set(BOOK_ARCHIVE.TITLE, BOOK.TITLE)
      .from(BOOK)
      .where(BOOK_ARCHIVE.ID.eq(BOOK.ID))
      .execute();
```

In many cases, such a joined update statement can be emulated using a correlated subquery, or using updatable views. For example, most databases allow for using scalar subselects in `UPDATE` statements in one way or another. jOOQ models this through a `set(Field<T>, Select<? extends Record1<T>>)` method in the `UPDATE` DSL API, for convenience (see the section about [scalar subqueries](#scalar-subqueries) for more details):

```sql
UPDATE AUTHOR
   SET FIRST_NAME = (
         SELECT FIRST_NAME
         FROM PERSON
         WHERE PERSON.ID = AUTHOR.ID
       ),
 WHERE ID = 3;
 
```

```java
create.update(AUTHOR)
      .set(AUTHOR.FIRST_NAME,
         select(PERSON.FIRST_NAME)
        .from(PERSON)
        .where(PERSON.ID.eq(AUTHOR.ID))
      )
      .where(AUTHOR.ID.eq(3))
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
update(BOOK_TO_BOOK_STORE).set(BOOK_TO_BOOK_STORE.STOCK, 0).from(BOOK).where(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK.ID)).and(BOOK.AUTHOR_ID.eq(1))
```

Translates to the following dialect specific expressions:

###### ASE, BigQuery, Oracle, SQLServer, Sybase

```sql
UPDATE BOOK_TO_BOOK_STORE
SET
  BOOK_TO_BOOK_STORE.STOCK = 0
FROM BOOK
WHERE (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
  AND BOOK.AUTHOR_ID = 1
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL, Trino

```sql
UPDATE BOOK_TO_BOOK_STORE
  CROSS JOIN BOOK
SET
  BOOK_TO_BOOK_STORE.STOCK = 0
WHERE (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
  AND BOOK.AUTHOR_ID = 1
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, SQLite, Snowflake, YugabyteDB

```sql
UPDATE BOOK_TO_BOOK_STORE
SET
  STOCK = 0
FROM BOOK
WHERE (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
  AND BOOK.AUTHOR_ID = 1
)
```

###### ClickHouse

```sql
UPDATE BOOK_TO_BOOK_STORE
SET
  STOCK = 0
WHERE (NAME, BOOK_ID) IN (
  SELECT BOOK_TO_BOOK_STORE.NAME, BOOK_TO_BOOK_STORE.BOOK_ID
  FROM BOOK_TO_BOOK_STORE, BOOK
  WHERE (
    BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
    AND BOOK.AUTHOR_ID = 1
  )
)
```

###### Databricks

```sql
UPDATE BOOK_TO_BOOK_STORE
SET
  STOCK = 0
WHERE EXISTS (
  SELECT alias_1.v0, alias_1.v1
  FROM (
    SELECT
      BOOK_TO_BOOK_STORE.NAME v0,
      BOOK_TO_BOOK_STORE.BOOK_ID v1
    FROM BOOK_TO_BOOK_STORE, BOOK
    WHERE (
      BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
      AND BOOK.AUTHOR_ID = 1
    )
  ) alias_1
  WHERE STRUCT (
    coalesce(BOOK_TO_BOOK_STORE.NAME),
    coalesce(BOOK_TO_BOOK_STORE.BOOK_ID)
  ) = STRUCT (
    coalesce(alias_1.v0),
    coalesce(alias_1.v1)
  )
)
```

###### DB2, Exasol, Firebird, H2, HSQLDB

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
  AND BOOK.AUTHOR_ID = 1
)
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.STOCK = 0
```

###### Hana

```sql
UPDATE BOOK_TO_BOOK_STORE
FROM BOOK_TO_BOOK_STORE, BOOK
SET
  BOOK_TO_BOOK_STORE.STOCK = 0
WHERE (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
  AND BOOK.AUTHOR_ID = 1
)
```

###### Spanner

```sql
UPDATE BOOK_TO_BOOK_STORE
SET
  BOOK_TO_BOOK_STORE.STOCK = 0
WHERE EXISTS (
  SELECT alias_1.v0, alias_1.v1
  FROM (
    SELECT
      BOOK_TO_BOOK_STORE.NAME v0,
      BOOK_TO_BOOK_STORE.BOOK_ID v1
    FROM BOOK_TO_BOOK_STORE, BOOK
    WHERE (
      BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
      AND BOOK.AUTHOR_ID = 1
    )
  ) alias_1
  WHERE (BOOK_TO_BOOK_STORE.NAME, BOOK_TO_BOOK_STORE.BOOK_ID) = (alias_1.v0, alias_1.v1)
)
```

###### SQLDataWarehouse

```sql
UPDATE BOOK_TO_BOOK_STORE
SET
  BOOK_TO_BOOK_STORE.STOCK = 0
WHERE EXISTS (
  SELECT alias_1.v0, alias_1.v1
  FROM (
    SELECT
      BOOK_TO_BOOK_STORE.NAME v0,
      BOOK_TO_BOOK_STORE.BOOK_ID v1
    FROM BOOK_TO_BOOK_STORE, BOOK
    WHERE (
      BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
      AND BOOK.AUTHOR_ID = 1
    )
  ) alias_1
  WHERE (
    BOOK_TO_BOOK_STORE.NAME = alias_1.v0
    AND BOOK_TO_BOOK_STORE.BOOK_ID = alias_1.v1
  )
)
```

###### Teradata, Vertica

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
  AND BOOK.AUTHOR_ID = 1
)
WHEN MATCHED THEN UPDATE SET
  STOCK = 0
```

###### Access, Informix

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="update-where"></a>
##### 3.5.5.4. UPDATE .. WHERE

The `WHERE` clause allows for adding a [conditional expressions](#conditional-expressions) to the `UPDATE` statement, which restricts the rows to be updated.

###### Dialect support

This example using jOOQ:

```java
update(BOOK).set(BOOK.TITLE, "New Title").where(BOOK.ID.eq(1))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, BigQuery, DB2, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, Spanner, Sybase, Trino

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE BOOK.ID = 1
```

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Postgres, Redshift, SQLite, Snowflake, Teradata, Vertica, YugabyteDB

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
WHERE BOOK.ID = 1
```

###### ClickHouse

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
WHERE ID = 1
```

###### Hana

```sql
UPDATE BOOK
FROM BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE BOOK.ID = 1
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="update-order-by-limit"></a>
##### 3.5.5.5. UPDATE .. ORDER BY .. LIMIT

The `ORDER BY` and `LIMIT` clauses allow for updating only a subset of the data in a table, based on their ordering. This can be useful to implement queue semantics, e.g. to update only the top row, and possibly [return it](#update-returning) in one go.

###### Dialect support

This example using jOOQ:

```java
update(BOOK).set(BOOK.TITLE, "New Title").orderBy(BOOK.ID.asc()).limit(1)
```

Translates to the following dialect specific expressions:

###### ASE, SQLDataWarehouse, SQLServer, Sybase

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT TOP 1 BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
)
```

###### Aurora MySQL, DB2, MariaDB, MySQL, Trino

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
ORDER BY BOOK.ID ASC
LIMIT 1
```

###### Aurora Postgres, Databricks, DuckDB, Redshift, SQLite, Snowflake, Vertica, YugabyteDB

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  LIMIT 1
)
```

###### BigQuery, Exasol, HSQLDB, Spanner

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  LIMIT 1
)
```

###### ClickHouse

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
WHERE ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  LIMIT 1
)
```

###### CockroachDB

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
ORDER BY BOOK.ID ASC
LIMIT 1
```

###### Firebird

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
ORDER BY BOOK.ID ASC
ROWS 1
```

###### H2, Oracle

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  FETCH NEXT 1 ROWS ONLY
)
```

###### Hana

```sql
UPDATE BOOK
FROM BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  LIMIT 1
)
```

###### Informix

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT *
  FROM (
    SELECT FIRST 1 BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID ASC
  ) x
)
```

###### MemSQL

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT *
  FROM (
    SELECT BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID ASC
    LIMIT 1
  ) t
)
```

###### Postgres

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  FETCH NEXT 1 ROWS ONLY
)
```

###### Teradata

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
WHERE BOOK.ID IN (
  SELECT *
  FROM (
    SELECT TOP 1 BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID ASC
  ) x
)
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="update-returning"></a>
##### 3.5.5.6. UPDATE .. RETURNING

Various dialect support a `RETURNING` clause or something similar on their `UPDATE` statements, similar as the `RETURNING` clause in [INSERT statements](#insert-statement). This is useful to fetch trigger-generated values in one go. An example is given here:

```sql
-- Fetch a trigger-generated value
UPDATE BOOK
SET TITLE = 'Animal Farm'
WHERE ID = 5
RETURNING TITLE
```

```java
String title = create.update(BOOK)
                  .set(BOOK.TITLE, "Animal Farm")
                  .where(BOOK.ID.eq(5))
                  .returningResult(BOOK.TITLE)
                  .fetchOne().getValue(BOOK.TITLE);
```

###### Dialect support

This example using jOOQ:

```java
update(BOOK).set(BOOK.TITLE, "New Title").returningResult(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, SQLite, YugabyteDB

```sql
UPDATE BOOK
SET
  TITLE = 'New Title'
RETURNING BOOK.ID
```

###### DB2, H2

```sql
SELECT ID
FROM FINAL TABLE (
  UPDATE BOOK
  SET
    BOOK.TITLE = 'New Title'
) BOOK
```

###### Firebird

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
RETURNING BOOK.ID
```

###### MariaDB

```sql
INSERT INTO BOOK (
  ID,
  AUTHOR_ID,
  TITLE,
  PUBLISHED_IN,
  LANGUAGE_ID
)
SELECT
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM BOOK
ON DUPLICATE KEY UPDATE
  BOOK.TITLE = 'New Title'
RETURNING ID
```

###### Oracle

```sql
DECLARE
  o0 DBMS_SQL.NUMBER_TABLE;
  c0 sys_refcursor;
BEGIN
  UPDATE BOOK
  SET
    BOOK.TITLE = 'New Title'
  RETURNING BOOK.ID
  BULK COLLECT INTO o0;
  ? := SQL%ROWCOUNT;
  OPEN c0 FOR SELECT * FROM TABLE(o0);
  ? := c0;
END;
```

###### Spanner

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
WHERE TRUE
THEN RETURN BOOK.ID
```

###### SQLServer

```sql
UPDATE BOOK
SET
  BOOK.TITLE = 'New Title'
OUTPUT inserted.ID
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, HSQLDB, Hana, Informix, MemSQL, MySQL, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="delete-statement"></a>
#### 3.5.6. The DELETE statement

The DELETE statement removes records from a database table. DELETE statements are only possible on single tables. Support for multi-table deletes might be implemented in the future. An example delete query is given here:

```sql
DELETE AUTHOR
 WHERE ID = 100;
 
```

```java
create.delete(AUTHOR)
      .where(AUTHOR.ID.eq(100))
      .execute();
```

The following subsections discuss the various subclauses of the `DELETE` statement.

<a id="delete-using"></a>
##### 3.5.6.1. DELETE .. USING

The `USING` clause allows for a `JOIN` between the table from which to delete rows with other tables.

###### Dialect support

This example using jOOQ:

```java
deleteFrom(BOOK).using(AUTHOR).where(BOOK.AUTHOR_ID.eq(AUTHOR.ID)).and(AUTHOR.LAST_NAME.eq("Poe"))
```

Translates to the following dialect specific expressions:

###### ASE, Oracle, SQLServer, Sybase

```sql
DELETE FROM BOOK
FROM AUTHOR
WHERE (
  BOOK.AUTHOR_ID = AUTHOR.ID
  AND AUTHOR.LAST_NAME = 'Poe'
)
```

###### Aurora MySQL, MariaDB, MySQL

```sql
DELETE FROM BOOK
USING BOOK, AUTHOR
WHERE (
  BOOK.AUTHOR_ID = AUTHOR.ID
  AND AUTHOR.LAST_NAME = 'Poe'
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake, YugabyteDB

```sql
DELETE FROM BOOK
USING AUTHOR
WHERE (
  BOOK.AUTHOR_ID = AUTHOR.ID
  AND AUTHOR.LAST_NAME = 'Poe'
)
```

###### BigQuery, Databricks, Hana, SQLDataWarehouse, SQLite, Spanner, Trino, Vertica

```sql
DELETE FROM BOOK
WHERE BOOK.ID IN (
  SELECT BOOK.ID
  FROM BOOK, AUTHOR
  WHERE (
    BOOK.AUTHOR_ID = AUTHOR.ID
    AND AUTHOR.LAST_NAME = 'Poe'
  )
)
```

###### ClickHouse

```sql
DELETE FROM BOOK
WHERE ID IN (
  SELECT BOOK.ID
  FROM BOOK, AUTHOR
  WHERE (
    BOOK.AUTHOR_ID = AUTHOR.ID
    AND AUTHOR.LAST_NAME = 'Poe'
  )
)
```

###### DB2, Firebird, H2, HSQLDB

```sql
MERGE INTO BOOK
USING AUTHOR
ON (
  BOOK.AUTHOR_ID = AUTHOR.ID
  AND AUTHOR.LAST_NAME = 'Poe'
)
WHEN MATCHED THEN DELETE
```

###### Exasol

```sql
MERGE INTO BOOK
USING AUTHOR
ON (
  BOOK.AUTHOR_ID = AUTHOR.ID
  AND AUTHOR.LAST_NAME = 'Poe'
)
WHEN MATCHED THEN UPDATE SET
  BOOK.ID = BOOK.ID DELETE
```

###### MemSQL

```sql
DELETE BOOK
FROM BOOK, AUTHOR
WHERE (
  BOOK.AUTHOR_ID = AUTHOR.ID
  AND AUTHOR.LAST_NAME = 'Poe'
)
```

###### Teradata

```sql
DELETE BOOK
FROM AUTHOR
WHERE (
  BOOK.AUTHOR_ID = AUTHOR.ID
  AND AUTHOR.LAST_NAME = 'Poe'
)
```

###### Access, Informix

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="delete-where"></a>
##### 3.5.6.2. DELETE .. WHERE

The `WHERE` clause allows for adding a [conditional expressions](#conditional-expressions) to the `DELETE` statement, which restricts the rows to be deleted.

###### Dialect support

This example using jOOQ:

```java
deleteFrom(BOOK).where(BOOK.ID.in(1, 2, 3))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
DELETE FROM BOOK
WHERE BOOK.ID IN (
  1, 2, 3
)
```

###### ClickHouse

```sql
DELETE FROM BOOK
WHERE ID IN (
  1, 2, 3
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="delete-order-by-limit"></a>
##### 3.5.6.3. DELETE .. ORDER BY .. LIMIT

The `ORDER BY` and `LIMIT` clauses allow for deleting only a subset of the data in a table, based on their ordering. This can be useful to implement queue semantics, e.g. to delete only the top row, and possibly [return it](#delete-returning) in one go.

###### Dialect support

This example using jOOQ:

```java
deleteFrom(BOOK).orderBy(BOOK.ID.asc()).limit(1)
```

Translates to the following dialect specific expressions:

###### ASE, SQLDataWarehouse, SQLServer, Sybase

```sql
DELETE FROM BOOK
WHERE BOOK.ID IN (
  SELECT TOP 1 BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
)
```

###### Aurora MySQL, CockroachDB, DB2, MariaDB, MySQL, Trino

```sql
DELETE FROM BOOK
ORDER BY BOOK.ID ASC
LIMIT 1
```

###### Aurora Postgres, BigQuery, Databricks, DuckDB, Exasol, HSQLDB, Hana, Redshift, SQLite, Snowflake, Spanner, Vertica, YugabyteDB

```sql
DELETE FROM BOOK
WHERE BOOK.ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  LIMIT 1
)
```

###### ClickHouse

```sql
DELETE FROM BOOK
WHERE ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  LIMIT 1
)
```

###### Firebird

```sql
DELETE FROM BOOK
ORDER BY BOOK.ID ASC
ROWS 1
```

###### H2, Oracle, Postgres

```sql
DELETE FROM BOOK
WHERE BOOK.ID IN (
  SELECT BOOK.ID
  FROM BOOK
  ORDER BY BOOK.ID ASC
  FETCH NEXT 1 ROWS ONLY
)
```

###### Informix

```sql
DELETE FROM BOOK
WHERE BOOK.ID IN (
  SELECT *
  FROM (
    SELECT FIRST 1 BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID ASC
  ) x
)
```

###### MemSQL

```sql
DELETE FROM BOOK
WHERE BOOK.ID IN (
  SELECT *
  FROM (
    SELECT BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID ASC
    LIMIT 1
  ) t
)
```

###### Teradata

```sql
DELETE FROM BOOK
WHERE BOOK.ID IN (
  SELECT *
  FROM (
    SELECT TOP 1 BOOK.ID
    FROM BOOK
    ORDER BY BOOK.ID ASC
  ) x
)
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="delete-returning"></a>
##### 3.5.6.4. DELETE .. RETURNING

The `RETURNING` clause allows for returning expressions based on the deleted rows.

###### Dialect support

This example using jOOQ:

```java
deleteFrom(BOOK).where(BOOK.ID.eq(1)).returningResult(BOOK.TITLE)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Firebird, Postgres, SQLite, YugabyteDB

```sql
DELETE FROM BOOK
WHERE BOOK.ID = 1
RETURNING BOOK.TITLE
```

###### DB2, H2

```sql
SELECT TITLE
FROM OLD TABLE (
  DELETE FROM BOOK
  WHERE BOOK.ID = 1
) BOOK
```

###### MariaDB

```sql
DELETE FROM BOOK
WHERE BOOK.ID = 1
RETURNING TITLE
```

###### Oracle

```sql
DECLARE
  o0 DBMS_SQL.VARCHAR2_TABLE;
  c0 sys_refcursor;
BEGIN
  DELETE FROM BOOK
  WHERE BOOK.ID = 1
  RETURNING BOOK.TITLE
  BULK COLLECT INTO o0;
  ? := SQL%ROWCOUNT;
  OPEN c0 FOR SELECT * FROM TABLE(o0);
  ? := c0;
END;
```

###### Spanner

```sql
DELETE FROM BOOK
WHERE BOOK.ID = 1
THEN RETURN BOOK.TITLE
```

###### SQLServer

```sql
DELETE FROM BOOK
OUTPUT deleted.TITLE
WHERE BOOK.ID = 1
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, HSQLDB, Hana, Informix, MemSQL, MySQL, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="merge-statement"></a>
#### 3.5.7. The MERGE statement

The `MERGE` statement is one of the most advanced standardised SQL features. While it can be used for `UPSERT` semantics (similar to [INSERT .. ON DUPLICATE KEY UPDATE](#insert-on-duplicate-key) or [INSERT .. ON CONFLICT](#insert-on-conflict)), it is much more than that.

The point of the standard `MERGE` statement is to take a `TARGET` table, and merge (`INSERT`, `UPDATE`, or `DELETE`) data from a `SOURCE` table into it.

Here is an example assuming that we have a `BOOK_TO_BOOK_STORE_STAGING` table that we use to load data into the "actual" `BOOK_TO_BOOK_STORE` data table when doing ETL:

```sql
-- Merge staging data into the real table
MERGE INTO BOOK_TO_BOOK_STORE
USING (
  SELECT * FROM BOOK_TO_BOOK_STORE_STAGING
)
ON BOOK_TO_BOOK_STORE.BOOK_ID
   = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
AND BOOK_TO_BOOK_STORE.NAME
   = BOOK_TO_BOOK_STORE_STAGING.NAME
WHEN MATCHED THEN UPDATE
  SET STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK
WHEN NOT MATCHED THEN INSERT (
  BOOK_ID,
  NAME,
  STOCK
)
VALUES (
  BOOK_TO_BOOK_STORE_STAGING.BOOK_ID,
  BOOK_TO_BOOK_STORE_STAGING.NAME,
  BOOK_TO_BOOK_STORE_STAGING.STOCK
);
```

```java
create.mergeInto(BOOK_TO_BOOK_STORE)
      .using(BOOK_TO_BOOK_STORE_STAGING)
      .on(BOOK_TO_BOOK_STORE.BOOK_ID
          .eq(BOOK_TO_BOOK_STORE_STAGING.BOOK_ID)
      .and(BOOK_TO_BOOK_STORE.NAME
          .eq(BOOK_TO_BOOK_STORE_STAGING.NAME)))
      .whenMatchedThenUpdate().set(
          BOOK_TO_BOOK_STORE.STOCK,
          BOOK_TO_BOOK_STORE_STAGING.STOCK
      )
      .whenNotMatchedThenInsert(
           BOOK_TO_BOOK_STORE.BOOK_ID,
           BOOK_TO_BOOK_STORE.NAME,
           BOOK_TO_BOOK_STORE.STOCK
      )
      .values(
           BOOK_TO_BOOK_STORE_STAGING.BOOK_ID,
           BOOK_TO_BOOK_STORE_STAGING.NAME,
           BOOK_TO_BOOK_STORE_STAGING.STOCK
       )
      .execute();
```

Think of the `MERGE` statement as a [RIGHT JOIN](#join-type-outer) between `TARGET` and `SOURCE` tables, where the `ON` clause defines whether there is a `MATCH` between `TARGET` and `SOURCE` rows:

- If there's a `MATCH`, an `UPDATE` or `DELETE` operation on the `TARGET` row is possible
- If there's no `MATCH`, then the `SOURCE` row can be used to perform an `INSERT` operation on the `TARGET` table
- If there's no `MATCH`, some dialects also support the `BY SOURCE` clause to specify that a [LEFT JOIN or FULL JOIN](#join-type-outer) should be performed instead, in order to allow for performing an `UPDATE` or `DELETE` operation on existing rows in the `TARGET` table that have no matching row in the `SOURCE` table..

The following sections explain the `MERGE` statement in detail.

<a id="merge-using"></a>
##### 3.5.7.1. USING .. ON

The `USING .. ON` clause specifies the [MERGE statement](#merge-statement) `SOURCE` table and `JOIN` condition with the `TARGET` table, based on which the remaining clauses will be applied. By default, the `SOURCE` table is [RIGHT JOIN](#join-type-outer)-ed to the `TARGET` table, meaning that actions take place for every row in the `SOURCE` table.

Some dialects also support a [BY SOURCE](#merge-when-not-matched-by-source) clause, which allows for `LEFT JOIN` or `FULL JOIN` semantics instead, allowing to act also on rows in the `TARGET` table for which there is no matching `SOURCE` row.

###### Dialect support

This example using jOOQ:

```java
mergeInto(BOOK_TO_BOOK_STORE)
    .using(BOOK_TO_BOOK_STORE_STAGING)
    .on(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK_TO_BOOK_STORE_STAGING.BOOK_ID)
        .and(BOOK_TO_BOOK_STORE.NAME.eq(BOOK_TO_BOOK_STORE_STAGING.NAME)))
    .whenMatchedThenUpdate().set(BOOK_TO_BOOK_STORE.STOCK, BOOK_TO_BOOK_STORE_STAGING.STOCK)
```

Translates to the following dialect specific expressions:

###### Databricks, DuckDB, Postgres, Snowflake, Teradata, Vertica

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN UPDATE SET
  STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK
```

###### DB2, Exasol, Firebird, H2, HSQLDB, Hana, Sybase

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK
```

###### Oracle

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON ((
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
))
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK
```

###### Redshift

```sql
UPDATE BOOK_TO_BOOK_STORE
SET
  STOCK = CASE
    WHEN 1 = 1 THEN BOOK_TO_BOOK_STORE_STAGING.STOCK
    ELSE BOOK_TO_BOOK_STORE.STOCK
  END
FROM BOOK_TO_BOOK_STORE_STAGING
WHERE (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
```

###### SQLServer

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK;
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="merge-when-matched-then-update"></a>
##### 3.5.7.2. WHEN MATCHED THEN UPDATE

When there's a `MATCH` between `SOURCE` row and `TARGET` row, then the `TARGET` row can be updated with values from the `SOURCE` row, similar to what the [UPDATE .. FROM](#update-from) clause would allow.

###### Dialect support

This example using jOOQ:

```java
mergeInto(BOOK_TO_BOOK_STORE)
    .using(BOOK_TO_BOOK_STORE_STAGING)
    .on(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK_TO_BOOK_STORE_STAGING.BOOK_ID)
        .and(BOOK_TO_BOOK_STORE.NAME.eq(BOOK_TO_BOOK_STORE_STAGING.NAME)))
    .whenMatchedThenUpdate().set(BOOK_TO_BOOK_STORE.STOCK, BOOK_TO_BOOK_STORE_STAGING.STOCK)
```

Translates to the following dialect specific expressions:

###### Databricks, DuckDB, Postgres, Snowflake, Teradata, Vertica

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN UPDATE SET
  STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK
```

###### DB2, Exasol, Firebird, H2, HSQLDB, Hana, Sybase

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK
```

###### Oracle

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON ((
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
))
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK
```

###### Redshift

```sql
UPDATE BOOK_TO_BOOK_STORE
SET
  STOCK = CASE
    WHEN 1 = 1 THEN BOOK_TO_BOOK_STORE_STAGING.STOCK
    ELSE BOOK_TO_BOOK_STORE.STOCK
  END
FROM BOOK_TO_BOOK_STORE_STAGING
WHERE (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
```

###### SQLServer

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.STOCK = BOOK_TO_BOOK_STORE_STAGING.STOCK;
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="merge-when-matched-then-delete"></a>
##### 3.5.7.3. WHEN MATCHED THEN DELETE

When there's a `MATCH` between `SOURCE` row and `TARGET` row, then the `TARGET` row can be deleted, similar to what the [DELETE .. USING](#delete-using) clause would allow.

###### Dialect support

This example using jOOQ:

```java
mergeInto(BOOK_TO_BOOK_STORE)
    .using(BOOK_TO_BOOK_STORE_STAGING)
    .on(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK_TO_BOOK_STORE_STAGING.BOOK_ID)
        .and(BOOK_TO_BOOK_STORE.NAME.eq(BOOK_TO_BOOK_STORE_STAGING.NAME)))
    .whenMatchedThenDelete()
```

Translates to the following dialect specific expressions:

###### DB2, Databricks, DuckDB, Firebird, H2, HSQLDB, Postgres, Snowflake, Sybase

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN DELETE
```

###### Exasol

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE.NAME DELETE
```

###### Oracle

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON ((
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
))
WHEN MATCHED THEN UPDATE SET
  BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE.NAME DELETE
```

###### Redshift

```sql
DELETE FROM BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
WHERE (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
```

###### SQLServer

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN DELETE;
```

###### Teradata

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN MATCHED THEN UPDATE SET
  NAME = BOOK_TO_BOOK_STORE.NAME DELETE
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="merge-when-matched-and"></a>
##### 3.5.7.4. WHEN MATCHED AND ..

Various dialects support the standard SQL syntax for having multiple `WHEN` clauses, where an additional [predicates](#conditional-expressions) are supplied with each clause.

This works in a similar way to a [CASE expression](#case-expressions), where the first matching `CASE` gets applied.

If the syntax isn't supported in a dialect, it can be emulated by collapsing the various `WHEN` clauses into a single one that uses a [CASE expression](#case-expressions) to cover all the conditions and results.

###### Dialect support

This example using jOOQ:

```java
mergeInto(AUTHOR)
    .using(selectOne())
    .on(AUTHOR.LAST_NAME.eq("Hitchcock"))
    .whenMatchedAnd(AUTHOR.FIRST_NAME.eq("Mary"))
      .thenUpdate().set(AUTHOR.YEAR_OF_BIRTH, 1849)
    .whenMatchedAnd(AUTHOR.FIRST_NAME.eq("Alfred"))
      .thenUpdate().set(AUTHOR.YEAR_OF_BIRTH, 1899)
```

Translates to the following dialect specific expressions:

###### Databricks, DuckDB, Snowflake

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
)
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Mary' THEN UPDATE SET
  YEAR_OF_BIRTH = 1849
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Alfred' THEN UPDATE SET
  YEAR_OF_BIRTH = 1899
```

###### DB2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
  FROM SYSIBM.DUAL
)
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Mary' THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = 1849
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Alfred' THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = 1899
```

###### Exasol

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
)
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = CASE
    WHEN AUTHOR.FIRST_NAME = 'Mary' THEN 1849
    WHEN AUTHOR.FIRST_NAME = 'Alfred' THEN 1899
    ELSE AUTHOR.YEAR_OF_BIRTH
  END
WHERE (
  AUTHOR.FIRST_NAME = 'Mary'
  OR AUTHOR.FIRST_NAME = 'Alfred'
)
```

###### Firebird

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
  FROM RDB$DATABASE
)
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Mary' THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = 1849
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Alfred' THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = 1899
```

###### H2

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
)
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Mary' THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = 1849
WHEN MATCHED AND (
  NOT (AUTHOR.FIRST_NAME = 'Mary')
  AND AUTHOR.FIRST_NAME = 'Alfred'
) THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = 1899
```

###### Hana

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
  FROM SYS.DUMMY
)
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND (
  AUTHOR.FIRST_NAME = 'Mary'
  OR AUTHOR.FIRST_NAME = 'Alfred'
) THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = CASE
    WHEN AUTHOR.FIRST_NAME = 'Mary' THEN 1849
    WHEN AUTHOR.FIRST_NAME = 'Alfred' THEN 1899
    ELSE AUTHOR.YEAR_OF_BIRTH
  END
```

###### HSQLDB

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
  FROM (VALUES (1)) AS dual (dual)
)
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND (
  AUTHOR.FIRST_NAME = 'Mary'
  OR (
    NOT (AUTHOR.FIRST_NAME = 'Mary')
    AND AUTHOR.FIRST_NAME = 'Alfred'
  )
) THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = CASE
    WHEN AUTHOR.FIRST_NAME = 'Mary' THEN 1849
    WHEN (
      NOT (AUTHOR.FIRST_NAME = 'Mary')
      AND NOT (AUTHOR.FIRST_NAME = 'Mary')
      AND AUTHOR.FIRST_NAME = 'Alfred'
    ) THEN 1899
    ELSE AUTHOR.YEAR_OF_BIRTH
  END
```

###### Oracle

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
)
ON (AUTHOR.LAST_NAME = 'Hitchcock')
WHEN MATCHED THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = CASE
    WHEN AUTHOR.FIRST_NAME = 'Mary' THEN 1849
    WHEN AUTHOR.FIRST_NAME = 'Alfred' THEN 1899
    ELSE AUTHOR.YEAR_OF_BIRTH
  END
WHERE (
  AUTHOR.FIRST_NAME = 'Mary'
  OR AUTHOR.FIRST_NAME = 'Alfred'
)
```

###### Postgres, Vertica

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
) AS dummy_30260683("one")
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Mary' THEN UPDATE SET
  YEAR_OF_BIRTH = 1849
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Alfred' THEN UPDATE SET
  YEAR_OF_BIRTH = 1899
```

###### Redshift

```sql
UPDATE AUTHOR
SET
  YEAR_OF_BIRTH = CASE
    WHEN AUTHOR.FIRST_NAME = 'Mary' THEN 1849
    WHEN AUTHOR.FIRST_NAME = 'Alfred' THEN 1899
    ELSE AUTHOR.YEAR_OF_BIRTH
  END
FROM (
  SELECT 1 one
) alias_30260683
WHERE (
  AUTHOR.LAST_NAME = 'Hitchcock'
  AND (
    AUTHOR.FIRST_NAME = 'Mary'
    OR AUTHOR.FIRST_NAME = 'Alfred'
  )
)
```

###### SQLServer

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
) AS dummy_30260683([one])
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND (
  AUTHOR.FIRST_NAME = 'Mary'
  OR (
    NOT (AUTHOR.FIRST_NAME = 'Mary')
    AND AUTHOR.FIRST_NAME = 'Alfred'
  )
) THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = CASE
    WHEN AUTHOR.FIRST_NAME = 'Mary' THEN 1849
    WHEN (
      NOT (AUTHOR.FIRST_NAME = 'Mary')
      AND NOT (AUTHOR.FIRST_NAME = 'Mary')
      AND AUTHOR.FIRST_NAME = 'Alfred'
    ) THEN 1899
    ELSE AUTHOR.YEAR_OF_BIRTH
  END;
```

###### Sybase

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
  FROM SYS.DUMMY
) AS dummy_30260683([one])
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Mary' THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = 1849
WHEN MATCHED AND AUTHOR.FIRST_NAME = 'Alfred' THEN UPDATE SET
  AUTHOR.YEAR_OF_BIRTH = 1899
```

###### Teradata

```sql
MERGE INTO AUTHOR
USING (
  SELECT 1 one
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
)
ON AUTHOR.LAST_NAME = 'Hitchcock'
WHEN MATCHED THEN UPDATE SET
  YEAR_OF_BIRTH = CASE
    WHEN AUTHOR.FIRST_NAME = 'Mary' THEN 1849
    WHEN AUTHOR.FIRST_NAME = 'Alfred' THEN 1899
    ELSE AUTHOR.YEAR_OF_BIRTH
  END
WHERE (
  AUTHOR.FIRST_NAME = 'Mary'
  OR AUTHOR.FIRST_NAME = 'Alfred'
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="merge-when-not-matched-then-insert"></a>
##### 3.5.7.5. WHEN NOT MATCHED THEN INSERT

When there's no `MATCH` between `SOURCE` row and `TARGET` table, then data derived from the `SOURCE` row can be inserted into the `TARGET` table, similar to what [INSERT .. SELECT](#insert-select) would allow.

###### Dialect support

This example using jOOQ:

```java
mergeInto(BOOK_TO_BOOK_STORE)
    .using(BOOK_TO_BOOK_STORE_STAGING)
    .on(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK_TO_BOOK_STORE_STAGING.BOOK_ID)
        .and(BOOK_TO_BOOK_STORE.NAME.eq(BOOK_TO_BOOK_STORE_STAGING.NAME)))
    .whenNotMatchedThenInsert(
        BOOK_TO_BOOK_STORE.BOOK_ID,
        BOOK_TO_BOOK_STORE.NAME,
        BOOK_TO_BOOK_STORE.STOCK
    )
    .values(
        BOOK_TO_BOOK_STORE_STAGING.BOOK_ID,
        BOOK_TO_BOOK_STORE_STAGING.NAME,
        BOOK_TO_BOOK_STORE_STAGING.STOCK
    )
```

Translates to the following dialect specific expressions:

###### DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, Snowflake, Sybase, Teradata, Vertica

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN NOT MATCHED THEN INSERT (BOOK_ID, NAME, STOCK)
VALUES (
  BOOK_TO_BOOK_STORE_STAGING.BOOK_ID, 
  BOOK_TO_BOOK_STORE_STAGING.NAME, 
  BOOK_TO_BOOK_STORE_STAGING.STOCK
)
```

###### Oracle

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON ((
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
))
WHEN NOT MATCHED THEN INSERT (BOOK_ID, NAME, STOCK)
VALUES (
  BOOK_TO_BOOK_STORE_STAGING.BOOK_ID, 
  BOOK_TO_BOOK_STORE_STAGING.NAME, 
  BOOK_TO_BOOK_STORE_STAGING.STOCK
)
```

###### SQLServer

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN NOT MATCHED THEN INSERT (BOOK_ID, NAME, STOCK)
VALUES (
  BOOK_TO_BOOK_STORE_STAGING.BOOK_ID, 
  BOOK_TO_BOOK_STORE_STAGING.NAME, 
  BOOK_TO_BOOK_STORE_STAGING.STOCK
);
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="merge-when-not-matched-and"></a>
##### 3.5.7.6. WHEN NOT MATCHED AND ..

Various dialects support the standard SQL syntax for having multiple `WHEN` clauses, where an additional [predicates](#conditional-expressions) are supplied with each clause.

This works in a similar way to a [CASE expression](#case-expressions), where the first matching `CASE` gets applied.

If the syntax isn't supported in a dialect, it can be emulated by collapsing the various `WHEN` clauses into a single one that uses a [CASE expression](#case-expressions) to cover all the conditions and results.

###### Dialect support

This example using jOOQ:

```java
mergeInto(BOOK_TO_BOOK_STORE)
    .using(BOOK_TO_BOOK_STORE_STAGING)
    .on(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK_TO_BOOK_STORE_STAGING.BOOK_ID)
        .and(BOOK_TO_BOOK_STORE.NAME.eq(BOOK_TO_BOOK_STORE_STAGING.NAME)))
    .whenNotMatchedAnd(BOOK_TO_BOOK_STORE_STAGING.STOCK.gt(100))
    .thenInsert(
        BOOK_TO_BOOK_STORE.BOOK_ID,
        BOOK_TO_BOOK_STORE.NAME,
        BOOK_TO_BOOK_STORE.STOCK
    )
    .values(
        BOOK_TO_BOOK_STORE_STAGING.BOOK_ID,
        BOOK_TO_BOOK_STORE_STAGING.NAME,
        BOOK_TO_BOOK_STORE_STAGING.STOCK
    )
```

Translates to the following dialect specific expressions:

###### DB2, Databricks, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Snowflake, Sybase, Vertica

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN NOT MATCHED AND BOOK_TO_BOOK_STORE_STAGING.STOCK > 100 THEN INSERT (BOOK_ID, NAME, STOCK)
VALUES (
  BOOK_TO_BOOK_STORE_STAGING.BOOK_ID, 
  BOOK_TO_BOOK_STORE_STAGING.NAME, 
  BOOK_TO_BOOK_STORE_STAGING.STOCK
)
```

###### Exasol, Redshift, Teradata

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN NOT MATCHED THEN INSERT (BOOK_ID, NAME, STOCK)
VALUES (
  BOOK_TO_BOOK_STORE_STAGING.BOOK_ID, 
  BOOK_TO_BOOK_STORE_STAGING.NAME, 
  BOOK_TO_BOOK_STORE_STAGING.STOCK
)
WHERE BOOK_TO_BOOK_STORE_STAGING.STOCK > 100
```

###### Oracle

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON ((
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
))
WHEN NOT MATCHED THEN INSERT (BOOK_ID, NAME, STOCK)
VALUES (
  BOOK_TO_BOOK_STORE_STAGING.BOOK_ID, 
  BOOK_TO_BOOK_STORE_STAGING.NAME, 
  BOOK_TO_BOOK_STORE_STAGING.STOCK
)
WHERE BOOK_TO_BOOK_STORE_STAGING.STOCK > 100
```

###### SQLServer

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN NOT MATCHED AND BOOK_TO_BOOK_STORE_STAGING.STOCK > 100 THEN INSERT (BOOK_ID, NAME, STOCK)
VALUES (
  BOOK_TO_BOOK_STORE_STAGING.BOOK_ID, 
  BOOK_TO_BOOK_STORE_STAGING.NAME, 
  BOOK_TO_BOOK_STORE_STAGING.STOCK
);
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="merge-when-not-matched-by-source"></a>
##### 3.5.7.7. WHEN NOT MATCHED BY SOURCE

A few dialects have added support for an additional `BY SOURCE` clause to turn the [RIGHT JOIN](#join-type-outer) semantics of the `MERGE` statement into a `LEFT JOIN` or `FULL JOIN` semantics, meaning that it is possible to act on rows from the `TARGET` table that are not matched by the `SOURCE` table. This is mostly useful to `DELETE` these rows, but other use-cases using `UPDATE` are possible as well.

> [!TIP]
> Many of these dialects also support a `BY TARGET` clause for symmetry reasons, and possibly, to make the statement's intent more clear. The `BY TARGET` clause has no logical effect on the [WHEN NOT MATCHED THEN INSERT](#merge-when-not-matched-then-insert) clause.

###### Dialect support

This example using jOOQ:

```java
mergeInto(BOOK_TO_BOOK_STORE)
    .using(BOOK_TO_BOOK_STORE_STAGING)
    .on(BOOK_TO_BOOK_STORE.BOOK_ID.eq(BOOK_TO_BOOK_STORE_STAGING.BOOK_ID)
        .and(BOOK_TO_BOOK_STORE.NAME.eq(BOOK_TO_BOOK_STORE_STAGING.NAME)))
    .whenNotMatchedBySource().thenDelete()
```

Translates to the following dialect specific expressions:

###### Databricks, Firebird, Postgres

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN NOT MATCHED BY SOURCE THEN DELETE
```

###### SQLServer

```sql
MERGE INTO BOOK_TO_BOOK_STORE
USING BOOK_TO_BOOK_STORE_STAGING
ON (
  BOOK_TO_BOOK_STORE.BOOK_ID = BOOK_TO_BOOK_STORE_STAGING.BOOK_ID
  AND BOOK_TO_BOOK_STORE.NAME = BOOK_TO_BOOK_STORE_STAGING.NAME
)
WHEN NOT MATCHED BY SOURCE THEN DELETE;
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="ddl-statements"></a>
### 3.6. SQL Statements (DDL)

The Data Definition Language (DDL) is used to [CREATE](#create-statement), [ALTER](#alter-statement), and [DROP](#drop-statement) various object types in the database catalog. jOOQ supports an increasing number of these operations natively, and also adds synthetic operation support for convenience.

While many DDL statements are supported natively, and have a 1:1 correspondence to the jOOQ API's representation, dialects differ in many subtle ways when it comes to DDL statement support. These differences may include:

- Different keywords to mean the same thing. For example, the keywords `ALTER`, `CHANGE`, or `MODIFY` may be used when altering columns or other attributes in a table.
- Different statements instead of subclauses. For example, some dialects may choose to support `RENAME [object type] .. TO ..` statements instead of making the rename operation a subclause of `ALTER [object type] .. RENAME TO ..`
- Some syntax may not be supported, or not be supported consistently, such as the various `IF EXISTS` and `IF NOT EXISTS` clauses. Emulations are possible using the dialect's procedural language

Because of these many differences, the jOOQ manual will not list each individual native SQL representation of each jOOQ API call. Also, some optional clauses may exist, such as the `IF EXISTS` or `OR REPLACE` clauses, which can easily be discovered from the API. The manual will omit documenting these clauses in every example.

#### Commercial support for emulations

A lot of DDL queries come with syntax that requires emulation using [anonymous blocks](#procedural-block). While basic anonymous blocks are supported in the jOOQ Open Source Edition as well, more sophisticated blocks and other procedural logic is a commercial only feature.

<a id="alter-statement"></a>
#### 3.6.1. The ALTER statement

`ALTER` statements are used to alter properties of existing objects in the database catalog.

<a id="alter-database-statement"></a>
##### 3.6.1.1. ALTER DATABASE

The only property of a database that can be changed, currently, is its name.

<a id="alter-database-rename"></a>
###### 3.6.1.1.1. ALTER DATABASE .. RENAME

Like most object types, databases can be renamed:

```java
// Renaming the database
create.alterDatabase("old_database").renameTo("new_database").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDatabase("d").renameTo("e")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, Snowflake, YugabyteDB

```sql
ALTER DATABASE d RENAME TO e
```

###### ClickHouse

```sql
RENAME DATABASE d TO e
```

###### ASE, Access, Aurora MySQL, BigQuery, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-database-if-exists"></a>
###### 3.6.1.1.2. ALTER DATABASE IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Renaming the database
create.alterDatabaseIfExists("old_database").renameTo("new_database").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDatabaseIfExists("d").renameTo("e")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
DO $$
BEGIN
  ALTER DATABASE d RENAME TO e;
EXCEPTION
  WHEN SQLSTATE '3D000' THEN NULL;
END $$
```

###### Snowflake

```sql
ALTER DATABASE IF EXISTS d RENAME TO e
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-statement"></a>
##### 3.6.1.2. ALTER DOMAIN

The `ALTER DOMAIN` statement allows for altering [DOMAIN](#domain-data-types) types for use as data types in table columns.

<a id="alter-domain-rename"></a>
###### 3.6.1.2.1. ALTER DOMAIN .. RENAME

Like most object types, domains can be renamed:

```java
// Renaming the domain
create.alterDomain("old_domain").renameTo("new_domain").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").renameTo("e")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
ALTER DOMAIN d RENAME TO e
```

###### Firebird

```sql
ALTER DOMAIN d TO e
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-set-default"></a>
###### 3.6.1.2.2. ALTER DOMAIN .. SET DEFAULT

A domain's `DEFAULT` value can be set to a new value using this syntax:

```java
// Setting a default to the domain
create.alterDomain("d").setDefault(1).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").setDefault(1)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Firebird, HSQLDB, Postgres, YugabyteDB

```sql
ALTER DOMAIN d SET DEFAULT 1
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-drop-default"></a>
###### 3.6.1.2.3. ALTER DOMAIN .. DROP DEFAULT

A domain's `DEFAULT` value can be set to a new value using this syntax:

```java
// Dropping a default from the domain
create.alterDomain("d").dropDefault().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").dropDefault()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Firebird, HSQLDB, Postgres, YugabyteDB

```sql
ALTER DOMAIN d DROP DEFAULT
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-set-not-null"></a>
###### 3.6.1.2.4. ALTER DOMAIN .. SET NOT NULL

A domain's `NOT NULL` constraint can be set using this syntax:

```java
// Setting a NOT NULL constraint to the domain
create.alterDomain("d").setNotNull().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").setNotNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
ALTER DOMAIN d SET NOT NULL
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-drop-not-null"></a>
###### 3.6.1.2.5. ALTER DOMAIN .. DROP NOT NULL

A domain's `NOT NULL` constraint can be dropped using this syntax:

```java
// Dropping the NOT NULL constraint from the domain
create.alterDomain("d").dropNotNull().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").dropNotNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
ALTER DOMAIN d DROP NOT NULL
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-add-constraint"></a>
###### 3.6.1.2.6. ALTER DOMAIN .. ADD CONSTRAINT

A domain's `CHECK` constraints can be added using this syntax:

```java
// Add CHECK constraints to a domain
create.alterDomain("d").add(constraint("c").check(value(INTEGER).gt(0))).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").add(constraint("c").check(value(INTEGER).gt(0)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, HSQLDB, Postgres

```sql
ALTER DOMAIN d ADD CONSTRAINT c CHECK (value > 0)
```

###### Firebird

```sql
ALTER DOMAIN d ADD CHECK (value > 0)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-rename-constraint"></a>
###### 3.6.1.2.7. ALTER DOMAIN .. RENAME CONSTRAINT

Like most object types, constraints belonging to domains can be renamed:

```java
// Renaming the domain
create.alterDomain("d").renameConstraint("old_constraint").to("new_constraint").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").renameConstraint("c").to("e")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
ALTER DOMAIN d RENAME CONSTRAINT c TO e
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-rename-constraint-if-exists"></a>
###### 3.6.1.2.8. ALTER DOMAIN .. RENAME CONSTRAINT IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Renaming the domain
create.alterDomain("d").renameConstraintIfExists("old_constraint").to("new_constraint").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").renameConstraintIfExists("c").to("e")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
DO $$
BEGIN
  ALTER DOMAIN d RENAME CONSTRAINT c TO e;
EXCEPTION
  WHEN SQLSTATE '42704' THEN NULL;
END $$
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-drop-constraint"></a>
###### 3.6.1.2.9. ALTER DOMAIN .. DROP CONSTRAINT

A domain's `CHECK` constraint can be dropped using this syntax:

```java
// Drop CHECK constraints from a domain
create.alterDomain("d").dropConstraint("c").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").dropConstraint("c")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, HSQLDB, Postgres

```sql
ALTER DOMAIN d DROP CONSTRAINT c
```

###### Firebird

```sql
ALTER DOMAIN d DROP CONSTRAINT
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-drop-constraint-if-exists"></a>
###### 3.6.1.2.10. ALTER DOMAIN .. DROP CONSTRAINT IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Drop CHECK constraints from a domain
create.alterDomain("d").dropConstraintIfExists("c").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomain("d").dropConstraintIfExists("c")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
ALTER DOMAIN d DROP CONSTRAINT IF EXISTS c
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    ALTER DOMAIN d DROP CONSTRAINT
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-domain-if-exists"></a>
###### 3.6.1.2.11. ALTER DOMAIN IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Renaming the database
create.alterDomainIfExists("old_domain").renameTo("new_domain").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterDomainIfExists("d").renameTo("e")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
ALTER DOMAIN IF EXISTS d RENAME TO e
```

###### Firebird

```sql
ALTER DOMAIN IF EXISTS d TO e
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-index-statement"></a>
##### 3.6.1.3. ALTER INDEX

The only property of an index that can be changed, currently, is its name.

<a id="alter-index-rename"></a>
###### 3.6.1.3.1. ALTER INDEX .. RENAME

Like most object types, indexes can be renamed:

```java
// Renaming an index with schema-scoped naming
create.alterIndex("old_index").renameTo("new_index").execute();

// Renaming an index with table-scoped naming
create.alterTable("t").renameIndex("old_index").renameTo("new_index").execute();
```

> [!TIP]
> Some RDBMS work with table-scoped index names, in case of which it is recommended to use the `ALTER TABLE` statement.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").renameIndex("i").to("j")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
EXEC sp_rename 't.i', j, 'index'
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
ALTER TABLE t RENAME INDEX i TO j
```

###### Aurora Postgres, CockroachDB, H2, HSQLDB, Oracle, Postgres

```sql
ALTER INDEX i RENAME TO j
```

###### DB2, Hana

```sql
RENAME INDEX i TO j
```

###### SQLDataWarehouse, SQLServer

```sql
EXEC sp_rename 't.i', j, 'INDEX'
```

###### Access, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, Informix, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-index-if-exists"></a>
###### 3.6.1.3.2. ALTER INDEX IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Renaming the index
create.alterIndexIfExists("old_index").renameTo("new_index").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterIndexIfExists("i").renameTo("j")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, H2, Postgres

```sql
ALTER INDEX IF EXISTS i RENAME TO j
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    RENAME INDEX i TO j
  ';
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 259 BEGIN END;
  EXECUTE IMMEDIATE '
    RENAME INDEX i TO j
  ';
END;
```

###### MariaDB

```sql
BEGIN NOT ATOMIC
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' BEGIN END;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' BEGIN END;
  ALTER TABLE  RENAME INDEX i TO j;
END
```

###### MySQL

```sql
CREATE PROCEDURE block_1794083325274_4193803()
MODIFIES SQL DATA
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' BEGIN END;
  ALTER TABLE  RENAME INDEX i TO j;
END;
CALL block_1794083325274_4193803();
DROP PROCEDURE block_1794083325274_4193803;
```

###### Oracle

```sql
BEGIN
  EXECUTE IMMEDIATE '
    ALTER INDEX i RENAME TO j
  ';
EXCEPTION
  WHEN others THEN
    IF sqlerrm LIKE 'ORA-01418%' THEN NULL;
    ELSE RAISE;
    END IF;
END;
```

###### SQLDataWarehouse

```sql
BEGIN TRY
  EXEC sp_rename 'i', j, 'INDEX'
END TRY
BEGIN CATCH
  IF error_number() NOT IN (2714) BEGIN
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
  END;
END CATCH
```

###### SQLServer

```sql
BEGIN TRY
  EXEC sp_rename 'i', j, 'INDEX'
END TRY
BEGIN CATCH
  IF error_number() NOT IN (2714) THROW;
END CATCH
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Informix, MemSQL, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-schema-statement"></a>
##### 3.6.1.4. ALTER SCHEMA

The only property of a schema that can be changed, currently, is its name.

<a id="alter-schema-rename"></a>
###### 3.6.1.4.1. ALTER SCHEMA .. RENAME

Like most object types, schemas can be renamed:

```java
// Renaming the schema
create.alterSchema("old_schema").renameTo("new_schema").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSchema("s").renameTo("t")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, H2, HSQLDB, Postgres, Redshift, Snowflake, Vertica

```sql
ALTER SCHEMA s RENAME TO t
```

###### ClickHouse

```sql
RENAME DATABASE s TO t
```

###### Hana

```sql
RENAME SCHEMA s TO t
```

###### ASE, Access, Aurora MySQL, BigQuery, DB2, Databricks, DuckDB, Exasol, Firebird, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-schema-if-exists"></a>
###### 3.6.1.4.2. ALTER SCHEMA IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Renaming the schema
create.alterSchemaIfExists("old_schema").renameTo("new_schema").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSchemaIfExists("s").renameTo("t")
```

Translates to the following dialect specific expressions:

###### H2, Snowflake

```sql
ALTER SCHEMA IF EXISTS s RENAME TO t
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 362 BEGIN END;
  EXECUTE IMMEDIATE '
    RENAME SCHEMA s TO t
  ';
END;
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-statement"></a>
##### 3.6.1.5. ALTER SEQUENCE

Most sequence properties can be altered after a sequence has been created.

<a id="alter-sequence-rename"></a>
###### 3.6.1.5.1. ALTER SEQUENCE .. RENAME

Like most object types, sequences can be renamed:

```java
// Renaming the sequence
create.alterSequence("old_sequence").renameTo("new_sequence").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequence("s").renameTo("t")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, HSQLDB, Postgres, Snowflake, Vertica

```sql
ALTER SEQUENCE s RENAME TO t
```

###### MariaDB

```sql
ALTER TABLE s RENAME TO t
```

###### Oracle

```sql
RENAME s TO t
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-cache"></a>
###### 3.6.1.5.2. ALTER SEQUENCE .. CACHE

Some RDBMS support the `CACHE` clause to specify a cache size for a sequence, allowing to pre-allocate sequence values in the current session or in some other scope.

```java
// Caching sequence values
create.alterSequence("s").cache(200).execute();

// Turning off the caching of sequence values
create.alterSequence("s").noCache().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequence("s").cache(200)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, H2, Hana, Informix, MariaDB, Oracle, Postgres, SQLServer, Sybase, Vertica, YugabyteDB

```sql
ALTER SEQUENCE s CACHE 200
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, HSQLDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-cycle"></a>
###### 3.6.1.5.3. ALTER SEQUENCE .. CYCLE

The `CYCLE` clause can be used to enable cycling of a sequence to its [MINVALUE](#create-sequence-minvalue) as soon as it reaches its [MAXVALUE](#create-sequence-maxvalue).

```java
// Enable cycling
create.alterSequence("s").cycle().execute();

// Disable cycling
create.alterSequence("s").noCycle().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequence("s").cycle()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, SQLServer, Sybase, Vertica, YugabyteDB

```sql
ALTER SEQUENCE s CYCLE
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-minvalue"></a>
###### 3.6.1.5.4. ALTER SEQUENCE .. MINVALUE

The `MINVALUE` of a sequence is the minimum value a sequence will [cycle](#create-sequence-cycle) to, as soon as it reaches its [MAXVALUE](#create-sequence-maxvalue).

```java
// Specify a MINVALUE
create.alterSequence("s").minvalue(1).execute();

// Disable the MINVALUE
create.alterSequence("s").noMinvalue().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequence("s").minvalue(1)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, SQLServer, Sybase, Vertica, YugabyteDB

```sql
ALTER SEQUENCE s MINVALUE 1
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-maxvalue"></a>
###### 3.6.1.5.5. ALTER SEQUENCE .. MAXVALUE

The `t reaches its MAXVALUE` of a sequence is the maximum value a sequence will reach before it [cycles](#create-sequence-cycle) to its [MINVALUE](#create-sequence-minvalue).

```java
// Specify a MAXVALUE
create.alterSequence("s").maxvalue(1).execute();

// Disable the MAXVALUE
create.alterSequence("s").noMaxvalue().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequence("s").maxvalue(1)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, SQLServer, Sybase, Vertica, YugabyteDB

```sql
ALTER SEQUENCE s MAXVALUE 1
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-increment-by"></a>
###### 3.6.1.5.6. ALTER SEQUENCE .. INCREMENT BY

by default, sequences increment by `1`, but this can be changed with the `INCREMENT BY` clause:

```java
// Specify the sequence's increment value
create.alterSequence("s").incrementBy(10).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequence("s").incrementBy(10)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, SQLServer, Snowflake, Sybase, Vertica, YugabyteDB

```sql
ALTER SEQUENCE s INCREMENT BY 10
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-start-with"></a>
###### 3.6.1.5.7. ALTER SEQUENCE .. START WITH

A sequence can be manually restarted using the [RESTART](#alter-sequence-restart) clause, in case of which it will be restarted at the [START WITH](#create-sequence-start-with) value, which can be altered as follows:

```java
// Specify the sequence's start value
create.alterSequence("s").startWith(10).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequence("s").startWith(10)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, MariaDB, Postgres, YugabyteDB

```sql
ALTER SEQUENCE s START WITH 10
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-restart"></a>
###### 3.6.1.5.8. ALTER SEQUENCE .. RESTART

A sequence can be manually restarted using the `RESTART` clause, in case of which it will be restarted at the [START WITH](#create-sequence-start-with) value.

```java
// Restart the sequence
create.alterSequence("s").restart().execute();
```

Alternatively, an explicit value can be provide to restart the sequence with:

```java
// Restart the sequence
create.alterSequence("s").restartWith(10).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequence("s").restart()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, HSQLDB, MariaDB, Oracle, Postgres, SQLServer, YugabyteDB

```sql
ALTER SEQUENCE s RESTART
```

###### Hana, Informix, Vertica

```sql
ALTER SEQUENCE s RESTART WITH 1
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-sequence-if-exists"></a>
###### 3.6.1.5.9. ALTER SEQUENCE IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Renaming the schema
create.alterSequenceIfExists("old_sequence").renameTo("new_sequence").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterSequenceIfExists("s").renameTo("t")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, Snowflake

```sql
ALTER SEQUENCE IF EXISTS s RENAME TO t
```

###### MariaDB

```sql
ALTER TABLE s RENAME TO t
```

###### Oracle

```sql
BEGIN
  EXECUTE IMMEDIATE '
    RENAME s TO t
  ';
EXCEPTION
  WHEN others THEN
    IF sqlerrm LIKE 'ORA-04043%' THEN NULL;
    ELSE RAISE;
    END IF;
END;
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-statement"></a>
##### 3.6.1.6. ALTER TABLE

The `ALTER TABLE` statement is certainly the most powerful among DDL statements, as tables are the most important object type in a database catalog.

<a id="alter-table-add-column"></a>
###### 3.6.1.6.1. ALTER TABLE .. ADD COLUMN

Most dialects support altering a table to add a single column per statement.

```java
// Adding a single column to a table. These statements are equivalent
create.alterTable("table").add("column", INTEGER).execute();
create.alterTable("table").addColumn("column", INTEGER).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add("c", INTEGER)
```

Translates to the following dialect specific expressions:

###### Access, DB2, Firebird, Informix, Teradata

```sql
ALTER TABLE t ADD c integer
```

###### ASE, Sybase

```sql
ALTER TABLE t ADD c int NULL
```

###### Aurora MySQL, Aurora Postgres, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Vertica, YugabyteDB

```sql
ALTER TABLE t ADD c int
```

###### BigQuery, Spanner

```sql
ALTER TABLE t ADD COLUMN c int64
```

###### ClickHouse

```sql
ALTER TABLE t ADD COLUMN c Nullable(integer)
```

###### CockroachDB

```sql
ALTER TABLE t ADD c int4
```

###### Databricks

```sql
ALTER TABLE t ADD COLUMN (c int)
```

###### Hana

```sql
ALTER TABLE t ADD (c integer)
```

###### Oracle, Snowflake

```sql
ALTER TABLE t ADD c number(10)
```

###### Trino

```sql
ALTER TABLE t ADD COLUMN c int
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-add-column-position"></a>
###### 3.6.1.6.2. ALTER TABLE .. ADD COLUMN .. FIRST, BEFORE, AFTER

Most RDBMS maintain both a logical and physical ordering of the columns in a table. While the physical ordering (how column values are stored in a disk block) are implementation details that are hidden from the SQL language, the logical ordering is relevant for numerous SQL features, including:

- The behaviour of the [SELECT *](#select-clause-asterisk) syntax (the `*` is expanded according to the logical ordering of columns in a table)
- Client languages, such as PL/SQL, store data in record representations when using `TABLE%ROWTYPE` and similar syntax
- Libraries like jOOQ will use this ordering for code generation of [tables](#codegen-tables), [records](#codegen-records), and more
- Client applications and SQL editors like Dbeaver will display results in the declared logical column order

All RDBMS will maintain the logical column ordering declared in the [CREATE TABLE statement](#create-table-statement), and will append new columns to the end of a table when using the [ALTER TABLE .. ADD COLUMN statement](#alter-table-add-column).

But only few RDBMS allow for modifying the logical column position when altering a table, after the table has been created. This is done with one of the following syntaxes:

```java
// Adding a single column and specify its position
create.alterTable("table").add("column", INTEGER).after("other_column").execute();
create.alterTable("table").add("column", INTEGER).before("other_column").execute();
create.alterTable("table").add("column", INTEGER).first().execute();
```

###### AFTER

The `AFTER` clause will allow for specifying a column after which the new column will be added.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add("c", INTEGER).after("other")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, H2, MariaDB, MemSQL, MySQL

```sql
ALTER TABLE t ADD c int AFTER other
```

###### ClickHouse

```sql
ALTER TABLE t ADD COLUMN c Nullable(integer) AFTER other
```

###### Databricks

```sql
ALTER TABLE t ADD COLUMN (c int AFTER other)
```

###### ASE, Access, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### BEFORE

The `BEFORE` clause will allow for specifying a column before which the new column will be added.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add("c", INTEGER).before("other")
```

Translates to the following dialect specific expressions:

###### H2, HSQLDB

```sql
ALTER TABLE t ADD c int BEFORE other
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### FIRST

The `FIRST` clause will allow for specifying that the new column will be added before all the other columns.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add("c", INTEGER).first()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, H2, MariaDB, MemSQL, MySQL

```sql
ALTER TABLE t ADD c int FIRST
```

###### ClickHouse

```sql
ALTER TABLE t ADD COLUMN c Nullable(integer) FIRST
```

###### Databricks

```sql
ALTER TABLE t ADD COLUMN (c int FIRST)
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    ALTER TABLE t ADD c integer
  ';
  EXECUTE STATEMENT '
    ALTER TABLE t ALTER c POSITION 1
  ';
END
```

###### ASE, Access, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, HSQLDB, Hana, Informix, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-add-multiple"></a>
###### 3.6.1.6.3. ALTER TABLE .. ADD COLUMNS

If multiple columns should be added atomically, and to save server round trips, some RDBMS support adding multiple columns to a table using a single `ALTER TABLE` statement.

```java
// Adding several columns to a table in one go
create.alterTable("table").add(field(name("column1"), INTEGER), field(name("column2"), INTEGER)).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add(field("c1", INTEGER), field("c2", INTEGER))
```

Translates to the following dialect specific expressions:

###### ASE

```sql
ALTER TABLE t ADD 
  c1 int NULL,
  c2 int NULL
```

###### Aurora MySQL, Aurora Postgres, MariaDB, MemSQL, MySQL, Postgres, YugabyteDB

```sql
ALTER TABLE t ADD c1 int,
ADD c2 int
```

###### BigQuery

```sql
ALTER TABLE t ADD COLUMN c1 int64,
ADD COLUMN c2 int64
```

###### ClickHouse

```sql
ALTER TABLE t ADD COLUMN c1 Nullable(integer),
ADD COLUMN c2 Nullable(integer)
```

###### CockroachDB

```sql
ALTER TABLE t ADD c1 int4,
ADD c2 int4
```

###### Databricks

```sql
ALTER TABLE t ADD COLUMN (
  c1 int,
  c2 int
)
```

###### DB2

```sql
ALTER TABLE t ADD c1 integer
ADD c2 integer
```

###### Firebird, Teradata

```sql
ALTER TABLE t ADD c1 integer,
ADD c2 integer
```

###### H2

```sql
ALTER TABLE t ADD (
  c1 int,
  c2 int
)
```

###### Hana, Informix

```sql
ALTER TABLE t ADD (
  c1 integer,
  c2 integer
)
```

###### Oracle, Snowflake

```sql
ALTER TABLE t ADD (
  c1 number(10),
  c2 number(10)
)
```

###### SQLDataWarehouse, SQLServer

```sql
ALTER TABLE t ADD 
  c1 int,
  c2 int
```

###### Access, DuckDB, Exasol, HSQLDB, Redshift, SQLite, Spanner, Sybase, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-add-column-if-not-exists"></a>
###### 3.6.1.6.4. ALTER TABLE .. ADD COLUMN IF NOT EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF NOT EXISTS` clause:

###### Dialect support

This example using jOOQ:

```java
alterTable("t").addIfNotExists("c", INTEGER)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DuckDB, Exasol, H2, MariaDB, Postgres, YugabyteDB

```sql
ALTER TABLE t ADD IF NOT EXISTS c int
```

###### BigQuery, Spanner

```sql
ALTER TABLE t ADD COLUMN IF NOT EXISTS c int64
```

###### ClickHouse

```sql
ALTER TABLE t ADD COLUMN IF NOT EXISTS c Nullable(integer)
```

###### CockroachDB

```sql
ALTER TABLE t ADD IF NOT EXISTS c int4
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42711' BEGIN END;
  EXECUTE IMMEDIATE '
    ALTER TABLE t ADD c integer
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    ALTER TABLE t ADD c integer
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 308 BEGIN END;
  EXECUTE IMMEDIATE '
    ALTER TABLE t ADD (c integer)
  ';
END;
```

###### Oracle

```sql
BEGIN
  EXECUTE IMMEDIATE '
    ALTER TABLE t ADD c number(10)
  ';
EXCEPTION
  WHEN others THEN
    IF sqlerrm LIKE 'ORA-01430%' THEN NULL;
    ELSE RAISE;
    END IF;
END;
```

###### SQLDataWarehouse

```sql
BEGIN TRY
  EXEC sp_executesql N'
    ALTER TABLE t ADD c int
  ';
END TRY
BEGIN CATCH
  IF error_number() NOT IN (2705) BEGIN
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
  END;
END CATCH
```

###### SQLServer

```sql
BEGIN TRY
  EXEC sp_executesql N'
    ALTER TABLE t ADD c int
  ';
END TRY
BEGIN CATCH
  IF error_number() NOT IN (2705) THROW;
END CATCH
```

###### Trino

```sql
ALTER TABLE t ADD COLUMN IF NOT EXISTS c int
```

###### ASE, Access, Aurora MySQL, Databricks, HSQLDB, Informix, MemSQL, MySQL, Redshift, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-add-primary-key"></a>
###### 3.6.1.6.5. ALTER TABLE .. ADD PRIMARY KEY

All constraint types can be added with the `ALTER TABLE` statement. This includes `PRIMARY KEY` constraints:

```java
// Adding an unnamed constraint to a table
create.alterTable("table").add(primaryKey("id")).execute();

// Adding a named constraint to a table
create.alterTable("table").add(constraint("pk").primaryKey("id")).execute();
```

> [!TIP]
> It is recommended to always provide a name with a constraint to simplify schema management. [See also this section of the manual](#dont-do-this-schema-unnamed-constraints)

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add(constraint("pk").primaryKey("id"))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica, YugabyteDB

```sql
ALTER TABLE t ADD CONSTRAINT pk PRIMARY KEY (id)
```

###### BigQuery

```sql
ALTER TABLE t ADD PRIMARY KEY (id) NOT ENFORCED
```

###### ClickHouse, Spanner

```sql
ALTER TABLE t ADD PRIMARY KEY (id)
```

###### Informix

```sql
ALTER TABLE t ADD CONSTRAINT PRIMARY KEY (id) CONSTRAINT pk
```

###### SQLDataWarehouse

```sql
ALTER TABLE t ADD CONSTRAINT pk PRIMARY KEY NONCLUSTERED (id) NOT ENFORCED
```

###### DuckDB, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-add-unique"></a>
###### 3.6.1.6.6. ALTER TABLE .. ADD UNIQUE

All constraint types can be added with the `ALTER TABLE` statement. This includes `UNIQUE` constraints:

```java
// Adding an unnamed constraint to a table
create.alterTable("table").add(unique("user_name")).execute();

// Adding a named constraint to a table
create.alterTable("table").add(constraint("uk").unique("user_name")).execute();
```

> [!TIP]
> It is recommended to always provide a name with a constraint to simplify schema management. [See also this section of the manual](#dont-do-this-schema-unnamed-constraints)

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add(constraint("uk").unique("user_name"))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
ALTER TABLE t ADD CONSTRAINT uk UNIQUE (user_name)
```

###### Informix

```sql
ALTER TABLE t ADD CONSTRAINT UNIQUE (user_name) CONSTRAINT uk
```

###### SQLDataWarehouse

```sql
ALTER TABLE t ADD CONSTRAINT uk UNIQUE (user_name) NOT ENFORCED
```

###### DuckDB, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-add-foreign-key"></a>
###### 3.6.1.6.7. ALTER TABLE .. ADD FOREIGN KEY

All constraint types can be added with the `ALTER TABLE` statement. This includes `FOREIGN KEY` constraints:

```java
// Adding an unnamed constraint to a table
create.alterTable("table").add(foreignKey("author_id").references("author")).execute();

// Adding a named constraint to a table
create.alterTable("table").add(constraint("fk").foreignKey("author_id").references("author")).execute();
```

> [!TIP]
> It is recommended to always provide a name with a constraint to simplify schema management. [See also this section of the manual](#dont-do-this-schema-unnamed-constraints)

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add(constraint("pk").foreignKey("author_id").references("author"))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
ALTER TABLE t ADD CONSTRAINT pk FOREIGN KEY (author_id) REFERENCES author
```

###### BigQuery, ClickHouse, SQLDataWarehouse

```sql
ALTER TABLE t ADD CONSTRAINT pk FOREIGN KEY (author_id) REFERENCES author NOT ENFORCED
```

###### Informix

```sql
ALTER TABLE t ADD CONSTRAINT FOREIGN KEY (author_id) REFERENCES author CONSTRAINT pk
```

###### DuckDB, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-add-check"></a>
###### 3.6.1.6.8. ALTER TABLE .. ADD CHECK

All constraint types can be added with the `ALTER TABLE` statement. This includes `CHECK` constraints:

```java
// Adding an unnamed constraint to a table
create.alterTable("table").add(check(length(field(name("c"), INTEGER)).gt(0))).execute();

// Adding a named constraint to a table
create.alterTable("table").add(constraint("ck").check(length(field(name("c"), INTEGER)).gt(0))).execute();
```

> [!TIP]
> It is recommended to always provide a name with a constraint to simplify schema management. [See also this section of the manual](#dont-do-this-schema-unnamed-constraints)

###### Dialect support

This example using jOOQ:

```java
alterTable("t").add(constraint("ck").check(field("c", INTEGER).gt(0)))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora Postgres, ClickHouse, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, SQLServer, SQLite, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
ALTER TABLE t ADD CONSTRAINT ck CHECK (c > 0)
```

###### Informix

```sql
ALTER TABLE t ADD CONSTRAINT CHECK (c > 0) CONSTRAINT ck
```

###### Aurora MySQL, BigQuery, Databricks, DuckDB, Exasol, MemSQL, Redshift, SQLDataWarehouse, Snowflake, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-rename"></a>
###### 3.6.1.6.9. ALTER TABLE .. RENAME

Like most object types, tables can be renamed:

```java
// Rename a table
create.alterTable("old_table").renameTo("new_table").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").renameTo("u")
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, H2, HSQLDB, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
ALTER TABLE t RENAME TO u
```

###### ASE, SQLDataWarehouse, SQLServer

```sql
EXEC sp_rename 't', u
```

###### ClickHouse, DB2, Exasol, Hana, Informix, Teradata

```sql
RENAME TABLE t TO u
```

###### Sybase

```sql
ALTER TABLE t RENAME u
```

###### Firebird

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-comment"></a>
###### 3.6.1.6.10. ALTER TABLE .. COMMENT

For convenience, jOOQ supports MySQL's `COMMENT` syntax also on `ALTER TABLE`, which corresponds to the more standard [COMMENT ON TABLE statement](#comment-statement)

```java
// Specify a new comment on a table
create.alterTable("table").comment("a comment describing the table").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").comment("comment")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
ALTER TABLE t COMMENT 'comment'
```

###### Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
COMMENT ON TABLE t IS 'comment'
```

###### BigQuery

```sql
ALTER TABLE t SET OPTIONS (DESCRIPTION = 'comment')
```

###### ClickHouse

```sql
ALTER TABLE t MODIFY COMMENT 'comment'
```

###### Snowflake

```sql
ALTER TABLE t SET COMMENT = 'comment'
```

###### SQLServer

```sql
BEGIN TRY
  DECLARE @u varchar(max) = schema_name();
  EXEC sp_addextendedproperty 'MS_Description', 'comment', 'schema', @u, 'table', 't', DEFAULT, DEFAULT
END TRY
BEGIN CATCH
  EXEC sp_updateextendedproperty 'MS_Description', 'comment', 'schema', @u, 'table', 't', DEFAULT, DEFAULT
END CATCH
```

###### ASE, Access, Informix, SQLDataWarehouse, SQLite, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-set-default"></a>
###### 3.6.1.6.11. ALTER TABLE .. ALTER COLUMN .. SET DEFAULT

A column `DEFAULT` value can be added to a column using the `ALTER TABLE`'s `SET DEFAULT` clause on a column:

```java
// Specify a new default value for a column
create.alterTable("table").alter("column").setDefault(1).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter("c").setDefault(1)
```

Translates to the following dialect specific expressions:

###### Access, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Postgres, Sybase, YugabyteDB

```sql
ALTER TABLE t ALTER c SET DEFAULT 1
```

###### ASE

```sql
ALTER TABLE t REPLACE c DEFAULT 1
```

###### Aurora MySQL, BigQuery, Databricks, MariaDB, MySQL, Vertica

```sql
ALTER TABLE t ALTER COLUMN c SET DEFAULT 1
```

###### ClickHouse

```sql
ALTER TABLE t MODIFY COLUMN c DEFAULT 1
```

###### MemSQL, Oracle

```sql
ALTER TABLE t MODIFY c DEFAULT 1
```

###### Spanner

```sql
ALTER TABLE t ALTER c SET DEFAULT (1)
```

###### SQLServer

```sql
DECLARE @constraint NVARCHAR(max);
DECLARE @command NVARCHAR(max);

SELECT @constraint = name
FROM sys.default_constraints
WHERE parent_object_id = object_id('t')
AND parent_column_id = columnproperty(object_id('t'), 'c', 'ColumnId');

IF @constraint IS NOT NULL
BEGIN
  SET @command = 'ALTER TABLE ' + 't' + ' DROP CONSTRAINT ' + @constraint
  EXECUTE sp_executesql @command

  SET @command = 'ALTER TABLE ' + 't' + ' ADD CONSTRAINT ' + @constraint + ' DEFAULT ' + '1' + ' FOR ' + 'c'
  EXECUTE sp_executesql @command
END
ELSE
BEGIN
  SET @command = 'ALTER TABLE ' + 't' + ' ADD DEFAULT ' + '1' + ' FOR ' + 'c'
  EXECUTE sp_executesql @command
END
```

###### Hana, Informix, Redshift, SQLDataWarehouse, SQLite, Snowflake, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-drop-default"></a>
###### 3.6.1.6.12. ALTER TABLE .. ALTER COLUMN .. DROP DEFAULT

An existing column `DEFAULT` value can be removed from a column using the `ALTER TABLE's` `DROP DEFAULT` clause on a column:

```java
// Drop the default from a column
create.alterTable("table").alter("column").dropDefault().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter("c").dropDefault()
```

Translates to the following dialect specific expressions:

###### Access, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Postgres, Spanner, Sybase, YugabyteDB

```sql
ALTER TABLE t ALTER c DROP DEFAULT
```

###### ASE

```sql
ALTER TABLE t REPLACE c DEFAULT NULL
```

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER TABLE t ALTER COLUMN c SET DEFAULT NULL
```

###### BigQuery, Databricks, Vertica

```sql
ALTER TABLE t ALTER COLUMN c DROP DEFAULT
```

###### ClickHouse

```sql
ALTER TABLE t MODIFY COLUMN c REMOVE DEFAULT
```

###### MemSQL, Oracle

```sql
ALTER TABLE t MODIFY c DEFAULT NULL
```

###### SQLServer

```sql
DECLARE @constraint NVARCHAR(max);
DECLARE @command NVARCHAR(max);

SELECT @constraint = name
FROM sys.default_constraints
WHERE parent_object_id = object_id('t')
AND parent_column_id = columnproperty(object_id('t'), 'c', 'ColumnId');

IF @constraint IS NOT NULL
BEGIN
  SET @command = 'ALTER TABLE ' + 't' + ' DROP CONSTRAINT ' + @constraint
  EXECUTE sp_executesql @command

  SET @command = 'ALTER TABLE ' + 't' + ' ADD CONSTRAINT ' + @constraint + ' DEFAULT ' + NULL + ' FOR ' + 'c'
  EXECUTE sp_executesql @command
END
ELSE
BEGIN
  SET @command = 'ALTER TABLE ' + 't' + ' ADD DEFAULT ' + NULL + ' FOR ' + 'c'
  EXECUTE sp_executesql @command
END
```

###### Hana, Informix, Redshift, SQLDataWarehouse, SQLite, Snowflake, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-set-identity"></a>
###### 3.6.1.6.13. ALTER TABLE .. ALTER COLUMN .. SET GENERATED BY DEFAULT AS IDENTITY

A column `IDENTITY` flag can be added to a column using the `ALTER TABLE`'s `SET GENERATED BY DEFAULT AS IDENTITY` clause on a column:

```java
// Specify a new identity flag for a column
create.alterTable("table").alter("column").setGeneratedByDefaultAsIdentity().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter("c").setGeneratedByDefaultAsIdentity()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER TABLE t CHANGE COLUMN c c other AUTO_INCREMENT
```

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
ALTER TABLE t ALTER c ADD GENERATED BY DEFAULT AS IDENTITY
```

###### DB2, HSQLDB

```sql
ALTER TABLE t ALTER c SET GENERATED BY DEFAULT AS IDENTITY
```

###### Exasol

```sql
ALTER TABLE t ALTER c SET IDENTITY
```

###### H2

```sql
ALTER TABLE t ALTER c SET GENERATED BY DEFAULT
```

###### ASE, Access, BigQuery, ClickHouse, Databricks, DuckDB, Firebird, Hana, Informix, MemSQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-drop-identity"></a>
###### 3.6.1.6.14. ALTER TABLE .. ALTER COLUMN .. DROP IDENTITY

An existing column `IDENTITY` flag can be removed from a column using the `ALTER TABLE's` `DROP IDENTITY` clause on a column:

```java
// Drop the identity flag from a column
create.alterTable("table").alter("column").dropIdentity().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter("c").dropIdentity()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Exasol, Firebird, H2, HSQLDB, Postgres, YugabyteDB

```sql
ALTER TABLE t ALTER c DROP IDENTITY
```

###### DB2

```sql
ALTER TABLE t ALTER c DROP GENERATED
```

###### Oracle

```sql
ALTER TABLE t MODIFY c DROP IDENTITY
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-set-generated"></a>
###### 3.6.1.6.15. ALTER TABLE .. ALTER COLUMN .. SET GENERATED

A column `GENERATED` expression can be added to a computed column using the `ALTER TABLE`'s `SET GENERATED` clause on a column:

```java
// Specify a new generated expression for a computed column
create.alterTable("table").alter("column").setGeneratedAlwaysAs(1).execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter("c").setGeneratedAlwaysAs(1)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
ALTER TABLE t ALTER c SET EXPRESSION AS (1)
```

###### DB2

```sql
BEGIN
  EXECUTE IMMEDIATE '
    SET INTEGRITY FOR t OFF
  ';
  EXECUTE IMMEDIATE '
    ALTER TABLE t ALTER c SET EXPRESSION AS (1)
  ';
  EXECUTE IMMEDIATE '
    SET INTEGRITY FOR t IMMEDIATE CHECKED FORCE GENERATED
  ';
END
```

###### Firebird

```sql
ALTER TABLE t ALTER c GENERATED ALWAYS AS (1)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-drop-generated"></a>
###### 3.6.1.6.16. ALTER TABLE .. ALTER COLUMN .. DROP GENERATED

An existing column `GENERATED` expression can be removed from a computed column using the `ALTER TABLE's` `DROP GENERATED` clause on a column:

```java
// Drop the generated expression from a column
create.alterTable("table").alter("column").dropGenerated().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter("c").dropGenerated()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, Postgres

```sql
ALTER TABLE t ALTER c DROP EXPRESSION
```

###### DB2

```sql
ALTER TABLE t ALTER c DROP GENERATED
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-set-not-null"></a>
###### 3.6.1.6.17. ALTER TABLE .. ALTER COLUMN .. SET NOT NULL

A column can be set to `NOT NULL` using the `ALTER TABLE`'s `NOT NULL` clause on a column:

```java
// Specify the not null constraint on a column
// Note that in some but not all dialects, the data type of the column needs to be known to jOOQ and the RDBMS
create.alterTable("table").alter(field("column", VARCHAR(10))).setNotNull().execute();
```

The existing data in the column must not contain any nulls or an error will be raised.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter(field("c", VARCHAR(10))).setNotNull()
```

Translates to the following dialect specific expressions:

###### ASE, Oracle

```sql
ALTER TABLE t MODIFY c NOT NULL
```

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER TABLE t CHANGE COLUMN c c varchar(10) NOT NULL
```

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, H2, HSQLDB, Postgres, SQLite, Snowflake, YugabyteDB

```sql
ALTER TABLE t ALTER c SET NOT NULL
```

###### Databricks, Vertica

```sql
ALTER TABLE t ALTER COLUMN c SET NOT NULL
```

###### Exasol

```sql
ALTER TABLE t MODIFY c SET NOT NULL
```

###### MemSQL

```sql
ALTER TABLE t MODIFY c varchar(10) NOT NULL
```

###### Access, BigQuery, ClickHouse, Hana, Informix, Redshift, SQLDataWarehouse, SQLServer, Spanner, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-drop-not-null"></a>
###### 3.6.1.6.18. ALTER TABLE .. ALTER COLUMN .. DROP NOT NULL

An existing column's `NOT NULL` constraint can be dropped using the `ALTER TABLE`'s `NOT NULL` clause on a column:

```java
// Drop the not null constraint on a column
// Note that in some but not all dialects, the data type of the column needs to be known to jOOQ and the RDBMS
create.alterTable("table").alter(field("column", VARCHAR(10))).dropNotNull().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter(field("c", VARCHAR(10))).dropNotNull()
```

Translates to the following dialect specific expressions:

###### ASE, Oracle

```sql
ALTER TABLE t MODIFY c NULL
```

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER TABLE t CHANGE COLUMN c c varchar(10) NULL
```

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, H2, HSQLDB, Postgres, SQLite, Snowflake, YugabyteDB

```sql
ALTER TABLE t ALTER c DROP NOT NULL
```

###### Databricks, Vertica

```sql
ALTER TABLE t ALTER COLUMN c DROP NOT NULL
```

###### Exasol

```sql
ALTER TABLE t MODIFY c DROP NOT NULL
```

###### MemSQL

```sql
ALTER TABLE t MODIFY c varchar(10) NULL
```

###### Access, BigQuery, ClickHouse, Hana, Informix, Redshift, SQLDataWarehouse, SQLServer, Spanner, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-column-set-type"></a>
###### 3.6.1.6.19. ALTER TABLE .. ALTER COLUMN .. SET TYPE

The type of a column can be changed using the `ALTER TABLE`'s `SET TYPE` clause on a column:

```java
// Set a new data type on the column
create.alterTable("table").alter("column").set(VARCHAR(50)).execute();
```

Whether this operation is supported for any given pair of existing/new types is vendor specific. If the existing data doesn't conform to the new type, an error is raised by the database.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alter("c").set(VARCHAR(50))
```

Translates to the following dialect specific expressions:

###### Access

```sql
ALTER TABLE t ALTER c text(50)
```

###### ASE, Exasol, MemSQL

```sql
ALTER TABLE t MODIFY c varchar(50)
```

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER TABLE t CHANGE COLUMN c c varchar(50)
```

###### Aurora Postgres, Firebird, Postgres, YugabyteDB

```sql
ALTER TABLE t ALTER c TYPE varchar(50)
```

###### BigQuery

```sql
ALTER TABLE t ALTER COLUMN c string
```

###### ClickHouse

```sql
ALTER TABLE t MODIFY COLUMN c Nullable(String(50))
```

###### CockroachDB

```sql
ALTER TABLE t ALTER c TYPE string(50)
```

###### Databricks

```sql
ALTER TABLE t ALTER COLUMN c TYPE varchar(50)
```

###### DB2, DuckDB

```sql
ALTER TABLE t ALTER c SET DATA TYPE varchar(50)
```

###### H2, HSQLDB, Snowflake, Sybase

```sql
ALTER TABLE t ALTER c varchar(50)
```

###### Hana

```sql
ALTER TABLE t ALTER (c varchar(50))
```

###### Informix

```sql
ALTER TABLE t MODIFY c lvarchar(50)
```

###### Oracle

```sql
ALTER TABLE t MODIFY c varchar2(50)
```

###### Spanner

```sql
ALTER TABLE t ALTER c string(50)
```

###### SQLDataWarehouse, SQLServer

```sql
ALTER TABLE t ALTER COLUMN c varchar(50)
```

###### Trino

```sql
ALTER TABLE t ALTER COLUMN c SET DATA TYPE varchar(50)
```

###### Redshift, SQLite, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-constraint-enforced"></a>
###### 3.6.1.6.20. ALTER TABLE .. ALTER CONSTRAINT .. ENFORCED

A constraint can be enabled using the `ALTER TABLE`'s `ENFORCED` clause on a constraint:

```java
// Set the enforced flag on a constraint
create.alterTable("table").alterConstraint("uk").enforced().execute();
```

If enforcement of the constraint fails, an error is raised by the database.

See also [constraint enforcement](#create-table-constraint-enforcement) in `CREATE TABLE`.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alterConstraint("c").enforced()
```

Translates to the following dialect specific expressions:

###### DB2, Hana, MySQL, Postgres

```sql
ALTER TABLE t ALTER CONSTRAINT c ENFORCED
```

###### Oracle

```sql
ALTER TABLE t MODIFY CONSTRAINT c ENABLE
```

###### Snowflake

```sql
ALTER TABLE t ALTER CONSTRAINT c ENABLE
```

###### Vertica

```sql
ALTER TABLE t ALTER CONSTRAINT c ENABLED
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-alter-constraint-not-enforced"></a>
###### 3.6.1.6.21. ALTER TABLE .. ALTER CONSTRAINT .. NOT ENFORCED

A constraint can be disabled using the `ALTER TABLE`'s `NOT ENFORCED` clause on a constraint:

```java
// Remove the enforced flag from a constraint
create.alterTable("table").alterConstraint("uk").notEnforced().execute();
```

See also [constraint enforcement](#create-table-constraint-enforcement) in `CREATE TABLE`.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").alterConstraint("c").notEnforced()
```

Translates to the following dialect specific expressions:

###### DB2, Hana, MySQL, Postgres

```sql
ALTER TABLE t ALTER CONSTRAINT c NOT ENFORCED
```

###### Oracle

```sql
ALTER TABLE t MODIFY CONSTRAINT c DISABLE
```

###### Snowflake

```sql
ALTER TABLE t ALTER CONSTRAINT c DISABLE
```

###### Vertica

```sql
ALTER TABLE t ALTER CONSTRAINT c DISABLED
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-change-column"></a>
###### 3.6.1.6.22. ALTER TABLE .. CHANGE COLUMN

jOOQ supports the MySQL style `CHANGE COLUMN` clause, which can be used to both rename and change the type of a column in one go:

```java
// Rename a column
create.alterTable("table").changeColumn("old_column", "new_column").set(INTEGER).execute();
```

> [!TIP]
> It is generally not recommended to use this legacy MySQL statement, which is supported by jOOQ for interoperability purposes only.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").changeColumn("c", "d").set(INTEGER)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER TABLE t CHANGE COLUMN c d int
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
DO $$
BEGIN
  ALTER TABLE t RENAME COLUMN c TO d;
  ALTER TABLE t ALTER d TYPE int;
END;
$$
```

###### CockroachDB

```sql
DO $$
BEGIN
  ALTER TABLE t RENAME COLUMN c TO d;
  ALTER TABLE t ALTER d TYPE int4;
END;
$$
```

###### DB2

```sql
BEGIN
  EXECUTE IMMEDIATE 'ALTER TABLE t RENAME COLUMN c TO d';
  EXECUTE IMMEDIATE 'ALTER TABLE t ALTER d SET DATA TYPE integer';
END
```

###### Exasol

```sql
BEGIN
  ALTER TABLE t RENAME COLUMN c TO d;
  ALTER TABLE t MODIFY d int;
END;
```

###### Firebird

```sql
EXECUTE BLOCK AS
BEGIN
  EXECUTE STATEMENT 'ALTER TABLE t ALTER COLUMN c TO d';
  EXECUTE STATEMENT 'ALTER TABLE t ALTER d TYPE integer';
END
```

###### H2

```sql
CREATE ALIAS block_1794083357090_4139857 AS $$
  void x(Connection c) throws SQLException {
    try (PreparedStatement s = c.prepareStatement(
      "ALTER TABLE t ALTER COLUMN c RENAME TO d"
    )) {
      s.execute();
    }
    try (PreparedStatement s = c.prepareStatement(
      "ALTER TABLE t ALTER d int"
    )) {
      s.execute();
    }
  }
$$;
CALL block_1794083357090_4139857();
DROP ALIAS block_1794083357090_4139857;
```

###### Hana

```sql
DO BEGIN
  EXECUTE IMMEDIATE 'RENAME COLUMN t.c TO d';
  EXECUTE IMMEDIATE 'ALTER TABLE t ALTER (d integer)';
END;
```

###### HSQLDB

```sql
BEGIN ATOMIC
  ALTER TABLE t ALTER COLUMN c RENAME TO d;
  ALTER TABLE t ALTER d int;
END;
```

###### Informix

```sql
BEGIN
  RENAME COLUMN t.c TO d;
  ALTER TABLE t MODIFY d integer;
END;
```

###### Oracle

```sql
BEGIN
  EXECUTE IMMEDIATE 'ALTER TABLE t RENAME COLUMN c TO d';
  EXECUTE IMMEDIATE 'ALTER TABLE t MODIFY d number(10)';
END;
```

###### Snowflake

```sql
BEGIN
  ALTER TABLE t RENAME COLUMN c TO d;
  ALTER TABLE t ALTER d number(10);
END;
```

###### SQLDataWarehouse, SQLServer

```sql
BEGIN
  EXEC sp_rename 't.c', d, 'COLUMN';
  ALTER TABLE t ALTER COLUMN d int;
END;
```

###### ASE, Access, BigQuery, ClickHouse, Databricks, DuckDB, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-rename-column"></a>
###### 3.6.1.6.23. ALTER TABLE .. RENAME COLUMN

Like most object types, columns can be renamed:

```java
// Rename a column
create.alterTable("table").renameColumn("old_column").to("new_column").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").renameColumn("c").to("d")
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Trino, Vertica, YugabyteDB

```sql
ALTER TABLE t RENAME COLUMN c TO d
```

###### ASE

```sql
EXEC sp_rename 't.c', d, 'column'
```

###### Firebird

```sql
ALTER TABLE t ALTER COLUMN c TO d
```

###### H2, HSQLDB

```sql
ALTER TABLE t ALTER COLUMN c RENAME TO d
```

###### Hana, Informix

```sql
RENAME COLUMN t.c TO d
```

###### MemSQL

```sql
ALTER TABLE t CHANGE c d
```

###### SQLDataWarehouse, SQLServer

```sql
EXEC sp_rename 't.c', d, 'COLUMN'
```

###### Sybase, Teradata

```sql
ALTER TABLE t RENAME c TO d
```

###### Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-rename-constraint"></a>
###### 3.6.1.6.24. ALTER TABLE .. RENAME CONSTRAINT

Like most object types, constraints can be renamed:

```java
// Rename a constraint
create.alterTable("table").renameConstraint("old_constraint").to("new_constraint").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").renameConstraint("c").to("d")
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, CockroachDB, H2, Informix, Oracle, Postgres, Snowflake, Sybase, Vertica, YugabyteDB

```sql
ALTER TABLE t RENAME CONSTRAINT c TO d
```

###### ASE

```sql
EXEC sp_rename 't.c', d, 'index'
```

###### HSQLDB

```sql
ALTER CONSTRAINT c RENAME TO d
```

###### SQLDataWarehouse, SQLServer

```sql
BEGIN TRY
  EXEC sp_rename 't.c', d
END TRY
BEGIN CATCH
  EXEC sp_rename 'c', d, 'object'
END CATCH
```

###### Teradata

```sql
ALTER TABLE t RENAME c TO d
```

###### BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, Hana, MariaDB, MemSQL, MySQL, Redshift, SQLite, Spanner, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-rename-index"></a>
###### 3.6.1.6.25. ALTER TABLE .. RENAME INDEX

Like most object types, indexes can be renamed. As some RDBMS treat indexes as objects contained in tables, just like constraints, this syntax is offered also as an alternative to the more popular variant of the [ALTER INDEX .. RENAME statement](#alter-index-rename):

```java
// Rename a index (as a convenience for the ALTER INDEX statement)
create.alterTable("table").renameIndex("old_index").to("new_index").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").renameIndex("i").to("j")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
EXEC sp_rename 't.i', j, 'index'
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
ALTER TABLE t RENAME INDEX i TO j
```

###### Aurora Postgres, CockroachDB, H2, HSQLDB, Oracle, Postgres

```sql
ALTER INDEX i RENAME TO j
```

###### DB2, Hana

```sql
RENAME INDEX i TO j
```

###### SQLDataWarehouse, SQLServer

```sql
EXEC sp_rename 't.i', j, 'INDEX'
```

###### Access, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, Informix, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-column"></a>
###### 3.6.1.6.26. ALTER TABLE .. DROP COLUMN

A single column can be dropped from a table using the `ALTER TABLE`'s `DROP COLUMN` clause:

```java
// Drop a single column
create.alterTable("table").drop("column").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").drop("c")
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
ALTER TABLE t DROP c
```

###### ASE

```sql
ALTER TABLE t DROP c WITH NO DATACOPY
```

###### BigQuery, ClickHouse, Databricks, Oracle, SQLDataWarehouse, SQLServer, Trino

```sql
ALTER TABLE t DROP COLUMN c
```

###### Hana

```sql
ALTER TABLE t DROP (c)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-column-restrict"></a>
###### 3.6.1.6.27. ALTER TABLE .. DROP COLUMN RESTRICT

An optional `RESTRICT` clause can be added to a `DROP COLUMN` clause to hint at the operation failing when there are objects depending on the column.

```java
// Add a RESTRICT clause when dropping columns
create.alterTable("table").drop("column").restrict().execute();
```

In most RDBMS, `RESTRICT` semantics is the default when dropping columns, although implementations do not agree on what dependent objects are included in the `RESTRICT` check.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").drop("c").restrict()
```

Translates to the following dialect specific expressions:

###### CockroachDB, DB2, DuckDB, HSQLDB, Postgres, Redshift, YugabyteDB

```sql
ALTER TABLE t DROP c RESTRICT
```

###### Databricks

```sql
ALTER TABLE t DROP COLUMN c RESTRICT
```

###### Oracle

```sql
ALTER TABLE t DROP COLUMN c
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-column-cascade"></a>
###### 3.6.1.6.28. ALTER TABLE .. DROP COLUMN CASCADE

An optional `CASCADE` clause can be added to a `DROP COLUMN` clause to cascade the `DROP` operatoin to dependent objects.

```java
// Add a CASCADE clause when dropping columns
create.alterTable("table").drop("column").cascade().execute();
```

Note: Implementations do not agree on what dependent objects are included in the `CASCADE` operation.

###### Dialect support

This example using jOOQ:

```java
alterTable("t").drop("c").cascade()
```

Translates to the following dialect specific expressions:

###### CockroachDB, DB2, HSQLDB, Postgres, Redshift, YugabyteDB

```sql
ALTER TABLE t DROP c CASCADE
```

###### Oracle

```sql
ALTER TABLE t DROP COLUMN c CASCADE CONSTRAINTS
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-multiple"></a>
###### 3.6.1.6.29. ALTER TABLE .. DROP COLUMNS

Multiple columns can be dropped from a table using the `ALTER TABLE`'s `DROP COLUMNS` clause:

```java
// Drop several columns in one go
create.alterTable("table").drop("column1", "column2").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").drop("c1", "c2")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
ALTER TABLE t DROP c1, c2 WITH NO DATACOPY
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Firebird, MariaDB, MemSQL, MySQL, Postgres, Teradata, YugabyteDB

```sql
ALTER TABLE t DROP c1, DROP c2
```

###### BigQuery, ClickHouse

```sql
ALTER TABLE t DROP COLUMN c1, DROP COLUMN c2
```

###### Databricks, SQLDataWarehouse, SQLServer

```sql
ALTER TABLE t DROP COLUMN c1, c2
```

###### DB2

```sql
ALTER TABLE t DROP c1 DROP c2
```

###### H2, Snowflake

```sql
ALTER TABLE t DROP c1, c2
```

###### Hana, Informix, Oracle

```sql
ALTER TABLE t DROP (c1, c2)
```

###### Access, DuckDB, Exasol, HSQLDB, Redshift, SQLite, Spanner, Sybase, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-column-if-exists"></a>
###### 3.6.1.6.30. ALTER TABLE .. DROP COLUMN IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

###### Dialect support

This example using jOOQ:

```java
alterTable("t").dropIfExists("c")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, Exasol, H2, MariaDB, Postgres, YugabyteDB

```sql
ALTER TABLE t DROP IF EXISTS c
```

###### BigQuery, ClickHouse, Databricks, Trino

```sql
ALTER TABLE t DROP COLUMN IF EXISTS c
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42703' BEGIN END;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    ALTER TABLE t DROP c
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    ALTER TABLE t DROP c
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 257 BEGIN END;
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 260 BEGIN END;
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 397 BEGIN END;
  EXECUTE IMMEDIATE '
    ALTER TABLE t DROP (c)
  ';
END;
```

###### Oracle

```sql
BEGIN
  EXECUTE IMMEDIATE '
    ALTER TABLE t DROP COLUMN c
  ';
EXCEPTION
  WHEN others THEN
    IF sqlerrm LIKE 'ORA-00904%' THEN NULL;
    ELSIF sqlerrm LIKE 'ORA-02443%' THEN NULL;
    ELSE RAISE;
    END IF;
END;
```

###### SQLDataWarehouse

```sql
BEGIN TRY
  EXEC sp_executesql N'
    ALTER TABLE t DROP COLUMN c
  ';
END TRY
BEGIN CATCH
  IF error_number() NOT IN (4924, 3728, 3727, 1750, 15248) BEGIN
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
  END;
END CATCH
```

###### SQLServer

```sql
BEGIN TRY
  EXEC sp_executesql N'
    ALTER TABLE t DROP COLUMN c
  ';
END TRY
BEGIN CATCH
  IF error_number() NOT IN (4924, 3728, 3727, 1750, 15248) THROW;
END CATCH
```

###### ASE, Access, Aurora MySQL, HSQLDB, Informix, MemSQL, MySQL, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-constraint"></a>
###### 3.6.1.6.31. ALTER TABLE .. DROP CONSTRAINT

A constraint can be dropped from the table using the `ALTER TABLE`'s `DROP CONSTRAINT` clause:

```java
// Drop a constraint
create.alterTable("table").dropConstraint("uk").execute();
```

Alternative syntaxes are available to restrict dropping only to specific types of constraints:

- [DROP PRIMARY KEY](#alter-table-drop-primary-key)
- [DROP UNIQUE](#alter-table-drop-unique)
- [DROP FOREIGN KEY](#alter-table-drop-foreign-key)

###### Dialect support

This example using jOOQ:

```java
alterTable("t").dropConstraint("c")
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
ALTER TABLE t DROP CONSTRAINT c
```

###### Aurora MySQL, DuckDB, MySQL, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-primary-key"></a>
###### 3.6.1.6.32. ALTER TABLE .. DROP PRIMARY KEY

A `PRIMARY KEY` constraint can be dropped from the table using the `ALTER TABLE`'s `DROP PRIMARY KEY` clause:

```java
// Drop specific types of constraints
create.alterTable("table").dropPrimaryKey().execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").dropPrimaryKey()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, BigQuery, DB2, Databricks, Exasol, H2, HSQLDB, Hana, MariaDB, MySQL, Snowflake

```sql
ALTER TABLE t DROP PRIMARY KEY
```

###### Aurora Postgres, Postgres

```sql
DO $$
DECLARE
  n varchar;
BEGIN
  n := (
    SELECT constraint_name
    FROM information_schema.table_constraints
    WHERE (
      (table_name = 't')
      AND (constraint_type = 'PRIMARY KEY')
    )
  );
  EXECUTE ('alter table "t" drop constraint ' || n);
END;
$$
```

###### ASE, Access, ClickHouse, CockroachDB, DuckDB, Firebird, Informix, MemSQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-unique"></a>
###### 3.6.1.6.33. ALTER TABLE .. DROP UNIQUE

A `UNIQUE` constraint can be dropped from the table using the `ALTER TABLE`'s `DROP UNIQUE` clause:

```java
// Drop specific types of constraints
create.alterTable("table").dropUnique("uk").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").dropUnique("c")
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, DB2, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Teradata, Vertica, YugabyteDB

```sql
ALTER TABLE t DROP CONSTRAINT c
```

###### CockroachDB

```sql
DROP INDEX c CASCADE
```

###### BigQuery, ClickHouse, Databricks, DuckDB, Exasol, MemSQL, SQLite, Spanner, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-foreign-key"></a>
###### 3.6.1.6.34. ALTER TABLE .. DROP FOREIGN KEY

A `FOREIGN KEY` constraint can be dropped from the table using the `ALTER TABLE`'s `DROP FOREIGN KEY` clause:

```java
// Drop specific types of constraints
create.alterTable("table").dropForeignKey("fk").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTable("t").dropForeignKey("c")
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
ALTER TABLE t DROP CONSTRAINT c
```

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER TABLE t DROP FOREIGN KEY c
```

###### ClickHouse, DuckDB, MemSQL, SQLite, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-drop-constraint-if-exists"></a>
###### 3.6.1.6.35. ALTER TABLE .. DROP CONSTRAINT IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

###### Dialect support

This example using jOOQ:

```java
alterTable("t").dropConstraintIfExists("c")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, H2, MariaDB, Postgres

```sql
ALTER TABLE t DROP CONSTRAINT IF EXISTS c
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42703' BEGIN END;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    ALTER TABLE t DROP CONSTRAINT c
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    ALTER TABLE t DROP CONSTRAINT c
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 257 BEGIN END;
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 260 BEGIN END;
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 397 BEGIN END;
  EXECUTE IMMEDIATE '
    ALTER TABLE t DROP CONSTRAINT c
  ';
END;
```

###### Oracle

```sql
BEGIN
  EXECUTE IMMEDIATE '
    ALTER TABLE t DROP CONSTRAINT c
  ';
EXCEPTION
  WHEN others THEN
    IF sqlerrm LIKE 'ORA-00904%' THEN NULL;
    ELSIF sqlerrm LIKE 'ORA-02443%' THEN NULL;
    ELSE RAISE;
    END IF;
END;
```

###### SQLServer

```sql
BEGIN TRY
  EXEC sp_executesql N'
    ALTER TABLE t DROP CONSTRAINT c
  ';
END TRY
BEGIN CATCH
  IF error_number() NOT IN (4924, 3728, 3727, 1750, 15248) THROW;
END CATCH
```

###### YugabyteDB

```sql
DO $$
BEGIN
  ALTER TABLE t DROP CONSTRAINT c;
EXCEPTION
  WHEN SQLSTATE '42703' THEN NULL;
  WHEN SQLSTATE '42704' THEN NULL;
END $$
```

###### ASE, Access, Aurora MySQL, DuckDB, Exasol, HSQLDB, Informix, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-table-if-exists"></a>
###### 3.6.1.6.36. ALTER TABLE IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Renaming the table
create.alterTableIfExists("old_table").renameTo("new_table").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTableIfExists("old").renameTo("new")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL

```sql
ALTER TABLE old RENAME TO new
```

###### Aurora Postgres, BigQuery, CockroachDB, DuckDB, H2, Oracle, Postgres, Snowflake, Trino, YugabyteDB

```sql
ALTER TABLE IF EXISTS old RENAME TO new
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    RENAME TABLE old TO new
  ';
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 259 BEGIN END;
  EXECUTE IMMEDIATE '
    RENAME TABLE old TO new
  ';
END;
```

###### MariaDB

```sql
BEGIN NOT ATOMIC
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' BEGIN END;
  ALTER TABLE old RENAME TO new;
END
```

###### MySQL

```sql
CREATE PROCEDURE block_1794083325369_2089324()
MODIFIES SQL DATA
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' BEGIN END;
  ALTER TABLE old RENAME TO new;
END;
CALL block_1794083325369_2089324();
DROP PROCEDURE block_1794083325369_2089324;
```

###### SQLServer

```sql
BEGIN TRY
  EXEC sp_executesql N'
    EXEC sp_rename ''old'', new
  ';
END TRY
BEGIN CATCH
  IF error_number() NOT IN (4902, 15165, 15225) THROW;
END CATCH
```

###### ASE, Access, ClickHouse, Databricks, Exasol, Firebird, HSQLDB, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-type-statement"></a>
##### 3.6.1.7. ALTER TYPE

The `ALTER TYPE` statement allows of altering existing types. It supports the following subclauses:

<a id="alter-type-rename"></a>
###### 3.6.1.7.1. ALTER TYPE .. RENAME

Like most object types, types can be renamed. This is independent of the object type:

```java
// Renaming the type
create.alterType("old_type").renameTo("new_type").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterType("old").renameTo("new")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres

```sql
ALTER TYPE old RENAME TO new
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-type-enum"></a>
###### 3.6.1.7.2. ALTER TYPE .. for enum alterations

Some alterations are specific to enum types, e.g. in PostgreSQL. These include:

```java
// Adding an enum value to an existing type
create.alterType("type").addValue("new_enum_value").execute();

// Renaming an enum value of an existing type to a new value
create.alterType("type").renameValue("old_enum_value").to("new_enum_value").execute();

// Move an enum type to a new schema
create.alterType("type").setSchema("new_schema").execute();
```

<a id="alter-type-if-exists"></a>
###### 3.6.1.7.3. ALTER TYPE IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

```java
// Renaming the type
create.alterTypeIfExists("old_type").renameTo("new_type").execute();
```

###### Dialect support

This example using jOOQ:

```java
alterTypeIfExists("old").renameTo("new")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
DO $$
BEGIN
  ALTER TYPE old RENAME TO new;
EXCEPTION
  WHEN SQLSTATE '42704' THEN NULL;
END $$
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-view-statement"></a>
##### 3.6.1.8. ALTER VIEW

The `ALTER VIEW` statement allows of altering existing views. It supports the following subclauses:

<a id="alter-view-as"></a>
###### 3.6.1.8.1. ALTER VIEW .. AS

This statement allows for replacing the contents of an existing view.

###### Dialect support

This example using jOOQ:

```java
alterView("v").as(select(one().as("a")))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
DO $$
BEGIN
  DROP VIEW v;
  CREATE VIEW v
  AS
  SELECT 1 a;
END;
$$
```

###### Databricks, SQLServer

```sql
ALTER VIEW v
AS
SELECT 1 a
```

###### DB2

```sql
BEGIN
  EXECUTE IMMEDIATE 'DROP VIEW v';
  EXECUTE IMMEDIATE 'CREATE VIEW v
  AS
  SELECT 1 a
  FROM SYSIBM.DUAL';
END
```

###### Firebird

```sql
EXECUTE BLOCK AS
BEGIN
  EXECUTE STATEMENT 'DROP VIEW v';
  EXECUTE STATEMENT 'CREATE VIEW v
  AS
  SELECT 1 a
  FROM RDB$DATABASE';
END
```

###### H2

```sql
CREATE ALIAS block_1794083346801_8664724 AS $$
  void x(Connection c) throws SQLException {
    try (PreparedStatement s = c.prepareStatement(
      "DROP VIEW v"
    )) {
      s.execute();
    }
    try (PreparedStatement s = c.prepareStatement(
      "CREATE VIEW v\n" +
      "AS\n" +
      "SELECT 1 a"
    )) {
      s.execute();
    }
  }
$$;
CALL block_1794083346801_8664724();
DROP ALIAS block_1794083346801_8664724;
```

###### Hana

```sql
DO BEGIN
  EXECUTE IMMEDIATE 'DROP VIEW v';
  EXECUTE IMMEDIATE 'CREATE VIEW v
  AS
  SELECT 1 a
  FROM SYS.DUMMY';
END;
```

###### MariaDB

```sql
BEGIN NOT ATOMIC
  DROP VIEW v;
  CREATE VIEW v
  AS
  SELECT 1 a;
END;
```

###### MySQL

```sql
CREATE PROCEDURE block_1794083346855_1044053()
MODIFIES SQL DATA
BEGIN
  DROP VIEW v;
  CREATE VIEW v
  AS
  SELECT 1 a;
END;
CALL block_1794083346855_1044053();
DROP PROCEDURE block_1794083346855_1044053;
```

###### Oracle

```sql
BEGIN
  EXECUTE IMMEDIATE 'DROP VIEW v';
  EXECUTE IMMEDIATE 'CREATE VIEW v
  AS
  SELECT 1 a';
END;
```

###### SQLDataWarehouse, Vertica

```sql
BEGIN
  DROP VIEW v;
  CREATE VIEW v
  AS
  SELECT 1 a;
END;
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DuckDB, Exasol, HSQLDB, Informix, MemSQL, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-view-comment"></a>
###### 3.6.1.8.2. ALTER VIEW .. COMMENT

This statement allows for changing the comment associated with a view. It is an alias for the [COMMENT ON VIEW statement](#comment-on-view)

###### Dialect support

This example using jOOQ:

```java
alterView("v").comment("new comment")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Firebird, Hana, Postgres, Redshift, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
COMMENT ON VIEW v IS 'new comment'
```

###### BigQuery

```sql
ALTER VIEW v SET OPTIONS (DESCRIPTION = 'new comment')
```

###### DB2, DuckDB, H2, HSQLDB, Oracle

```sql
COMMENT ON TABLE v IS 'new comment'
```

###### Snowflake

```sql
ALTER VIEW v SET COMMENT = 'new comment'
```

###### SQLServer

```sql
BEGIN TRY
  DECLARE @u varchar(max) = schema_name();
  EXEC sp_addextendedproperty 'MS_Description', 'new comment', 'schema', @u, 'view', 'v', DEFAULT, DEFAULT
END TRY
BEGIN CATCH
  EXEC sp_updateextendedproperty 'MS_Description', 'new comment', 'schema', @u, 'view', 'v', DEFAULT, DEFAULT
END CATCH
```

###### ASE, Access, Aurora MySQL, ClickHouse, CockroachDB, Databricks, Exasol, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-view-rename"></a>
###### 3.6.1.8.3. ALTER VIEW .. RENAME

This statement allows for renaming a view.

###### Dialect support

This example using jOOQ:

```java
alterView("v").renameTo("new_name")
```

Translates to the following dialect specific expressions:

###### ASE, SQLServer

```sql
EXEC sp_rename v, new_name
```

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, H2, Postgres, Snowflake, Trino, Vertica

```sql
ALTER VIEW v RENAME TO new_name
```

###### Exasol, Teradata

```sql
RENAME VIEW v TO new_name
```

###### HSQLDB, Redshift, YugabyteDB

```sql
ALTER TABLE v RENAME TO new_name
```

###### Oracle

```sql
RENAME v TO new_name
```

###### Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="alter-view-if-exists"></a>
###### 3.6.1.8.4. ALTER VIEW IF EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF EXISTS` clause:

###### Dialect support

This example using jOOQ:

```java
alterViewIfExists("v").renameTo("new_name")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, Postgres

```sql
ALTER VIEW IF EXISTS v RENAME TO new_name
```

###### Oracle

```sql
BEGIN
  EXECUTE IMMEDIATE '
    RENAME v TO new_name
  ';
EXCEPTION
  WHEN others THEN
    IF sqlerrm LIKE 'ORA-00942%' THEN NULL;
    ELSIF sqlerrm LIKE 'ORA-04043%' THEN NULL;
    ELSE RAISE;
    END IF;
END;
```

###### Snowflake

```sql
ALTER VIEW v RENAME TO new_name
```

###### SQLServer

```sql
BEGIN TRY
  EXEC sp_rename v, new_name
END TRY
BEGIN CATCH
  IF error_number() NOT IN (15225) THROW;
END CATCH
```

###### YugabyteDB

```sql
ALTER TABLE IF EXISTS v RENAME TO new_name
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="comment-statement"></a>
#### 3.6.2. The COMMENT statement

The `COMMENT` statement can be used to store a description for an object from the database catalog.

It is available for the following types of object:

<a id="comment-on-column"></a>
##### 3.6.2.1. COMMENT ON COLUMN

This statement is used to comment on a column.

###### Dialect support

This example using jOOQ:

```java
commentOnColumn(name("t", "col")).is("the comment")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
COMMENT ON COLUMN t.col IS 'the comment'
```

###### ClickHouse

```sql
ALTER TABLE t COMMENT COLUMN col 'the comment'
```

###### Databricks, Snowflake

```sql
ALTER TABLE t ALTER COLUMN col COMMENT 'the comment'
```

###### SQLServer

```sql
BEGIN TRY
  DECLARE @u varchar(max) = schema_name();
  EXEC sp_addextendedproperty 'MS_Description', 'the comment', 'schema', @u, 'table', 't', 'column', 'col'
END TRY
BEGIN CATCH
  EXEC sp_updateextendedproperty 'MS_Description', 'the comment', 'schema', @u, 'table', 't', 'column', 'col'
END CATCH
```

###### ASE, Access, Aurora MySQL, BigQuery, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="comment-on-function"></a>
##### 3.6.2.2. COMMENT ON FUNCTION

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This statement is used to comment on a function.

###### Dialect support

This example using jOOQ:

```java
commentOnFunction("f").parameters(in("p1", INTEGER), in("p2", INTEGER)).is("the comment")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER FUNCTION f COMMENT 'the comment'
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
COMMENT ON FUNCTION f(
  p1 int,
  p2 int
) IS 'the comment'
```

###### ASE, Access, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="comment-on-materialized-view"></a>
##### 3.6.2.3. COMMENT ON MATERIALIZED VIEW

This statement is used to comment on a materialized view.

###### Dialect support

This example using jOOQ:

```java
commentOnMaterializedView("v").is("the comment")
```

Translates to the following dialect specific expressions:

###### BigQuery

```sql
ALTER MATERIALIZED VIEW v SET OPTIONS (DESCRIPTION = 'the comment')
```

###### Oracle, Postgres, Sybase, YugabyteDB

```sql
COMMENT ON MATERIALIZED VIEW v IS 'the comment'
```

###### Redshift

```sql
COMMENT ON VIEW v IS 'the comment'
```

###### Snowflake

```sql
ALTER TABLE v SET COMMENT = 'the comment'
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="comment-on-procedure"></a>
##### 3.6.2.4. COMMENT ON PROCEDURE

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This statement is used to comment on a procedure.

###### Dialect support

This example using jOOQ:

```java
commentOnProcedure("p").parameters(in("p1", INTEGER), in("p2", INTEGER)).is("the comment")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MySQL

```sql
ALTER PROCEDURE p COMMENT 'the comment'
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
COMMENT ON PROCEDURE p(
  p1 int,
  p2 int
) IS 'the comment'
```

###### ASE, Access, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="comment-on-table"></a>
##### 3.6.2.5. COMMENT ON TABLE

This statement is used to comment on a table.

###### Dialect support

This example using jOOQ:

```java
commentOnTable("t").is("the comment")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
ALTER TABLE t COMMENT = 'the comment'
```

###### Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
COMMENT ON TABLE t IS 'the comment'
```

###### BigQuery

```sql
ALTER TABLE t SET OPTIONS (DESCRIPTION = 'the comment')
```

###### ClickHouse

```sql
ALTER TABLE t MODIFY COMMENT 'the comment'
```

###### Snowflake

```sql
ALTER TABLE t SET COMMENT = 'the comment'
```

###### SQLServer

```sql
BEGIN TRY
  DECLARE @u varchar(max) = schema_name();
  EXEC sp_addextendedproperty 'MS_Description', 'the comment', 'schema', @u, 'table', 't', DEFAULT, DEFAULT
END TRY
BEGIN CATCH
  EXEC sp_updateextendedproperty 'MS_Description', 'the comment', 'schema', @u, 'table', 't', DEFAULT, DEFAULT
END CATCH
```

###### ASE, Access, Informix, SQLDataWarehouse, SQLite, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="comment-on-view"></a>
##### 3.6.2.6. COMMENT ON VIEW

This statement is used to comment on a view.

###### Dialect support

This example using jOOQ:

```java
commentOnView("v").is("the comment")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Firebird, Hana, Postgres, Redshift, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
COMMENT ON VIEW v IS 'the comment'
```

###### BigQuery

```sql
ALTER VIEW v SET OPTIONS (DESCRIPTION = 'the comment')
```

###### ClickHouse

```sql
ALTER TABLE v MODIFY COMMENT 'the comment'
```

###### DB2, DuckDB, H2, HSQLDB, Oracle

```sql
COMMENT ON TABLE v IS 'the comment'
```

###### Snowflake

```sql
ALTER VIEW v SET COMMENT = 'the comment'
```

###### SQLServer

```sql
BEGIN TRY
  DECLARE @u varchar(max) = schema_name();
  EXEC sp_addextendedproperty 'MS_Description', 'the comment', 'schema', @u, 'view', 'v', DEFAULT, DEFAULT
END TRY
BEGIN CATCH
  EXEC sp_updateextendedproperty 'MS_Description', 'the comment', 'schema', @u, 'view', 'v', DEFAULT, DEFAULT
END CATCH
```

###### ASE, Access, Aurora MySQL, CockroachDB, Databricks, Exasol, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-statement"></a>
#### 3.6.3. The CREATE statement

The `CREATE` statement is the most important DDL statement. It allows for creating new objects in the database catalog.

<a id="create-database-statement"></a>
##### 3.6.3.1. CREATE DATABASE

The `CREATE DATABASE` statement is used to create a new database (catalog).

```java
// Create a database
create.createDatabase("new_database").execute();
```

###### Dialect support

This example using jOOQ:

```java
createDatabase("d")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, ClickHouse, CockroachDB, MariaDB, MemSQL, MySQL, Postgres, SQLDataWarehouse, SQLServer, Snowflake, YugabyteDB

```sql
CREATE DATABASE d
```

###### Databricks

```sql
CREATE CATALOG d
```

###### ASE, Access, Aurora MySQL, BigQuery, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Redshift, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-domain-statement"></a>
##### 3.6.3.2. CREATE DOMAIN

The `CREATE DOMAIN` statement allows for creating [DOMAIN](#domain-data-types) types for use as data types in table columns.

Depending on the dialect, a `DOMAIN` combines the following features:

- A qualified name
- A base data type
- A `DEFAULT` value
- A `NOT NULL` constraint
- A `COLLATION`
- A set of `CHECK` constraints

Domains can be created in jOOQ using:

```java
// Create a domain on a base type
create.createDomain("d1").as(INTEGER).execute();

// Create a domain on a base type and add a DEFAULT expression
create.createDomain("d2").as(INTEGER).default_(1).execute();

// Create a domain on a base type and add a CHECK constraint
create.createDomain("d3").as(INTEGER).constraints(check(value(INTEGER).gt(0))).execute();
```

###### Dialect support

This example using jOOQ:

```java
createDomain("d").as(INTEGER)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, HSQLDB, Postgres, YugabyteDB

```sql
CREATE DOMAIN d AS int
```

###### Firebird

```sql
CREATE DOMAIN d AS integer
```

###### Oracle

```sql
CREATE DOMAIN d AS number(10)
```

###### SQLServer

```sql
CREATE TYPE d FROM int
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-function-statement"></a>
##### 3.6.3.3. CREATE FUNCTION

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `CREATE FUNCTION` statement allows for creating stored functions in your catalog.

A stored function, as opposed to a [stored procedure](#create-procedure-statement), can be used in SQL statements as a scalar [column expression](#column-expressions), specifically a [user defined function](#user-defined-functions), or as a [table expression](#table-expressions), specifically a [table valued functions](#table-valued-functions).

<a id="create-scalar-function-statement"></a>
###### 3.6.3.3.1. Scalar functions

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The most common type of [user defined function](#user-defined-functions) is a scalar function, i.e. a function that returns a single scalar value. Such functions can be used in [the SELECT clause](#select-clause), [the WHERE clause](#where-clause), [the GROUP BY clause](#group-by-clause), [the HAVING clause](#having-clause), [the ORDER BY clause](#order-by-clause), and elsewhere, where [column expressions](#column-expressions) can be used.

A simple example for creating such a function is:

```java
// Create a function that always return 1
create.createFunction("one")
      .returns(INTEGER)
      .as(return_(1))
      .execute();

// Create a function that returns the sum of its inputs
Parameter<Integer> i1 = in("i1", INTEGER);
Parameter<Integer> i2 = in("i2", INTEGER);

create.createFunction("my_sum")
      .parameters(i1, i2)
      .returns(INTEGER)
      .as(return_(i1.plus(i2)))
      .execute();
```

Once you've created the above functions, you can either run code generation to get a type safe stub for calling them, or use [plain SQL](#plain-sql) (specifically, [`DSL.function()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#function(org.jooq.Name,org.jooq.DataType,org.jooq.Field...))) from within a [SELECT statement](#select-statement):

```java
// Call the previously created functions with generated code:
create.select(one(), mySum(1, 2)).fetchOne();

// ...or with plain SQL
create.select(
  function(name("one"), INTEGER),
  function(name("my_sum"), INTEGER, val(1), val(2))
).fetchOne();
```

Both yielding:

```text
+-----+--------+
| ONE | MY_SUM |
+-----+--------+
|   1 |      3 |
+-----+--------+
```

<a id="create-or-replace-function"></a>
###### 3.6.3.3.2. CREATE OR REPLACE FUNCTION

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

In most cases, you will want to `CREATE OR REPLACE` a function, not `CREATE [ OR FAIL ]` when the function already exists. For this, just use the auxiliary `OR REPLACE` clause, which can be emulated by jOOQ via an additional [DROP FUNCTION statement](#drop-function-statement) if this syntax is not available in your dialect.

```java
// Create a function that always return 1
create.createOrReplaceFunction("one")
      .returns(INTEGER)
      .as(return_(1))
      .execute();
```

<a id="create-function-characteristics-sql-data-access"></a>
###### 3.6.3.3.3. SQL data access characteristics

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Some dialects require the explicit specification of a few characteristics of a function, defining what kind of content a function is allowed (and expected) to have. These act both as contracts for your development (similar to the [`java.lang.FunctionalInterface`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/FunctionalInterface.html) annotation), as well as hints to the database regarding whether a function is expected to have side-effects (and thus maybe cannot be used in a [SELECT statement](#select-statement)), or whether it depends on data, or is purely deterministic (see also [the DETERMINISTIC characteristic](#create-function-characteristics-deterministic)). The SQL data access characteristics include:

- `NO SQL`
- `CONTAINS SQL`
- `READS SQL DATA`
- `MODIFIES SQL DATA`

While the semantics seem pretty clear, please refer to your database manual for the details, as there may be subtle differences, e.g. regarding what particular [procedural statement](#procedural-statements) constitues "SQL".

If a characteristic is not supported by your dialect, you can still specify it, and jOOQ will simply ignore it in generated SQL.

```java
create.createFunction("f1").returns(INTEGER).noSQL().as(return_(1)).execute();
create.createFunction("f2").returns(INTEGER).containsSQL().as(return_(select(val(1)))).execute();
create.createFunction("f3").returns(INTEGER).readsSQLData().as(return_(selectCount().from(BOOK))).execute();
create.createFunction("f4").returns(INTEGER).modifiesSQLData().as(
  insertInto(LOGS).columns(LOGS.TEXT).values("Function F4 was called"),
  return_(1)
).execute();
```

This works just like [SQL data access characteristics for procedures](#create-procedure-characteristics-sql-data-access)

<a id="create-function-characteristics-deterministic"></a>
###### 3.6.3.3.4. DETERMINISTIC characteristic

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Some dialects require the explicit specification of a few characteristics of a function. The `DETERMINISTIC` characteristic can be used to tell the database that contents of a function are guaranteed by the user to be "deterministic" (or "`IMMUTABLE`" in PostgreSQL), meaning that the result of a function is purely defined by the function arguments (never by data or session values or the current time or random number generators, etc.) such that a function expression can be replaced by the result value at the call site. Such a function is also said to be side-effect free, and pure. Some dialects (e.g. Oracle) allow for using `DETERMINISTIC` functions in function based indexes.

If `DETERMINISTIC` is not supported by your dialect, you can still specify it, and jOOQ will simply ignore it in generated SQL.

```java
create.createFunction("f1").returns(INTEGER).deterministic().as(return_(1)).execute();
create.createFunction("f2").returns(INTEGER).notDeterministic().as(return_(rand())).execute();
```

<a id="create-function-characteristics-on-null-input"></a>
###### 3.6.3.3.5. ON NULL INPUT characteristic

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This characteristic both determines a contract for use by optimisers, as well as influences the behaviour of a function.

Most built-in SQL functions return `NULL` as soon as any of the arguments are `NULL`. For example [SUBSTRING](#substring-function):

```java
create.select(
  substring("abc"             , 2)                 .as("s1"),
  substring("abc"             , val(null, INTEGER)).as("s2"),
  substring(val(null, VARCHAR), 2)                 .as("s3"),
  substring(val(null, VARCHAR), val(null, INTEGER)).as("s4"),
).fetchOne();
```

Yielding:

```text
+----+--------+--------+--------+
| s1 | s2     | s3     | s4     |
+----+--------+--------+--------+
| bc | {null} | {null} | {null} |
+----+--------+--------+--------+
```

While it is easy to implement this manually, it is both convenient, and helpful for optimisers, to just use the characteristic to achieve this standard behaviour, and possibly even to prevent calling the function, preventing the overhead from the context switches, etc.

If not natively supported by your dialect, jOOQ will simply wrap your function body in a [IF statement](#procedural-if) checking for argument value nullability.

```java
Parameter<Integer> i1 = in("i1", INTEGER);
Parameter<Integer> i2 = in("i2", INTEGER);

// The function always returns NULL if any argument value is NULL
create.createFunction("my_sum")
      .parameters(i1, i2)
      .returns(INTEGER)
      .returnsNullOnNullInput()
      .as(return_(i1.plus(i2)))
      .execute();

// The function may not return NULL if any argument value is NULL
create.createFunction("my_null_safe_sum")
      .parameters(i1, i2)
      .returns(INTEGER)
      .calledOnNullInput()
      .as(return_(coalesce(i1, 0).plus(coalesce(i2, 0))))
      .execute();
```

<a id="create-function-characteristics-comment"></a>
###### 3.6.3.3.6. COMMENT characteristic

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Some RDBMS support a SQL `COMMENT` as a characteristic on functions, which can be inlined directly with the function definition.

```java
create.createFunction("f1").returns(INTEGER).comment("my function").as(return_(1)).execute();
```

<a id="create-index-statement"></a>
##### 3.6.3.4. CREATE INDEX

The `CREATE INDEX` statement allows for creating indexes on table columns.

###### CREATE INDEX

In its simplest form, the statement can be used like this:

```java
// Create an index on a single column
create.createIndex("index").on("table", "column").execute();

// Create an index on several columns
create.createIndex("index").on("table", "column1", "column2").execute();
```

###### CREATE UNIQUE INDEX

In many dialects, there is a possibility of creating a unique index, which acts like a constraint (see [ALTER TABLE](#alter-table-statement) or [CREATE TABLE](#create-table-statement)), but is not really a constraint. Most dialects will create an index automatically to enforce a `UNIQUE` constraint, so using a constraint instead may seem a bit cleaner. A `UNIQUE INDEX` is created like this:

```java
// Create an index on a single column
create.createUniqueIndex("index").on("table", "column").execute();

// Create an index on several columns
create.createUniqueIndex("index").on("table", "column1", "column2").execute();
```

###### Sorted indexes

In most dialects, indexes have their columns sorted ascendingly by default. If you wish to create an index with a differing sort order, you can do so by providing the order explicitly:

```java
// Create a sorted index on several columns
create.createIndex("index").on(
  table(name("table")),
  field(name("column1")).asc(),
  field(name("column2")).desc()
).execute();
```

###### Covering indexes (with INCLUDE clause)

A few dialects support an `INCLUDE` clause when creating an index. This can be useful to create covering indexes. These are indexes that "cover" the needs of an entire query, such that no secondary lookup needs to be done in a heap table or clustered index, after finding only parts of the projection in the index data structure. The data from the columns of the `INCLUDE` clause will be located only in the index leaf nodes (useful for projections), not in the index tree structure (useful for searches), which reduces index maintenance overhead, and index size.

If a dialect does not support this clause, jOOQ will simply add the `INCLUDE` columns into the ordinary index column list.

```java
// Create a covering index with included columns
create.createIndex("index").on("table", "search_column").include("projection_column").execute();
```

###### Partial indexes (with WHERE clause)

A few dialects support a `WHERE` clause when creating an index. This is very useful to drastically reduce the size of an index, and thus index maintenance, if only parts of the data of a column need to be included in the index.

```java
// Create a partial index
create.createIndex("index").on("table", "column").where(field(name("column")).gt(0)).execute();
```

<a id="create-procedure-statement"></a>
##### 3.6.3.5. CREATE PROCEDURE

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `CREATE PROCEDURE` statement allows for creating stored procedures in your catalog.

A stored procedure, as opposed to a [stored function](#create-function-statement), is expected to have side effects of some sort, and can thus not be used in SQL statements.

A simple example for creating such a procedure is:

```java
// Create a procedure that inserts a log message in a table
create.createProcedure("log")
      .as(insertInto(LOG).columns(LOG.TEXT).values("Log called"))
      .execute();
```

Once you've created the above procedure, you can either run code generation to get a type safe stub for calling them, or use [CALL](#procedural-call) in an [anonymous block](#procedural-block), or directly:

```java
// Call the previously created procedure with generated code:
log(configuration);

// ...or with the CALL statement in an anonymous block
create.begin(call(name("log"))).execute();

// ...or with the CALL statement directly
call(name("log")).execute();
```

<a id="create-or-replace-procedure"></a>
###### 3.6.3.5.1. CREATE OR REPLACE PROCEDURE

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

In most cases, you will want to `CREATE OR REPLACE` a procedure, not `CREATE [ OR FAIL ]` when the procedure already exists. For this, just use the auxiliary `OR REPLACE` clause, which can be emulated by jOOQ via an additional [DROP PROCEDURE statement](#drop-procedure-statement) if this syntax is not available in your dialect.

```java
// Create a procedure that inserts a log message in a table
create.createOrReplaceProcedure("log")
      .as(insertInto(LOG).columns(LOG.TEXT).values("Log called"))
      .execute();
```

<a id="create-procedure-characteristics-sql-data-access"></a>
###### 3.6.3.5.2. SQL data access characteristics

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Some dialects require the explicit specification of a few characteristics of a procedure, defining what kind of content a procedure is allowed (and expected) to have. These act both as contracts for your development (similar to the [`java.lang.FunctionalInterface`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/FunctionalInterface.html) annotation), as well as hints to the database regarding whether a procedure is expected to have side-effects (and thus maybe cannot be used indirectly via a [stored function](#create-function-statement) in a [SELECT statement](#select-statement)), or whether it depends on data, or is purely deterministic. The SQL data access characteristics include:

While procedures are generally expected to yield side effects, it may be useful to use a procedure as a "function with quirky syntax" to be consumed by other functions, because it can return several `OUT` parameters, instead of just a single `RETURN` value, like function, hence the utility of these characteristics also in procedures.

- `NO SQL`
- `CONTAINS SQL`
- `READS SQL DATA`
- `MODIFIES SQL DATA`

While the semantics seem pretty clear, please refer to your database manual for the details, as there may be subtle differences, e.g. regarding what particular [procedural statement](#procedural-statements) constitues "SQL".

If a characteristic is not supported by your dialect, you can still specify it, and jOOQ will simply ignore it in generated SQL.

```java
Parameter<Integer> o = out("o", INTEGER);

create.createProcedure("p1")
      .parameters(o)
      .noSQL()
      .as(o.set(1))
      .execute();

create.createProcedure("p2")
      .parameters(o)
      .containsSQL()
      .as(o.set(select(val(1))))
      .execute();

create.createProcedure("p3")
      .parameters(o)
      .readsSQLData()
      .as(o.set(selectCount().from(BOOK)))
      .execute();

create.createProcedure("p4")
      .parameters(o)
      .modifiesSQLData()
      .as(
        insertInto(LOGS).columns(LOGS.TEXT).values("Function F4 was called"),
        o.set(1)
      )
      .execute();
```

This works just like [SQL data access characteristics for functions](#create-function-characteristics-sql-data-access)

<a id="create-procedure-characteristics-comment"></a>
###### 3.6.3.5.3. COMMENT characteristic

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Some RDBMS support a SQL `COMMENT` as a characteristic on procedures, which can be inlined directly with the procedure definition.

```java
create.createProcedure("f1").comment("my function").as(return_()).execute();
```

<a id="create-schema-statement"></a>
##### 3.6.3.6. CREATE SCHEMA

The `CREATE SCHEMA` statement is used to create a new schema in the database catalog.

```java
// Create a schema
create.createSchema("new_schema").execute();
```

###### Dialect support

This example using jOOQ:

```java
createSchema("s")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Vertica, YugabyteDB

```sql
CREATE SCHEMA s
```

###### ClickHouse

```sql
CREATE DATABASE s
```

###### Oracle

```sql
CREATE USER s NO AUTHENTICATION QUOTA UNLIMITED ON USERS
```

###### ASE, Access, Aurora MySQL, BigQuery, Firebird, Informix, SQLite, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-statement"></a>
##### 3.6.3.7. CREATE SEQUENCE

The `CREATE SEQUENCE` statement is used to create a new sequence in the database catalog.

```java
// Create a sequence with default flags
create.createSequence("sequence").execute();
```

###### Dialect support

This example using jOOQ:

```java
createSequence("s")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, Snowflake, Sybase, Vertica, YugabyteDB

```sql
CREATE SEQUENCE s
```

###### Spanner

```sql
CREATE SEQUENCE s BIT_REVERSED_POSITIVE
```

###### SQLServer

```sql
CREATE SEQUENCE s START WITH 1
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-if-not-exists"></a>
###### 3.6.3.7.1. CREATE SEQUENCE IF NOT EXISTS

A popular subclause of DDL statements that jOOQ can usually emulate, is the `IF NOT EXISTS` clause:

###### Dialect support

This example using jOOQ:

```java
createSequenceIfNotExists("s")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, HSQLDB, Informix, MariaDB, Oracle, Postgres, Snowflake, Vertica, YugabyteDB

```sql
CREATE SEQUENCE IF NOT EXISTS s
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42710' BEGIN END;
  EXECUTE IMMEDIATE '
    CREATE SEQUENCE s
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    CREATE SEQUENCE s
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 324 BEGIN END;
  EXECUTE IMMEDIATE '
    CREATE SEQUENCE s
  ';
END;
```

###### Spanner

```sql
CREATE SEQUENCE IF NOT EXISTS s BIT_REVERSED_POSITIVE
```

###### SQLServer

```sql
BEGIN TRY
  CREATE SEQUENCE s START WITH 1
END TRY
BEGIN CATCH
  IF error_number() NOT IN (2714) THROW;
END CATCH
```

###### Sybase

```sql
BEGIN
  CREATE SEQUENCE s;
EXCEPTION
  WHEN others THEN
END;
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-as"></a>
###### 3.6.3.7.2. CREATE SEQUENCE .. AS

In order to specify a sequence data type explicitly, the optional `AS` clause can be used. The typical default in the absence of `AS` is `BIGINT`, although it may be dialect specific.

###### Dialect support

This example using jOOQ:

```java
createSequence("s").as(SMALLINT)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, H2, HSQLDB, Postgres, YugabyteDB

```sql
CREATE SEQUENCE s AS smallint
```

###### SQLServer

```sql
CREATE SEQUENCE s AS smallint START WITH 1
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-cache"></a>
###### 3.6.3.7.3. CREATE SEQUENCE .. CACHE

Some RDBMS support caching a number of sequence value in the database session in order to speed up concurrent access to the sequence resource.

```java
// Cache a number of values for the sequence, typically on a per session basis.
create.createSequence("sequence").cache(200).execute();
create.createSequence("sequence").noCache().execute();
```

###### Dialect support

This example using jOOQ:

```java
createSequence("s").cache(200)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, H2, Hana, Informix, MariaDB, Oracle, Postgres, Sybase, Vertica, YugabyteDB

```sql
CREATE SEQUENCE s CACHE 200
```

###### SQLServer

```sql
CREATE SEQUENCE s START WITH 1 CACHE 200
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, HSQLDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-cycle"></a>
###### 3.6.3.7.4. CREATE SEQUENCE .. CYCLE

Normally, a sequence starts at `1` and is increased to "infinity" (or rather, until it reaches its data type's [MAXVALUE](#create-sequence-maxvalue)). In some cases, it may be useful to restart the sequence again at some [MINVALUE](#create-sequence-maxvalue). This can be achieved by using the `CYCLE` flag:

```java
// Specify whether the sequence should cycle when it reaches the MAXVALUE
create.createSequence("sequence").cycle().execute();
create.createSequence("sequence").noCycle().execute();
```

###### Dialect support

This example using jOOQ:

```java
createSequence("s").cycle()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, DuckDB, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, Sybase, Vertica, YugabyteDB

```sql
CREATE SEQUENCE s CYCLE
```

###### SQLServer

```sql
CREATE SEQUENCE s START WITH 1 CYCLE
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, Exasol, Firebird, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-minvalue"></a>
###### 3.6.3.7.5. CREATE SEQUENCE .. MINVALUE

When using the [CYCLE](#create-sequence-cycle) clause, it may be useful to specify a different `MINVALUE` than the default of `1`:

```java
// The MINVALUE from which the sequence should cycle if applicable
create.createSequence("sequence").minvalue(1).execute();
create.createSequence("sequence").noMinvalue().execute();
```

###### Dialect support

This example using jOOQ:

```java
createSequence("s").minvalue(1)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, DuckDB, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, Sybase, Vertica, YugabyteDB

```sql
CREATE SEQUENCE s MINVALUE 1
```

###### SQLServer

```sql
CREATE SEQUENCE s START WITH 1 MINVALUE 1
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, Firebird, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-maxvalue"></a>
###### 3.6.3.7.6. CREATE SEQUENCE .. MAXVALUE

When using the [CYCLE](#create-sequence-cycle) clause, it may be useful to specify a different `MAXVALUE` than the default of the sequence data type's maximum representable value:

```java
// The MAXVALUE before which the sequence should cycle if applicable
create.createSequence("sequence").maxvalue(1000).execute();
create.createSequence("sequence").noMaxvalue().execute();
```

###### Dialect support

This example using jOOQ:

```java
createSequence("s").maxvalue(10)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, DuckDB, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, Sybase, Vertica, YugabyteDB

```sql
CREATE SEQUENCE s MAXVALUE 10
```

###### SQLServer

```sql
CREATE SEQUENCE s START WITH 1 MAXVALUE 10
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, Firebird, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-increment-by"></a>
###### 3.6.3.7.7. CREATE SEQUENCE .. INCREMENT BY

In some cases, it may be useful to skip values in a sequence. This can be achieved using the `INCREMENT BY` clause

###### Dialect support

This example using jOOQ:

```java
createSequence("s").incrementBy(10)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, Snowflake, Sybase, Vertica, YugabyteDB

```sql
CREATE SEQUENCE s INCREMENT BY 10
```

###### SQLServer

```sql
CREATE SEQUENCE s START WITH 1 INCREMENT BY 10
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-sequence-start-with"></a>
###### 3.6.3.7.8. CREATE SEQUENCE .. START WITH

In some cases, it may be useful to start a sequence with a different value than the default of `1`, for example when a sequence is introduced on a table containing existing data.

###### Dialect support

This example using jOOQ:

```java
createSequence("s").startWith(1000)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, SQLServer, Snowflake, Sybase, Vertica, YugabyteDB

```sql
CREATE SEQUENCE s START WITH 1000
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-synonym-statement"></a>
##### 3.6.3.8. CREATE SYNONYM

A `SYNONYM` or `ALIAS` is an alternative name for an object, mostly a `TABLE` or `VIEW`, which can be used just like the actual name in any SQL statement. With a synonym `S_BOOK` for the table `BOOK`, for example, you can write the following query:

```sql
SELECT s_book.id FROM s_book
```

To create the synonym, write

```java
create.createSynonym("s").for_("t").execute();
```

To create a `PUBLIC` synonym, i.e. a synonym that doesn't belong to any schema or owner, write

```java
create.createPublicSynonym("s").for_("t").execute();
```

###### Dialect support

This example using jOOQ:

```java
createSynonym("s").for_("t")
```

Translates to the following dialect specific expressions:

###### DB2

```sql
CREATE ALIAS s FOR t
```

###### H2, HSQLDB, Hana, Informix, Oracle, SQLServer

```sql
CREATE SYNONYM s FOR t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-or-replace-synonym"></a>
###### 3.6.3.8.1. CREATE OR REPLACE SYNONYM

Many dialects support a convenient `OR REPLACE` clause that allows for dropping any pre-existing synonym by the same name in a single statement.

```java
create.createOrReplaceSynonym("s").for_("t").execute();
```

###### Dialect support

This example using jOOQ:

```java
createOrReplaceSynonym("s").for_("t")
```

Translates to the following dialect specific expressions:

###### DB2

```sql
CREATE OR REPLACE ALIAS s FOR t
```

###### H2, Hana, Oracle

```sql
CREATE OR REPLACE SYNONYM s FOR t
```

###### SQLServer

```sql
DROP SYNONYM IF EXISTS s;
CREATE SYNONYM s FOR t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-statement"></a>
##### 3.6.3.9. CREATE TABLE

Arguably the most used DDL statement is the `CREATE TABLE` statement.

The following subsections discuss various usages of `CREATE TABLE`, as well as the relevant bits of meta data that can be added to a table.

<a id="create-table-columns"></a>
###### 3.6.3.9.1. Columns

All tables contain at least one column ([except for some esoteric cases in PostgreSQL](https://blog.jooq.org/creating-tables-dum-and-dee-in-postgresql/)), and all SQL dialects support creating such tables:

```java
// Create a new table with a column
create.createTable("table")
      .column("col1", INTEGER)
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createTable("table").column("col1", INTEGER)
```

Translates to the following dialect specific expressions:

###### Access, DB2, Firebird, Hana, Informix, Teradata

```sql
CREATE TABLE table (
  col1 integer
)
```

###### ASE, Sybase

```sql
CREATE TABLE table (
  col1 int NULL
)
```

###### Aurora MySQL, Aurora Postgres, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE table (
  col1 int
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE table (
  col1 int64
)
```

###### ClickHouse

```sql
CREATE TABLE table (
  col1 Nullable(integer)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE table (
  col1 int4
)
```

###### Databricks

```sql
CREATE TABLE table (
  col1 int
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE table (
  col1 number(10)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-nullability"></a>
###### 3.6.3.9.2. Nullability

Nullability is a property of a data type, and as such can be attached to the data type using various methods. The default nullability is RDBMS specific, so if you want to be vendor agnostic about nullability in your DDL, better always state it explicitly, for example:

```java
// Specify nullability on columns
create.createTable("table")
      .column("vendor_specific_default", INTEGER)
      .column("explicit_nullable", INTEGER.null_())
      .column("explicit_not_nullable", INTEGER.notNull())
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("vendor_specific_default", INTEGER)
      .column("explicit_nullable", INTEGER.null_())
      .column("explicit_not_nullable", INTEGER.notNull())
```

Translates to the following dialect specific expressions:

###### Access, DB2, Hana, Informix, Teradata

```sql
CREATE TABLE table (
  vendor_specific_default integer,
  explicit_nullable integer NULL,
  explicit_not_nullable integer NOT NULL
)
```

###### ASE, Sybase

```sql
CREATE TABLE table (
  vendor_specific_default int NULL,
  explicit_nullable int NULL,
  explicit_not_nullable int NOT NULL
)
```

###### Aurora MySQL, Aurora Postgres, DuckDB, Exasol, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Vertica, YugabyteDB

```sql
CREATE TABLE table (
  vendor_specific_default int,
  explicit_nullable int NULL,
  explicit_not_nullable int NOT NULL
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE table (
  vendor_specific_default int64,
  explicit_nullable int64,
  explicit_not_nullable int64 NOT NULL
)
```

###### ClickHouse

```sql
CREATE TABLE table (
  vendor_specific_default Nullable(integer),
  explicit_nullable Nullable(integer),
  explicit_not_nullable integer
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE table (
  vendor_specific_default int4,
  explicit_nullable int4 NULL,
  explicit_not_nullable int4 NOT NULL
)
```

###### Databricks

```sql
CREATE TABLE table (
  vendor_specific_default int,
  explicit_nullable int,
  explicit_not_nullable int NOT NULL
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Firebird

```sql
CREATE TABLE table (
  vendor_specific_default integer,
  explicit_nullable integer,
  explicit_not_nullable integer NOT NULL
)
```

###### H2, HSQLDB

```sql
CREATE TABLE table (
  vendor_specific_default int,
  explicit_nullable int,
  explicit_not_nullable int NOT NULL
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE table (
  vendor_specific_default number(10),
  explicit_nullable number(10) NULL,
  explicit_not_nullable number(10) NOT NULL
)
```

###### Trino

```sql
CREATE TABLE table (
  vendor_specific_default int,
  explicit_nullable int,
  explicit_not_nullable int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-default"></a>
###### 3.6.3.9.3. Defaults

The `DEFAULT` expression on a column definition defines what value the column should contain if it is omitted in an [INSERT statement](#insert-statement), or if an explicit `DEFAULT` expression is used in [INSERT](#insert-default-values) or [UPDATE](#update-statement). By default, this is `NULL` in most dialects

```java
// Create a new table with a column with a default expression
create.createTable("table")
      .column("column1", INTEGER.default_(1))
      .execute();
```

To trigger this `DEFAULT` expression, you can run this, for example:

```java
// Insert a row using the default expression
create.insertInto(table(name("table"))).defaultValues().execute();
```

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("column1", INTEGER.default_(1))
```

Translates to the following dialect specific expressions:

###### Access, DB2, Firebird, Hana, Informix, Teradata

```sql
CREATE TABLE table (
  column1 integer DEFAULT 1
)
```

###### ASE

```sql
CREATE TABLE table (
  column1 int DEFAULT 1 NULL
)
```

###### Aurora MySQL, Aurora Postgres, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Vertica, YugabyteDB

```sql
CREATE TABLE table (
  column1 int DEFAULT 1
)
```

###### BigQuery

```sql
CREATE TABLE table (
  column1 int64 DEFAULT 1
)
```

###### ClickHouse

```sql
CREATE TABLE table (
  column1 Nullable(integer) DEFAULT 1
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE table (
  column1 int4 DEFAULT 1
)
```

###### Databricks

```sql
CREATE TABLE table (
  column1 int DEFAULT 1
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE table (
  column1 number(10) DEFAULT 1
)
```

###### Spanner

```sql
CREATE TABLE table (
  column1 int64 DEFAULT (1)
)
```

###### SQLite

```sql
CREATE TABLE table (
  column1 int DEFAULT (1)
)
```

###### Sybase

```sql
CREATE TABLE table (
  column1 int NULL DEFAULT 1
)
```

###### Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-identity"></a>
###### 3.6.3.9.4. Identities

An `IDENTITY` is a special type of [DEFAULT](#create-table-default) on a column, which is computed only on [INSERT](#insert-statement), and should usually not be replaced by user content. It computes a new value for a surrogate key. Most dialects default to using some [system sequence](#create-sequence-statement) based `IDENTITY`, though a `UUID` or some other unique value might work as well.

In jOOQ, it is currently only possible to specify whether a column is an `IDENTITY` at all, not to influence the value generation algorithm.

```java
// Create a new table with a column with a default expression
create.createTable("table")
      .column("column1", INTEGER.generatedByDefaultAsIdentity())
      .execute();
```

Whether an `IDENTITY` also needs to be explicitly [NOT NULL](#create-table-nullability) or a [PRIMARY KEY](#create-table-primary-key) is vendor specific. Ideally, both of these properties are set as well on identities.

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("column1", INTEGER.generatedByDefaultAsIdentity())
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE table (
  column1 AUTOINCREMENT NOT NULL
)
```

###### ASE, Exasol

```sql
CREATE TABLE table (
  column1 int IDENTITY NOT NULL
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
CREATE TABLE table (
  column1 int NOT NULL AUTO_INCREMENT
)
```

###### Aurora Postgres

```sql
CREATE TABLE table (
  column1 SERIAL4 NOT NULL
)
```

###### CockroachDB

```sql
CREATE TABLE table (
  column1 int4 GENERATED BY DEFAULT AS IDENTITY NOT NULL
)
```

###### DB2, Firebird

```sql
CREATE TABLE table (
  column1 integer GENERATED BY DEFAULT AS IDENTITY NOT NULL
)
```

###### H2

```sql
CREATE TABLE table (
  column1 int NOT NULL GENERATED BY DEFAULT AS IDENTITY
)
```

###### Hana, Teradata

```sql
CREATE TABLE table (
  column1 integer NOT NULL GENERATED BY DEFAULT AS IDENTITY
)
```

###### HSQLDB

```sql
CREATE TABLE table (
  column1 int GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
)
```

###### Informix

```sql
CREATE TABLE table (
  column1 SERIAL NOT NULL
)
```

###### Oracle

```sql
CREATE TABLE table (
  column1 number(10) GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
)
```

###### Postgres, YugabyteDB

```sql
CREATE TABLE table (
  column1 int GENERATED BY DEFAULT AS IDENTITY NOT NULL
)
```

###### Redshift, SQLDataWarehouse, SQLServer

```sql
CREATE TABLE table (
  column1 int IDENTITY(1, 1) NOT NULL
)
```

###### Snowflake

```sql
CREATE TABLE table (
  column1 number(10) IDENTITY NOT NULL
)
```

###### SQLite

```sql
CREATE TABLE table (
  column1 integer PRIMARY KEY AUTOINCREMENT NOT NULL
)
```

###### Sybase

```sql
CREATE TABLE table (
  column1 int NOT NULL IDENTITY
)
```

###### Vertica

```sql
CREATE TABLE table (
  column1 IDENTITY(1, 1) NOT NULL
)
```

###### BigQuery, ClickHouse, Databricks, DuckDB, Spanner, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-computed-columns"></a>
###### 3.6.3.9.5. Computed columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

[Computed columns](#computed-columns), sometimes also called "virtual" columns, are columns that are generated from an expression based on other columns of the same row directly in the database. They cannot be written to, but may be used in projections, filters, and even [indexes](#create-index-statement), as a complement or replacement of function based indexes.

Like any other data type modifying flag, the generator expression can be passed to the data type in jOOQ when creating such a table with computed columns:

###### Dialect support

This example using jOOQ:

```java
createTable(name("x"))
   .column(name("interest"), DOUBLE)
   .column(name("interest_percent"), VARCHAR.generatedAlwaysAs(field(name("interest"), DOUBLE).times(100.0).concat(" %")))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
CREATE TABLE x (
  interest double precision,
  interest_percent varchar GENERATED ALWAYS AS ((cast(
    (interest * cast(1E2 AS double precision))
    AS varchar
  ) || ' %')) STORED
)
```

###### ClickHouse

```sql
CREATE TABLE x (
  interest Nullable(double),
  interest_percent Nullable(String) MATERIALIZED (cast(
    (interest * 1E2)
    AS Nullable(String)
  ) || ' %')
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE x (
  interest double precision,
  interest_percent string GENERATED ALWAYS AS ((cast(
    (interest * cast(
      1E2
      AS double precision
    ))
    AS string
  ) || ' %')) STORED
)
```

###### Databricks

```sql
CREATE TABLE x (
  interest double,
  interest_percent varchar(2147483647) GENERATED ALWAYS AS ((cast(
    (interest * 1E2)
    AS varchar(2147483647)
  ) || ' %'))
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2

```sql
CREATE TABLE x (
  interest double,
  interest_percent varchar(32672) GENERATED ALWAYS AS ((cast(
    (interest * cast(1E2 AS double))
    AS varchar(32672)
  ) || ' %'))
)
```

###### DuckDB, Hana

```sql
CREATE TABLE x (
  interest double,
  interest_percent varchar GENERATED ALWAYS AS ((cast(
    (interest * 1E2)
    AS varchar
  ) || ' %'))
)
```

###### Firebird

```sql
CREATE TABLE x (
  interest double precision,
  interest_percent varchar(4000) GENERATED ALWAYS AS ((cast(
    (interest * cast(1E2 AS double precision))
    AS varchar(4000)
  ) || ' %'))
)
```

###### H2

```sql
CREATE TABLE x (
  interest double,
  interest_percent varchar AS ((cast(
    (interest * cast(
      1E2
      AS double
    ))
    AS varchar
  ) || ' %'))
)
```

###### HSQLDB

```sql
CREATE TABLE x (
  interest double,
  interest_percent varchar(32672) GENERATED ALWAYS AS ((cast(
    (interest * 1E2)
    AS varchar(32672)
  ) || ' %'))
)
```

###### MariaDB, MySQL

```sql
CREATE TABLE x (
  interest double,
  interest_percent text GENERATED ALWAYS AS (concat(
    cast(
      (interest * 1E2)
      AS char
    ),
    ' %'
  ))
)
```

###### Oracle

```sql
CREATE TABLE x (
  interest float,
  interest_percent varchar2(4000) GENERATED ALWAYS AS ((cast(
    (interest * 1E2)
    AS varchar2(4000)
  ) || ' %'))
)
```

###### Spanner

```sql
CREATE TABLE x (
  interest float64,
  interest_percent string(2621440) AS ((cast(
    (interest * 1E2)
    AS string
  ) || ' %'))
)
```

###### SQLServer

```sql
CREATE TABLE x (
  interest float,
  interest_percent AS (cast(
    (interest * cast(1E2 AS float))
    AS varchar(max)
  ) + ' %')
)
```

###### ASE, Access, Aurora MySQL, BigQuery, Exasol, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-primary-key"></a>
###### 3.6.3.9.6. Primary key

In a [normalised database](https://en.wikipedia.org/wiki/Database_normalization), all tables should have a `PRIMARY KEY`. In jOOQ, numerous features are enabled by tables that have one, including for example [UpdatableRecords](#crud-with-updatablerecords). To create a table with a primary key, write any of these:

```java
// Create a new table with columns and unnamed constraints
create.createTable("table")
      .column("column1", INTEGER)
      .primaryKey("column1")
      .execute();

// Equivalent to the above
create.createTable("table")
      .column("column1", INTEGER)
      .constraints(
          primaryKey("column1")
      )
      .execute();

// Create a new table with columns and named constraints (recommended if you want to alter the constraint)
create.createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("pk").primaryKey("column1")
      )
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("pk").primaryKey("column1")
      )
```

Translates to the following dialect specific expressions:

###### Access, Firebird, Hana

```sql
CREATE TABLE table (
  column1 integer,
  CONSTRAINT pk PRIMARY KEY (column1)
)
```

###### ASE, MariaDB, MemSQL, MySQL, SQLServer

```sql
CREATE TABLE table (
  column1 int NOT NULL,
  CONSTRAINT pk PRIMARY KEY (column1)
)
```

###### Aurora MySQL, Aurora Postgres, DuckDB, Exasol, H2, HSQLDB, Postgres, Redshift, SQLite, YugabyteDB

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT pk PRIMARY KEY (column1)
)
```

###### BigQuery

```sql
CREATE TABLE table (
  column1 int64,
  PRIMARY KEY (column1) NOT ENFORCED
)
```

###### ClickHouse

```sql
CREATE TABLE table (
  column1 integer,
  PRIMARY KEY (column1)
)
ENGINE MergeTree()
SETTINGS enable_block_number_column = 1, enable_block_offset_column = 1
```

###### CockroachDB

```sql
CREATE TABLE table (
  column1 int4,
  CONSTRAINT pk PRIMARY KEY (column1)
)
```

###### Databricks

```sql
CREATE TABLE table (
  column1 int NOT NULL,
  CONSTRAINT pk PRIMARY KEY (column1)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, Teradata

```sql
CREATE TABLE table (
  column1 integer NOT NULL,
  CONSTRAINT pk PRIMARY KEY (column1)
)
```

###### Informix

```sql
CREATE TABLE table (
  column1 integer,
  PRIMARY KEY (column1) CONSTRAINT pk
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE table (
  column1 number(10),
  CONSTRAINT pk PRIMARY KEY (column1)
)
```

###### Spanner

```sql
CREATE TABLE table (
  column1 int64
)
PRIMARY KEY (column1)
```

###### SQLDataWarehouse

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT pk PRIMARY KEY NONCLUSTERED (column1) NOT ENFORCED
)
```

###### Sybase

```sql
CREATE TABLE table (
  column1 int NULL,
  CONSTRAINT pk PRIMARY KEY (column1)
)
```

###### Trino

```sql
CREATE TABLE table (
  column1 int
)
```

###### Vertica

```sql
CREATE TABLE table (
  column1 int,
  dummy int,
  CONSTRAINT pk PRIMARY KEY (column1)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-unique"></a>
###### 3.6.3.9.7. Unique constraints

A candidate key that is not ideal for a [Primary key](#create-table-primary-key) should still be declared `UNIQUE` to enforce uniqueness, as well as for query performance reasons. In jOOQ, this can be done with the following approaches:

```java
// Create a new table with columns and unnamed constraints
create.createTable("table")
      .column("column1", INTEGER)
      .column("column2", INTEGER)
      .column("column3", INTEGER)
      .unique("column1")
      .unique("column2", "column3")
      .execute();

// Equivalent to the above
create.createTable("table")
      .column("column1", INTEGER)
      .column("column2", INTEGER)
      .column("column3", INTEGER)
      .constraints(
          unique("column1"),
          unique("column2", "column3")
      )
      .execute();

// Create a new table with columns and named constraints (recommended if you want to alter the constraint)
create.createTable("table")
      .column("column1", INTEGER)
      .column("column2", INTEGER)
      .column("column3", INTEGER)
      .constraints(
          constraint("uk1").unique("column1"),
          constraint("uk2").unique("column2", "column3")
      )
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("uk").unique("column1")
      )
```

Translates to the following dialect specific expressions:

###### Access, DB2, Firebird, Hana, Teradata

```sql
CREATE TABLE table (
  column1 integer,
  CONSTRAINT uk UNIQUE (column1)
)
```

###### ASE, Sybase

```sql
CREATE TABLE table (
  column1 int NULL,
  CONSTRAINT uk UNIQUE (column1)
)
```

###### Aurora MySQL, Aurora Postgres, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLServer, SQLite, Vertica, YugabyteDB

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT uk UNIQUE (column1)
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE table (
  column1 int64
)
```

###### ClickHouse

```sql
CREATE TABLE table (
  column1 Nullable(integer)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE table (
  column1 int4,
  CONSTRAINT uk UNIQUE (column1)
)
```

###### Databricks

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT uk UNIQUE (column1)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Informix

```sql
CREATE TABLE table (
  column1 integer,
  UNIQUE (column1) CONSTRAINT uk
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE table (
  column1 number(10),
  CONSTRAINT uk UNIQUE (column1)
)
```

###### SQLDataWarehouse

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT uk UNIQUE (column1) NOT ENFORCED
)
```

###### Trino

```sql
CREATE TABLE table (
  column1 int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-foreign-key"></a>
###### 3.6.3.9.8. Foreign keys

A foreign key is a tool that helps further [normalise your database](https://en.wikipedia.org/wiki/Database_normalization) by guaranteeing that a referenced value exists in a parent table. In our [sample database](#sample-database), it enforces the integrity of the `BOOK.AUTHOR_ID` reference. Besides integrity, it can be a very useful tool for optimising more sophisticated execution plans, e.g. to support [JOIN elimination](https://blog.jooq.org/join-elimination-an-essential-optimiser-feature-for-advanced-sql-usage/). In jOOQ, create foreign keys like this:

```java
// Create a new table with columns and unnamed constraints
create.createTable("table")
      .column("column1", INTEGER)
      .constraints(
          foreignKey("column1").references("other_table", "other_column1")
      )
      .execute();

// Create a new table with columns and named constraints (recommended if you want to alter the constraint)
create.createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("fk").foreignKey("column1").references("other_table", "other_column1")
      )
      .execute();
```

jOOQ's code generator will pick up foreign keys for a variety of purposes, including navigational methods, the [ON KEY joins](#join-predicate-on-key)and most prominently, the very powerful [implicit joins](#implicit-join).

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("fk").foreignKey("column1").references("other_table", "other_column1")
      )
```

Translates to the following dialect specific expressions:

###### Access, DB2, Firebird, Hana, Teradata

```sql
CREATE TABLE table (
  column1 integer,
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1)
)
```

###### ASE, Sybase

```sql
CREATE TABLE table (
  column1 int NULL,
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1)
)
```

###### Aurora MySQL, Aurora Postgres, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLServer, SQLite, Vertica, YugabyteDB

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1)
)
```

###### BigQuery

```sql
CREATE TABLE table (
  column1 int64,
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1) NOT ENFORCED
)
```

###### ClickHouse

```sql
CREATE TABLE table (
  column1 Nullable(integer)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE table (
  column1 int4,
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1)
)
```

###### Databricks

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Informix

```sql
CREATE TABLE table (
  column1 integer,
  FOREIGN KEY (column1) REFERENCES other_table (other_column1) CONSTRAINT fk
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE table (
  column1 number(10),
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1)
)
```

###### Spanner

```sql
CREATE TABLE table (
  column1 int64,
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1)
)
```

###### SQLDataWarehouse

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT fk FOREIGN KEY (column1) REFERENCES other_table (other_column1) NOT ENFORCED
)
```

###### Trino

```sql
CREATE TABLE table (
  column1 int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-check"></a>
###### 3.6.3.9.9. Check constraints

A `CHECK` constraint is a simple, yet very effective means of enforcing data integrity on a row basis. Want to ensure a number is only ever positive? Use a `CHECK` constraint(or even a [DOMAIN](#create-domain-statement) that contains a `CHECK` constraint).

```java
// Create a new table with columns and unnamed constraints
create.createTable("table")
      .column("column1", INTEGER)
      .check(field(name("column1"), INTEGER).gt(0))
      .execute();

// Equivalent to the above
create.createTable("table")
      .column("column1", INTEGER)
      .constraints(
          check(field(name("column1"), INTEGER).gt(0))
      )
      .execute();

// Create a new table with columns and named constraints (recommended if you want to alter the constraint)
create.createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("chk").check(field(name("column1"), INTEGER).gt(0))
      )
      .execute();
```

Just like the previous constraints, this one can be used by the optimiser to remove some redundant predicates, [see e.g. this blog post](https://blog.jooq.org/10-cool-sql-optimisations-that-do-not-depend-on-the-cost-model/).

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("chk").check(field(name("column1"), INTEGER).gt(0))
      )
```

Translates to the following dialect specific expressions:

###### Access, DB2, Firebird, Hana, Teradata

```sql
CREATE TABLE table (
  column1 integer,
  CONSTRAINT chk CHECK (column1 > 0)
)
```

###### ASE, Sybase

```sql
CREATE TABLE table (
  column1 int NULL,
  CONSTRAINT chk CHECK (column1 > 0)
)
```

###### Aurora Postgres, DuckDB, H2, HSQLDB, MariaDB, MySQL, Postgres, SQLServer, SQLite, Vertica, YugabyteDB

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT chk CHECK (column1 > 0)
)
```

###### ClickHouse

```sql
CREATE TABLE table (
  column1 Nullable(integer),
  CONSTRAINT chk CHECK (column1 > 0)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE table (
  column1 int4,
  CONSTRAINT chk CHECK (column1 > 0)
)
```

###### Informix

```sql
CREATE TABLE table (
  column1 integer,
  CHECK (column1 > 0) CONSTRAINT chk
)
```

###### Oracle

```sql
CREATE TABLE table (
  column1 number(10),
  CONSTRAINT chk CHECK (column1 > 0)
)
```

###### Spanner

```sql
CREATE TABLE table (
  column1 int64,
  CONSTRAINT chk CHECK (column1 > 0)
)
```

###### Aurora MySQL, BigQuery, Databricks, Exasol, MemSQL, Redshift, SQLDataWarehouse, Snowflake, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-constraint-enforcement"></a>
###### 3.6.3.9.10. Constraint enforcement

Some RDBMS support disabling constraints, or removing constraint enforcement, respectively. This can be useful for various purposes:

- Simplify data migrations
- Speed up querying while maintaining descriptive meta data (e.g. in data warehouses)
- Tooling interactions

jOOQ supports specifying whether a constraint should be enforced or not using the `ENFORCED` and `NOT ENFORCED` keywords.

> [!TIP]
> Not all RDBMS support constraint enforcement for all constraint types. Please check your RDBMS manual for details about support.

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("chk").check(field(name("column1"), INTEGER).gt(0)).notEnforced()
      )
```

Translates to the following dialect specific expressions:

###### DB2, Hana

```sql
CREATE TABLE table (
  column1 integer,
  CONSTRAINT chk CHECK (column1 > 0) NOT ENFORCED
)
```

###### Informix

```sql
CREATE TABLE table (
  column1 integer,
  CHECK (column1 > 0) CONSTRAINT chk DISABLED
)
```

###### MySQL, Postgres

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT chk CHECK (column1 > 0) NOT ENFORCED
)
```

###### Oracle

```sql
CREATE TABLE table (
  column1 number(10),
  CONSTRAINT chk CHECK (column1 > 0) DISABLE
)
```

###### Vertica

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT chk CHECK (column1 > 0) DISABLED
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, MariaDB, MemSQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-constraint-deferrability"></a>
###### 3.6.3.9.11. Constraint deferrability

Some RDBMS support deferring the enforcement of constraints. This can be useful for various purposes:

- Simplify data migrations
- Speed up querying while maintaining descriptive meta data (e.g. in data warehouses)
- Tooling interactions

This is generally a safer alternative to [turning off enforcement entirely](#create-table-constraint-enforcement) as it affects only local transaction scope. Some RDBMS even allow for overriding the constraint's property on a per-transaction basis using the [SET CONSTRAINTS statement](#set-constraints-statement).

jOOQ supports specifying whether a constraint should be immediately enforced or not using the `DEFERRABLE` and `DEFERRED` keywords.

> [!TIP]
> Not all RDBMS support constraint deferrability for all constraint types. Please check your RDBMS manual for details about support.

###### Dialect support

This example using jOOQ:

```java
createTable("table")
      .column("column1", INTEGER)
      .constraints(
          constraint("chk").check(field(name("column1"), INTEGER).gt(0)).deferrable().initiallyDeferred()
      )
```

Translates to the following dialect specific expressions:

###### Hana

```sql
CREATE TABLE table (
  column1 integer,
  CONSTRAINT chk CHECK (column1 > 0) INITIALLY DEFERRED
)
```

###### Oracle

```sql
CREATE TABLE table (
  column1 number(10),
  CONSTRAINT chk CHECK (column1 > 0) DEFERRABLE INITIALLY DEFERRED
)
```

###### Postgres, SQLite, YugabyteDB

```sql
CREATE TABLE table (
  column1 int,
  CONSTRAINT chk CHECK (column1 > 0) DEFERRABLE INITIALLY DEFERRED
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-as-select"></a>
###### 3.6.3.9.12. From a SELECT

Occasionally, creating a table from a [SELECT statement](#select-statement) is very useful, copying the source table's data types and data.

```java
// Create a new table from a source SELECT statement
create.createTable("book_archive")
      .as(select(BOOK.ID, BOOK.TITLE).from(BOOK))
      .execute();

// Create a new table from a source SELECT statement and specify that data should be included, explicitly
create.createTable("book_archive")
      .as(select(BOOK.ID, BOOK.TITLE).from(BOOK))
      .withData()
      .execute();

// Create a new table from a source SELECT statement and specify that data should be excluded, explicitly
create.createTable("book_archive")
      .as(select(BOOK.ID, BOOK.TITLE).from(BOOK))
      .withNoData()
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createTable("book_archive")
      .as(select(BOOK.ID, BOOK.TITLE).from(BOOK))
      .withNoData()
```

Translates to the following dialect specific expressions:

###### ASE, Access, SQLDataWarehouse, SQLServer

```sql
SELECT BOOK.ID, BOOK.TITLE
INTO book_archive
FROM BOOK
WHERE 1 = 0
```

###### Aurora MySQL, MemSQL, Oracle, Redshift, SQLite, Vertica

```sql
CREATE TABLE book_archive
AS
SELECT BOOK.ID, BOOK.TITLE
FROM BOOK
WHERE 1 = 0
```

###### Aurora Postgres, Exasol, Postgres, YugabyteDB

```sql
CREATE TABLE book_archive
AS
SELECT BOOK.ID, BOOK.TITLE
FROM BOOK
WITH NO DATA
```

###### BigQuery

```sql
CREATE TABLE book_archive
AS (
  SELECT BOOK.ID, BOOK.TITLE
  FROM BOOK
  WHERE FALSE
)
```

###### CockroachDB, DuckDB, H2, MariaDB, MySQL, Snowflake

```sql
CREATE TABLE book_archive
AS
SELECT BOOK.ID, BOOK.TITLE
FROM BOOK
WHERE FALSE
```

###### Databricks

```sql
CREATE TABLE book_archive
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
AS
SELECT BOOK.ID, BOOK.TITLE
FROM BOOK
WHERE FALSE
```

###### DB2

```sql
CREATE TABLE book_archive
AS (
  SELECT BOOK.ID, BOOK.TITLE
  FROM BOOK
) WITH NO DATA
```

###### HSQLDB, Hana

```sql
CREATE TABLE book_archive
AS (
  SELECT BOOK.ID, BOOK.TITLE
  FROM BOOK
)
WITH NO DATA
```

###### Teradata

```sql
CREATE TABLE book_archive
AS (
  SELECT BOOK.ID, BOOK.TITLE
  FROM BOOK
  WHERE 1 = 0
)
WITH DATA
```

###### ClickHouse, Firebird, Informix, Spanner, Sybase, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-global-temporary"></a>
###### 3.6.3.9.13. Global temporary tables

A `GLOBAL TEMPORARY` table is a table whose meta data is shared among all sessions or transaction, but where each session or transaction contains its own data. It acts like a table with a session or transaction based [policy](#policies) enabled, starting from jOOQ 3.19.

```java
// Create a new temporary table
create.createGlobalTemporaryTable("book_archive")
      .column("column1", INTEGER)
      .execute();
```

Historically, jOOQ also supported the `CREATE TEMPORARY TABLE` syntax via [`DSLContext.createTemporaryTable(Table)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#createTemporaryTable(org.jooq.Table)) (without explicit `GLOBAL` or `LOCAL` keyword):

```java
// Create a new temporary table
create.createTemporaryTable("book_archive")
      .column("column1", INTEGER)
      .execute();
```

- `GLOBAL TEMPORARY` if it's supported by a dialect
- `LOCAL TEMPORARY` otherwise

> [!TIP]
> This alternative syntax is still supported, but no longer recommended with jOOQ 3.21, as the two types of temporary tables work quite differently.

###### Dialect support

This example using jOOQ:

```java
createGlobalTemporaryTable("book_archive")
      .column("column1", INTEGER)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres

```sql
CREATE TEMPORARY TABLE book_archive (
  column1 int
)
```

###### DB2, Firebird, Hana, Teradata

```sql
CREATE GLOBAL TEMPORARY TABLE book_archive (
  column1 integer
)
```

###### H2, Vertica

```sql
CREATE GLOBAL TEMPORARY TABLE book_archive (
  column1 int
)
```

###### MemSQL

```sql
CREATE ROWSTORE GLOBAL TEMPORARY TABLE book_archive (
  column1 int
)
```

###### Oracle

```sql
CREATE GLOBAL TEMPORARY TABLE book_archive (
  column1 number(10)
)
```

###### SQLServer

```sql
CREATE TABLE ##book_archive (
  column1 int
)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, HSQLDB, Informix, MariaDB, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-table-local-temporary"></a>
###### 3.6.3.9.14. Local temporary tables

A `LOCAL TEMPORARY` table is a table whose meta data and data are local to a session or transaction.

```java
// Create a new temporary table
create.createLocalTemporaryTable("book_archive")
      .column("column1", INTEGER)
      .execute();
```

> [!TIP]
> The SQL standard also specifies a `LOCAL TEMPORARY` syntax with a different semantics, where the locality is with respect to a "SQL module," not a session or transaction. Many RDBMS use the keyword `LOCAL` with a different meaning from the standard, and thus jOOQ follows the implementations here, not the standard.

Historically, jOOQ also supported the `CREATE TEMPORARY TABLE` syntax via [`DSLContext.createTemporaryTable(Table)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#createTemporaryTable(org.jooq.Table)) (without explicit `GLOBAL` or `LOCAL` keyword):

```java
// Create a new temporary table
create.createTemporaryTable("book_archive")
      .column("column1", INTEGER)
      .execute();
```

- `GLOBAL TEMPORARY` if it's supported by a dialect
- `LOCAL TEMPORARY` otherwise

> [!TIP]
> This alternative syntax is still supported, but no longer recommended with jOOQ 3.21, as the two types of temporary tables work quite differently.

###### Dialect support

This example using jOOQ:

```java
createLocalTemporaryTable("book_archive")
      .column("column1", INTEGER)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, DuckDB, MariaDB, MemSQL, MySQL, Redshift, Vertica, YugabyteDB

```sql
CREATE TEMPORARY TABLE book_archive (
  column1 int
)
```

###### BigQuery

```sql
CREATE TEMPORARY TABLE book_archive (
  column1 int64
)
```

###### ClickHouse

```sql
CREATE TEMPORARY TABLE book_archive (
  column1 Nullable(integer)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TEMPORARY TABLE book_archive (
  column1 int4
)
```

###### DB2

```sql
DECLARE GLOBAL TEMPORARY TABLE book_archive (
  column1 integer
)
```

###### H2

```sql
CREATE LOCAL TEMPORARY TABLE book_archive (
  column1 int
)
```

###### Hana

```sql
CREATE LOCAL TEMPORARY TABLE book_archive (
  column1 integer
)
```

###### Oracle

```sql
CREATE PRIVATE TEMPORARY TABLE book_archive (
  column1 number(10)
)
```

###### Snowflake

```sql
CREATE TEMPORARY TABLE book_archive (
  column1 number(10)
)
```

###### SQLServer

```sql
CREATE TABLE #book_archive (
  column1 int
)
```

###### ASE, Access, Aurora Postgres, Databricks, Exasol, Firebird, HSQLDB, Informix, Postgres, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-trigger-statement"></a>
##### 3.6.3.10. CREATE TRIGGER

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Most dialects support triggers, which is SQL or procedural logic that executes at certain events to perform actions including:

- Changing the data about to be inserted or updated (e.g. when a column `DEFAULT` in a [table definition](#create-table-statement) doesn't do the trick)
- Performing additional integrity checks prior to any DML statement (e.g. when a `CHECK` constraint doesn't suffice)
- Logging extra data, such as audit data.
- Etc.

<a id="create-trigger-statement-events"></a>
###### 3.6.3.10.1. Events

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Most dialects supporting triggers can fire ...

- `BEFORE`
- `AFTER`
- `INSTEAD OF`

... a certain event, including ...

- `INSERT`
- `UPDATE`
- `DELETE`

Note that the above refer to events, not the statements, meaning that a trigger may fire also for [the MERGE statement](#merge-statement).

Some examples illustrating possible triggers:

```java
create.createTrigger("trg1")
      .beforeInsert()
      .on(BOOK)
      .forEachRow()
      .as(insertInto(LOG).columns(LOG.TEXT).values("Row inserted in BOOK"))
      .execute();

create.createTrigger("trg")
      .beforeUpdate()
      .on(BOOK)
      .forEachRow()
      .as(insertInto(LOG).columns(LOG.TEXT).values("Row updated in BOOK"))
      .execute();

create.createTrigger("trg")
      .beforeDelete()
      .on(BOOK)
      .forEachRow()
      .as(insertInto(LOG).columns(LOG.TEXT).values("Row deleted in BOOK"))
      .execute();

create.createTrigger("trg")
      .beforeInsert().orUpdate().orDelete()
      .on(BOOK)
      .forEachRow()
      .as(insertInto(LOG).columns(LOG.TEXT).values("Row inserted or updated or deleted in BOOK"))
      .execute();
```

<a id="create-trigger-statement-referencing"></a>
###### 3.6.3.10.2. REFERENCING clause

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A trigger is executed while a data mutation is being executed. During this time, it is possible for a trigger to see a [row or table's](#create-trigger-statement-statement-vs-row) state before (`OLD` pseudo table) or after (`NEW` pseudo table) the modification. Specifically:

- `INSERT`: Only `NEW` is available
- `UPDATE`: Both `OLD` and `NEW` are available
- `DELETE`: Only `OLD` is available

In the rare event when the default `OLD` or `NEW` pseudo table identifiers conflict with actual tables in the schema, the `REFERENCING` clause can be used to rename these identifiers for the scope of a trigger. In some dialects, `REFERENCING` is always mandatory, and in others, it's not supported at all.

An example would be

```java
 // A trigger that prevents the update of NULL titles in BOOK
create.createTrigger("trg")
      .beforeUpdate().of(BOOK.TITLE)
      .on(BOOK)
      .referencingOldAs("o")
      .referencingNewAs("n")
      .forEachRow()
      .as(if_(BOOK.as("o").TITLE.isNull()).then(
            variable(BOOK.as("n").TITLE.getQualifiedName(), BOOK.TITLE.getDataType()).setNull()
      ))
      .execute();
```

<a id="create-trigger-statement-statement-vs-row"></a>
###### 3.6.3.10.3. STATEMENT vs ROW triggers

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A trigger can choose whether it fires only once for entire sets of data being changed (`FOR EACH STATEMENT`), or for each individual row (`FOR EACH ROW`). The specific semantics of each of these clauses, and what's possible to do with each is vendor specific. Please refer to your database manual to see what's possible here.

An example of such triggers:

```java
create.createTrigger("trg")
      .beforeInsert()
      .on(BOOK)
      .forEachRow()
      .as(insertInto(LOG).columns(LOG.TEXT).values("Row inserted in BOOK"))
      .execute();

create.createTrigger("trg")
      .beforeInsert()
      .on(BOOK)
      .forEachStatement()
      .as(insertInto(LOG).columns(LOG.TEXT).values("Rows inserted in BOOK"))
      .execute();
```

<a id="create-trigger-statement-when"></a>
###### 3.6.3.10.4. WHEN clause

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A trigger can specify a filter, which helps avoid context switching, etc. when the trigger does not need to be fired. This can be achieved with the `WHEN` clause, which can access the `OLD` and `NEW` pseudo table columns, see also [the REFERENCING clause](#create-trigger-statement-referencing).

```java
create.createTrigger("trg")
      .beforeInsert()
      .on(BOOK)
      .referencingNewAs("n")
      .forEachRow()
      .when(BOOK.as("n").TITLE.isNotNull())
      .as(insertInto(LOG).columns(LOG.TEXT).values("Row inserted in BOOK"))
      .execute();
```

<a id="create-type-statement"></a>
##### 3.6.3.11. CREATE TYPE .. AS ENUM

jOOQ supports creating PostgreSQL `ENUM` types:

```java
// Create a new ENUM type
create.createType("weekday")
      .asEnum("mon", "tue", "wed", "thu", "fri", "sat", "sun")
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createType("t").asEnum("a", "b", "c")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, Postgres, YugabyteDB

```sql
CREATE TYPE t AS ENUM ('a', 'b', 'c')
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-composite-type-statement"></a>
##### 3.6.3.12. CREATE TYPE .. AS OBJECT

jOOQ supports creating standard SQL composite types

```java
// Create a new ENUM type
create.createType("point")
      .as(field("x", INTEGER), field("y", INTEGER))
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createType("point").as(field("x", INTEGER), field("y", INTEGER))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
CREATE TYPE point AS (
  x int,
  y int
)
```

###### CockroachDB

```sql
CREATE TYPE point AS (
  x int4,
  y int4
)
```

###### DuckDB

```sql
CREATE TYPE point AS STRUCT (
  x int,
  y int
)
```

###### Oracle

```sql
CREATE TYPE point AS OBJECT (
  x number(10),
  y number(10)
)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-view-statement"></a>
##### 3.6.3.13. CREATE VIEW

This statement allows for creating a `VIEW` in the database catalog:

```java
// Create a new view
create.createView("books_and_authors", "author_id", "first_name", "last_name", "book_id", "title")
      .as(select(AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, BOOK.ID, BOOK.TITLE)
          .from(AUTHOR)
          .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID)))
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createView("a", "id").as(select(AUTHOR.ID).from(AUTHOR))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica, YugabyteDB

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
```

###### ClickHouse, MemSQL

```sql
CREATE VIEW a
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID id
  FROM AUTHOR
) t
```

###### Spanner

```sql
CREATE VIEW a
SQL SECURITY INVOKER
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID id
  FROM AUTHOR
) t
```

###### Trino

```sql
CREATE VIEW a
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID
  FROM AUTHOR
) t (id)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-or-replace-view"></a>
###### 3.6.3.13.1. CREATE OR REPLACE VIEW

Many dialects support a convenient `OR REPLACE` clause that allows for dropping any pre-existing view by the same name in a single statement.

```java
// Create a new view
create.createOrReplaceView("early_authors", "author_id", "first_name", "last_name")
      .as(select(AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
          .from(AUTHOR)

          // Any inserted or updated authors must continue to satisfy this condition
          .where(AUTHOR.ID.lt(200)))
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createOrReplaceView("a", "id").as(select(AUTHOR.ID).from(AUTHOR))
```

Translates to the following dialect specific expressions:

###### ASE, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, Hana, MariaDB, MySQL, Oracle, Postgres, Redshift, Vertica, YugabyteDB

```sql
CREATE OR REPLACE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
```

###### ClickHouse

```sql
CREATE OR REPLACE VIEW a
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID id
  FROM AUTHOR
) t
```

###### Firebird, SQLServer

```sql
CREATE OR ALTER VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
```

###### Spanner

```sql
CREATE OR REPLACE VIEW a
SQL SECURITY INVOKER
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID id
  FROM AUTHOR
) t
```

###### Teradata

```sql
REPLACE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
```

###### Trino

```sql
CREATE OR REPLACE VIEW a
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID
  FROM AUTHOR
) t (id)
```

###### Access, Aurora MySQL, HSQLDB, Informix, MemSQL, SQLDataWarehouse, SQLite, Snowflake, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-view-with-check-option"></a>
###### 3.6.3.13.2. WITH CHECK OPTION

A [CREATE VIEW](#create-view-statement) statement of an updatable view can have a `WITH CHECK OPTION` clause appended to it, to make sure that any [INSERT](#insert-statement) or [UPDATE](#update-statement) statement will produce rows that are also visible through this view.

```java
// Create a new view
create.createView("early_authors", "author_id", "first_name", "last_name")
      .as(select(AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
          .from(AUTHOR)

          // Any inserted or updated authors must continue to satisfy this condition
          .where(AUTHOR.ID.lt(200))

          // The flag is set on the Select object, not the view
          .withCheckOption())
      .execute();
```

> [!TIP]
> The flag is set on the `SELECT` object, not the `CREATE VIEW` statement, as it is also made available to inline views.

###### Dialect support

This example using jOOQ:

```java
createView("a", "id").as(select(AUTHOR.ID).from(AUTHOR).withCheckOption())
```

Translates to the following dialect specific expressions:

###### ASE, DB2, Firebird, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, SQLServer, Sybase, Teradata

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
WITH CHECK OPTION
```

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-view-with-read-only"></a>
###### 3.6.3.13.3. WITH READ ONLY

A [CREATE VIEW](#create-view-statement) statement of an updatable view can have a `WITH READ ONLY` clause appended to it, to make sure that it cannot be updated.

```java
// Create a new view
create.createView("authors", "author_id", "first_name", "last_name")
      .as(select(AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
          .from(AUTHOR)
          .withReadOnly())
      .execute();
```

> [!TIP]
> The flag is set on the `SELECT` object, not the `CREATE VIEW` statement, as it is also made available to inline views.

###### Dialect support

This example using jOOQ:

```java
createView("a", "id").as(select(AUTHOR.ID).from(AUTHOR).withReadOnly())
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
FROM (
  SELECT count(*) dual
  FROM MSysResources
) AS dual
WHERE 1 = 0
```

###### ASE, Redshift, SQLDataWarehouse, SQLServer, SQLite, Vertica

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
WHERE 1 = 0
```

###### Aurora MySQL

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
FROM DUAL
WHERE 1 = 0
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT cast(NULL AS int)
WHERE FALSE
```

###### BigQuery

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION DISTINCT
SELECT cast(NULL AS int64)
FROM UNNEST([STRUCT(1 AS dual)]) AS dual
WHERE FALSE
```

###### CockroachDB, H2, MariaDB, MySQL, Snowflake

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
WHERE FALSE
```

###### DB2

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
FROM SYSIBM.DUAL
WHERE 1 = 0
```

###### Exasol

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
FROM DUAL
WHERE FALSE
```

###### Firebird

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
FROM RDB$DATABASE
WHERE 1 = 0
```

###### Hana, Oracle

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
WITH READ ONLY
```

###### HSQLDB

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT cast(NULL AS int)
FROM (VALUES (1)) AS dual (dual)
WHERE FALSE
```

###### Informix

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
FROM (
  SELECT 1 AS dual
  FROM systables
  WHERE (tabid = 1)
) AS dual
WHERE 1 = 0
```

###### MemSQL

```sql
CREATE VIEW a
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID id
  FROM AUTHOR
  UNION
  SELECT NULL
  FROM DUAL
  WHERE 1 = 0
) t
```

###### Spanner

```sql
CREATE VIEW a
SQL SECURITY INVOKER
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID id
  FROM AUTHOR
  UNION DISTINCT
  SELECT cast(NULL AS int64)
  FROM UNNEST([STRUCT(1 AS dual)]) AS dual
  WHERE FALSE
) t
```

###### Sybase

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
FROM SYS.DUMMY
WHERE 1 = 0
```

###### Teradata

```sql
CREATE VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
UNION
SELECT NULL
FROM (
  SELECT 1 AS "dual"
) AS "dual"
WHERE 1 = 0
```

###### ClickHouse, Databricks, DuckDB, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="create-materialized-view"></a>
###### 3.6.3.13.4. MATERIALIZED

A `VIEW` can be marked as `MATERIALIZED`, which means that its data as defined by `SELECT * FROM view` is stored on disk for faster retrieval, and synchronised with underlying tables either immediately when those tables are changed (similar to an index), or upon request (similar to a cache that is allowed to be stale).

```java
// Create a new view
create.createMaterializedView("authors", "author_id", "first_name", "last_name")
      .as(select(AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
          .from(AUTHOR))
      .execute();
```

###### Dialect support

This example using jOOQ:

```java
createMaterializedView("a", "id").as(select(AUTHOR.ID).from(AUTHOR))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Oracle, Postgres, Snowflake, Sybase, YugabyteDB

```sql
CREATE MATERIALIZED VIEW a(id)
AS
SELECT AUTHOR.ID
FROM AUTHOR
```

###### BigQuery

```sql
CREATE MATERIALIZED VIEW a
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID id
  FROM AUTHOR
) t
```

###### Databricks, Redshift

```sql
CREATE MATERIALIZED VIEW a
AS
SELECT t.id
FROM (
  SELECT AUTHOR.ID
  FROM AUTHOR
) t (id)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-statement"></a>
#### 3.6.4. The DROP statement

The `DROP` statement is used to drop objects from the database catalog.

<a id="drop-database-statement"></a>
##### 3.6.4.1. DROP DATABASE

This statement is used to drop a `DATABASE`.

```java
// Drop a database
create.dropDatabase("database").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropDatabase("t")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, ClickHouse, CockroachDB, MariaDB, MemSQL, MySQL, Postgres, SQLDataWarehouse, SQLServer, Snowflake, YugabyteDB

```sql
DROP DATABASE t
```

###### Databricks

```sql
DROP CATALOG t CASCADE
```

###### ASE, Access, Aurora MySQL, BigQuery, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Redshift, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-database-if-exists"></a>
###### 3.6.4.1.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a database
create.dropDatabaseIfExists("database").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropDatabaseIfExists("database")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, ClickHouse, CockroachDB, MariaDB, MemSQL, MySQL, Postgres, Snowflake, YugabyteDB

```sql
DROP DATABASE IF EXISTS database
```

###### Databricks

```sql
DROP CATALOG IF EXISTS database CASCADE
```

###### SQLDataWarehouse

```sql
BEGIN TRY
  DROP DATABASE database
END TRY
BEGIN CATCH
  IF error_number() NOT IN (2714) BEGIN
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
  END;
END CATCH
```

###### SQLServer

```sql
BEGIN TRY
  DROP DATABASE database
END TRY
BEGIN CATCH
  IF error_number() NOT IN (2714) THROW;
END CATCH
```

###### ASE, Access, Aurora MySQL, BigQuery, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Redshift, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-domain-statement"></a>
##### 3.6.4.2. DROP DOMAIN

The `DROP DOMAIN` statement allows for droping [DOMAIN](#domain-data-types) types.

```java
create.dropDomain("d").execute();
```

###### CASCADE

It is possible to supply a `CASCADE` or `RESTRICT` clause, explicitly

```java
// Specify the CASCADE / RESTRICT clauses explicitly
create.dropDomain("d").cascade().execute();
create.dropDomain("d").restrict().execute();
```

Please refer to your database manual for an understanding of the semantics of `CASCADE` (e.g. in PostgreSQL, all referencing columns are dropped!)

###### Dialect support

This example using jOOQ:

```java
dropDomain("d")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Firebird, H2, HSQLDB, Oracle, Postgres, YugabyteDB

```sql
DROP DOMAIN d
```

###### SQLServer

```sql
DROP TYPE d
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-domain-if-exists"></a>
###### 3.6.4.2.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a domain
create.dropDomainIfExists("d").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropDomainIfExists("d")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, HSQLDB, Oracle, Postgres, YugabyteDB

```sql
DROP DOMAIN IF EXISTS d
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    DROP DOMAIN d
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### SQLServer

```sql
DROP TYPE IF EXISTS d
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-function-statement"></a>
##### 3.6.4.3. DROP FUNCTION

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This statement is used to drop a `FUNCTION` from the database catalog.

```java
// Drop a function
create.dropFunction("func").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropFunction("f")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, SQLDataWarehouse, SQLServer, Vertica, YugabyteDB

```sql
DROP FUNCTION f
```

###### Trino

```sql
DROP FUNCTION f()
```

###### ASE, Access, Aurora MySQL, ClickHouse, DuckDB, H2, MemSQL, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-function-if-exists"></a>
###### 3.6.4.3.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a function
create.dropFunctionIfExists("func").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropFunctionIfExists("func")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, Databricks, Exasol, HSQLDB, Informix, MariaDB, MySQL, Oracle, Postgres, SQLServer, Vertica, YugabyteDB

```sql
DROP FUNCTION IF EXISTS func
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP FUNCTION func
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    DROP FUNCTION func
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Trino

```sql
DROP FUNCTION IF EXISTS func()
```

###### ASE, Access, Aurora MySQL, ClickHouse, DuckDB, H2, Hana, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-function-specific-signature"></a>
###### 3.6.4.3.2. DROP FUNCTION with signature

When working with a dialect that supports `FUNCTION` overloading, the [DROP FUNCTION statement](#drop-function-statement) may need to be supplied with an explicit function signature, similar to the signature provided with the [CREATE FUNCTION statement](#create-function-statement). Some dialects may require only a list of parameter types without parameter names. jOOQ's API requires passing the complete parameter specification instead.

```java
// Drop a function
create.dropFunction("proc").parameters(in("p1", INTEGER), in("p2", INTEGER)).execute();
```

###### Dialect support

This example using jOOQ:

```java
dropFunction("p").parameters(in("p1", INTEGER), in("p2", INTEGER))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Exasol, Postgres, Vertica, YugabyteDB

```sql
DROP FUNCTION p(
  p1 int,
  p2 int
)
```

###### BigQuery, Databricks, Firebird, HSQLDB, Hana, MariaDB, MySQL, Oracle, SQLDataWarehouse, SQLServer

```sql
DROP FUNCTION p
```

###### CockroachDB

```sql
DROP FUNCTION p(
  p1 int4,
  p2 int4
)
```

###### DB2, Informix

```sql
DROP FUNCTION p(
  integer,
  integer
)
```

###### Trino

```sql
DROP FUNCTION p(
  int,
  int
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DuckDB, H2, MemSQL, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-index-statement"></a>
##### 3.6.4.4. DROP INDEX

This statement is used to drop an `INDEX` from the database catalog.

```java
// Drop an index (for indexes stored in the schema namespace, i.e. most dialects)
create.dropIndex("index").execute();

// Drop an index (for indexes stored in the table namespace, e.g. MySQL, SQL Server)
create.dropIndex("index").on("table").execute();
```

###### CASCADE

It is possible to supply a `CASCADE` or `RESTRICT` clause, explicitly

```java
// Specify the CASCADE / RESTRICT clauses explicitly
create.dropIndex("index").cascade().execute();
create.dropIndex("index").restrict().execute();
```

###### Dialect support

This example using jOOQ:

```java
dropIndex("i")
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, YugabyteDB

```sql
DROP INDEX i
```

###### ClickHouse

```sql
ALTER TABLE  DROP INDEX i
```

###### BigQuery, Databricks, Exasol, Redshift, Snowflake, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-index-if-exists"></a>
###### 3.6.4.4.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop an index
create.dropIndexIfExists("index").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropIndexIfExists("index")
```

Translates to the following dialect specific expressions:

###### Access

```sql
DROP INDEX index
```

###### Aurora Postgres, CockroachDB, DuckDB, H2, HSQLDB, Informix, MariaDB, Oracle, Postgres, SQLite, Spanner, Sybase, YugabyteDB

```sql
DROP INDEX IF EXISTS index
```

###### ClickHouse

```sql
ALTER TABLE  DROP INDEX IF EXISTS index
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP INDEX index
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    DROP INDEX index
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 261 BEGIN END;
  EXECUTE IMMEDIATE '
    DROP INDEX index
  ';
END;
```

###### MySQL

```sql
CREATE PROCEDURE block_1794083325375_8760950()
MODIFIES SQL DATA
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' BEGIN END;
  DROP INDEX index;
END;
CALL block_1794083325375_8760950();
DROP PROCEDURE block_1794083325375_8760950;
```

###### SQLDataWarehouse

```sql
BEGIN TRY
  DROP INDEX index
END TRY
BEGIN CATCH
  IF error_number() NOT IN (3701) BEGIN
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
  END;
END CATCH
```

###### SQLServer

```sql
BEGIN TRY
  DROP INDEX index
END TRY
BEGIN CATCH
  IF error_number() NOT IN (3701) THROW;
END CATCH
```

###### ASE, Aurora MySQL, BigQuery, Databricks, Exasol, MemSQL, Redshift, Snowflake, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-procedure-statement"></a>
##### 3.6.4.5. DROP PROCEDURE

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This statement is used to drop a `PROCEDURE` from the database catalog.

```java
// Drop a procedure
create.dropProcedure("proc").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropProcedure("p")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Firebird, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, SQLDataWarehouse, SQLServer, YugabyteDB

```sql
DROP PROCEDURE p
```

###### Snowflake

```sql
DROP PROCEDURE p()
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, H2, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-procedure-if-exists"></a>
###### 3.6.4.5.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a procedure
create.dropProcedureIfExists("procedure").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropProcedureIfExists("procedure")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, HSQLDB, Informix, MariaDB, MySQL, Oracle, Postgres, SQLServer, YugabyteDB

```sql
DROP PROCEDURE IF EXISTS procedure
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP PROCEDURE procedure
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    DROP PROCEDURE procedure
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Snowflake

```sql
DROP PROCEDURE IF EXISTS procedure()
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, H2, Hana, MemSQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-procedure-specific-signature"></a>
###### 3.6.4.5.2. DROP PROCEDURE with signature

When working with a dialect that supports `PROCEDURE` overloading, the [DROP PROCEDURE statement](#drop-procedure-statement) may need to be supplied with an explicit procedure signature, similar to the signature provided with the [CREATE PROCEDURE statement](#create-procedure-statement). Some dialects may require only a list of parameter types without parameter names. jOOQ's API requires passing the complete parameter specification instead.

```java
// Drop a procedure
create.dropProcedure("proc").parameters(in("p1", INTEGER), in("p2", INTEGER)).execute();
```

###### Dialect support

This example using jOOQ:

```java
dropProcedure("p").parameters(in("p1", INTEGER), in("p2", INTEGER))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
DROP PROCEDURE p(
  p1 int,
  p2 int
)
```

###### BigQuery, Firebird, HSQLDB, Hana, MariaDB, MySQL, Oracle, SQLDataWarehouse, SQLServer

```sql
DROP PROCEDURE p
```

###### CockroachDB

```sql
DROP PROCEDURE p(
  p1 int4,
  p2 int4
)
```

###### DB2, Informix

```sql
DROP PROCEDURE p(
  integer,
  integer
)
```

###### Snowflake

```sql
DROP PROCEDURE p(
  number,
  number
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, H2, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-schema-statement"></a>
##### 3.6.4.6. DROP SCHEMA

This statement is used to drop a `SCHEMA` from the database catalog.

```java
// Drop a schema
create.dropSchema("schema").execute();
```

###### CASCADE

It is possible to supply a `CASCADE` or `RESTRICT` clause, explicitly

```java
// Specify the CASCADE / RESTRICT clauses explicitly
create.dropSchema("schema").cascade().execute();
create.dropSchema("schema").restrict().execute();
```

###### Dialect support

This example using jOOQ:

```java
dropSchema("s")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Vertica, YugabyteDB

```sql
DROP SCHEMA s
```

###### ClickHouse

```sql
DROP DATABASE s
```

###### DB2

```sql
DROP SCHEMA s RESTRICT
```

###### Oracle

```sql
DROP USER s
```

###### ASE, Access, Aurora MySQL, BigQuery, Firebird, Informix, SQLite, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-schema-if-exists"></a>
###### 3.6.4.6.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a schema
create.dropSchemaIfExists("schema").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropSchemaIfExists("schema")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Spanner, Vertica, YugabyteDB

```sql
DROP SCHEMA IF EXISTS schema
```

###### ClickHouse

```sql
DROP DATABASE IF EXISTS schema
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP SCHEMA schema RESTRICT
  ';
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 362 BEGIN END;
  EXECUTE IMMEDIATE '
    DROP SCHEMA schema
  ';
END;
```

###### Oracle

```sql
DROP USER IF EXISTS schema
```

###### SQLDataWarehouse

```sql
BEGIN TRY
  DROP SCHEMA schema
END TRY
BEGIN CATCH
  IF error_number() NOT IN (15151) BEGIN
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
  END;
END CATCH
```

###### SQLServer

```sql
BEGIN TRY
  DROP SCHEMA schema
END TRY
BEGIN CATCH
  IF error_number() NOT IN (15151) THROW;
END CATCH
```

###### ASE, Access, Aurora MySQL, BigQuery, Firebird, Informix, SQLite, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-sequence-statement"></a>
##### 3.6.4.7. DROP SEQUENCE

This statement is used to drop a `SEQUENCE` from the database catalog.

```java
// Drop a sequence
create.dropSequence("sequence").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropSequence("s")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, Oracle, Postgres, SQLServer, Snowflake, Spanner, Sybase, Vertica, YugabyteDB

```sql
DROP SEQUENCE s
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-sequence-if-exists"></a>
###### 3.6.4.7.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a sequence
create.dropSequenceIfExists("sequence").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropSequenceIfExists("sequence")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, HSQLDB, Informix, MariaDB, Oracle, Postgres, Snowflake, Spanner, Vertica, YugabyteDB

```sql
DROP SEQUENCE IF EXISTS sequence
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP SEQUENCE sequence
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    DROP SEQUENCE sequence
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 313 BEGIN END;
  EXECUTE IMMEDIATE '
    DROP SEQUENCE sequence
  ';
END;
```

###### SQLServer

```sql
BEGIN TRY
  DROP SEQUENCE sequence
END TRY
BEGIN CATCH
  IF error_number() NOT IN (3701) THROW;
END CATCH
```

###### Sybase

```sql
BEGIN
  DROP SEQUENCE sequence;
EXCEPTION
  WHEN others THEN
END;
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-synonym-statement"></a>
##### 3.6.4.8. DROP SYNONYM

This statement is used to drop a `SYNONYM` from the database catalog.

```java
// Drop a synonym
create.dropSynonym("synonym").execute();
```

To drop a `PUBLIC` synonym, i.e. a synonym that doesn't belong to any schema or owner, write

```java
create.dropPublicSynonym("s").execute();
```

> [!TIP]
> Some RDBMS use a table namespace for synonyms, not a schema namespace. In those cases, add the optional `FOR` clause to the `DROP SYNONYM` statement.

###### Dialect support

This example using jOOQ:

```java
dropSynonym("s").for_("t")
```

Translates to the following dialect specific expressions:

###### DB2

```sql
DROP ALIAS s
```

###### H2, HSQLDB, Hana, Informix, Oracle, SQLServer

```sql
DROP SYNONYM s
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-synonym-if-exists"></a>
###### 3.6.4.8.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a synonym
create.dropSynonymIfExists("sequence").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropSynonymIfExists("sequence")
```

Translates to the following dialect specific expressions:

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP ALIAS sequence
  ';
END
```

###### H2, HSQLDB, Informix, Oracle, SQLServer

```sql
DROP SYNONYM IF EXISTS sequence
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 315 BEGIN END;
  EXECUTE IMMEDIATE '
    DROP SYNONYM sequence
  ';
END;
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-table-statement"></a>
##### 3.6.4.9. DROP TABLE

This statement is used to drop a `TABLE` from the database catalog.

```java
// Drop a table
create.dropTable("table").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropTable("t")
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
DROP TABLE t
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-table-cascade"></a>
###### 3.6.4.9.1. CASCADE

When dropping a table, the `CASCADE` clause extends the dropping to all dependent objects, including views, etc. The following two syntactic elements can be added to a `DROP TABLE` statement:

- `RESTRICT` (the default): The `DROP` operation should fail if there are any dependent objects, such as views.
- `CASCADE`: The `DROP` operation should succeed if there are any dependent objects, and drop those as well.

> [!TIP]
> This is a potentially very dangerous operation. While dropping dependent views seems reasonable, some RDMS may also drop dependent child tables if their `FOREIGN KEY` constraints point to the dropped table. Use the `CASCADE` clause with great care!

###### Dialect support

This example using jOOQ:

```java
dropTable("t").cascade()
```

Translates to the following dialect specific expressions:

###### CockroachDB, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, Postgres, Redshift, Snowflake, Vertica, YugabyteDB

```sql
DROP TABLE t CASCADE
```

###### Oracle

```sql
DROP TABLE t CASCADE CONSTRAINTS
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, Firebird, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-table-if-exists"></a>
###### 3.6.4.9.2. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a table
create.dropTableIfExists("table").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropTableIfExists("table")
```

Translates to the following dialect specific expressions:

###### Access

```sql
DROP TABLE table
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Sybase, Vertica, YugabyteDB

```sql
DROP TABLE IF EXISTS table
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP TABLE table
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    DROP TABLE table
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 259 BEGIN END;
  EXECUTE IMMEDIATE '
    DROP TABLE table
  ';
END;
```

###### SQLDataWarehouse

```sql
BEGIN TRY
  DROP TABLE table
END TRY
BEGIN CATCH
  IF error_number() NOT IN (3701) BEGIN
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
  END;
END CATCH
```

###### SQLServer

```sql
BEGIN TRY
  DROP TABLE table
END TRY
BEGIN CATCH
  IF error_number() NOT IN (3701) THROW;
END CATCH
```

###### ASE, ClickHouse, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-trigger-statement"></a>
##### 3.6.4.10. DROP TRIGGER

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This statement is used to drop a `TRIGGER` from the database catalog.

```java
// Drop a trigger
create.dropTrigger("trg").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropTrigger("t")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
DO $$
BEGIN
  DROP TRIGGER t;
  DROP FUNCTION t_function;
END;
$$
```

###### DB2, Firebird, HSQLDB, MariaDB, MySQL, Oracle, SQLServer, SQLite

```sql
DROP TRIGGER t
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-trigger-if-exists"></a>
###### 3.6.4.10.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a trigger
create.dropTriggerIfExists("trg").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropTriggerIfExists("type")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
DO $$
BEGIN
  DROP TRIGGER IF EXISTS type;
  DROP FUNCTION IF EXISTS type_function;
END;
$$
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP TRIGGER type
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    DROP TRIGGER type
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### MariaDB, MySQL, Oracle, SQLServer

```sql
DROP TRIGGER IF EXISTS type
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-type-statement"></a>
##### 3.6.4.11. DROP TYPE

This statement is used to drop a `TYPE` from the database catalog.

```java
// Drop a type
create.dropType("type").execute();
```

###### CASCADE

It is possible to supply a `CASCADE` or `RESTRICT` clause, explicitly

```java
// Specify the CASCADE / RESTRICT clauses explicitly
create.dropType("type").cascade().execute();
create.dropType("type").restrict().execute();
```

###### Dialect support

This example using jOOQ:

```java
dropType("t")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, Oracle, Postgres, YugabyteDB

```sql
DROP TYPE t
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-type-if-exists"></a>
###### 3.6.4.11.1. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a type
create.dropTypeIfExists("type").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropTypeIfExists("type")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, Oracle, Postgres, YugabyteDB

```sql
DROP TYPE IF EXISTS type
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-view-statement"></a>
##### 3.6.4.12. DROP VIEW

This statement is used to drop a `VIEW` from the database catalog.

```java
// Drop a view
create.dropView("view").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropView("v")
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
DROP VIEW v
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-view-cascade"></a>
###### 3.6.4.12.1. CASCADE

When dropping a view, the `CASCADE` clause extends the dropping to all dependent objects, including views, etc. The following two syntactic elements can be added to a `DROP VIEW` statement:

- `RESTRICT` (the default): The `DROP` operation should fail if there are any dependent objects, such as views.
- `CASCADE`: The `DROP` operation should succeed if there are any dependent objects, and drop those as well.

###### Dialect support

This example using jOOQ:

```java
dropView("v").cascade()
```

Translates to the following dialect specific expressions:

###### CockroachDB, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, Postgres, Redshift, YugabyteDB

```sql
DROP VIEW v CASCADE
```

###### Oracle

```sql
DROP VIEW v CASCADE CONSTRAINTS
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, Firebird, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="drop-view-if-exists"></a>
###### 3.6.4.12.2. IF EXISTS

For idempotent execution of DDL scripts, the useful `IF EXISTS` clause is supported by jOOQ, and emulated using an [anonymous, procedural block](#procedural-block) if possible.

```java
// Drop a view
create.dropViewIfExists("view").execute();
```

###### Dialect support

This example using jOOQ:

```java
dropViewIfExists("v")
```

Translates to the following dialect specific expressions:

###### Access

```sql
DROP VIEW v
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
DROP VIEW IF EXISTS v
```

###### DB2

```sql
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END;
  EXECUTE IMMEDIATE '
    DROP VIEW v
  ';
END
```

###### Firebird

```sql
EXECUTE BLOCK
AS
BEGIN
  EXECUTE STATEMENT '
    DROP VIEW v
  ';
  WHEN sqlcode -607 DO
    BEGIN END
END
```

###### Hana

```sql
DO BEGIN
  DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 321 BEGIN END;
  EXECUTE IMMEDIATE '
    DROP VIEW v
  ';
END;
```

###### SQLDataWarehouse

```sql
BEGIN TRY
  DROP VIEW v
END TRY
BEGIN CATCH
  IF error_number() NOT IN (3701) BEGIN
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
    DECLARE @ErrorState INT = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
  END;
END CATCH
```

###### SQLServer

```sql
BEGIN TRY
  DROP VIEW v
END TRY
BEGIN CATCH
  IF error_number() NOT IN (3701) THROW;
END CATCH
```

###### ASE, Snowflake, Teradata

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="grant-statement"></a>
#### 3.6.5. The GRANT statement

Databases that implement access control for their database catalog allow for using `GRANT` and [REVOKE](#revoke-statement) privileges from [`org.jooq.User`](https://www.jooq.org/javadoc/3.22.x/org/jooq/User.html) and [`org.jooq.Role`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Role.html) objects.

In jOOQ, this can be done as follows:

```java
// Define privileges
Privilege select = privilege("select");
Privilege insert = privilege("insert");
User user = user("user");

// Grant privileges to a given user or role
create.grant(select, insert).on(BOOK).to(user).execute();

// Grant privileges to a given user or role with the grant option
create.grant(select, insert).on(BOOK).to(user).withGrantOption().execute();

// Grant privileges to everyone
create.grant(select, insert).on(BOOK).toPublic().execute();
```

<a id="revoke-statement"></a>
#### 3.6.6. The REVOKE statement

Databases that implement access control for their database catalog allow for using [GRANT](#grant-statement) and `REVOKE` privileges from [`org.jooq.User`](https://www.jooq.org/javadoc/3.22.x/org/jooq/User.html) and [`org.jooq.Role`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Role.html) objects.

In jOOQ, this can be done as follows:

```java
// Define privileges
Privilege select = privilege("select");
Privilege insert = privilege("insert");
User user = user("user");

// Revoke privileges from a given user or role
create.revoke(select, insert).on(BOOK).from(user).execute();

// Revoke the grant option from a given user or role
create.revokeGrantOptionFor(select, insert).on(BOOK).from(user).execute();

// Revoke privileges from everyone
create.revoke(select, insert).on(BOOK).fromPublic().execute();
```

<a id="set-statement"></a>
#### 3.6.7. The SET statement

Most databases support a variety of `SET` statements to set session specific environment variables.

<a id="set-catalog-statement"></a>
##### 3.6.7.1. SET CATALOG

Depending on whether your database product supports [catalogs and schemas](#catalog-and-schema-expressions), the below `SET` statement may be supported to set the current session's catalog (e.g. the database).

```sql
SET CATALOG catalogname;
```

```java
create.setCatalog("catalogname").execute();
```

###### Dialect support

This example using jOOQ:

```java
setCatalog("c")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, ClickHouse, DuckDB, MariaDB, MemSQL, MySQL, SQLServer

```sql
USE c
```

###### Databricks

```sql
USE CATALOG c
```

###### Snowflake

```sql
USE DATABASE c
```

###### Teradata

```sql
DATABASE c
```

###### ASE, Access, Aurora Postgres, BigQuery, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLite, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="set-constraints-statement"></a>
##### 3.6.7.2. SET CONSTRAINTS

[Constraint deferrability](#create-table-constraint-deferrability) is a useful feature that allows for specifying the default deferrability mode on a constraint at data definition time. It is often useful to immediately enforce a constraint by default, but to defer enforcement for the scope of a single transaction that profits from disabling the constraint, e.g. to speed up certain data migration operations. This temporary session setting can be achieved with the `SET CONSTRAINTS` statement:

```sql
SET CONSTRAINTS constraint_name DEFERRED;
```

```java
create.setConstraints("constraint_name").deferred().execute();
```

See also [constraint enforcement](#create-table-constraint-enforcement) in `CREATE TABLE`.

###### Dialect support

This example using jOOQ:

```java
setConstraints("c").deferred()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Oracle, Postgres, YugabyteDB

```sql
SET CONSTRAINTS c DEFERRED
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="set-schema-statement"></a>
##### 3.6.7.3. SET SCHEMA

Depending on whether your database product supports [catalogs and schemas](#catalog-and-schema-expressions), the below `SET` statement may be supported to set the current session's schema.

```sql
SET SCHEMA schemaname;
```

```java
create.setSchema("schemaname").execute();
```

###### Dialect support

This example using jOOQ:

```java
setSchema("c")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, ClickHouse, DuckDB, MariaDB, MemSQL, MySQL

```sql
USE c
```

###### Aurora Postgres, CockroachDB, Postgres, Vertica, YugabyteDB

```sql
SET SEARCH_PATH = c
```

###### Databricks, Snowflake

```sql
USE SCHEMA c
```

###### DB2, H2, HSQLDB, Hana

```sql
SET SCHEMA c
```

###### Exasol

```sql
OPEN SCHEMA c
```

###### Oracle

```sql
ALTER SESSION SET CURRENT_SCHEMA = c
```

###### Teradata

```sql
DATABASE c
```

###### ASE, Access, BigQuery, Firebird, Informix, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="truncate-statement"></a>
#### 3.6.8. The TRUNCATE statement

Even if the `TRUNCATE` statement mainly modifies data, it is generally considered to be a DDL statement. It is popular in many databases when you want to bypass constraints for table truncation. Databases may behave differently, when a truncated table is referenced by other tables. For instance, they may fail if records from a truncated table are referenced, even with `ON DELETE CASCADE` clauses in place. Please, consider your database manual to learn more about its `TRUNCATE` implementation.

The `TRUNCATE` syntax is trivial:

```java
create.truncate(AUTHOR).execute();
```

`TRUNCATE` is not supported by all dialects. jOOQ will execute a `DELETE FROM AUTHOR` statement instead, which is roughly equivalent.

##### Dialect support

This example using jOOQ:

```java
truncate(AUTHOR)
```

Translates to the following dialect specific expressions:

###### Access, Firebird, SQLite, Teradata

```sql
DELETE FROM AUTHOR
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Trino, Vertica, YugabyteDB

```sql
TRUNCATE TABLE AUTHOR
```

###### DB2

```sql
TRUNCATE TABLE AUTHOR IMMEDIATE
```

###### Spanner

```sql
DELETE FROM AUTHOR
WHERE TRUE
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="generating-ddl"></a>
#### 3.6.9. Generating DDL from objects

When using jOOQ's [code generator](#code-generation), a whole set of meta data is generated with the generated artefacts, such as schemas, tables, columns, data types, constraints, default values, etc.

This meta data can be used to generate DDL `CREATE` statements in any SQL dialect, in order to partially restore the original schema again on a new database instance. This is particularly useful, for instance, when working with an Oracle production database, and an H2 in-memory test database. The following code produces the DDL for a schema:

```java
// SCHEMA is the generated schema that contains a reference to all generated tables
Queries ddl =
DSL.using(configuration)
   .ddl(SCHEMA);

for (Query query : ddl.queries()) {
    System.out.println(query);
}
```

When executing the above, you should see something like the following:

```java
create table "PUBLIC"."AUTHOR"(
  "ID" int not null,
  "FIRST_NAME" varchar(50) null,
  "LAST_NAME" varchar(50) not null,
  ...
  constraint "PK_AUTHOR"
    primary key ("ID")
)
create table "PUBLIC"."BOOK"(
  "ID" int not null,
  "AUTHOR_ID" int not null,
  "TITLE" varchar(400) not null,
  ...
  constraint "PK_BOOK"
    primary key ("ID")
)
...
alter table "PUBLIC"."BOOK"
  add constraint "FK_BOOK_AUTHOR_ID"
    foreign key ("AUTHOR_ID")
    references "AUTHOR" ("ID")
```

Do note that these features only restore *parts* of the original schema. For instance, vendor-specific storage clauses that are not available to jOOQ's generated meta data cannot be reproduced this way.

<a id="transactional-statements"></a>
### 3.7. Transactional statements

In addition to using the [transaction management](#transaction-management) API, which wraps JDBC or R2DBC transaction calls, it is possible to run explicit transactional statements directly as jOOQ [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html):

- Either by executing the [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html)
- Or by embedding it in a `procedural statement`, such as e.g. a [procedural block](#procedural-block)

All the standard SQL transactional statements are supported:

<a id="start-transaction-statement"></a>
#### 3.7.1. START TRANSACTION statement

In standard SQL, a `START TRANSACTION` statement can be issued in order to switch from a non-transactional session state to a transactional one. The standard mandates that an error should be raised if the session was already in a transaction. Implementations usually have a different opinion, including:

- Follow the SQL standard.
- Ignore the statement if a transaction exists.
- Support the statement only at the top level, not within a `procedural context`.
- Do not support the statement at all, always starting transactions implicitly.

jOOQ attempts to standardise on this behaviour in a way that it should be safe to always start a transaction, even if the statement is not supported, in case of which a no-op is generated.

> [!TIP]
> Depending on whether this statement is supported, dialects might treat [COMMIT](#commit-statement) and [ROLLBACK](#rollback-statement) as statements effectively ending a transaction, after which transactional code can only be executed after another explicit `START TRANSACTION` statement. This behaviour isn't standardised by jOOQ, it is recommended to always explicitly use `START TRANSACTION`.

##### Dialect support

This example using jOOQ:

```java
startTransaction()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, MariaDB, MemSQL, MySQL, Postgres, YugabyteDB

```sql
START TRANSACTION
```

###### DB2

```sql
BEGIN
END
```

###### Exasol

```sql
COMMIT
```

###### Firebird

```sql
EXECUTE BLOCK AS
BEGIN
END
```

###### H2, SQLDataWarehouse, SQLServer, SQLite, Teradata

```sql
BEGIN TRANSACTION
```

###### Hana

```sql
DO BEGIN
END;
```

###### HSQLDB

```sql
START TRANSACTION READ WRITE
```

###### Informix

```sql
BEGIN WORK
```

###### Oracle

```sql
BEGIN
  NULL;
END;
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Redshift, Snowflake, Spanner, Sybase, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="commit-statement"></a>
#### 3.7.2. COMMIT statement

The `COMMIT` statement commits all changes of the current transaction.

Depending on the dialect, this might end a transaction, possibly requiring a new [START TRANSACTION statement](#start-transaction-statement) to be issued.

##### Dialect support

This example using jOOQ:

```java
commit()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, SQLDataWarehouse, SQLServer, SQLite, YugabyteDB

```sql
COMMIT
```

###### Teradata

```sql
END TRANSACTION
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Redshift, Snowflake, Spanner, Sybase, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="rollback-statement"></a>
#### 3.7.3. ROLLBACK statement

The `ROLLBACK` statement reverts all changes of the current transaction.

Depending on the dialect, this might end a transaction, possibly requiring a new [START TRANSACTION statement](#start-transaction-statement) to be issued.

##### Dialect support

This example using jOOQ:

```java
rollback()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, SQLDataWarehouse, SQLServer, SQLite, Teradata, YugabyteDB

```sql
ROLLBACK
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Redshift, Snowflake, Spanner, Sybase, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

##### ROLLBACK TO SAVEPOINT

If the current transaction has active [SAVEPOINTs](#savepoint-statement), then those can be rolled back to instead of to the beginning of the transaction.

##### Dialect support

This example using jOOQ:

```java
rollback().toSavepoint("s")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, SQLite, YugabyteDB

```sql
ROLLBACK TO SAVEPOINT s
```

###### SQLDataWarehouse, SQLServer

```sql
ROLLBACK TRANSACTION s
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, Redshift, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="savepoint-statement"></a>
#### 3.7.4. SAVEPOINT statement

Most dialects support the `SAVEPOINT` statement, which allows for applying a marker in the middle of a transaction, to which the transaction can rollback using the [ROLLBACK TO SAVEPOINT statement](#rollback-statement)

##### Dialect support

This example using jOOQ:

```java
savepoint("s")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, SQLite, YugabyteDB

```sql
SAVEPOINT s
```

###### DB2

```sql
SAVEPOINT s ON ROLLBACK RETAIN CURSORS
```

###### SQLDataWarehouse, SQLServer

```sql
SAVE TRANSACTION s
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, Redshift, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="release-savepoint-statement"></a>
#### 3.7.5. RELEASE SAVEPOINT statement

Most dialects support the [SAVEPOINT statement](#savepoint-statement). Instead of committing savepoints (which act as nested transactions, a `SAVEPOINT` can be released using the `RELEASE SAVEPOINT` statement, when it is no longer needed.

##### Dialect support

This example using jOOQ:

```java
releaseSavepoint("s")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, SQLite, YugabyteDB

```sql
RELEASE SAVEPOINT s
```

###### SQLDataWarehouse, SQLServer

```sql
BEGIN
  IF 1 = 0 SELECT 1;
END;
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, Redshift, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-statements"></a>
### 3.8. Procedural statements

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Most RDBMS support some sort of procedural language that allows for running imperative code inside of the database. The syntax of these languages is often similar, and hence it is supported and standardised by jOOQ as well.

In some databases, the procedural language can exist in the form of anonymous blocks, i.e. ad-hoc programs that are interpreted (or compiled) on the fly. In most RDBMS, however, the main approach to using the procedural languages is to store the procedural logic in stored procedures or functions, such that they can be pre-compiled and translated to native code for performance reasons.

The jOOQ API currently supports anonymous blocks only. In some dialects where anonymous blocks are not supported, a procedure is stored, called, and dropped again as an emulation.

An example of an anonymous block that inserts values 1 - 10 into a table:

```sql
-- PL/SQL syntax
BEGIN
  FOR i IN 1 .. 10 LOOP
    INSERT INTO t (col) VALUES (i);
  END LOOP;
END;
```

```java
Variable<Integer> i = var(name("i"), INTEGER);
create.begin(
  for_(i).in(1, 10).loop(
    insertInto(T).columns(T.COL).values(i)
  )
).execute();
```

The entire loop is executed on the server, which may greatly help reduce client server round trips.

Apart from the [block statement](#procedural-block), this feature set is available only in our commercial distributions.

<a id="procedural-block"></a>
#### 3.8.1. Block statement

The most basic building block in procedural languages is the block statement, which allows for creating scope (except for T-SQL, which has no block scope), and for logically grouping related statement together. Just like in Java, where any set of statements can be grouped using curly braces: `{ statement1; statement2; }`, in procedural languages, usually, the keywords `BEGIN` and `END` are used to delimit a block. For example:

```sql
BEGIN
  INSERT INTO t (col) VALUES (1);
  INSERT INTO t (col) VALUES (2);
END;
```

```java
create.begin(
  insertInto(T).columns(T.COL).values(1),
  insertInto(T).columns(T.COL).values(2)
).execute();
```

Notice how jOOQ's [`DSLContext.begin(Statement...)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#begin(org.jooq.Statement...)) takes an ordinary varargs array (or collection) of [`org.jooq.Statement`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Statement.html) as an argument. As such, the statements are comma separated, not semi colon separated. Also, it is important that statements passed to the procedural API do not call the [`Query.execute()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html#execute()) method, as that would execute a statement in the client, rather than embedding a statement expression in a block.

Just like in SQL, such blocks can be nested with any depth, e.g.

```sql
BEGIN
  BEGIN
    INSERT INTO t (col) VALUES (1);
    INSERT INTO t (col) VALUES (2);
  END;
  BEGIN
    INSERT INTO t (col) VALUES (3);
    INSERT INTO t (col) VALUES (4);
  END;
END;
```

```java
create.begin(
  begin(
    insertInto(T).columns(T.COL).values(1),
    insertInto(T).columns(T.COL).values(2)
  ),
  begin(
    insertInto(T).columns(T.COL).values(3),
    insertInto(T).columns(T.COL).values(4)
  )
).execute();
```

##### Client side "blocks"

In some cases, it may be desireable to group several statements in a "block" in the client only, without producing the `BEGIN` and `END` keywords on the server, in case it is not needed. This can be done using [`DSLContext.statements(Statement...)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#statements(org.jooq.Statement...)).

```sql
INSERT INTO t (col) VALUES (1);
INSERT INTO t (col) VALUES (2);
 
```

```java
statements(
  insertInto(T).columns(T.COL).values(1),
  insertInto(T).columns(T.COL).values(2))
```

This API is useful whenever you want to group several statements into one logical [`org.jooq.Statement`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Statement.html) and let jOOQ figure out if `BEGIN .. END` block syntax is required or not. If it is required, then they are added - e.g. when the block is executed on the top level, or nested inside an [IF statement](#procedural-if), in case the `IF` statement doesn't already have its own `THEN` keyword to delimit multi-statement content.

##### Block execution

[`org.jooq.Block`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Block.html) extends [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html), which in turn extends [`org.jooq.Statement`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Statement.html). A `Query` is a statement that can be executed on its own, as a standalone executable.

All other [`org.jooq.Statement`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Statement.html) types (as explained in the following sections) cannot be executed on their own. For example, it makes no sense to execute a [GOTO statement](#procedural-goto) outside of a statement block.

##### Dialect support

This example using jOOQ:

```java
begin(deleteFrom(BOOK), deleteFrom(AUTHOR))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
DO $$
BEGIN
  DELETE FROM BOOK;
  DELETE FROM AUTHOR;
END;
$$
```

###### BigQuery

```sql
BEGIN
  DELETE FROM BOOK
  WHERE TRUE;
  DELETE FROM AUTHOR
  WHERE TRUE;
END;
```

###### DB2, Trino

```sql
BEGIN
  DELETE FROM BOOK;
  DELETE FROM AUTHOR;
END
```

###### Exasol, Informix, Oracle, SQLDataWarehouse, SQLServer, Snowflake, Teradata, Vertica

```sql
BEGIN
  DELETE FROM BOOK;
  DELETE FROM AUTHOR;
END;
```

###### Firebird

```sql
EXECUTE BLOCK AS
BEGIN
  DELETE FROM BOOK;
  DELETE FROM AUTHOR;
END
```

###### H2

```sql
CREATE ALIAS block_1794083324732_7827936 AS $$
  void x(Connection c) throws SQLException {
    try (PreparedStatement s = c.prepareStatement(
      "DELETE FROM BOOK"
    )) {
      s.execute();
    }
    try (PreparedStatement s = c.prepareStatement(
      "DELETE FROM AUTHOR"
    )) {
      s.execute();
    }
  }
$$;
CALL block_1794083324732_7827936();
DROP ALIAS block_1794083324732_7827936;
```

###### Hana

```sql
DO BEGIN
  DELETE FROM BOOK;
  DELETE FROM AUTHOR;
END;
```

###### HSQLDB

```sql
BEGIN ATOMIC
  DELETE FROM BOOK;
  DELETE FROM AUTHOR;
END;
```

###### MariaDB

```sql
BEGIN NOT ATOMIC
  DELETE FROM BOOK;
  DELETE FROM AUTHOR;
END;
```

###### MySQL

```sql
CREATE PROCEDURE block_1794083325376_8141903()
MODIFIES SQL DATA
BEGIN
  DELETE FROM BOOK;
  DELETE FROM AUTHOR;
END;
CALL block_1794083325376_8141903();
DROP PROCEDURE block_1794083325376_8141903;
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, MemSQL, Redshift, SQLite, Spanner, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-call"></a>
#### 3.8.2. CALL statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

When using [CREATE PROCEDURE statements](#create-procedure-statement), for greater composability, it is essential to be able to call a procedure from another procedure. This is done using the `CALL` statement.

```java
// Create a procedure that inserts a log message in a table
Parameter<String> message = in("message", VARCHAR);

create.createProcedure("log")
      .parameters(message)
      .as(insertInto(LOG).columns(LOG.TEXT).values(message))
      .execute();

create.createProcedure("some_other_procedure")
      .as(
      // ...
      call("log").args(val("My first message")),
      // ...
      call("log").args(val("My second message"))
      // ...
      )
      .execute();
```

##### Dialect support

This example using jOOQ:

```java
call("log").args(val("message"))
```

Translates to the following dialect specific expressions:

###### BigQuery, DB2, HSQLDB, Hana, MariaDB, MySQL, Postgres, Snowflake, YugabyteDB

```sql
CALL log('message')
```

###### Firebird, Informix

```sql
EXECUTE PROCEDURE log('message')
```

###### Oracle

```sql
BEGIN
  log('message');
END;
```

###### SQLDataWarehouse, SQLServer

```sql
EXEC log 'message'
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-continue"></a>
#### 3.8.3. CONTINUE statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A safer way to jump to labels than via [GOTO](#procedural-goto) is to use [EXIT](#procedural-exit) (jumping out of a [LOOP](#procedural-loop), or [block](#procedural-block), or other statement) or [CONTINUE](#procedural-continue) (skipping a [LOOP iteration](#procedural-loop)).

Just like Java's `continue`, the `CONTINUE` statement skips the rest of the current iteration in a loop and continues the next iteration. Some dialects use the `ITERATE` statement for this.

**Without a label**

```sql
-- PL/SQL
LOOP
  i := i + 1;
  CONTINUE WHEN i <= 10;
END LOOP;
```

```java
// All dialects
loop(
  i.set(i.plus(1)),
  continueWhen(i.gt(10))
)
```

**With a label**

```sql
-- PL/SQL
<<label>>
LOOP
  i := i + 1;
  CONTINUE label WHEN i <= 10;
END LOOP;
```

```java
// All dialects
Label label = label("label");
label.label(loop(
  i.set(i.plus(1)),
  continue(label).when(i.le(10))
))
```

Notice that `continue` is a reserved keyword in the Java language, so the jOOQ API cannot use it as a method name. We've suffixed such conflicts with an underscore: `continue_()`.

##### Dialect support

This example using jOOQ:

```java
loop(i.set(i.plus(1)), continueWhen(i.gt(10)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Oracle, Postgres, YugabyteDB

```sql
LOOP
  i := (i + 1);
  CONTINUE WHEN i > 10;
END LOOP
```

###### BigQuery

```sql
LOOP
  SET i = (i + 1);
  IF i > 10 THEN
    CONTINUE;
  END IF;
END LOOP
```

###### DB2, HSQLDB, MariaDB, MySQL, Trino

```sql
alias_1:
LOOP
  SET i = (i + 1);
  IF i > 10 THEN
    ITERATE alias_1;
  END IF;
END LOOP
```

###### H2

```sql
for (;;) {
  i = (i + 1);
  if (i > 10) {
    continue;
  }
}
```

###### Hana

```sql
WHILE 1 = 1 DO
  i = (i + 1);
  IF i > 10 THEN
    CONTINUE;
  END IF;
END WHILE
```

###### Informix

```sql
LOOP
  LET i = (i + 1);
  IF i > 10 THEN
    CONTINUE;
  END IF;
END LOOP
```

###### Snowflake

```sql
LOOP
  i := (:i + 1);
  IF (:i > 10) THEN
    CONTINUE;
  END IF;
END LOOP
```

###### SQLDataWarehouse, SQLServer

```sql
WHILE 1 = 1 BEGIN
  SET @i = (@i + 1);
  IF @i > 10
    CONTINUE;
END
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, Firebird, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-execute"></a>
#### 3.8.4. EXECUTE statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Many dialects support some way of running dynamic SQL from procedural code. For this, the `EXECUTE` or `EXECUTE IMMEDIATE` statements can be used.

In some dialects (e.g. Oracle PL/SQL), using `EXECUTE` is the only way to run DDL from procedural code.

For example:

```sql
-- PL/SQL
BEGIN
  EXECUTE IMMEDIATE 'CREATE TABLE t (col int)';
END;
```

```java
// All dialects
create.begin(
  execute(createTable("t").column("col", INTEGER).getSQL())
).excute();
```

You could obviously just pass an arbitrary string to the `EXECUTE` statement, as in PL/SQL, but the above example shows how to use this approach also with dynamically created jOOQ statements, by calling [`Query.getSQL()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html#getSQL()).

##### Dialect support

This example using jOOQ:

```java
execute("create table t (i int)")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
EXECUTE 'create table t (i int)'
```

###### BigQuery, DB2, Hana, MariaDB, Oracle, Snowflake

```sql
EXECUTE IMMEDIATE 'create table t (i int)'
```

###### Firebird

```sql
EXECUTE STATEMENT 'create table t (i int)'
```

###### MySQL

```sql
CREATE PROCEDURE block_1794083325377_5825765()
MODIFIES SQL DATA
BEGIN
  PREPARE s FROM 'create table t (i int)';
  EXECUTE s;
  DEALLOCATE PREPARE s;
END;
CALL block_1794083325377_5825765();
DROP PROCEDURE block_1794083325377_5825765;
```

###### SQLServer

```sql
EXECUTE ('create table t (i int)')
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, H2, HSQLDB, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-exit"></a>
#### 3.8.5. EXIT statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A safer way to jump to labels than via [GOTO](#procedural-goto) is to use [EXIT](#procedural-exit) (jumping out of a [LOOP](#procedural-loop), or [block](#procedural-block), or other statement) or [CONTINUE](#procedural-continue) (skipping a [LOOP iteration](#procedural-loop)).

For example, in the absence of more sophisticated `LOOP` syntaxes, you may choose to exit a loop using `EXIT` (which translates to `LEAVE` or `BREAK` in some dialects, and works the same way as Java's `break`):

**Without a label**

```sql
-- PL/SQL
LOOP
  i := i + 1;
  EXIT WHEN i > 10;
END LOOP;
```

```java
// All dialects
loop(
  i.set(i.plus(1)),
  exitWhen(i.gt(10))
)
```

**With a label**

```sql
-- PL/SQL
<<label>>
LOOP
  i := i + 1;
  EXIT label WHEN i > 10;
END LOOP;
```

```java
// All dialects
Label label = label("label");
label.label(loop(
  i.set(i.plus(1)),
  exit(label).when(i.gt(10))
))
```

##### Dialect support

This example using jOOQ:

```java
loop(i.set(i.plus(1)), exitWhen(i.gt(10)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Oracle, Postgres, YugabyteDB

```sql
LOOP
  i := (i + 1);
  EXIT WHEN i > 10;
END LOOP
```

###### BigQuery

```sql
LOOP
  SET i = (i + 1);
  IF i > 10 THEN
    BREAK;
  END IF;
END LOOP
```

###### DB2, HSQLDB, MariaDB, MySQL, Trino

```sql
alias_1:
LOOP
  SET i = (i + 1);
  IF i > 10 THEN
    LEAVE alias_1;
  END IF;
END LOOP
```

###### Firebird

```sql
WHILE (1 = 1) DO BEGIN
  :i = (:i + 1);
  IF (:i > 10) THEN
    LEAVE;
END
```

###### H2

```sql
for (;;) {
  i = (i + 1);
  if (i > 10) {
    break;
  }
}
```

###### Hana

```sql
WHILE 1 = 1 DO
  i = (i + 1);
  IF i > 10 THEN
    BREAK;
  END IF;
END WHILE
```

###### Informix

```sql
LOOP
  LET i = (i + 1);
  EXIT WHEN i > 10;
END LOOP
```

###### Snowflake

```sql
LOOP
  i := (:i + 1);
  IF (:i > 10) THEN
    BREAK;
  END IF;
END LOOP
```

###### SQLDataWarehouse, SQLServer

```sql
WHILE 1 = 1 BEGIN
  SET @i = (@i + 1);
  IF @i > 10
    BREAK;
END
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-for"></a>
#### 3.8.6. FOR statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

When iterating over a sequence of numeric values, the `FOR` loop provides useful syntax sugar over the previous types of loops, including the [WHILE loop](#procedural-while), despite being functional equivalent.

An example:

```sql
-- PL/SQL

FOR i IN 1 .. 10 LOOP
  INSERT INTO t (col) VALUES (i);
END LOOP;
```

```java
// All dialects
Variable<Integer> i = var("i", INTEGER);
for_(i).in(1, 10).loop(
  insertInto(T).columns(T.COL).values(i)
)
```

In addition to simplifying the most common case, there are also options of traversing the arguments in a reversed way, and using an additional optional step variable, for example:

```sql
-- pgplsql

FOR i IN REVERSE 10 .. 1 BY 2 LOOP
  INSERT INTO t (col) VALUES (i);
END LOOP;
```

```java
// All dialects
Variable<Integer> i = var("i", INTEGER);
for_(i).inReverse(10, 1).by(2).loop(
  insertInto(T).columns(T.COL).values(i)
)
```

Not all dialects support the entirety of this syntax, but luckily it is easy for jOOQ to emulate in all dialects using [WHILE](#procedural-while):

```sql
-- PL/SQL
WHILE i >= 1 LOOP
  INSERT INTO t (col) VALUES (i);
  i := i - 2;
END LOOP;
```

Notice that `for` is a reserved keyword in the Java language, so the jOOQ API cannot use it as a method name. We've suffixed such conflicts with an underscore: `for_()`.

##### Dialect support

This example using jOOQ:

```java
for_(i).in(1, 10).loop(insertInto(BOOK).columns(BOOK.ID).values(i))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Exasol, Oracle, Postgres, YugabyteDB

```sql
FOR i IN 1 .. 10 LOOP
  INSERT INTO BOOK (ID)
  VALUES (i);
END LOOP
```

###### BigQuery

```sql
BEGIN
  DECLARE i int64 DEFAULT 1;
  WHILE i <= 10 DO
    INSERT INTO BOOK (ID)
    VALUES (i);
    SET i = (i + 1);
  END WHILE;
END;
```

###### DB2

```sql
BEGIN
  DECLARE i integer;
  SET i = 1;
  WHILE i <= 10 DO
    INSERT INTO BOOK (ID)
    VALUES (i);
    SET i = (i + 1);
  END WHILE;
END;
```

###### Firebird

```sql
DECLARE i integer DEFAULT 1;
WHILE (:i <= 10) DO BEGIN
  INSERT INTO BOOK (ID)
  VALUES (:i);
  :i = (:i + 1);
END
```

###### H2

```sql
for (Integer i = 1; i <= 10; i++) {
  try (PreparedStatement s = c.prepareStatement(
    "INSERT INTO BOOK (ID)\n" +
    "VALUES (?)"
  )) {
    s.setObject(1, i);
    s.execute();
  }
}
```

###### Hana

```sql
BEGIN
  DECLARE i integer;
  FOR i IN 1 .. 10 DO
    INSERT INTO BOOK (ID)
    VALUES (i);
  END FOR;
END;
```

###### HSQLDB

```sql
BEGIN ATOMIC
  DECLARE i int;
  SET i = 1;
  WHILE i <= 10 DO
    INSERT INTO BOOK (ID)
    VALUES (i);
    SET i = (i + 1);
  END WHILE;
END;
```

###### Informix

```sql
BEGIN
  DEFINE i integer;
  LET i = 1;
  FOR i IN (1 TO 10) LOOP
    INSERT INTO BOOK (ID)
    VALUES (i);
  END LOOP;
END;
```

###### MariaDB

```sql
FOR i IN 1 .. 10 DO
  INSERT INTO BOOK (ID)
  VALUES (i);
END FOR
```

###### MySQL

```sql
BEGIN
  DECLARE i int;
  SET i = 1;
  WHILE i <= 10 DO
    INSERT INTO BOOK (ID)
    VALUES (i);
    SET i = (i + 1);
  END WHILE;
END;
```

###### Snowflake

```sql
FOR i IN 1 TO 10 DO
  INSERT INTO BOOK (ID)
  SELECT :i;
END FOR
```

###### SQLDataWarehouse

```sql
BEGIN
  DECLARE @i int DEFAULT 1;
  WHILE @i <= 10 BEGIN
    INSERT INTO BOOK (ID)
    SELECT @i;
    SET @i = (@i + 1);
  END;
END;
```

###### SQLServer

```sql
BEGIN
  DECLARE @i int = 1;
  WHILE @i <= 10 BEGIN
    INSERT INTO BOOK (ID)
    VALUES (@i);
    SET @i = (@i + 1);
  END;
END;
```

###### Trino

```sql
BEGIN
  DECLARE i int;
  SET i = 1;
  WHILE i <= 10 DO
    INSERT INTO BOOK (ID)
    VALUES (i);
    SET i = (i + 1);
  END WHILE;
END
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-goto"></a>
#### 3.8.7. GOTO statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Hey, we don't judge anyone. You have your reasons for using this statement.

In the previous section, we introduced [labels](#procedural-label). Now we make use of them. For instance, to conditionally skip a set of statements. Or to simplify the example, to inconditionally skip them:

```sql
-- PL/SQL
BEGIN
  INSERT INTO t (col) VALUES (1);
  GOTO l1;
  INSERT INTO t (col) VALUES (2);

  <<l1>>
  INSERT INTO t (col) VALUES (3);
END;
```

```java
// All dialects
Label l1 = label("l1");

begin(
  insertInto(T).columns(T.COL).values(1),
  goto_(l1),
  insertInto(T).columns(T.COL).values(2),
  l1.label(insertInto(T).columns(T.COL).values(3))
)
```

Some dialects (e.g. T-SQL) may implement "full GOTO" in the ways that are generally not really helping readability or maintainability of code, namely the idea that `GOTO` can be used to jump into any arbitrary scope that should not be reachable through ordinary control flow. This is not possible in other languages, like PL/SQL, and currently cannot be emulated by jOOQ.

Notice that `goto` is a reserved keyword in the Java language, so the jOOQ API cannot use it as a method name. We've suffixed such conflicts with an underscore: `goto_()`.

##### Dialect support

This example using jOOQ:

```java
begin(l.label(insertInto(BOOK).columns(BOOK.ID).values(1)), goto_(l))
```

Translates to the following dialect specific expressions:

###### DB2

```sql
BEGIN
  l:
  BEGIN
    INSERT INTO BOOK (ID)
    VALUES (1);
  END;
  GOTO l;
END
```

###### Informix

```sql
BEGIN
  <<l>>
  INSERT INTO BOOK (ID)
  VALUES (1);
  GOTO l;
END;
```

###### Oracle

```sql
BEGIN
  <<l>>
  WHILE 1 = 1 LOOP
    INSERT INTO BOOK (ID)
    VALUES (1);
    EXIT l;
  END LOOP;
  GOTO l;
END;
```

###### SQLDataWarehouse, SQLServer

```sql
BEGIN
  l:
  INSERT INTO BOOK (ID)
  VALUES (1);
  GOTO l;
END;
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-if"></a>
#### 3.8.8. IF statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Conditional branching is an essential feature of all languages. Procedural languages support the `IF` statement.

There are different styles of `IF` statements in dialects, including:

- Requiring a `THEN` clause for the body of a branch, in case of which no [BEGIN .. END block](#procedural-block) is required for multi-statement bodies.
- Allowing a dedicated `ELSIF` clause for alternative, nested branches, to avoid nesting. This is mostly a syntax sugar feature only.

In jOOQ, an `IF` statement might look as follows:

```sql
-- PL/SQL syntax
IF i = 0 THEN
  INSERT INTO a (col) VALUES (1);
ELSIF i = 1 THEN
  INSERT INTO b (col) VALUES (2);
ELSE
  INSERT INTO c (col) VALUES (3);
END IF;
```

```java
// All dialects
if_(i.eq(0)).then(
  insertInto(A).columns(A.COL).values(1)
).elsif(i.eq(1)).then(
  insertInto(B).columns(B.COL).values(2)
).else_(
  insertInto(C).columns(C.COL).values(3)
)
```

Notice that both `if` and `else` are reserved keywords in the Java language, so the jOOQ API cannot use them as method names. We've suffixed such conflicts with an underscore: `if_()` and `else_()`.

##### Dialect support

This example using jOOQ:

```java
if_(i.eq(0)).then(deleteFrom(BOOK)).else_(deleteFrom(AUTHOR))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Exasol, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, Trino, YugabyteDB

```sql
IF i = 0 THEN
  DELETE FROM BOOK;
ELSE
  DELETE FROM AUTHOR;
END IF
```

###### BigQuery

```sql
IF i = 0 THEN
  DELETE FROM BOOK
  WHERE TRUE;
ELSE
  DELETE FROM AUTHOR
  WHERE TRUE;
END IF
```

###### Firebird

```sql
IF (:i = 0) THEN
  DELETE FROM BOOK;
ELSE
  DELETE FROM AUTHOR;
```

###### H2

```sql
if (i = 0) {
  try (PreparedStatement s = c.prepareStatement(
    "DELETE FROM BOOK"
  )) {
    s.execute();
  }
} else {
  try (PreparedStatement s = c.prepareStatement(
    "DELETE FROM AUTHOR"
  )) {
    s.execute();
  }
}
```

###### Snowflake

```sql
IF (:i = 0) THEN
  DELETE FROM BOOK;
ELSE
  DELETE FROM AUTHOR;
END IF
```

###### SQLDataWarehouse, SQLServer

```sql
IF @i = 0
  DELETE FROM BOOK;
ELSE
  DELETE FROM AUTHOR;
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-label"></a>
#### 3.8.9. Labels

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

In imperative languages, labels are essential with simpler cases of loops (e.g. the [LOOP statement](#procedural-loop)), with nested loops, or if you must, when using the [GOTO statement](#procedural-goto).

Using jOOQ, you can label any [`org.jooq.Statement`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Statement.html) by using [`DSL.label()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#label(java.lang.String)):

```sql
-- PL/SQL
<<label>>
BEGIN NULL; END;
```

```java
// All dialects
Label label = label("label");
label.label(begin())
```

That's a lot of labels.

The main usages of these labels will be discussed in the following sections about, [EXIT](#procedural-exit), and [CONTINUE](#procedural-continue)

##### Dialect support

This example using jOOQ:

```java
l.label(loop())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Informix, Postgres, YugabyteDB

```sql
<<l>>
LOOP
END LOOP
```

###### DB2, HSQLDB, MariaDB, MySQL, Trino

```sql
l:
LOOP
END LOOP
```

###### Firebird

```sql
l:
WHILE (1 = 1) DO BEGIN
END
```

###### H2

```sql
l:
for (;;) {
}
```

###### Oracle

```sql
<<l>>
LOOP
  NULL;
END LOOP
```

###### Snowflake

```sql
LOOP
  NULL;
END LOOP l
```

###### SQLDataWarehouse, SQLServer

```sql
l:
WHILE 1 = 1 BEGIN
  IF 1 = 0 SELECT 1;
END
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Hana, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-loop"></a>
#### 3.8.10. LOOP statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Many procedural languages support a condition-less loop, which in its pure form, just loops forever. In order to create an infinite number of records in a table, one might write the following:

```sql
-- PL/SQL syntax
LOOP
  INSERT INTO t (col) VALUES (1);
END LOOP;
```

```java
// All dialects
loop(
  insertInto(T).columns(T.COL).values(1)
)
```

An "infinite" loop is usually exited using an [EXIT statement](#procedural-exit).

##### Dialect support

This example using jOOQ:

```java
loop(update(BOOK_TO_BOOK_STORE).set(BOOK_TO_BOOK_STORE.STOCK, BOOK_TO_BOOK_STORE.STOCK.plus(1)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, Snowflake, YugabyteDB

```sql
LOOP
  UPDATE BOOK_TO_BOOK_STORE
  SET
    STOCK = (BOOK_TO_BOOK_STORE.STOCK + 1);
END LOOP
```

###### BigQuery

```sql
LOOP
  UPDATE BOOK_TO_BOOK_STORE
  SET
    BOOK_TO_BOOK_STORE.STOCK = (BOOK_TO_BOOK_STORE.STOCK + 1)
  WHERE TRUE;
END LOOP
```

###### DB2, Exasol, HSQLDB, Informix, MariaDB, MySQL, Oracle, Trino

```sql
LOOP
  UPDATE BOOK_TO_BOOK_STORE
  SET
    BOOK_TO_BOOK_STORE.STOCK = (BOOK_TO_BOOK_STORE.STOCK + 1);
END LOOP
```

###### Firebird

```sql
WHILE (1 = 1) DO BEGIN
  UPDATE BOOK_TO_BOOK_STORE
  SET
    BOOK_TO_BOOK_STORE.STOCK = (BOOK_TO_BOOK_STORE.STOCK + 1);
END
```

###### H2

```sql
for (;;) {
  try (PreparedStatement s = c.prepareStatement(
    "UPDATE BOOK_TO_BOOK_STORE\n" +
    "SET\n" +
    "  BOOK_TO_BOOK_STORE.STOCK = (BOOK_TO_BOOK_STORE.STOCK + 1)"
  )) {
    s.execute();
  }
}
```

###### Hana

```sql
WHILE 1 = 1 DO
  UPDATE BOOK_TO_BOOK_STORE
  FROM BOOK_TO_BOOK_STORE
  SET
    BOOK_TO_BOOK_STORE.STOCK = (BOOK_TO_BOOK_STORE.STOCK + 1);
END WHILE
```

###### SQLDataWarehouse, SQLServer

```sql
WHILE 1 = 1 BEGIN
  UPDATE BOOK_TO_BOOK_STORE
  SET
    BOOK_TO_BOOK_STORE.STOCK = (BOOK_TO_BOOK_STORE.STOCK + 1);
END
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-repeat"></a>
#### 3.8.11. REPEAT statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

[WHILE](#procedural-while)'s lesser known little sibling is `REPEAT`, which works the same way as Java's `do` statement. It is mostly not as useful as `WHILE`, but can be, occasionally, when a loop must be iterated *at least* once.

An example:

```sql
-- MySQL syntax
REPEAT
  INSERT INTO t (col) VALUES (i);
  SET i = i + 1;
UNTIL i > 10 END REPEAT;
```

```java
// All dialects
Variable<Integer> i = var("i", INTEGER);
repeat(
  insertInto(T).columns(T.COL).values(i),
  i.set(i.plus(1))
).until(i.gt(10))
```

##### Dialect support

This example using jOOQ:

```java
repeat(deleteFrom(BOOK).where(BOOK.ID.eq(i)), i.set(i.plus(1))).until(i.gt(10))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Oracle, Postgres, YugabyteDB

```sql
<<alias_2>>
LOOP
  DELETE FROM BOOK
  WHERE BOOK.ID = i;
  i := (i + 1);
  EXIT alias_2 WHEN i > 10;
END LOOP
```

###### BigQuery, DB2, HSQLDB, MariaDB, MySQL, Trino

```sql
REPEAT
  DELETE FROM BOOK
  WHERE BOOK.ID = i;
  SET i = (i + 1);
UNTIL i > 10
END REPEAT
```

###### Exasol

```sql
REPEAT
  DELETE FROM BOOK
  WHERE BOOK.ID = i;
  i := (i + 1);
UNTIL i > 10
END REPEAT
```

###### Firebird

```sql
alias_2:
WHILE (1 = 1) DO BEGIN
  DELETE FROM BOOK
  WHERE BOOK.ID = :i;
  :i = (:i + 1);
  IF (:i > 10) THEN
    LEAVE alias_2;
END
```

###### H2

```sql
do {
  try (PreparedStatement s = c.prepareStatement(
    "DELETE FROM BOOK\n" +
    "WHERE BOOK.ID = ?"
  )) {
    s.setObject(1, i);
    s.execute();
  }
  i = (i + 1);
}
while (!(i > 10))
```

###### Hana

```sql
WHILE 1 = 1 DO
  DELETE FROM BOOK
  WHERE BOOK.ID = i;
  i = (i + 1);
  IF i > 10 THEN
    BREAK;
  END IF;
END WHILE
```

###### Informix

```sql
<<alias_2>>
LOOP
  DELETE FROM BOOK
  WHERE BOOK.ID = i;
  LET i = (i + 1);
  EXIT alias_2 WHEN i > 10;
END LOOP
```

###### Snowflake

```sql
REPEAT
  DELETE FROM BOOK
  WHERE BOOK.ID = :i;
  i := (:i + 1);
UNTIL (:i > 10)
END REPEAT
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, MemSQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-signal"></a>
#### 3.8.12. SIGNAL

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The standard SQL way to raise exceptions is via the `SIGNAL` statement, which is supported natively in a few dialects, and can be emulated in some others.

Some example `SIGNAL` invocations.

```java
begin(signalSQLState("45000")).execute();
begin(signalSQLState("45000").setMessageText("Custom message")).execute();
```

##### Dialect support

This example using jOOQ:

```java
signalSQLState("45000").setMessageText("Custom message")
```

Translates to the following dialect specific expressions:

###### CockroachDB, Postgres, YugabyteDB

```sql
RAISE SQLSTATE '45000' USING MESSAGE = 'Custom message'
```

###### DB2, HSQLDB, MariaDB, MySQL

```sql
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Custom message'
```

###### Hana

```sql
SIGNAL SQL_ERROR_CODE '45000' SET MESSAGE_TEXT = 'Custom message'
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, H2, Informix, MemSQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-variables"></a>
#### 3.8.13. Variables

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

In imperative languages, local variables are an essential way of temporarily storing data for further processing. All procedural languages have a way to declare, assign, and reference such local variables.

##### Declaration

In jOOQ, local variable expressions can be created using [`DSL.var()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#var(java.lang.String,org.jooq.DataType)) (not to be confused with [`DSL.val(T)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#val(T)), which creates bind values!)

```java
Variable<Integer> i = var("i", INTEGER);
```

This variable doesn't do anything on its own yet. But like many things in jOOQ, it has to be declared first, outside of an actual jOOQ expression, in order to be usable in jOOQ expressions.

We can now reference the variable in a declaration statement as follows:

```sql
-- MySQL syntax
DECLARE i INTEGER;
```

```java
// All dialects
declare(i)
```

Notice that there are many different ways to declare a local variable in different dialects. There is

**The Oracle PL/SQL, PostgreSQL pgplsql style**

In these languages, the `DECLARE` statement is actually not an independent statement that can be used anywhere. It is part of a [procedural block](#procedural-block), prepended to `BEGIN .. END`:

```sql
-- PL/SQL syntax
DECLARE
  i INT;
BEGIN
  NULL;
END;
```

When using jOOQ, you can safely ignore this fact, and prepend that there is a `DECLARE` statement also in these dialects. jOOQ will add additional `BEGIN .. END` blocks to your surrounding block, to make sure the whole block becomes syntactically and semantically correct.

**The T-SQL, MySQL style**

In these languages, the `DECLARE` statement is really an independent statement that can be used anywhere. Just like in the Java language, variables can be declared at any position and used only "further down", lexically. Ignoring T-SQL's JavaScript-esque understanding of scope for a moment.

```sql
-- T-SQL syntax
DECLARE @i INTEGER;
```

Notice that you can safely ignore the `@` sign that is required in some dialects, such as T-SQL. jOOQ will generate it for you.

##### Assignment

A local variable needs a way to have a value assigned to it. Assignments are possible both on [`org.jooq.Variable`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Variable.html), or on [`org.jooq.Declaration`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Declaration.html), directly. For example

```sql
-- T-SQL syntax
DECLARE @i INTEGER = 1;
```

```java
// All dialects
declare(i).set(1)
```

Alternatively, you can split declaration and assignment, or re-assign new values to variables:

```sql
-- T-SQL syntax
DECLARE @i INTEGER;
SET @i = 1;
SET @i = 2;
```

```java
// All dialects
declare(i),
i.set(1),
i.set(2)
```

Some dialects also support using subqueries in assignment expressions, and other expresions in their procedural languages. For example:

```sql
-- T-SQL syntax
SET @i = (SELECT MAX(col) FROM t);
```

```java
// All dialects
i.set(select(max(T.COL)).from(T))
```

The above is equivalent to this:

```sql
-- PL/SQL syntax
SELECT MAX(col) INTO i FROM t;
```

```java
// All dialects
select(max(T.COL)).into(i).from(T)
```

##### Row assignment

Some dialects support row assignment of variables, which other languages call "destructuring". This is particularly useful when assigning multiple values from a query:

```sql
-- HSQLDB syntax
SET (i, j) = (SELECT MIN(col), MAX(col) FROM t);
```

```java
// All dialects
row(i, j).set(select(min(T.COL), max(T.COL)).from(T))
```

The above is equivalent to this:

```sql
-- PL/SQL syntax
SELECT MIN(col), MAX(col) INTO i, j FROM t;
```

```java
// All dialects
select(min(T.COL), max(T.COL)).into(i, j).from(T)
```

##### Referencing

Obviously, once we've assigned a value to a local variable, we want to reference it as well in arbitrary expressions, and queries.

For this purpose, [`org.jooq.Variable`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Variable.html) extends [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html), and as such, can be used in arbitrary places where any other [column expression](#column-expressions) can be used. Within the procedural language, a simple example would be to increment a local variable:

```sql
-- PL/SQL syntax
i := i + 1;
```

```java
// All dialects
i.set(i.plus(1))
```

Or in a more complete example, use it in a SQL statement:

```sql
-- PL/SQL syntax
DECLARE
  i INT;
BEGIN
  i := 1;
  INSERT INTO t (col) VALUES (i);
END;
```

```java
// All dialects
Variable<Integer> i = var("i", INTEGER);
create.begin(
  declare(i),
  i.set(1),
  insertInto(T).columns(T.COL).values(i)
).execute();
```

##### Dialect support

This example using jOOQ:

```java
begin(declare(i), i.set(1))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
DO $$
DECLARE
  i int;
BEGIN
  i := 1;
END;
$$
```

###### BigQuery

```sql
BEGIN
  DECLARE i int64;
  SET i = 1;
END;
```

###### CockroachDB

```sql
DO $$
DECLARE
  i int4;
BEGIN
  i := 1;
END;
$$
```

###### DB2

```sql
BEGIN
  DECLARE i integer;
  SET i = 1;
END
```

###### Exasol

```sql
BEGIN
  i int;
  i := 1;
END;
```

###### Firebird

```sql
EXECUTE BLOCK AS
  DECLARE i integer;
BEGIN
  :i = 1;
END
```

###### H2

```sql
CREATE ALIAS block_1794083324747_9642749 AS $$
  void x(Connection c) throws SQLException {
    Integer i = null;
    i = 1;
  }
$$;
CALL block_1794083324747_9642749();
DROP ALIAS block_1794083324747_9642749;
```

###### Hana

```sql
DO BEGIN
  DECLARE i integer;
  i = 1;
END;
```

###### HSQLDB

```sql
BEGIN ATOMIC
  DECLARE i int;
  SET i = 1;
END;
```

###### Informix

```sql
BEGIN
  DEFINE i integer;
  LET i = 1;
END;
```

###### MariaDB

```sql
BEGIN NOT ATOMIC
  DECLARE i int;
  SET i = 1;
END;
```

###### MySQL

```sql
CREATE PROCEDURE block_1794083325381_7381783()
MODIFIES SQL DATA
BEGIN
  DECLARE i int;
  SET i = 1;
END;
CALL block_1794083325381_7381783();
DROP PROCEDURE block_1794083325381_7381783;
```

###### Oracle

```sql
DECLARE
  i number(10);
BEGIN
  i := 1;
END;
```

###### Snowflake

```sql
BEGIN
  LET i number(10);
  i := 1;
END;
```

###### SQLDataWarehouse, SQLServer

```sql
BEGIN
  DECLARE @i int;
  SET @i = 1;
END;
```

###### Trino

```sql
BEGIN
  DECLARE i int;
  SET i = 1;
END
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="procedural-while"></a>
#### 3.8.14. WHILE statement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

One of the most commonly used loop types is the `WHILE` statement, which in its procedural form works just like a Java `while` statement with slightly different syntax.

Procedural dialects may or may not use the `LOOP` keyword to delimite the loop body, just as with the previous [LOOP statement](#procedural-loop). The jOOQ API always uses it for DSL design reasons. For example, combining the `WHILE` loop with the [variable assignment statement](#procedural-variables):

```sql
-- PL/SQL syntax
WHILE i <= 10
LOOP
  INSERT INTO t (col) VALUES (i);
END LOOP;
```

```java
// All dialects
Variable<Integer> i = var("i", INTEGER);
while_(i.le(10)).loop(
  insertInto(T).columns(T.COL).values(i)
)
```

Notice that `while` is a reserved keyword in the Java language, so the jOOQ API cannot use it as a method name. We've suffixed such conflicts with an underscore: `while_()`.

##### Dialect support

This example using jOOQ:

```java
while_(i.le(10)).loop(deleteFrom(BOOK).where(BOOK.ID.eq(i)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Exasol, Informix, Oracle, Postgres, YugabyteDB

```sql
WHILE i <= 10 LOOP
  DELETE FROM BOOK
  WHERE BOOK.ID = i;
END LOOP
```

###### BigQuery, DB2, HSQLDB, Hana, MariaDB, MySQL, Trino

```sql
WHILE i <= 10 DO
  DELETE FROM BOOK
  WHERE BOOK.ID = i;
END WHILE
```

###### Firebird

```sql
WHILE (:i <= 10) DO BEGIN
  DELETE FROM BOOK
  WHERE BOOK.ID = :i;
END
```

###### H2

```sql
while (i <= 10) {
  try (PreparedStatement s = c.prepareStatement(
    "DELETE FROM BOOK\n" +
    "WHERE BOOK.ID = ?"
  )) {
    s.setObject(1, i);
    s.execute();
  }
}
```

###### Snowflake

```sql
WHILE (:i <= 10) DO
  DELETE FROM BOOK
  WHERE BOOK.ID = :i;
END WHILE
```

###### SQLDataWarehouse, SQLServer

```sql
WHILE @i <= 10 BEGIN
  DELETE FROM BOOK
  WHERE BOOK.ID = @i;
END
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, MemSQL, Redshift, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="catalog-and-schema-expressions"></a>
### 3.9. Catalog and schema expressions

Most databases know some sort of namespace to group objects like [tables](#table-expressions), [stored procedures](#stored-procedures), [sequences](#sequences-and-serials) and others into a common catalog or schema. jOOQ uses the types [`org.jooq.Catalog`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Catalog.html) and [`org.jooq.Schema`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Schema.html) to model these groupings, following SQL standard naming.

#### The catalog

A catalog is a collection of schemas. In many databases, the catalog corresponds to the database, or the database instance. Most often, catalogs are completely independent and their tables cannot be joined or combined in any way in a single query. The exception here is SQL Server and Sybase ASE, which allow for fully referencing tables from multiple catalogs:

```sql
SELECT *
FROM [Catalog1].[Schema1].[Table1] AS [t1]
JOIN [Catalog2].[Schema2].[Table2] AS [t2] ON [t1].[ID] = [t2].[ID]
```

Some dialects, including MariaDB, MemSQL, MySQL, use catalogs (databases) and schemas as the same thing. jOOQ treats databases in those dialects as schemas instead.

By default, the `Settings.renderCatalog` flag is turned on. In case a database supports querying multiple catalogs, jOOQ will generate fully qualified object names, including catalog name. For more information about this setting, see [the manual's section about settings](#custom-settings)

jOOQ's [code generator](#code-generation) generates subpackages for each catalog.

#### The schema

A schema is a collection of objects, such as tables. Most databases support some sort of schema (except for some embedded databases like Access, Firebird, SQLite). In most databases, the schema is an independent structural entity. In Oracle, the schema and the user / owner is mostly treated as the same thing. An example of a query that uses fully qualified tables including schema names is:

```sql
SELECT *
FROM "Schema1"."Table1" AS "t1"
JOIN "Schema2"."Table2" AS "t2" ON "t1"."ID" = "t2"."ID"
```

By default, the `Settings.renderSettings` flag is turned on. jOOQ will thus generate fully qualified object names, including the setting name. For more information about this setting, see [the manual's section about settings](#custom-settings)

<a id="table-expressions"></a>
### 3.10. Table expressions

The following sections explain the various types of table expressions supported by jOOQ

<a id="generated-tables"></a>
#### 3.10.1. Generated Tables

Most of the times, when thinking about a [table expression](#table-expressions) you're probably thinking about an actual table in your database schema. If you're using jOOQ's [code generator](#code-generation), you will have all tables from your database schema available to you as type safe Java objects. You can then use these tables in SQL [FROM clauses](#from-clause), [JOIN clauses](#join-clause) or in other [SQL statements](#sql-statements), just like any other table expression. An example is given here:

```sql
SELECT *
FROM AUTHOR -- Table expression AUTHOR
JOIN BOOK   -- Table expression BOOK
ON (AUTHOR.ID = BOOK.AUTHOR_ID)
 
```

```java
create.select()
      .from(AUTHOR) // Table expression AUTHOR
      .join(BOOK)   // Table expression BOOK
      .on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
      .fetch();
```

The above example shows how AUTHOR and BOOK tables are joined in a [SELECT statement](#select-statement). It also shows how you can access [table columns](#table-columns) by dereferencing the relevant Java attributes of their tables.

See the manual's section about [generated tables](#codegen-tables) for more information about what is really generated by the [code generator](#code-generation)

<a id="aliased-tables"></a>
#### 3.10.2. Aliased Tables

The following sections illustrate how to alias tables, their columns, and how to reference columns from aliased tables.

> [!TIP]
> Regardless of how the aliased table is defined, the same aliased table instance is rendered differently depending on where it is placed in the jOOQ expression tree. See the manual's section about [rendering declarations vs references](#declaration-vs-reference) for more details.

<a id="aliased-generated-tables"></a>
##### 3.10.2.1. Aliased generated tables

The strength of jOOQ's [code generator](#code-generation) becomes more obvious when you perform table aliasing and dereference fields from generated aliased tables. This can best be shown by example:

```sql
-- Select all books by authors born after 1920,
-- named "Paulo" from a catalogue:



SELECT *
  FROM author a
  JOIN book b ON a.id = b.author_id
 WHERE a.year_of_birth > 1920
   AND a.first_name = 'Paulo'
 ORDER BY b.title
 
```

```java
// Declare your aliases before using them in SQL:
Author a = AUTHOR.as("a");
Book b = BOOK.as("b");

// Use aliased tables in your statement
create.select()
      .from(a)
      .join(b).on(a.ID.eq(b.AUTHOR_ID))
      .where(a.YEAR_OF_BIRTH.gt(1920)
      .and(a.FIRST_NAME.eq("Paulo")))
      .orderBy(b.TITLE)
      .fetch();
```

As you can see in the above example, calling `as()` on generated tables returns an object of the same type as the table. This means that the resulting object can be used to dereference fields from the aliased table. This is quite powerful in terms of having your Java compiler check the syntax of your SQL statements. If you remove a column from a table, dereferencing that column from that table alias will cause compilation errors.

###### Dialect support

This example using jOOQ:

```java
select(a.ID).from(a)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
SELECT a.ID
FROM AUTHOR a
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="aliased-table-expressions"></a>
##### 3.10.2.2. Aliased table expressions

Only few types of table expressions can leverage [code generation](#aliased-generated-tables) to provide the SQL syntax typesafety shown previously, where generated tables are used. All tables, however, allow for [dereferencing their fields](#dereferenced-table-columns) through `Table::field` methods:

```java
// "Type-unsafe" aliased table:
Table<?> a = AUTHOR.as("a");

// Get fields from a:
Field<?> id = a.field("ID");
Field<?> firstName = a.field("FIRST_NAME");
```

The same is true for [derived tables](#derived-tables), including [unnamed derived tables](#unnamed-derived-tables) whose synthetic table name is generated by jOOQ:

```java
Table<?> named = table(select(AUTHOR.ID).from(AUTHOR)).as("t");
Table<?> unnamed = table(select(AUTHOR.ID).from(AUTHOR));

Field<?> id = named.field("ID");   // Produces a t.ID reference
Field<?> id = unnamed.field("ID"); // Produces a <generated-alias>.ID reference
```

Note that if you *know* that the `ID` column is of the same type as the `AUTHOR.ID` column, you can use that again to dereference the column as is explained again in the section [dereferencing table columns](#dereferenced-table-columns).

```java
// Now with inferred Integer type
Field<Integer> id = named.field(AUTHOR.ID);   // Produces a t.ID reference
Field<Integer> id = unnamed.field(AUTHOR.ID); // Produces a <generated-alias>.ID reference
```

<a id="aliased-join-tables"></a>
##### 3.10.2.3. Aliased joined tables

Some SQL dialects follow the SQL standard that allows for aliasing also [joined tables](#joined-tables), i.e. the product of a `JOIN` operator, not just the individual `JOIN` operands. If that isn't available, jOOQ will try to emulate the feature assuming there can't be any column ambiguities.

```java
Table<?> t = AUTHOR.join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID)).as("t");
```

###### Dialect support

This example using jOOQ:

```java
selectFrom(AUTHOR.join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID)).as("t"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
SELECT
  t.ID,
  t.FIRST_NAME,
  t.LAST_NAME,
  t.DATE_OF_BIRTH,
  t.YEAR_OF_BIRTH,
  t.DISTINGUISHED,
  t.ID,
  t.AUTHOR_ID,
  t.TITLE,
  t.PUBLISHED_IN,
  t.LANGUAGE_ID
FROM (
  AUTHOR
    INNER JOIN BOOK
      ON AUTHOR.ID = BOOK.AUTHOR_ID
) t
```

###### ASE, Aurora Postgres, ClickHouse, CockroachDB, Databricks, Exasol, H2, HSQLDB, Informix, Postgres, Redshift, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT
  t.ID,
  t.FIRST_NAME,
  t.LAST_NAME,
  t.DATE_OF_BIRTH,
  t.YEAR_OF_BIRTH,
  t.DISTINGUISHED,
  t.ID,
  t.AUTHOR_ID,
  t.TITLE,
  t.PUBLISHED_IN,
  t.LANGUAGE_ID
FROM (
  AUTHOR
    JOIN BOOK
      ON AUTHOR.ID = BOOK.AUTHOR_ID
) t
```

###### Aurora MySQL, BigQuery, DB2, DuckDB, Firebird, Hana, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase

```sql
SELECT
  t.ID,
  t.FIRST_NAME,
  t.LAST_NAME,
  t.DATE_OF_BIRTH,
  t.YEAR_OF_BIRTH,
  t.DISTINGUISHED,
  t.ID,
  t.AUTHOR_ID,
  t.TITLE,
  t.PUBLISHED_IN,
  t.LANGUAGE_ID
FROM (
  SELECT *
  FROM AUTHOR
    JOIN BOOK
      ON AUTHOR.ID = BOOK.AUTHOR_ID
) t
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="derived-column-lists"></a>
##### 3.10.2.4. Derived column lists

The SQL standard specifies how a table can be renamed / aliased in one go along with its columns. It references the term "derived column list" for the following syntax:

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 2
) t(a, b)
```

This feature is useful in various use-cases where column names are not known in advance (but the table's degree is!). An example for this are [unnested tables](#array-and-cursor-unnesting), or the [VALUES() table constructor](#values):

```sql
-- Unnested tables
SELECT t.a, t.b
FROM unnest(my_table_function()) t(a, b)

-- VALUES() constructor
SELECT t.a, t.b
FROM VALUES(1, 2),(3, 4) t(a, b)
```

Only few databases really support such a syntax, but fortunately, jOOQ can emulate it easily using `UNION ALL` and an empty dummy record specifying the new column names. The two statements are equivalent:

```sql
-- Using derived column lists
SELECT t.a, t.b
FROM (
  SELECT 1, 2
) t(a, b)

-- Using UNION ALL and a dummy record
SELECT t.a, t.b
FROM (
  SELECT null a, null b FROM DUAL WHERE 1 = 0
  UNION ALL
  SELECT 1, 2 FROM DUAL
) t
```

In jOOQ, you would simply specify a varargs list of column aliases as such:

```java
// Unnested tables
create.select().from(unnest(myTableFunction()).as("t", "a", "b")).fetch();

// VALUES() constructor
create.select().from(values(
  row(1, 2),
  row(3, 4)
).as("t", "a", "b"))
.fetch();
```

###### Dialect support

This example using jOOQ:

```java
selectFrom(values(row(1, 2)).as("t", "a", "b"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
SELECT t.a, t.b
FROM (
  SELECT
    1 a,
    2 b
  FROM (
    SELECT count(*) dual
    FROM MSysResources
  ) AS dual
) t
```

###### ASE, Redshift, SQLDataWarehouse, Vertica

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 2
) t (a, b)
```

###### Aurora MySQL, MemSQL

```sql
SELECT t.a, t.b
FROM (
  SELECT
    1 a,
    2 b
  FROM DUAL
) t
```

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, H2, HSQLDB, Oracle, Postgres, SQLServer, Snowflake, Trino, YugabyteDB

```sql
SELECT t.a, t.b
FROM (
  VALUES (1, 2)
) t (a, b)
```

###### BigQuery

```sql
SELECT t.a, t.b
FROM (
  SELECT
    null a,
    null b
  FROM UNNEST([STRUCT(1 AS dual)]) AS dual
  WHERE FALSE
  UNION ALL
  SELECT *
  FROM UNNEST ([ STRUCT (1, 2)]) t
) t
```

###### ClickHouse, MariaDB, Spanner

```sql
SELECT t.a, t.b
FROM (
  SELECT
    1 a,
    2 b
) t
```

###### Databricks

```sql
SELECT t.a, t.b
FROM (
  VALUES STRUCT (1, 2)
) t (a, b)
```

###### Firebird

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 2
  FROM RDB$DATABASE
) t (a, b)
```

###### Hana

```sql
SELECT t.a, t.b
FROM (
  SELECT
    1 a,
    2 b
  FROM SYS.DUMMY
) t
```

###### Informix

```sql
SELECT t.a, t.b
FROM (
  TABLE (MULTISET { ROW (1, 2)})
) t (a, b)
```

###### MySQL

```sql
SELECT t.a, t.b
FROM (
  VALUES ROW (1, 2)
) t (a, b)
```

###### SQLite

```sql
SELECT t.a, t.b
FROM (
  SELECT
    null a,
    null b
  WHERE 1 = 0
  UNION ALL
  SELECT *
  FROM (
    VALUES (1, 2)
  ) t
) t
```

###### Sybase

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 2
  FROM SYS.DUMMY
) t (a, b)
```

###### Teradata

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 2
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (a, b)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="unnamed-derived-tables"></a>
##### 3.10.2.5. Unnamed derived tables

The [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) type can reference a [derived table](#derived-tables):

```sql
-- Derived table
(SELECT 1 AS a)
```

```java
// Derived table
table(select(inline(1).as("a")));
```

Most databases do not support unnamed derived tables, they require an explicit alias. If you do not provide jOOQ with such an explicit alias, an alias will be generated based on the derived table's content, to make sure the generated SQL will be syntactically correct. The generated alias is not specified and should not be referenced explicitly.

> [!TIP]
> While the actual alias shouldn't be relied upon, as the generation algorithm might change between jOOQ versions, the alias will remain stable per SQL content of the derived table, in order to prevent execution plan cache contention in dialects with an execution plan. In other words, two consecutive renderings of a structurally identical derived table should produce the same generated alias. Of course, it's usually better to provide an explicit alias nonetheless.

<a id="client-side-aliased-tables"></a>
##### 3.10.2.6. Client-side aliased tables

Table expressions can be "aliased" in your Java code only, without any effect on generated SQL. This can greatly help improve readability of your jOOQ query, without running into the occasional edge case when a table is aliased in SQL, e.g. when working with [DML statements](#sql-statements) that may have poor aliasing support in some dialects.

```sql
-- No aliasing done in SQL
SELECT BOOK.ID FROM BOOK;
```

```java
Book b = BOOK;
create.select(b.ID).from(b).fetch();
```

This is just a special case illustrating that every jOOQ query is a [dynamic SQL query](#dynamic-sql), even if it doesn't necessarily look this way.

<a id="joined-tables"></a>
#### 3.10.3. Joined tables

The [JOIN operators](#join-clause) that can be used in [SQL SELECT statements](#select-statement) are the most powerful and best supported means of creating new [table expressions](#table-expressions) in SQL.

This section will explain the different types of join:

- `CROSS JOIN`: A cross product
- `INNER JOIN`: A cross product filtering on matches
- `OUTER JOIN`: A cross product filtering on matches, additionally producing some unmatched rows
- `SEMI JOIN`: A check for existence of rows from one table in another table (using `EXISTS` or `IN`)
- `ANTI JOIN`: A check for non-existence of rows from one table in another table (using `NOT EXISTS` or some conditions `NOT IN`)

... as well as the different types of forming join predicates:

- `ON`: Expressing join predicates explicitly
- `ON KEY`: Expressing join predicates explicitly or implicitly based on a `FOREIGN KEY`
- `USING`: Expressing join predicates implicitly based on an explicit set of shared column names in both tables
- `NATURAL`: Expressing join predicates implicitly based on an implicit set of shared column names in both tables

... and then, there are additional ways to enrich joins:

- `APPLY` or `LATERAL`: Ordering the join tree from left to right, allowing the right side to access rows from the left side
- `PARTITION BY` on `OUTER JOIN`: To fill the gaps in a report that uses `OUTER JOIN`

All of these approaches are available twice in the jOOQ API:

- On the [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) API, where they form binary operators
- On the [SELECT](#join-clause) API, where they are offered as convenience in jOOQ's DSL, to tame the parentheses

<a id="join-type-cross"></a>
##### 3.10.3.1. CROSS JOIN

A `CROSS JOIN` creates a cartesian product or cross product between the two tables it joins. It does not allow for any join predicates to be specified.

It is an occasionally useful operator in reporting, when every element of one set need to be combined with every element of another set. For example, when you want to produce a report combining employees and weekdays, and then do something with the resulting table:

```sql
SELECT EMPLOYEE.NAME, WEEKDAY.NAME
FROM EMPLOYEE
CROSS JOIN WEEKDAY
 
```

```java
create.select(EMPLOYEE.NAME, WEEKDAY.NAME)
      .from(EMPLOYEE)
      .crossJoin(WEEKDAY)
      .fetch();
```

Some example output might be:

```text
+---------------+--------------+
| EMPLOYEE.NAME | WEEKDAY.NAME |
+---------------+--------------+
| Jon           | Monday       |
| Jon           | Tuesday      |
| Jon           | Wednesday    |
| Jon           | Thursday     |
| Jon           | Friday       |
| Jon           | Saturday     |
| Jon           | Sunday       |
| Jane          | Monday       |
| Jane          | Tuesday      |
| Jane          | Wednesday    |
| Jane          | Thursday     |
| Jane          | Friday       |
| Jane          | Saturday     |
| Jane          | Sunday       |
| ...           | ...          |
+---------------+--------------+
```

###### Table lists

Note that a `CROSS JOIN` is functionally (but not syntactically) equivalent to a table list that you can provide in the [FROM clause](#from-clause):

```sql
SELECT EMPLOYEE.NAME, WEEKDAY.NAME
FROM EMPLOYEE, WEEKDAY
 
```

```java
create.select(EMPLOYEE.NAME, WEEKDAY.NAME)
      .from(EMPLOYEE, WEEKDAY)
      .fetch();
```

It is usually recommended to prefer the `CROSS JOIN` syntax in order to clearly communicate intent.

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID, AUTHOR.ID).from(BOOK.crossJoin(AUTHOR))
```

Translates to the following dialect specific expressions:

###### ASE

```sql
SELECT BOOK.ID, AUTHOR.ID
FROM BOOK
  JOIN AUTHOR
    ON 1 = 1
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT BOOK.ID, AUTHOR.ID
FROM BOOK
  CROSS JOIN AUTHOR
```

###### Access, DuckDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-type-inner"></a>
##### 3.10.3.2. INNER JOIN

An `INNER JOIN` or just `JOIN` works like a [CROSS JOIN](#join-type-cross), but adds a predicate of some sort filtering out unwanted combinations. This is the most popular way to join tables, as we hardly ever want to combine arbitrary rows from both tables, but the ones that have some relationship with each other, e.g. a `FOREIGN KEY` reference match.

```sql
SELECT *
FROM AUTHOR
JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select()
      .from(AUTHOR)
      .join(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

The above query will return all authors and their books. True to the nature of an `INNER JOIN`, authors without books are excluded as well as books without authors (if the `FOREIGN KEY` is optional).

The result might look like this:

```text
+------------+-----------+--------------+
| FIRST_NAME | LAST_NAME | TITLE        |
+------------+-----------+--------------+
| George     | Orwell    | 1984         |
| George     | Orwell    | Animal Farm  |
| Paulo      | Coelho    | O Alquimista |
| Paulo      | Coelho    | Brida        |
+------------+-----------+--------------+
```

In the example, we're using the [ON clause](#join-predicate-on) to form the `JOIN` predicate, but other options will be discussed in later sections as well.

The `INNER` keyword is optional both in SQL and in jOOQ, and does not affect the query semantics at all.

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID, AUTHOR.ID).from(BOOK.join(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
```

Translates to the following dialect specific expressions:

###### Access

```sql
SELECT BOOK.ID, AUTHOR.ID
FROM BOOK
  INNER JOIN AUTHOR
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT BOOK.ID, AUTHOR.ID
FROM BOOK
  JOIN AUTHOR
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-type-outer"></a>
##### 3.10.3.3. OUTER JOIN

`OUTER JOIN` allows for producing some additional rows when an [INNER JOIN](#join-type-inner) does not match. There are 3 types of `OUTER JOIN`:

- `LEFT JOIN` or `LEFT OUTER JOIN`: Always produce *all* rows from the left side of the join, and only matched rows from the right side of the join
- `RIGHT JOIN` or `RIGHT OUTER JOIN`: Always produce *all* rows from the right side of the join, and only matched rows from the left side of the join
- `FULL JOIN` or `FULL OUTER JOIN`: Always produce *all* rows from both left and right side of the join

The `OUTER` keyword is optional both in SQL and in jOOQ, and does not affect the query semantics at all.

This is best explained by example.

###### LEFT JOIN

`LEFT JOIN` is the most popular among the `OUTER JOIN` types.

The following query produces *all* authors, and possibly, their books:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  BOOK.TITLE
FROM AUTHOR
LEFT JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select(
         AUTHOR.FIRST_NAME,
         AUTHOR.LAST_NAME,
         BOOK.TITLE)
      .from(AUTHOR)
      .leftJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

The result might look like this:

```text
+------------+-----------+--------------+
| FIRST_NAME | LAST_NAME | TITLE        |
+------------+-----------+--------------+
| George     | Orwell    | 1984         |
| George     | Orwell    | Animal Farm  |
| Paulo      | Coelho    | O Alquimista |
| Paulo      | Coelho    | Brida        | <-- Above rows are also produced by INNER JOIN
| Jane       | Austen    |              | <-- This row is only produced by LEFT JOIN or FULL JOIN
+------------+-----------+--------------+
```

As can be seen, *all* rows from the *left* side of the join (authors) are produced, including the ones that do not have any matches on the right side of the join (books). We don't have any books for Jane Austen yet, but Jane Austen is in the result set. She wouldn't be if this were an [INNER JOIN](#join-type-inner).

###### RIGHT JOIN

`RIGHT JOIN` is just the inverse of a `LEFT JOIN`, and is hardly ever used.

The following query produces *all* books, and possibly, their authors:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  BOOK.TITLE
FROM AUTHOR
RIGHT JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select(
         AUTHOR.FIRST_NAME,
         AUTHOR.LAST_NAME,
         BOOK.TITLE)
      .from(AUTHOR)
      .rightJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

The result might look like this:

```text
+------------+-----------+--------------------+
| FIRST_NAME | LAST_NAME | TITLE              |
+------------+-----------+--------------------+
| George     | Orwell    | 1984               |
| George     | Orwell    | Animal Farm        |
| Paulo      | Coelho    | O Alquimista       |
| Paulo      | Coelho    | Brida              | <-- Above rows are also produced by INNER JOIN
|            |           | The Arabian Nights | <-- This row is only produced by RIGHT JOIN or FULL JOIN
+------------+-----------+--------------------+
```

As can be seen, *all* rows from the *right* side of the join (books) are produced, including the ones that do not have any matches on the left side of the join (authors). The Arabian Night does not have a specific author, but it is still in the result set. It wouldn't be if this were an [INNER JOIN](#join-type-inner).

Not that a `RIGHT JOIN` is just an inversed `LEFT JOIN`, and you would be much more likely to write the same query like this, with no semantic difference:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  BOOK.TITLE
FROM BOOK
LEFT JOIN AUTHOR ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select(
         AUTHOR.FIRST_NAME,
         AUTHOR.LAST_NAME,
         BOOK.TITLE)
      .from(BOOK)
      .leftJoin(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

There are complex join trees where a `RIGHT JOIN` may make things simpler, but in most cases, it only complicates readability and maintainability of your query.

###### FULL JOIN

`FULL JOIN` is an occasionally useful way to join two tables when no rows from either table should be omitted. This can be useful e.g. to compare two data sets.

The following query produces *all* authors and *all* books:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  BOOK.TITLE
FROM AUTHOR
FULL JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select(
         AUTHOR.FIRST_NAME,
         AUTHOR.LAST_NAME,
         BOOK.TITLE)
      .from(AUTHOR)
      .fullJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

The result might look like this:

```text
+------------+-----------+--------------------+
| FIRST_NAME | LAST_NAME | TITLE              |
+------------+-----------+--------------------+
| George     | Orwell    | 1984               |
| George     | Orwell    | Animal Farm        |
| Paulo      | Coelho    | O Alquimista       |
| Paulo      | Coelho    | Brida              | <-- Above rows are also produced by INNER JOIN
| Jane       | Austen    |                    | <-- This row is only produced by LEFT JOIN or FULL JOIN
|            |           | The Arabian Nights | <-- This row is only produced by RIGHT JOIN or FULL JOIN
+------------+-----------+--------------------+
```

As can be seen, *all* rows from the *left* side of the join (authors) as well as from the *right* side of the join (books) are produced, including the ones that do not have any matches on the respective other side of the join.

###### Dialect support

This example using jOOQ:

```java
select(BOOK.ID, AUTHOR.ID).from(BOOK.leftJoin(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
SELECT BOOK.ID, AUTHOR.ID
FROM BOOK
  LEFT OUTER JOIN AUTHOR
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-type-semi"></a>
##### 3.10.3.4. SEMI JOIN

Relational algebra defines a `SEMI JOIN` operation that regrettably didn't make it into standard SQL (yet), though it is easy to emulate using the [EXISTS predicate](#exists-predicate) or [IN predicate](#in-predicate), which is what most people are doing.

jOOQ offers a convenient `LEFT SEMI JOIN` operator to match the relational algebra semantics. The following query will produce all authors that have books (but doesn't produce any books):

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME
FROM AUTHOR
WHERE EXISTS (
  SELECT * FROM BOOK WHERE BOOK.AUTHOR_ID = AUTHOR.ID
)
```

```java
create.select(
         AUTHOR.FIRST_NAME,
         AUTHOR.LAST_NAME
      )
      .from(AUTHOR)
      .leftSemiJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

The result might look like this:

```text
+------------+-----------+
| FIRST_NAME | LAST_NAME |
+------------+-----------+
| George     | Orwell    |
| Paulo      | Coelho    |
+------------+-----------+
```

Of course, you can form an equivalent query using `EXISTS` or `IN` as well in jOOQ. It is also possible to achieve `SEMI JOIN` semantics by using an [INNER JOIN](#join-type-inner), and possibly the `SELECT DISTINCT` clause, but chances are, that query is slower and incorrect (e.g. removing too many distinct rows). A `SEMI JOIN` both using jOOQ's convenience syntax or the equivalent SQL emulation using `EXISTS` or `IN` are semantically more precise and should be preferred.

`SEMI JOIN` is the inverse of the [ANTI JOIN](#join-type-anti) operator.

###### Dialect support

This example using jOOQ:

```java
select(AUTHOR.ID).from(AUTHOR).leftSemiJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT AUTHOR.ID
FROM AUTHOR
WHERE EXISTS (
  SELECT 1
  FROM BOOK
  WHERE BOOK.AUTHOR_ID = AUTHOR.ID
)
```

###### ClickHouse, Databricks

```sql
SELECT AUTHOR.ID
FROM AUTHOR
  LEFT SEMI JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### DuckDB

```sql
SELECT AUTHOR.ID
FROM AUTHOR
  SEMI JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-type-anti"></a>
##### 3.10.3.5. ANTI JOIN

Relational algebra defines a `ANTI JOIN` operation that regrettably didn't make it into standard SQL (yet), though it is easy to emulate using the [NOT EXISTS predicate](#exists-predicate). Unlike [SEMI JOIN](#join-type-semi), it is not advised to use the [NOT IN predicate](#in-predicate) to emulate `ANTI JOIN`, because that risks being incorrect in the presence of `NULL` values, a mistake that can be very subtle and thus hard to find.

jOOQ offers a convenient `LEFT ANTI JOIN` operator to match the relational algebra semantics. The following query will produce all authors that have no books:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME
FROM AUTHOR
WHERE NOT EXISTS (
  SELECT * FROM BOOK WHERE BOOK.AUTHOR_ID = AUTHOR.ID
)
```

```java
create.select(
         AUTHOR.FIRST_NAME,
         AUTHOR.LAST_NAME
      )
      .from(AUTHOR)
      .leftAntiJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

The result might look like this, i.e. we might have an author Jane Austen in our database, but we don't have any books for her yet:

```text
+------------+-----------+
| FIRST_NAME | LAST_NAME |
+------------+-----------+
| Jane       | Austen    |
+------------+-----------+
```

Of course, you can form an equivalent query using `NOT EXISTS` as well in jOOQ. It is also possible to achieve `ANTI JOIN` semantics by using an [LEFT JOIN](#join-type-outer) and a [NULL predicate](#null-predicate) on the anti joined table's primary key placed outside of the [ON clause](#join-predicate-on), though that might be a bit esoteric and hard to read:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME
FROM AUTHOR
LEFT JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
WHERE BOOK.ID IS NULL
 
```

```java
create.select(
         AUTHOR.FIRST_NAME,
         AUTHOR.LAST_NAME)
      .from(AUTHOR)
      .leftJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .where(BOOK.ID.isNull())
      .fetch();
```

Think of the [LEFT JOIN](#join-type-outer) example result:

```text
+------------+-----------+--------------+
| FIRST_NAME | LAST_NAME | TITLE        |
+------------+-----------+--------------+
| George     | Orwell    | 1984         |
| George     | Orwell    | Animal Farm  |
| Paulo      | Coelho    | O Alquimista |
| Paulo      | Coelho    | Brida        | <-- Reject all of the above where we have BOOK.ID IS NOT NULL
| Jane       | Austen    |              | <-- Keep only this row, where BOOK.ID IS NULL
+------------+-----------+--------------+
```

As can be seen, no `DISTINCT` is required to remove duplicates, because there's always only 1 row for an author without books.

`ANTI JOIN` is the inverse of the [SEMI JOIN](#join-type-semi) operator.

###### Dialect support

This example using jOOQ:

```java
select(AUTHOR.ID).from(AUTHOR).leftAntiJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
SELECT AUTHOR.ID
FROM AUTHOR
WHERE NOT EXISTS (
  SELECT 1
  FROM BOOK
  WHERE BOOK.AUTHOR_ID = AUTHOR.ID
)
```

###### ClickHouse, Databricks

```sql
SELECT AUTHOR.ID
FROM AUTHOR
  LEFT ANTI JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### DuckDB

```sql
SELECT AUTHOR.ID
FROM AUTHOR
  ANTI JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-predicate-on"></a>
##### 3.10.3.6. ON clause

All of [INNER JOIN](#join-type-inner), [OUTER JOIN](#join-type-outer), [SEMI JOIN](#join-type-semi), [ANTI JOIN](#join-type-anti) require a join predicate.

One way to supply this join predicate is the `ON` clause, which offers most flexibility. The following example shows how to "equi join" the author and books tables based on their `FOREIGN KEY` relationship:

```sql
SELECT *
FROM AUTHOR
JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select()
      .from(AUTHOR)
      .join(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

But in most dialects, any type of join predicate is possible in `ON` to specify what rows should be produced by the join operation. Note that while for [INNER JOIN](#join-type-inner), the predicates in the `ON` clause and the predicates in the [WHERE clause](#where-clause) have the same effect, this isn't true for all the other join types, including [OUTER JOIN](#join-type-outer), [SEMI JOIN](#join-type-semi), [ANTI JOIN](#join-type-anti). For example, the following query will list *all* authors and their books, but only if the book was published before the year 1950:

```sql
SELECT *
FROM AUTHOR
LEFT JOIN BOOK
  ON BOOK.AUTHOR_ID = AUTHOR.ID
  AND BOOK.PUBLISHED_IN < 1950
 
```

```java
create.select()
      .from(AUTHOR)
      .leftJoin(BOOK)
        .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
        .and(BOOK.PUBLISHED_IN.lt(1950))
      .fetch();
```

The result might look like this:

```text
+------------+-----------+--------------+
| FIRST_NAME | LAST_NAME | TITLE        |
+------------+-----------+--------------+
| George     | Orwell    | 1984         |
| George     | Orwell    | Animal Farm  | <-- This author's books were all published before 1950
| Paulo      | Coelho    |              | <-- This author's books were published after 1950
+------------+-----------+--------------+
```

We still get *all* the authors, but only the books that fulfil the `ON` predicate. This is very different from putting that additional predicate in the [WHERE clause](#where-clause):

```sql
SELECT *
FROM AUTHOR
LEFT JOIN BOOK
  ON BOOK.AUTHOR_ID = AUTHOR.ID
WHERE BOOK.PUBLISHED_IN < 1950
 
```

```java
create.select()
      .from(AUTHOR)
      .leftJoin(BOOK)
        .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .where(BOOK.PUBLISHED_IN.lt(1950))
      .fetch();
```

The result might now look like this:

```text
+------------+-----------+--------------+
| FIRST_NAME | LAST_NAME | TITLE        |
+------------+-----------+--------------+
| George     | Orwell    | 1984         |
| George     | Orwell    | Animal Farm  | <-- This author's books were all published before 1950
+------------+-----------+--------------+
```

Now the predicate is applied *after* the join operator, not *as a part of* the join operator, so it's just an ordinary predicate.

<a id="join-predicate-on-key"></a>
##### 3.10.3.7. ON KEY clause

> [!TIP]
> The `ON KEY` clause can quickly produce ambiguities as the implicit key path between two tables in a complex join tree isn't always unique. This can even happen for queries that have worked in the past, but due to new `FOREIGN KEY` constraints being added to tables, will stop working. Use this clause with caution!

All of [INNER JOIN](#join-type-inner), [OUTER JOIN](#join-type-outer), [SEMI JOIN](#join-type-semi), [ANTI JOIN](#join-type-anti) require a join predicate.

One way to supply this join predicate is the `ON KEY` clause, which allows for conveniently joining two tables based on their `FOREIGN KEY` relationship, assuming the relevant meta data is known to jOOQ via [code generation](#code-generation):

```sql
SELECT *
FROM AUTHOR
JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select()
      .from(AUTHOR)
      .join(BOOK).onKey()
      .fetch();
```

There are different overloads of this `onKey()` method. The above one is applicable when there are no ambiguous paths between the two joined tables. If there are several `FOREIGN KEY` declarations (e.g. a book has an `AUTHOR_ID` and a `CO_AUTHOR_ID`), then you can pass the [`org.jooq.ForeignKey`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ForeignKey.html) reference to the method, instead, to resolve the ambiguity.

```sql
SELECT *
FROM AUTHOR
JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select()
      .from(AUTHOR)
      .join(BOOK).onKey(Keys.FK_BOOK_AUTHOR)
      .fetch();
```

A similar way to join between tables by using the `FOREIGN KEY` information is [implicit JOIN](#implicit-join), which offers path-based navigational expressions from child table to parent table. Unlike the `ON KEY` syntax, implicit joins will never run into ambiguities.

<a id="join-predicate-using"></a>
##### 3.10.3.8. USING clause

> [!TIP]
> The `USING` clause can quickly produce ambiguities as the column names between two tables in a complex join tree aren't always unique. This can even happen for queries that have worked in the past, but due to new columns being added to tables, will stop working. Use this clause with caution!

All of [INNER JOIN](#join-type-inner), [OUTER JOIN](#join-type-outer), [SEMI JOIN](#join-type-semi), [ANTI JOIN](#join-type-anti) require a join predicate.

One way to supply this join predicate is the `USING` clause, which allows for specifying a set of column names that are common to both tables, based on which to form a join predicate. Assuming we called our `AUTHOR.ID` column `AUTHOR.AUTHOR_ID` instead:

```sql
SELECT *
FROM AUTHOR
JOIN BOOK USING (AUTHOR_ID)
 
```

```java
create.select()
      .from(AUTHOR)
      .join(BOOK).using(AUTHOR.AUTHOR_ID)
      .fetch();
```

There is a certain risk of ambiguities as well in more complex join trees, but in simple cases, this can be a very convenient way to join tables if you design your schema accordingly. The [https://www.jooq.org/sakila](https://www.jooq.org/sakila) is a good example where all `FOREIGN KEY` columns share the referenced `PRIMARY KEY` column's names.

<a id="join-predicate-natural"></a>
##### 3.10.3.9. NATURAL clause

> [!TIP]
> The `NATURAL KEY` operator can quickly produce ambiguities as the column names between two tables in a complex join tree aren't always unique, nor should they be included in a `JOIN` predicate (e.g. `LAST_UPDATE` or other technical columns, present on every table). This can even happen for queries that have worked in the past, but due to new columns being added to tables, will stop working. In fact, it's very hard to design a schema to allow for using `NATURAL JOIN`. Use this clause with caution!

All of [INNER JOIN](#join-type-inner), [OUTER JOIN](#join-type-outer), [SEMI JOIN](#join-type-semi), [ANTI JOIN](#join-type-anti) require a join predicate.

One way to supply this join predicate is the `NATURAL` clause, which works like [USING clause](#join-predicate-using), except that it discovers shared column names implicitly from the table metadata. Assuming we called our `AUTHOR.ID` column `AUTHOR.AUTHOR_ID` instead:

```sql
SELECT *
FROM AUTHOR
NATURAL JOIN BOOK
 
```

```java
create.select()
      .from(AUTHOR)
      .naturalJoin(BOOK)
      .fetch();
```

There is a high risk of ambiguities even in simple join trees, which is why this syntax is hardly ever used. It can be very rarely useful combined with [FULL JOIN](#join-type-outer) to form a [`NATURAL FULL JOIN`](https://blog.jooq.org/impress-your-coworkers-with-a-sql-natural-full-outer-join/), which can create a sort of SQL-style untagged union type between two row types. A bit esoteric for every day usage.

<a id="join-mode-lateral"></a>
##### 3.10.3.10. LATERAL

`LATERAL` is a SQL standard table operator to wrap derived tables (or other [table expressions](#table-expressions), in some dialects), such that the tables and columns declared *before* the `LATERAL` derived table become in scope. See [APPLY](#join-mode-apply) for an alternative, SQL Server specific syntax.

An example:

```sql
SELECT *
FROM
  AUTHOR,

  -- All previous objects (i.e. AUTHOR)
  -- are now in scope for the following subquery
  LATERAL (
    SELECT count(*)
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID -- AUTHOR is in scope
  );
```

```java
DSL.using(configuration)
   .select()
   .from(
      AUTHOR,
      lateral(
        select(count()
        .from(BOOK)
        .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
      )
   )
   .fetch();
```

This is most useful for:

- [TOP N per category queries](https://blog.jooq.org/how-to-write-efficient-top-n-queries-in-sql/), which are harder to implement otherwise
- [Local column variables](https://blog.jooq.org/lateral-is-your-friend-to-create-local-column-variables-in-sql/)
- [Calling table valued functions](#codegen-database-table-valued-functions) on a row-by-row basis

###### Dialect support

This example using jOOQ:

```java
select().from(AUTHOR, lateral(selectCount().from(BOOK).where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Databricks, Firebird, Hana, MySQL, Oracle, Postgres, Snowflake, Sybase, Trino, YugabyteDB

```sql
SELECT
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  alias_124651337.count
FROM
  AUTHOR,
  LATERAL (
    SELECT count(*)
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  ) alias_124651337
```

###### SQLDataWarehouse, SQLServer

```sql
SELECT
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  alias_124651337.count
FROM AUTHOR
  CROSS APPLY (
    SELECT count(*)
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  ) alias_124651337
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DuckDB, Exasol, H2, HSQLDB, Informix, MariaDB, MemSQL, Redshift, SQLite, Spanner, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-mode-apply"></a>
##### 3.10.3.11. APPLY

`APPLY` (specifically, `CROSS APPLY` or `OUTER APPLY`) is the SQL Server specific syntax for the SQL standard [LATERAL derived table syntax](#join-mode-lateral).

An example:

```sql
SELECT *
FROM
  AUTHOR

  -- All previous objects (i.e. AUTHOR)
  -- are now in scope for the following subquery
  CROSS APPLY (
    SELECT count(*)
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID -- AUTHOR is in scope
  );
```

```java
DSL.using(configuration)
   .select()
   .from(
      AUTHOR
      .crossApply(
        select(count()
        .from(BOOK)
        .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
      )
   )
   .fetch();
```

This is most useful for:

- [TOP N per category queries](https://blog.jooq.org/how-to-write-efficient-top-n-queries-in-sql/), which are harder to implement otherwise
- [Local column variables](https://blog.jooq.org/lateral-is-your-friend-to-create-local-column-variables-in-sql/)
- [Calling table valued functions](#codegen-database-table-valued-functions) on a row-by-row basis

###### Dialect support

This example using jOOQ:

```java
selectFrom(AUTHOR.crossApply(selectCount().from(BOOK).where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Databricks, Firebird, Hana, Postgres, Snowflake, Trino, YugabyteDB

```sql
SELECT
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  alias_124651337.count
FROM AUTHOR
  CROSS JOIN LATERAL (
    SELECT count(*)
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  ) alias_124651337
```

###### Oracle, SQLDataWarehouse, SQLServer, Sybase

```sql
SELECT
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  alias_124651337.count
FROM AUTHOR
  CROSS APPLY (
    SELECT count(*)
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  ) alias_124651337
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DuckDB, Exasol, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLite, Spanner, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-mode-partition-by"></a>
##### 3.10.3.12. PARTITION BY

Standard SQL (e.g. implemented by Oracle) ships with a special syntax available for [OUTER JOIN](#join-type-outer) clauses. This can be used to fill gaps for simplified analytical calculations. jOOQ only supports putting the `PARTITION BY` clause to the right of the `OUTER JOIN` clause. The following example will create at least one record per AUTHOR and per existing value in BOOK.PUBLISHED_IN, regardless if an AUTHOR has actually published a book in that year.

```sql
SELECT *
FROM AUTHOR
LEFT OUTER JOIN BOOK
PARTITION BY (PUBLISHED_IN)
ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select()
      .from(AUTHOR)
      .leftOuterJoin(BOOK)
      .partitionBy(BOOK.PUBLISHED_IN)
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

<a id="join-hints"></a>
##### 3.10.3.13. JOIN hints

By default, a `JOIN` operator can be implemented in multiple ways by an RDBMS. The chosen algorithm is vendor specific, and not specified in the SQL standard, as long as it correctly implements the [correct JOIN semantics](#joined-tables).

Sometimes, however, you may want to hint a more optimal algorithm to your RDBMS with a "join hint." The following sections show how to do that with jOOQ.

> [!TIP]
> In modern RDBMS, hinting is almost never necessary. A hint that may work for a given data set (size, distribution, etc.) may not work well for tomorrow's data anymore. Be very careful when hinting join algorithms, and use this tool only as a last resort. There are often better ways to tune your SQL.

`JOIN` hints are only available for:

- `INNER JOIN`
- `LEFT JOIN`
- `RIGHT JOIN`
- `FULL JOIN`

<a id="join-hint-hash"></a>
###### 3.10.3.13.1. HASH JOIN

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `HASH JOIN` algorithm uses a hash map to look up keys of one table when joining another. While this algorithm uses potentially large intermediary data structures, storing all data from tables in the hash maps (after applying predicates on them), it can join data in linear time, which is why it can be a fast choice for large data sets. An example:

```sql
SELECT *
FROM AUTHOR
INNER HASH JOIN BOOK
ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select()
      .from(AUTHOR)
      .hashJoin(BOOK)
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
selectFrom(AUTHOR.hashJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
```

Translates to the following dialect specific expressions:

###### CockroachDB, SQLServer

```sql
SELECT
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  INNER HASH JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### Oracle

```sql
SELECT /*+leading(AUTHOR BOOK) use_hash(AUTHOR BOOK)*/
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### YugabyteDB

```sql
SELECT /*+leading(AUTHOR BOOK) HashJoin(AUTHOR BOOK)*/
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-hint-loop"></a>
###### 3.10.3.13.2. LOOP JOIN

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `LOOP JOIN` (or nested loop join) algorithm runs a nested loop to fetch all rows of the second table corresponding to the rows of the first table. This typically has a higher algorithmic complexity than a linear one, which is why it can be a slower choice for larger data sets, although it's a good choice for small data sets - especially when indexes are available for nested loop lookups. An example:

```sql
SELECT *
FROM AUTHOR
INNER LOOP JOIN BOOK
ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select()
      .from(AUTHOR)
      .loopJoin(BOOK)
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
selectFrom(AUTHOR.loopJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
```

Translates to the following dialect specific expressions:

###### CockroachDB

```sql
SELECT
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  INNER LOOKUP JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### Oracle

```sql
SELECT /*+leading(AUTHOR BOOK) use_nl(AUTHOR BOOK)*/
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### SQLServer

```sql
SELECT
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  INNER LOOP JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### YugabyteDB

```sql
SELECT /*+leading(AUTHOR BOOK) NestLoop(AUTHOR BOOK)*/
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="join-hint-merge"></a>
###### 3.10.3.13.3. MERGE JOIN

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `MERGE JOIN` algorithm has similar characteristics as the `HASH JOIN` algorithm in that it reads all data of the tables involved (after applying predicates on them). But it does not require storing that data in memory, as it can "merge" all the tables' data in cases where it is fetched in a pre-sorted order, e.g. due to a covering index on the join key. An example:

```sql
SELECT *
FROM AUTHOR
INNER MERGE JOIN BOOK
ON BOOK.AUTHOR_ID = AUTHOR.ID
 
```

```java
create.select()
      .from(AUTHOR)
      .mergeJoin(BOOK)
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch();
```

###### Dialect support

This example using jOOQ:

```java
selectFrom(AUTHOR.mergeJoin(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
```

Translates to the following dialect specific expressions:

###### CockroachDB, SQLServer

```sql
SELECT
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  INNER MERGE JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### Oracle

```sql
SELECT /*+leading(AUTHOR BOOK) use_merge(AUTHOR BOOK)*/
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### YugabyteDB

```sql
SELECT /*+leading(AUTHOR BOOK) MergeJoin(AUTHOR BOOK)*/
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  AUTHOR.DATE_OF_BIRTH,
  AUTHOR.YEAR_OF_BIRTH,
  AUTHOR.DISTINGUISHED,
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM AUTHOR
  JOIN BOOK
    ON BOOK.AUTHOR_ID = AUTHOR.ID
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="values"></a>
#### 3.10.4. The VALUES() table constructor

Some databases allow for expressing in-memory temporary tables using a `VALUES()` constructor. This constructor usually works the same way as the `VALUES()` clause known from the [INSERT statement](#insert-statement) or from the [MERGE statement](#merge-statement). With jOOQ, you can also use the `VALUES()` table constructor, to create tables that can be used in a [SELECT statement's](#select-statement) [FROM clause](#from-clause):

```sql
SELECT a, b
FROM VALUES(1, 'a'),
           (2, 'b') t(a, b)
 
```

```java
create.select()
      .from(values(row(1, "a"),
                   row(2, "b")).as("t", "a", "b"))
      .fetch();
```

Note, that it is usually quite useful to provide column aliases ("derived column lists") along with the table alias for the `VALUES()` constructor.

If the data is already available in a [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html), e.g. after [creating it in memory](#in-memory-results) or after reading it from CSV, JSON, or other formats, then [`DSL.table(Result)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#table(org.jooq.Result)) produces such a `VALUES()` constructor with derived column lists from the `Result`. See the section about [working with in-memory results](#in-memory-usage) for an example.

##### Dialect support

This example using jOOQ:

```java
selectFrom(values(row(1, "a"), row(2, "b")).as("t", "a", "b"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
SELECT t.a, t.b
FROM (
  SELECT
    1 a,
    'a' b
  FROM (
    SELECT count(*) dual
    FROM MSysResources
  ) AS dual
  UNION ALL
  SELECT 2, 'b'
  FROM (
    SELECT count(*) dual
    FROM MSysResources
  ) AS dual
) t
```

###### ASE, Redshift, SQLDataWarehouse, Vertica

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 'a'
  UNION ALL
  SELECT 2, 'b'
) t (a, b)
```

###### Aurora MySQL, MemSQL

```sql
SELECT t.a, t.b
FROM (
  SELECT
    1 a,
    'a' b
  FROM DUAL
  UNION ALL
  SELECT 2, 'b'
  FROM DUAL
) t
```

###### Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, H2, HSQLDB, Oracle, Postgres, SQLServer, Snowflake, Trino, YugabyteDB

```sql
SELECT t.a, t.b
FROM (
  VALUES
    (1, 'a'),
    (2, 'b')
) t (a, b)
```

###### BigQuery

```sql
SELECT t.a, t.b
FROM (
  SELECT
    null a,
    null b
  FROM UNNEST([STRUCT(1 AS dual)]) AS dual
  WHERE FALSE
  UNION ALL
  SELECT *
  FROM UNNEST ([
    STRUCT (1, 'a'),
    STRUCT (2, 'b')
  ]) t
) t
```

###### ClickHouse, MariaDB, Spanner

```sql
SELECT t.a, t.b
FROM (
  SELECT
    1 a,
    'a' b
  UNION ALL
  SELECT 2, 'b'
) t
```

###### Databricks

```sql
SELECT t.a, t.b
FROM (
  VALUES
    STRUCT (1, 'a'),
    STRUCT (2, 'b')
) t (a, b)
```

###### Firebird

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 'a'
  FROM RDB$DATABASE
  UNION ALL
  SELECT 2, 'b'
  FROM RDB$DATABASE
) t (a, b)
```

###### Hana

```sql
SELECT t.a, t.b
FROM (
  SELECT
    1 a,
    'a' b
  FROM SYS.DUMMY
  UNION ALL
  SELECT 2, 'b'
  FROM SYS.DUMMY
) t
```

###### Informix

```sql
SELECT t.a, t.b
FROM (
  TABLE (MULTISET {
    ROW (1, 'a'),
    ROW (2, 'b')
  })
) t (a, b)
```

###### MySQL

```sql
SELECT t.a, t.b
FROM (
  VALUES
    ROW (1, 'a'),
    ROW (2, 'b')
) t (a, b)
```

###### SQLite

```sql
SELECT t.a, t.b
FROM (
  SELECT
    null a,
    null b
  WHERE 1 = 0
  UNION ALL
  SELECT *
  FROM (
    VALUES
      (1, 'a'),
      (2, 'b')
  ) t
) t
```

###### Sybase

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 'a'
  FROM SYS.DUMMY
  UNION ALL
  SELECT 2, 'b'
  FROM SYS.DUMMY
) t (a, b)
```

###### Teradata

```sql
SELECT t.a, t.b
FROM (
  SELECT 1, 'a'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
  UNION ALL
  SELECT 2, 'b'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
) t (a, b)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="derived-tables"></a>
#### 3.10.5. Derived tables

A derived table is a nested [SELECT](#select-statement) in the [FROM clause](#from-clause), i.e. it can be used as a [table expression](#table-expressions). As such, it works differently from a [scalar subquery](#scalar-subqueries), which is a [column expression](#column-expressions).

```sql
 

SELECT nested.* FROM (
      SELECT AUTHOR_ID, count(*) books
        FROM BOOK
    GROUP BY AUTHOR_ID
) nested
ORDER BY nested.books DESC
 
```

```java
Table<?> nested =
    create.select(BOOK.AUTHOR_ID, count().as("books"))
          .from(BOOK)
          .groupBy(BOOK.AUTHOR_ID).asTable("nested");

create.select(nested.fields())
      .from(nested)
      .orderBy(nested.field("books"))
      .fetch();
```

##### Dialect support

This example using jOOQ:

```java
selectFrom(select(BOOK.ID).from(BOOK).asTable("t"))
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
SELECT t.ID
FROM (
  SELECT BOOK.ID
  FROM BOOK
) t
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="inline-derived-tables"></a>
#### 3.10.6. Inline derived tables

An inline derived table is a [Table expression](#table-expressions) with a [WHERE clause](#where-clause), both of which can be inlined into the calling query in a lot of cases.

The main use-case for this feature is [dynamic SQL](#dynamic-sql), where you can add predicates to tables without call sites noticing, and without giving up on type safety.

```sql
-- In SQL, the derived table is inlined
SELECT
  BOOK.ID,
  BOOK.TITLE
FROM BOOK
WHERE BOOK.TITLE LIKE 'A%'
```

```java
// This book reference can be supplied dynamically
Book aBooks = BOOK.where(BOOK.TITLE.like("A%"));

create.select(aBooks.ID, aBooks.TITLE)
      .from(aBooks)
      .fetch();
```

Whenever the context requires, the inline derived table generates an explicit [derived table](#derived-tables), e.g. when used in a `LEFT JOIN`:

```sql
-- In SQL, the derived table created explicitly
SELECT BOOK.ID, BOOK.TITLE
FROM AUTHOR
LEFT JOIN (
  SELECT * FROM BOOK WHERE BOOK.TITLE LIKE 'A%'
) BOOK
ON AUTHOR.ID = BOOK.AUTHOR_ID
```

```java
// This book reference can be supplied dynamically
Book aBooks = BOOK.where(BOOK.TITLE.like("A%"));

create.select(AUTHOR.ID, aBooks.ID, aBooks.TITLE)
      .from(AUTHOR)
      .leftJoin(aBooks).on(AUTHOR.ID.eq(aBooks.AUTHOR_ID))
      .fetch();
```

<a id="common-table-expressions"></a>
#### 3.10.7. Common table expressions (CTE)

Common table expressions are table variables that are declared in the [WITH clause](#with-clause) of a [DML statement](#sql-statements) for multiple use within the query.

When using common table expressions with jOOQ, there are essentially two approaches:

- Declaring and assigning common table expressions explicitly to [names](#names)
- Inlining common table expressions into a [SELECT statement](#select-statement)

##### Explicit common table expressions

The following example makes use of [names](#names) to construct common table expressions, which can then be supplied to a `WITH` clause or a `FROM` clause of a [SELECT statement](#select-statement):

```sql
-- Pseudo-SQL for a common table expression specification
"t1" ("f1", "f2") AS (SELECT 1, 'a')
```

```java
// Code for creating a CommonTableExpression instance
name("t1").fields("f1", "f2").as(select(val(1), val("a")));
```

The above expression can be assigned to a variable in Java and then be used to create a full [SELECT statement](#select-statement):

```sql
WITH "t1" ("f1", "f2") AS (SELECT 1, 'a'),
     "t2" ("f3", "f4") AS (SELECT 2, 'b')
SELECT
    "t1"."f1" + "t2"."f3" AS "add",
    "t1"."f2" || "t2"."f4" AS "concat"
FROM "t1", "t2"
;
```

```java
CommonTableExpression<Record2<Integer, String>> t1 =
  name("t1").fields("f1", "f2").as(select(val(1), val("a")));
CommonTableExpression<Record2<Integer, String>> t2 =
  name("t2").fields("f3", "f4").as(select(val(2), val("b")));

Result<?> result2 =
create.with(t1)
      .with(t2)
      .select(
          t1.field("f1").add(t2.field("f3")).as("add"),
          t1.field("f2").concat(t2.field("f4")).as("concat"))
      .from(t1, t2)
      .fetch();
```

Note that the [`org.jooq.CommonTableExpression`](https://www.jooq.org/javadoc/3.22.x/org/jooq/CommonTableExpression.html) type extends the commonly used [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) type, and can thus be used wherever a table can be used.

##### Inlined common table expressions

If you're just operating on [plain SQL](#plain-sql), you may not need to keep intermediate references to such common table expressions. An example of such usage would be this:

```sql
WITH "a" AS (SELECT
               1 AS "x",
               'a' AS "y"
            )
SELECT
FROM "a"
;
```

```java
create.with("a").as(select(
                        val(1).as("x"),
                        val("a").as("y")
                   ))
      .select()
      .from(table(name("a")))
      .fetch();
```

<a id="pivot-tables"></a>
#### 3.10.8. The Oracle PIVOT clause

If you are closely coupling your application to an Oracle database, you can take advantage of some Oracle-specific features, such as the PIVOT clause, used for statistical analyses. The formal syntax definition is as follows:

```text
-- SELECT ..
     FROM table PIVOT (aggregateFunction [, aggregateFunction] FOR column IN (expression [, expression]))
--  WHERE ..
```

The PIVOT clause is available from the [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) type, as pivoting is done directly on a table. Currently, only Oracle's PIVOT clause is supported. Support for SQL Server's slightly different PIVOT clause will be added later. Also, jOOQ may emulate PIVOT for other dialects in the future.

<a id="relational-division"></a>
#### 3.10.9. Relational division

There is one operation in relational algebra that is not given a lot of attention, because it is rarely used in real-world applications. It is the relational division, the opposite operation of the cross product (or, relational multiplication). The following is an approximate definition of a relational division:

```
Assume the following cross join / cartesian product
C = A × B

Then it can be said that
A = C ÷ B
B = C ÷ A
```

With jOOQ, you can simplify using relational divisions by using the following syntax:

```java
C.divideBy(B).on(C.ID.eq(B.C_ID)).returning(C.TEXT)
```

The above roughly translates to

```sql
SELECT DISTINCT C.TEXT FROM C "c1"
WHERE NOT EXISTS (
  SELECT 1 FROM B
  WHERE NOT EXISTS (
    SELECT 1 FROM C "c2"
    WHERE "c2".TEXT = "c1".TEXT
    AND "c2".ID = B.C_ID
  )
)
```

Or in plain text: Find those TEXT values in C whose ID's correspond to all ID's in B. Note that from the above SQL statement, it is immediately clear that proper indexing is of the essence. Be sure to have indexes on all columns referenced from the on(...) and returning(...) clauses.

For more information about relational division and some nice, real-life examples, see

- [https://en.wikipedia.org/wiki/Relational_algebra#Division](https://en.wikipedia.org/wiki/Relational_algebra#Division)
- [https://www.red-gate.com/simple-talk/databases/sql-server/t-sql-programming-sql-server/divided-we-stand-the-sql-of-relational-division/](https://www.red-gate.com/simple-talk/databases/sql-server/t-sql-programming-sql-server/divided-we-stand-the-sql-of-relational-division/)

<a id="array-and-cursor-unnesting"></a>
#### 3.10.10. Array and cursor unnesting

The SQL standard specifies how SQL databases should implement ARRAY and TABLE types, as well as CURSOR types. Put simply, a CURSOR is a pointer to any materialised [table expression](#table-expressions). Depending on the cursor's features, this table expression can be scrolled through in both directions, records can be locked, updated, removed, inserted, etc. Often, CURSOR types contain s, whereas ARRAY and TABLE types contain simple scalar values, although that is not a requirement

ARRAY types in SQL are similar to Java's array types. They contain a "component type" or "element type" and a "dimension". This sort of ARRAY type is implemented in H2, HSQLDB and Postgres and supported by jOOQ as such. Oracle uses strongly-typed arrays, which means that an ARRAY type (VARRAY or TABLE type) has a name and possibly a maximum capacity associated with it.

##### Unnesting array and cursor types

The real power of these types become more obvious when you fetch them from [stored procedures](#stored-procedures) to unnest them as [table expressions](#table-expressions) and use them in your [FROM clause](#from-clause). An example is given here, where Oracle's DBMS_XPLAN package is used to fetch a cursor containing data about the most recent execution plan:

```sql
SELECT *
FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));
 
```

```java
create.select()
      .from(table(DbmsXplan.displayCursor(null, null, "ALLSTATS"))
      .fetch();
```

Note, in order to access the DbmsXplan package, you can use the [code generator](#code-generation) to generate Oracle's SYS schema.

<a id="table-valued-functions"></a>
#### 3.10.11. Table-valued functions

Some databases support functions that can produce tables for use in arbitrary [SELECT statements](#select-statement). jOOQ supports these functions out-of-the-box for such databases. For instance, in SQL Server, the following function produces a table of `(ID, TITLE)` columns containing either all the books or just one book by ID:

```sql
CREATE FUNCTION f_books (@id INTEGER)
RETURNS @out_table TABLE (
    id INTEGER,
    title VARCHAR(400)
)
AS
BEGIN
    INSERT @out_table
    SELECT id, title
    FROM book
    WHERE @id IS NULL OR id = @id
    ORDER BY id
    RETURN
END
```

The jOOQ code generator will now produce a [generated table](#generated-tables) from the above, which can be used as a SQL function:

```java
// Fetching all books records
Result<FBooksRecord> r1 = create.selectFrom(fBooks(null)).fetch();

// Lateral joining the table-valued function to another table using CROSS APPLY:
create.select(BOOK.ID, F_BOOKS.TITLE)
      .from(BOOK.crossApply(fBooks(BOOK.ID)))
      .fetch();
```

<a id="generate-series"></a>
#### 3.10.12. GENERATE_SERIES

A nice built-in [table-valued function](#table-valued-functions) from the PostgreSQL dialect is the `GENERATE_SERIES()` function, which allows for creating a table for a range of numeric values. Many dialects have some way of generating such a table, and if not, it can be emulated using [recursive SQL](#with-recursive-clause).

```java
// Values from 1 to 10
Result<Record1<Integer>> r = create.selectFrom(generateSeries(1, 10)).fetch();
```

##### Dialect support

This example using jOOQ:

```java
selectFrom(generateSeries(1, 10))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DuckDB, Postgres, YugabyteDB

```sql
SELECT generate_series.generate_series
FROM generate_series(1, 10)
```

###### BigQuery, Spanner

```sql
SELECT generate_series.generate_series
FROM (
  SELECT null generate_series
  FROM UNNEST([STRUCT(1 AS dual)]) AS dual
  WHERE FALSE
  UNION ALL
  SELECT *
  FROM unnest(generate_array(1, 10)) generate_series
) generate_series
```

###### ClickHouse

```sql
SELECT generate_series.generate_series
FROM (
  SELECT null generate_series
  WHERE FALSE
  UNION ALL
  SELECT *
  FROM (
    SELECT cast(number AS Nullable(integer)) generate_series
    FROM numbers(1, (10 + 1))
  ) generate_series
) generate_series
```

###### CockroachDB

```sql
SELECT generate_series.generate_series
FROM generate_series(1, 10) generate_series (generate_series)
```

###### Databricks

```sql
SELECT generate_series.generate_series
FROM explode(sequence(1, 10)) generate_series (generate_series)
```

###### DB2

```sql
SELECT generate_series.generate_series
FROM (
  WITH
    generate_series(generate_series) AS (
      SELECT 1
      FROM SYSIBM.DUAL
      UNION ALL
      SELECT (generate_series + 1)
      FROM generate_series
      WHERE generate_series < 10
    )
  SELECT generate_series
  FROM generate_series
) generate_series
```

###### Exasol, Oracle

```sql
SELECT generate_series.generate_series
FROM (
  SELECT (level + (1 - 1)) generate_series
  FROM DUAL
  CONNECT BY level <= ((10 + 1) - 1)
) generate_series
```

###### Firebird

```sql
SELECT generate_series.generate_series
FROM (
  WITH RECURSIVE
    generate_series(generate_series) AS (
      SELECT 1
      FROM RDB$DATABASE
      UNION ALL
      SELECT (generate_series + 1)
      FROM generate_series
      WHERE generate_series < 10
    )
  SELECT generate_series
  FROM generate_series
) generate_series
```

###### H2

```sql
SELECT generate_series.generate_series
FROM system_range(1, 10) generate_series (generate_series)
```

###### Hana

```sql
SELECT generate_series.generate_series
FROM (
  SELECT cast(
    null
    AS integer
  ) generate_series
  FROM SYS.DUMMY
  WHERE 1 = 0
  UNION ALL
  SELECT *
  FROM (
    SELECT generated_period_end generate_series
    FROM series_generate_integer(1, (1 - 1), 10)
  ) generate_series
) generate_series
```

###### HSQLDB

```sql
SELECT generate_series.generate_series
FROM (
  WITH RECURSIVE
    generate_series(generate_series) AS (
      SELECT 1
      FROM (VALUES (1)) AS dual (dual)
      UNION ALL
      SELECT (generate_series + 1)
      FROM generate_series
      WHERE generate_series < 10
    )
  SELECT generate_series
  FROM generate_series
) generate_series
```

###### Informix

```sql
SELECT generate_series.generate_series
FROM (
  SELECT (level + (1 - 1)) generate_series
  FROM (
    SELECT 1 AS dual
    FROM systables
    WHERE (tabid = 1)
  ) AS dual
  CONNECT BY level <= ((10 + 1) - 1)
) generate_series
```

###### MariaDB, MySQL, SQLite, Trino

```sql
SELECT generate_series.generate_series
FROM (
  WITH RECURSIVE
    generate_series(generate_series) AS (
      SELECT 1
      UNION ALL
      SELECT (generate_series + 1)
      FROM generate_series
      WHERE generate_series < 10
    )
  SELECT generate_series
  FROM generate_series
) generate_series
```

###### Snowflake

```sql
SELECT generate_series.generate_series
FROM (
  SELECT ((seq4() + 1) + (1 - 1)) generate_series
  FROM TABLE(generator(rowcount => (10 - (1 - 1))))
) generate_series (generate_series)
```

###### SQLDataWarehouse

```sql
WITH
  generate_series(generate_series) AS (
    SELECT 1
    UNION ALL
    SELECT (generate_series + 1)
    FROM generate_series
    WHERE generate_series < 10
  )
SELECT generate_series.generate_series
FROM (
  SELECT generate_series
  FROM generate_series
) generate_series
```

###### SQLServer

```sql
SELECT generate_series.generate_series
FROM (
  SELECT *
  FROM generate_series(1, 10)
) generate_series (generate_series)
```

###### Sybase

```sql
SELECT generate_series.generate_series
FROM (
  WITH RECURSIVE
    generate_series(generate_series) AS (
      SELECT 1
      FROM SYS.DUMMY
      UNION ALL
      SELECT (generate_series + 1)
      FROM generate_series
      WHERE generate_series < 10
    )
  SELECT generate_series
  FROM generate_series
) generate_series
```

###### Teradata

```sql
WITH RECURSIVE
  generate_series(generate_series) AS (
    SELECT 1
    FROM (
      SELECT 1 AS "dual"
    ) AS "dual"
    UNION ALL
    SELECT (generate_series + 1)
    FROM generate_series
    WHERE generate_series < 10
  )
SELECT generate_series.generate_series
FROM (
  SELECT generate_series
  FROM generate_series
) generate_series
```

###### ASE, Access, Aurora MySQL, MemSQL, Redshift, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="with-ordinality"></a>
#### 3.10.13. WITH ORDINALITY

The SQL standard specifies a `WITH ORDINALITY` clause that can be appended to any [UNNEST function call](#array-and-cursor-unnesting) (also known as collection derived table). PostgreSQL goes a bit further and allows for the syntax to be used also with [any type of table valued function](#table-valued-functions), considering that `UNNEST` is just another table value function in their implementation. CockroachDB, on the other hand, allows for using `WITH ORDINALITY` with almost any table expression, which makes sense for [derived tables](#derived-tables) (if they're ordered) or the [VALUES() table constructor](#values). Note that [JSON_TABLE](#json-table-function) and [XMLTABLE](#xml-table-function) have their own native `FOR ORDINALITY` syntax, so `WITH ORDINALITY` is redundant, there.

jOOQ supports the syntax like CockroachDB, on any [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html):

```sql
SELECT *
FROM UNNEST(ARRAY['a', 'b']) WITH ORDINALITY
 
```

```java
create.select()
      .from(unnest(array("a", "b")).withOrdinality())
      .fetch();
```

> [!TIP]
> An emulation using a [ROW_NUMBER() window function](#window-functions) is possible. The ordering stability of such a derived table is at the mercy of the optimiser implementation, and may break "unexpectedly," derived table ordering isn't required to be stable in most RDBMS. So, unless the ordinality can be assigned without any ambiguity (e.g. through native support or because the emulation is entirely implemented in jOOQ, client side), it is better not to rely on deterministic ordinalities, other than the fact that all numbers from `1` to `N` will be assigned uniquely.

##### Dialect support

This example using jOOQ:

```java
select().from(unnest(array("a", "b")).withOrdinality().as("t", "a", "b"))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, H2, HSQLDB, Postgres

```sql
SELECT t.a, t.b
FROM UNNEST(ARRAY['a', 'b']) WITH ORDINALITY t (a, b)
```

###### BigQuery, Spanner

```sql
SELECT t.a, t.b
FROM (
  SELECT
    null a,
    null b
  FROM UNNEST([STRUCT(1 AS dual)]) AS dual
  WHERE FALSE
  UNION ALL
  SELECT *
  FROM (
    SELECT
      COLUMN_VALUE,
      (offset + 1) ordinal
    FROM UNNEST(ARRAY['a', 'b']) AS COLUMN_VALUE WITH OFFSET
  ) t
) t
```

###### Databricks

```sql
SELECT t.a, t.b
FROM (
  SELECT
    array_table.COLUMN_VALUE,
    row_number() OVER (
      ORDER BY (
        SELECT 1
      )
    ) ordinal
  FROM EXPLODE(ARRAY('a', 'b')) array_table (COLUMN_VALUE)
) t (a, b)
```

###### DuckDB

```sql
SELECT t.a, t.b
FROM (
  SELECT
    array_table.COLUMN_VALUE,
    row_number() OVER () ordinal
  FROM UNNEST(ARRAY['a', 'b']) array_table (COLUMN_VALUE)
) t (a, b)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-table-function"></a>
#### 3.10.14. JSON_TABLE

Some dialects ship with a built-in standard SQL [table-valued function](#table-valued-functions) called `JSON_TABLE`, which can be used to unnest a JSON data structure into a SQL table.

```sql
SELECT *
FROM json_table(
  '[{"a":5,"b":{"x":10}},{"a":7,"b":{"y":20}}]',
  '$[*]'
  COLUMNS (
    id FOR ORDINALITY,
    a INT,
    x INT PATH '$.b.x',
    y INT PATH '$.b.y'
  )
) AS t
```

```java
create.select()
      .from(jsonTable(
          json("[{\"a\":5,\"b\":{\"x\":10}},"
              + "{\"a\":7,\"b\":{\"y\":20}}]"),
          "$[*]")
        .column("id").forOrdinality()
        .column("a", INTEGER)
        .column("x", INTEGER).path("$.b.x")
        .column("y", INTEGER).path("$.b.y")
        .as("t"))
      .fetch();
```

The result would look like this:

```text
+----+---+----+----+
| ID | A |  X |  Y |
+----+---+----+----+
|  1 | 5 | 10 |    |
|  2 | 7 |    | 20 |
+----+---+----+----+
```

##### Dialect support

This example using jOOQ:

```java
selectFrom(jsonTable(json("[{\"a\":5,\"b\":{\"x\":10}}]"), "$[*]").column("id").forOrdinality().column("a", INTEGER).column("x", INTEGER).path("$.b.x").as("t"))
```

Translates to the following dialect specific expressions:

###### DB2

```sql
SELECT t.id, t.a, t.x
FROM JSON_TABLE(
  '[{"a":5,"b":{"x":10}}]',
  '$[*]'
  COLUMNS (
    id FOR ORDINALITY,
    a integer,
    x integer PATH '$.b.x'
  )
  ERROR ON ERROR
) t
```

###### Hana

```sql
SELECT t.id, t.a, t.x
FROM JSON_TABLE(
  '[{"a":5,"b":{"x":10}}]',
  '$[*]'
  COLUMNS (
    id FOR ORDINALITY,
    a integer PATH '$.a',
    x integer PATH '$.b.x'
  )
) t
```

###### MariaDB

```sql
SELECT t.id, t.a, t.x
FROM JSON_TABLE(
  json_extract('[{"a":5,"b":{"x":10}}]', '$'),
  '$[*]'
  COLUMNS (
    id FOR ORDINALITY,
    a int PATH '$.a',
    x int PATH '$.b.x'
  )
) t
```

###### MySQL

```sql
SELECT t.id, t.a, t.x
FROM JSON_TABLE(
  cast('[{"a":5,"b":{"x":10}}]' AS json),
  '$[*]'
  COLUMNS (
    id FOR ORDINALITY,
    a int PATH '$.a',
    x int PATH '$.b.x'
  )
) t
```

###### Oracle

```sql
SELECT t.id, t.a, t.x
FROM JSON_TABLE(
  '[{"a":5,"b":{"x":10}}]',
  '$[*]'
  COLUMNS (
    id FOR ORDINALITY,
    a number(10),
    x number(10) PATH '$.b.x'
  )
) t
```

###### Postgres, YugabyteDB

```sql
SELECT t.id, t.a, t.x
FROM (
  SELECT
    o id,
    cast((jsonb_path_query_first(j, cast('$.a' as jsonpath))->>0) as INT) a,
    cast((jsonb_path_query_first(j, cast('$.b.x' as jsonpath))->>0) as INT) x
  FROM jsonb_path_query(cast('[{"a":5,"b":{"x":10}}]' AS jsonb), cast('$[*]' as jsonpath)) WITH ORDINALITY AS t(j, o)
) t
```

###### SQLServer

```sql
SELECT t.id, t.a, t.x
FROM (
  SELECT
    row_number() OVER (
      ORDER BY (
        SELECT 1
      )
    ) id,
    a,
    x
  FROM openjson('[{"a":5,"b":{"x":10}}]', '$[*]') WITH (
    a int,
    x int '$.b.x'
  ) t
) t
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-table-function"></a>
#### 3.10.15. XMLTABLE

Some dialects ship with a built-in standard SQL [table-valued function](#table-valued-functions) called `XMLTABLE`, which can be used to unnest an XML data structure into a SQL table.

```sql
SELECT *
FROM xmltable('//row'
  PASSING
    '<rows>
       <row><a>5</a><b><x>10</x></b></row>
       <row><a>7</a><b><y>20</y></b></row>
     </rows>'
  COLUMNS
    id FOR ORDINALITY,
    a INT,
    x INT PATH 'b/x',
    y INT PATH 'b/y'
)
```

```java
create.select()
      .from(xmltable("//row")
        .passing(xml(
          "<rows>"
        + "<row><a>5</a><b><x>10</x></b></row>"
        + "<row><a>7</a><b><y>20</y></b></row>"
        + "</rows>"
        ))
        .column("id").forOrdinality()
        .column("a", INTEGER)
        .column("x", INTEGER).path("b/x")
        .column("y", INTEGER).path("b/y"))
      .fetch();
```

The result would look like this:

```text
+----+---+----+----+
| ID | A |  X |  Y |
+----+---+----+----+
|  1 | 5 | 10 |    |
|  2 | 7 |    | 20 |
+----+---+----+----+
```

##### Dialect support

This example using jOOQ:

```java
selectFrom(xmltable("//row").passing(xml("<rows><row><a>5</a><b><x>10</x></b></row></rows>")).column("id").forOrdinality().column("a", INTEGER).column("x", INTEGER).path("b/x"))
```

Translates to the following dialect specific expressions:

###### DB2

```sql
SELECT id, a, x
FROM XMLTABLE(
  '//row'
  PASSING xmlparse(DOCUMENT '<rows><row><a>5</a><b><x>10</x></b></row></rows>')
  COLUMNS
    id FOR ORDINALITY,
    a integer,
    x integer PATH 'b/x'
)
```

###### Hana

```sql
SELECT id, a, x
FROM XMLTABLE(
  '//row'
  PASSING '<rows><row><a>5</a><b><x>10</x></b></row></rows>'
  COLUMNS
    id FOR ORDINALITY,
    a integer PATH 'a',
    x integer PATH 'b/x'
)
```

###### Oracle

```sql
SELECT id, a, x
FROM XMLTABLE(
  '//row'
  PASSING xmltype.createxml('<rows><row><a>5</a><b><x>10</x></b></row></rows>')
  COLUMNS
    id FOR ORDINALITY,
    a number(10),
    x number(10) PATH 'b/x'
)
```

###### Postgres

```sql
SELECT id, a, x
FROM XMLTABLE(
  '//row'
  PASSING cast('<rows><row><a>5</a><b><x>10</x></b></row></rows>' AS xml)
  COLUMNS
    id FOR ORDINALITY,
    a int,
    x int PATH 'b/x'
)
```

###### SQLServer

```sql
SELECT id, a, x
FROM (
  SELECT
    row_number() OVER (
      ORDER BY (
        SELECT 1
      )
    ) id,
    t2.x.value('(a)[1]', 'int') a,
    t2.x.value('(b/x)[1]', 'int') x
  FROM (
    SELECT cast('<rows><row><a>5</a><b><x>10</x></b></row></rows>' AS xml)
  ) t1 (x)
    CROSS APPLY t1.x.nodes('//row') t2 (x)
)
```

###### Teradata

```sql
SELECT id, a, x
FROM XMLTABLE(
  '//row'
  PASSING '<rows><row><a>5</a><b><x>10</x></b></row></rows>'
  COLUMNS
    id FOR ORDINALITY,
    a integer,
    x integer PATH 'b/x'
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="dual"></a>
#### 3.10.16. The DUAL table

The SQL standard specifies that the [FROM clause](#from-clause) is mandatory in a [SELECT statement](#select-statement). However, in the real world, there exist three types of databases:

- The ones that always require a `FROM` clause (as required by the SQL standard)
- The ones that never require a `FROM` clause (and still allow a `WHERE` clause)
- The ones that require a `FROM` clause only with a `WHERE` clause, `GROUP BY` clause, or `HAVING` clause

With jOOQ, you don't have to worry about the above distinction of SQL dialects. jOOQ never requires a `FROM` clause, but renders the necessary `"DUAL"` table, if needed. The following program shows how jOOQ renders `"DUAL"` tables

> [!TIP]
> Note, that some databases (H2, MySQL) can normally do without `"DUAL"`. However, there exist some corner-cases with complex nested `SELECT` statements, where this will cause syntax errors (or parser bugs). To stay on the safe side, jOOQ will always render "dual" in those dialects.

##### Dialect support

This example using jOOQ:

```java
select(inline(1))
```

Translates to the following dialect specific expressions:

###### Access

```sql
SELECT 1
FROM (
  SELECT count(*) dual
  FROM MSysResources
) AS dual
```

###### ASE, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
SELECT 1
```

###### Aurora MySQL, MemSQL

```sql
SELECT 1
FROM DUAL
```

###### DB2

```sql
SELECT 1
FROM SYSIBM.DUAL
```

###### Firebird

```sql
SELECT 1
FROM RDB$DATABASE
```

###### Hana, Sybase

```sql
SELECT 1
FROM SYS.DUMMY
```

###### HSQLDB

```sql
SELECT 1
FROM (VALUES (1)) AS dual (dual)
```

###### Informix

```sql
SELECT 1
FROM (
  SELECT 1 AS dual
  FROM systables
  WHERE (tabid = 1)
) AS dual
```

###### Teradata

```sql
SELECT 1
FROM (
  SELECT 1 AS "dual"
) AS "dual"
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="temporal-tables"></a>
#### 3.10.17. Temporal tables

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

SQL:2011 standardised a feature called temporal validity, which comes in two flavours implemented through temporal tables:

- System versioned tables
- Application versioned tables

A few dialects, including DB2, MariaDB, Oracle, SQL Server implement one or the other, or both types of temporal tables through standard or vendor specific syntax.

##### System versioned tables

A system versioned table can be used for automatic backups or audit logging of all content in a table. Each "version" of a record has a validity period, until the record is updated or deleted, when a new "version" of the record is created.

Consider the following table (please consider your database manual for actual syntax. There are restrictions on data types and on how the history table is managed.):

```sql
CREATE TABLE product_price (
  product_id BIGINT NOT NULL PRIMARY KEY,
  price DECIMAL NOT NULL,
  start_ts TIMESTAMP GENERATED ALWAYS AS ROW START,
  end_ts TIMESTAMP GENERATED ALWAYS AS ROW END,
  PERIOD FOR SYSTEM_TIME (start_ts, end_ts)
);
```

A table that is defined using the above (simplified) syntax can now be used in DML statements as follows:

```sql
-- At time T1, a new product is created:
INSERT INTO product (product_id, price)
VALUES (1, 100.00);

-- Later, at time T2, the price is updated:
UPDATE product
SET price = 200.00
WHERE product_id = 1;
```

```java
create.insertInto(PRODUCT, PRODUCT.PRODUCT_ID, PRODUCT.PRICE)
      .values(1, new BigDecimal("100.00"))
      .execute();

create.update(PRODUCT)
      .set(PRODUCT.PRICE, new BigDecimal("200.00"))
      .where(PRODUCT.PRODUCT_ID.eq(1))
      .execute();
```

Thanks to system versioning, the [UPDATE statement](#update-statement) is no longer "destructive", meaning that the original row containing the `(1, 100.00)` price information is still available from the archive. We can query the `PRODUCT` table and its archive as follows (see example query results further down):

```sql
-- 1. Get the current version by default
SELECT * FROM product;

-- 2. Get the version at a given time
SELECT * FROM product
  FOR system_time AS OF :t1;

-- 3. Get several versions overlapping a time range [t1, t2]
SELECT * FROM product
  FOR system_time BETWEEN :t1 AND :t2;

-- 4. Get several versions overlapping a time range [t1, t2)
SELECT * FROM product
  FOR system_time FROM :t1 TO :t2;

-- 5. Get several versions included in a time range [t1, t2]
SELECT * FROM product
  FOR system_time CONTAINED IN (:t1, :t2);

-- 6. Get all versions
SELECT * FROM product
  FOR system_time ALL;
```

```java
// Get the current version by default
create.selectFrom(product).fetch();

create.selectFrom(product.for_(
  systemTime().asOf(t1)
)).fetch();

create.selectFrom(product.for_(
  systemTime().between(t1).and(t2))
)).fetch();

create.selectFrom(product.for_(
  systemTime().from(t1).to(t2)
)).fetch();

create.selectFrom(product.for_(
  systemTime().containedIn(t1, t2)
)).fetch();

create.selectFrom(product.for_(
  systemTime().all()
)).fetch();
```

The results of the above queries might look like this:

```text
+----------+------------+-------+----------+--------+
| QUERY_NO | PRODUCT_ID | PRICE | START_TS | END_TS |
+----------+------------+-------+----------+--------+
|        1 |          1 |   200 | T2       |        |
+----------+------------+-------+----------+--------+

+----------+------------+-------+----------+--------+
| QUERY_NO | PRODUCT_ID | PRICE | START_TS | END_TS |
+----------+------------+-------+----------+--------+
|  2, 4, 5 |          1 |   100 | T1       | T2     |
+----------+------------+-------+----------+--------+

+----------+------------+-------+----------+--------+
| QUERY_NO | PRODUCT_ID | PRICE | START_TS | END_TS |
+----------+------------+-------+----------+--------+
|     3, 6 |          1 |   100 | T1       | T2     |
|     3, 6 |          1 |   200 | T2       |        |
+----------+------------+-------+----------+--------+
```

jOOQ 3.13 only supports the above syntaxes if they are natively supported by the underlying dialect as well. Future jOOQ versions may emulate the syntax also in other dialects, or where a specific clause is not supported.

##### Application versioned tables

While system versioned tables allow for implementing backups and audit logs, some data is naturally versioned from a business perspective as well. Perhaps, instead of just archiving the pricing information, we may wish to specify a validity range for which a given price was valid on a given product. That way, we can accurately restore the old price on an old period in case we need it for reporting or accounting reasons. The (simplified) syntax is almost the same as with system versioned tables, except that instead of using a "magic" `SYSTEM_TIME` period name, we can now use our own (or in case of DB2, use `BUSINESS_TIME`). Please look up your dialect's manual again, for exact syntax:

```sql
CREATE TABLE product_price (
  product_id BIGINT NOT NULL PRIMARY KEY,
  price DECIMAL NOT NULL,
  start_ts TIMESTAMP,
  end_ts TIMESTAMP,
  PERIOD FOR validity (start_ts, end_ts)
);
```

A table that is defined using the above (simplified) syntax can now be used in DML statements as follows:

```sql
-- A new product is created
INSERT INTO product (product_id, price)
VALUES (1, 100.00);

-- For the time between [t1, t2], a discount is applied
UPDATE product
  FOR PORTION OF validity FROM t1 TO t2
SET price = 50.00
WHERE product_id = 1;
```

```java
create.insertInto(PRODUCT, PRODUCT.PRODUCT_ID, PRODUCT.PRICE)
      .values(1, new BigDecimal("100.00"))
      .execute();

create.update(PRODUCT.forPortionOf(
  period(unquotedName("validity")).from(t1).to(t2)))
      .set(PRODUCT.PRICE, new BigDecimal("50.00"))
      .where(PRODUCT.PRODUCT_ID.eq(1))
      .execute();
```

If not combined with system versioning, this is again a destructive [UPDATE statement](#update-statement), which is effectively transformed into several statements. The resulting table content now looks like this:

```text
+------------+-------+----------+--------+
| PRODUCT_ID | PRICE | START_TS | END_TS |
+------------+-------+----------+--------+
|          1 | 100.0 |          | T1     |
|          1 |  50.0 | T1       | T2     |
|          1 | 100.0 | T2       |        |
+------------+-------+----------+--------+
```

Depending on your dialect, you can reuse the previous `FOR` clauses in [SELECT statements](#select-statement), for example:

```sql
-- 2. Get the version at a given time
SELECT * FROM product
  FOR validity AS OF :t1;
```

```java
create.selectFrom(product.for_(
  period(unquotedName("validity")).asOf(t1)
)).fetch();
```

Which will produce the value of your attribute(s) given their validity at a given timestamp T1:

```text
+------------+-------+----------+--------+
| PRODUCT_ID | PRICE | START_TS | END_TS |
+------------+-------+----------+--------+
|          1 |  50.0 | T1       | T2     |
+------------+-------+----------+--------+
```

<a id="tablesample-tables"></a>
#### 3.10.18. TABLESAMPLE

The SQL standard specifies a `TABLESAMPLE` clause that can be used to extract a sample percentage or number of rows from a given table.

jOOQ supports the following sample size types:

- `PERCENT` using `TABLE.tablesample(n).percent()`
- `ROWS` using `TABLE.tablesample(n).rows()`

As well as the following sample methods:

- `BERNOULLI` using `TABLE.tablesampleBernoulli(n)`
- `SYSTEM` using `TABLE.tablesampleBernoulli(n)`

For repeatable results, an optional `repeatable(seed)`clause can be added.

##### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(BOOK.tablesample(10))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, Hana, Postgres, Trino

```sql
SELECT BOOK.ID
FROM BOOK TABLESAMPLE BERNOULLI (10)
```

###### BigQuery

```sql
SELECT BOOK.ID
FROM BOOK TABLESAMPLE SYSTEM (10 PERCENT)
```

###### ClickHouse, SQLDataWarehouse, SQLServer, Snowflake, Teradata, Vertica

```sql
SELECT BOOK.ID
FROM BOOK TABLESAMPLE (10)
```

###### Databricks

```sql
SELECT BOOK.ID
FROM BOOK TABLESAMPLE (10 PERCENT)
```

###### DuckDB

```sql
SELECT BOOK.ID
FROM BOOK USING SAMPLE (10)
```

###### Oracle

```sql
SELECT BOOK.ID
FROM BOOK SAMPLE (10)
```

###### Spanner

```sql
SELECT BOOK.ID
FROM BOOK TABLESAMPLE BERNOULLI (10 PERCENT)
```

###### ASE, Access, Aurora MySQL, CockroachDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLite, Sybase, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-change-delta-tables"></a>
#### 3.10.19. Data change delta tables

The SQL standard specifies how to turn a DML statement into a [table expression](#table-expressions) that can be used in the [FROM clause](#from-clause) of a [SELECT statement](#select-statement). Other dialects support [a RETURNING or OUTPUT clause](#insert-returning) of some sort to produce the same behaviour, though less powerful.

A data change delta table has two parts:

- The result option (`OLD`, `NEW`, `FINAL`)
- The data change statement, which includes [DELETE](#delete-statement), [INSERT](#insert-statement), [MERGE](#merge-statement), [UPDATE](#update-statement)

You can thus express a query like the following to return all the inserted data (including `DEFAULT` and `TRIGGER` generated values):

```sql
SELECT *
FROM FINAL TABLE (
  INSERT INTO BOOK
    (ID, TITLE)
  VALUES
    (1, 'The Book')
)
```

```java
create.select()
      .from(finalTable(
          insertInto(BOOK)
          .columns(BOOK.ID, BOOK.TITLE)
          .values(1, "The Book")
      ))
      .fetch();
```

Following the restrictions implemented by your dialect, the results of such tables can be further processed, projected, etc.

The semantics of the result options are:

- `OLD`: Access the row data as it was prior to being modified by the data change statement. This does not work for [INSERT](#insert-statement)
- `NEW`: Access the row data as it is after being modified by the data change statement, but before any `AFTER TRIGGERS` are fired. This does not work for [DELETE](#delete-statement)
- `FINAL`: Access the row data as it is after being modified by the data change statement, and all triggers. The data is in its "final" form. This does not work for [DELETE](#delete-statement)

##### Dialect support

This example using jOOQ:

```java
select(BOOK.ID).from(finalTable(insertInto(BOOK).columns(BOOK.ID, BOOK.TITLE).values(1, "The Book")))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres

```sql
WITH
  BOOK AS (
    INSERT INTO BOOK (ID, TITLE)
    VALUES (
      1, 
      'The Book'
    )
    RETURNING 
      BOOK.ID,
      BOOK.AUTHOR_ID,
      BOOK.TITLE,
      BOOK.PUBLISHED_IN,
      BOOK.LANGUAGE_ID
  )
SELECT BOOK.ID
FROM BOOK BOOK
```

###### DB2, H2

```sql
SELECT BOOK.ID
FROM FINAL TABLE (
  INSERT INTO BOOK (ID, TITLE)
  VALUES (
    1, 
    'The Book'
  )
) BOOK
```

###### DuckDB, Firebird

```sql
INSERT INTO BOOK (ID, TITLE)
VALUES (
  1, 
  'The Book'
)
RETURNING BOOK.ID
```

###### MariaDB

```sql
INSERT INTO BOOK (ID, TITLE)
VALUES (
  1, 
  'The Book'
)
RETURNING ID
```

###### Spanner

```sql
INSERT INTO BOOK (ID, TITLE)
VALUES (
  1, 
  'The Book'
)
THEN RETURN BOOK.ID
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, Exasol, HSQLDB, Hana, Informix, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="column-expressions"></a>
### 3.11. Column expressions

Column expressions can be used in various SQL clauses in order to refer to one or several columns. This chapter explains how to form various types of column expressions with jOOQ. A particular type of column expression is given in the section about [tuples or row value expressions](#row-value-expressions), where an expression may have a degree of more than one.

#### Using column expressions in jOOQ

jOOQ allows you to freely create arbitrary column expressions using a fluent expression construction API. Many expressions can be formed as functions from [DSL methods](#dsl), other expressions can be formed based on a pre-existing column expression. For example:

```java
// A regular table column expression
Field<String> field1 = BOOK.TITLE;

// A function created from the DSL
Field<String> field2 = trim(BOOK.TITLE);

// More complex function with advanced DSL syntax
Field<String> field4 = listAgg(BOOK.TITLE)
                          .withinGroupOrderBy(BOOK.ID.asc())
                          .over().partitionBy(AUTHOR.ID);
```

<a id="table-columns"></a>
#### 3.11.1. Table columns

Table columns are the most simple implementations of a [column expression](#column-expressions). They are mainly produced by jOOQ's [code generator](#code-generation) and can be dereferenced from the generated tables, but other ways of creating table column references are possible.

<a id="generated-table-columns"></a>
##### 3.11.1.1. Generated table columns

The main type of [column expression](#column-expressions) are the ones produced by jOOQ's [code generator](#code-generation) and can be dereferenced from the generated tables. This manual is full of examples involving table columns. Another example is given in this query:

```sql
SELECT BOOK.ID, BOOK.TITLE
FROM BOOK
WHERE BOOK.TITLE LIKE '%SQL%'
ORDER BY BOOK.TITLE
 
```

```java
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .where(BOOK.TITLE.like("%SQL%"))
      .orderBy(BOOK.TITLE)
      .fetch();
```

Table columns implement a more specific interface called [`org.jooq.TableField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableField.html), which is parameterised with its associated `<R extends Record>` record type, and provides access to the container [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) instance.

See the manual's section about [generated tables](#codegen-tables) for more information about what is really generated by the [code generator](#code-generation)

<a id="dereferenced-table-columns"></a>
##### 3.11.1.2. Dereferenced table columns

Any [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) instance that is constructed in a way to know its own columns can be used to dereference those columns. Examples include:

- [Generated tables](#generated-tables) know their [generated table columns](#generated-table-columns)
- [Derived tables](#derived-tables)
- [Table valued functions](#table-valued-functions), including built-in ones, such as e.g. [unnested arrays](#array-and-cursor-unnesting) or [GENERATE_SERIES](#generate-series)

All of these table expressions, as well as some others, extend the [`org.jooq.Fields`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Fields.html) type, which allows for all of these field accessing types, like [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) but also [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) and others to share field accessing logic.

```java
// Get fields from AUTHOR dynamically, without type safety:
Field<?> id = AUTHOR.field("ID");
Field<?> firstName = AUTHOR.field("FIRST_NAME");
```

<a id="named-table-columns"></a>
##### 3.11.1.3. Named table columns

When no [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) instance is available to [dereference a column from](#dereferenced-table-columns), the column expression can still be constructed on the fly, dynamically using a [Name](#names) reference, and optionally a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html) reference:

```java
// Get fields from AUTHOR dynamically, without type safety:
Field<?> id = field(name("AUTHOR", "ID"));
Field<String> firstName = field(name("AUTHOR", "FIRST_NAME"), INTEGER);
```

Note that by default, these names are quoted (among other reasons to prevent [SQL injection](#sql-injection)), and thus case sensitive. For more details, please refer to [the section about names and identifiers](#names).

<a id="system-table-columns"></a>
##### 3.11.1.4. System table columns: ROWID

Certain RDBMS offer a standard way to access a system specific row locator on arbitrary tables, including tables that do not have a `PRIMARY KEY`. This system ID can be used to access such a row and make updates to it. Certain restrictions may apply, e.g. related to row movement (the ID may not be permanent over time). Please consult your RDBMS manual for details.

jOOQ offers this via the [`Table.rowid()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#rowid()) API.

```sql
SELECT BOOK.ROWID FROM BOOK
```

```java
create.select(BOOK.rowid()).from(BOOK).fetch();
```

The data type of such a column is [`org.jooq.RowId`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RowId.html) (see [ROWID data type](#data-type-rowid)), which allows for abstracting over the various implementation specific representations.

###### Dialect support

This example using jOOQ:

```java
BOOK.rowid()
```

Translates to the following dialect specific expressions:

###### DB2, Exasol, Informix, Oracle, SQLite

```sql
BOOK.rowid
```

###### H2

```sql
BOOK._rowid_
```

###### Hana

```sql
BOOK."$rowid$"
```

###### Postgres

```sql
BOOK.ctid
```

###### SQLServer

```sql
BOOK.%%physloc%%
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Firebird, HSQLDB, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="aliased-columns"></a>
#### 3.11.2. Aliased columns

Just like [tables](#aliased-tables), columns can be renamed using aliases. Here is an example:

```sql
  SELECT FIRST_NAME || ' ' || LAST_NAME author, COUNT(*) books
    FROM AUTHOR
    JOIN BOOK ON AUTHOR.ID = AUTHOR_ID
GROUP BY FIRST_NAME, LAST_NAME;
```

Here is how it's done with jOOQ:

```java
Record record = create.select(
         concat(AUTHOR.FIRST_NAME, inline(" "), AUTHOR.LAST_NAME).as("author"),
         count().as("books"))
      .from(AUTHOR)
      .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
      .groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .fetchAny();
```

When you alias Fields like above, you can access those Fields' values using the alias name:

```java
System.out.println("Author : " + record.getValue("author"));
System.out.println("Books  : " + record.getValue("books"));
```

##### Unnamed column expressions

In most SQL databases, aliasing of column expressions in top level selects is optional. The database will generate a column name that is roughly based on the expression for documentation purposes (e.g. when running the query in a tool like SQL Developer), but applications cannot rely on the name explicitly. This is not a problem as columns can still be referenced by index.

In a similar fashion, jOOQ will assume an unspecified, generated column name for column expressions, based on their content.

```sql
-- Arithmetic expression
1 + 2

-- Correlated subquery
(SELECT 1 AS a)
```

```java
// Arithmetic expression
inline(1).plus(inline(2));

// Correlated subquery
field(select(inline(1).as("a")));
```

These unnamed expressions can be used both in SQL as well as with jOOQ. However, do note that jOOQ will use [`Field.getName()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#getName()) to extract this column name from the field, when referencing the field or when nesting it in derived tables. In order to stay in full control of any such column names, it is always a good idea to provide explicit aliasing for column expressions, both in SQL as well as in jOOQ.

##### Rendering declarations or references

The same aliased column instance is rendered differently depending on where it is placed in the jOOQ expression tree. See the manual's section about [rendering declarations vs references](#declaration-vs-reference) for more details.

<a id="cast-expressions"></a>
#### 3.11.3. Cast expressions

jOOQ's source code generator tries to find the most accurate type mapping between your vendor-specific data types and a matching Java type. For instance, most `VARCHAR`, `CHAR`, `CLOB` types will map to String. Most `BINARY`, `BYTEA`, `BLOB` types will map to `byte[]`. `NUMERIC` types will default to [`java.math.BigDecimal`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/math/BigDecimal.html), but can also be any of [`java.math.BigInteger`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/math/BigInteger.html), [`java.lang.Long`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Long.html), [`java.lang.Integer`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Integer.html), [`java.lang.Short`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Short.html), [`java.lang.Byte`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Byte.html), [`java.lang.Double`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Double.html), [`java.lang.Float`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Float.html).

Sometimes, this automatic mapping might not be what you needed, or jOOQ cannot know the type of a field. In those cases you would write SQL type `CAST` like this:

```sql
-- Let's say, your Postgres column LAST_NAME was VARCHAR(30)
-- Then you could do this:
SELECT CAST(AUTHOR.LAST_NAME AS TEXT) FROM DUAL
```

in jOOQ, you can write something like that:

```java
create.select(AUTHOR.LAST_NAME.cast(VARCHAR(100))).fetch();
```

The complete `CAST` API in [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) consists of these three methods:

```java
public interface Field<T> {

    // Cast this field to the type of another field
    <Z> Field<Z> cast(Field<Z> field);

    // Cast this field to a given DataType
    <Z> Field<Z> cast(DataType<Z> type);

    // Cast this field to the default DataType for a given Class
    <Z> Field<Z> cast(Class<? extends Z> type);
}

// And additional convenience methods in the DSL:
public class DSL {
    <T> Field<T> cast(Object object, Field<T> field);
    <T> Field<T> cast(Object object, DataType<T> type);
    <T> Field<T> cast(Object object, Class<? extends T> type);
    <T> Field<T> castNull(Field<T> field);
    <T> Field<T> castNull(DataType<T> type);
    <T> Field<T> castNull(Class<? extends T> type);
}
```

> [!TIP]
> The `CAST` expression converts between data types directly in SQL. If you wish to change a data type without any effect on rendered SQL, you may prefer to [coerce](#datatype-coercions) your expressions.

##### Dialect support

This example using jOOQ:

```java
cast("1", VARCHAR(10))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr('1')
```

###### ASE, Aurora Postgres, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast('1' AS varchar(10))
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast('1' AS char(10))
```

###### BigQuery, Spanner

```sql
cast('1' AS string)
```

###### ClickHouse

```sql
cast('1' AS String(10))
```

###### CockroachDB

```sql
cast('1' AS string(10))
```

###### Informix

```sql
cast('1' AS lvarchar(10))
```

###### Oracle

```sql
cast('1' AS varchar2(10))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="try-cast-expressions"></a>
#### 3.11.4. Cast expressions (with TRY_CAST)

The standard SQL [CAST expression](#cast-expressions) will error when a value cannot be cast to the target data type.

Some dialects allow for ignoring such errors, returning `NULL` instead. This can be useful when sanitising data that is not well structured.

```sql
SELECT TRY_CAST("a", INTEGER)
```

```java
create.select(tryCast("a", INTEGER)).fetch();
```

##### Dialect support

This example using jOOQ:

```java
tryCast("a", VARCHAR(10))
```

Translates to the following dialect specific expressions:

###### BigQuery, Spanner

```sql
safe_cast('a' AS string)
```

###### ClickHouse

```sql
accurateCastOrNull('a', 'Nullable(String(10))')
```

###### Databricks, DuckDB, SQLDataWarehouse, SQLServer, Snowflake, Trino

```sql
try_cast('a' AS varchar(10))
```

###### Oracle

```sql
cast('a' AS varchar2(10) DEFAULT NULL ON CONVERSION ERROR)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLite, Sybase, Teradata, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="datatype-coercions"></a>
#### 3.11.5. Datatype coercions

A slightly different use case than [CAST expressions](#cast-expressions) are data type coercions, which are not rendered through to generated SQL. Sometimes, you may want to pretend that a numeric value is really treated as a string value, for instance when binding a numeric [bind value](#variable-binding):

```java
Field<String>  field1 = val(1).coerce(String.class);
Field<Integer> field2 = val("1").coerce(Integer.class);
```

In the above example, `field1` will be treated by jOOQ as a `Field<String>`, binding the numeric literal `1` as a `VARCHAR` value. The same applies to `field2`, whose string literal `"1"` will be bound as an `INTEGER` value.

This technique is better than performing unsafe or rawtype casting in Java, if you cannot access the "right" field type from any given expression.

<a id="hidden-columns"></a>
#### 3.11.6. Hidden columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator may decide that a column is [hidden](#codegen-database-hidden-columns), in case of which using it in various DML statements may subtly change. In particular, the column will be excluded by default from all projections, [* expansions](#select-clause-asterisk), meta data queries. The column is still available in generated tables for explicit usage, though:

```java
// UpdatableRecords don't contain the column anymore:
TRecord r1 = create.selectFrom(T).fetchOne();
r1.getInvisible();   // compilation error

// * expansions don't include the column anymore
Record r2 = create.select().from(T).fetchOne();
r2.get(T.INVISIBLE); // throws IllegalArgumentException, the column isn't available

Record r3 = create.select(asterisk()).from(T).fetchOne();
r3.get(T.INVISIBLE); // throws IllegalArgumentException, the column isn't available

// Meta data queries don't produce the column anymore:
assertNull(T.get(T.INVISIBLE));

// However, explicit usage is still possible
create.select(T.ID, T.INVISIBLE, T.VISIBLE)
      .from(T)
      .fetch();
```

The fact whether data is hidden is governed by the [`DataType.hidden()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html#hidden()) flag.

<a id="redacted-columns"></a>
#### 3.11.7. Redacted columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator may decide that a column is [redacted](#codegen-database-redacted-columns), in case of which its formatted content will be changed. This is especially useful to prevent leakage of sensitive information into debug logs, etc.

```java
// Tables, records, etc. still contain the column like any other:
Customer customer = create.selectFrom(CUSTOMER).where(CUSTOMER.ID.eq(123)).fetchOne();
assertEquals("John", customer.getFirstName());
assertEquals("Doe", customer.getLastName());
assertEquals("1234 5678 9012 3456", customer.getCreditCardNo());

// But printing out the customer will redact sensitive information:
System.out.println(customer);
```

The output of the above may be:

```text
+------------+-----------+----------------+
| first_name | last_name | credit_card_no |
+------------+-----------+----------------+
| John       | Doe       | ****           |
+------------+-----------+----------------+
```

The fact whether data is redacted is governed by the [`DataType.redacted()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html#redacted()) flag.

By default, all such `redacted` fields will be redacted in:

- [Text output](#exporting-text)
- [HTML output](#exporting-html)

By specifying Settings.redact, it is possible to apply redacting also to:

- [CSV output](#exporting-csv)
- [JSON output](#exporting-json)
- [XML output](#exporting-xml)

<a id="readonly-columns"></a>
#### 3.11.8. Readonly columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator may decide that a column is [readonly](#codegen-database-readonly-columns), in case of which using it in various DML statements may change. By default, `INSERT`, or `UPDATE` operations on such columns are simply ignored.

```sql
INSERT INTO
  MY_TABLE (ID) -- READONLY_COLUMN is ignored
VALUES
  (1);
```

```java
create.insertInto(MY_TABLE)
      .columns(MY_TABLE.ID, MY_TABLE.READONLY_COLUMN)
      .values(1, 1)
      .execute();
```

This also affects any [UpdatableRecord](#crud-with-updatablerecords) call:

```sql
INSERT INTO
  MY_TABLE (ID) -- READONLY_COLUMN is ignored
VALUES
  (1);
```

```java
MyTableRecord rec = create.newRecord(MY_TABLE);
rec.setId(1);
rec.setReadonlyColumn(1);
rec.store();
```

The default behaviour of `readonly` columns in [INSERT](#insert-statement) and [UPDATE](#update-statement) statements can be overridden with these 4 [readonly settings](#settings-readonly-columns):

- [`Settings.readonlyInsert`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyInsert): Behaviour of `readonly` columns in an `INSERT` context.
- [`Settings.readonlyUpdate`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyUpdate): Behaviour of `readonly` columns in an `UPDATE` context.
- [`Settings.readonlyTableRecordInsert`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyTableRecordInsert): Behaviour of `readonly` columns in a `TableRecord.insert()` context.
- [`Settings.readonlyUpdatableRecordUpdate`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#readonlyUpdatableRecordUpdate): Behaviour of `readonly` columns in an `UpdatableRecord.update()` context.

For more details about the settings, [refer to the page about readonly settings](#settings-readonly-columns)

<a id="computed-columns"></a>
#### 3.11.9. Computed columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Computed columns, sometimes also called "virtual" columns, are columns that are generated from an expression based on other columns of the same row directly in the database. They cannot be written to, but may be used in projections, filters, and even [indexes](#create-index-statement), as a complement or replacement of function based indexes.

jOOQ's [code generator](#code-generation) picks up computed columns like any other, but marks them as [read only](#readonly-columns) for your convenience, such that they are excluded from DML statements, by default.

See the [section about computed columns in CREATE TABLE](#create-table-computed-columns) for more details.

<a id="collations"></a>
#### 3.11.10. Collations

Many databases support "collations", which defines the sort order on character data types, such as `VARCHAR`.

Such databases usually allow for specifying:

- System-wide default collations
- Session-wide default collations
- Per-table specific default collations
- Per-column specific default collations
- Per-usage specific collation

The actual implementation is vendor-specific, including the way the above defaults override each other.

To accommodate most use-cases jOOQ 3.11 introduced the [`org.jooq.Collation`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Collation.html) type, which can be attached to a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html) through [`DataType.collate(Collation)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html#collate(org.jooq.Collation)), or to a [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) through [`Field.collate(Collation)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#collate(org.jooq.Collation)), for example:

```sql
SELECT *
FROM book
ORDER BY title COLLATE utf8_bin
```

```java
create.selectFrom(BOOK)
      .orderBy(BOOK.TITLE.collate("utf8_bin"))
      .fetch();
```

<a id="arithmetic-expressions"></a>
#### 3.11.11. Arithmetic expressions

##### Numeric arithmetic expressions

Your database can do the math for you. Arithmetic operations are implemented just like [numeric functions](#numeric-functions), with similar limitations as far as type restrictions are concerned. You can use any of these operators:

```
  +  -  *  /  %
```

In order to express a SQL query like this one:

```sql
SELECT ((1 + 2) * (5 - 3) / 2) % 10 FROM DUAL
```

You can write something like this in jOOQ:

```java
create.select(val(1).add(2).mul(val(5).sub(3)).div(2).mod(10)).fetch();
```

##### Operator precedence

jOOQ does not know any operator precedence (see also [boolean operator precedence](#boolean-operator-precedence)). All operations are evaluated from left to right, as with any object-oriented API. The two following expressions are the same:

```java
   val(1).add(2) .mul(val(5).sub(3)) .div(2) .mod(10);
(((val(1).add(2)).mul(val(5).sub(3))).div(2)).mod(10);
```

##### Datetime arithmetic expressions

jOOQ also supports the Oracle-style syntax for adding days to a Field<? extends java.util.Date>

```sql
SELECT SYSDATE + 3 FROM DUAL;
```

```java
create.select(currentTimestamp().add(3)).fetch();
```

For more advanced datetime arithmetic, use the DSL's timestampDiff() and dateDiff() functions, as well as jOOQ's built-in SQL standard `INTERVAL` data type support:

- `INTERVAL YEAR TO MONTH`: [`org.jooq.types.YearToMonth`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/YearToMonth.html)
- `INTERVAL DAY TO SECOND`: [`org.jooq.types.DayToSecond`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/DayToSecond.html)

<a id="string-concatenation"></a>
#### 3.11.12. String concatenation

The SQL standard defines the concatenation operator to be an infix operator, similar to the ones we've seen in the chapter about [arithmetic expressions](#arithmetic-expressions). This operator looks like this: `||`. Some other dialects do not support this operator, but expect a `concat()` function, instead. jOOQ renders the right operator / function, depending on your [SQL dialect](#sql-dialects):

```sql
SELECT 'A' || 'B' || 'C' FROM DUAL
-- Or in MySQL:
SELECT concat('A', 'B', 'C') FROM DUAL
```

```java
 
// For all RDBMS, including MySQL:
create.select(concat("A", "B", "C")).fetch();
```

<a id="case-sensitivity"></a>
#### 3.11.13. Case sensitivity with strings

Most databases allow for specifying a `COLLATION` which allows for re-defining the ordering of string values. By default, ASCII, ISO, or Unicode encodings are applied to character data, and ordering is applied according to the respective encoding.

Sometimes, however, certain queries like to ignore parts of the encoding by treating upper-case and lower-case characters alike, such that `ABC = abc`, or such that `ABC, jkl, XyZ` are an ordered list of strings (case-insensitively).

For these ad-hoc ordering use-cases, most people resort to using `LOWER()` or `UPPER()` as follows:

```sql
-- Case-insensitive filtering:
SELECT * FROM BOOK
WHERE upper(TITLE) = 'ANIMAL FARM'

-- Case-insensitive ordering:
SELECT *
FROM AUTHOR
ORDER BY upper(FIRST_NAME), upper(LAST_NAME)
```

```java
// Case-insensitive filtering:
create.selectFrom(BOOK)
      .where(upper(BOOK.TITLE).eq("ANIMAL FARM")).fetch();

// Case-insensitive ordering:
create.selectFrom(AUTHOR)
      .orderBy(upper(AUTHOR.FIRST_NAME), upper(AUTHOR.LAST_NAME))
      .fetch();
```

<a id="general-functions"></a>
#### 3.11.14. General functions

There are a variety of general functions supported by jOOQ. As discussed in the chapter about [SQL dialects](#sql-dialects) functions are mostly emulated in your database, in case they are not natively supported.

<a id="choose-function"></a>
##### 3.11.14.1. CHOOSE

The `CHOOSE()` function acts as a switch over an integer to return the nth argument. It is an abbreviated [CASE expression](#case-expressions)

```sql
SELECT
  choose(1, 'a', 'b'),
  choose(2, 'a', 'b'),
  choose(3, 'a', 'b');
```

```java
create.select(
  choose(val(1), val("a"), val("b")),
  choose(val(2), val("a"), val("b")),
  choose(val(3), val("a"), val("b"))).fetch();
```

The result being

```text
+--------+--------+--------+
| choose | choose | choose |
+--------+--------+--------+
| a      | b      | {null} |
+--------+--------+--------+
```

###### Dialect support

This example using jOOQ:

```java
choose(val(1), val("a"), val("b"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
SWITCH(1 = 1, 'a', 1 = 2, 'b')
```

###### ASE, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
CASE 1
  WHEN 1 THEN 'a'
  WHEN 2 THEN 'b'
END
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
elt(1, 'a', 'b')
```

###### Databricks

```sql
elt(
  CASE
    WHEN 1 BETWEEN 1 AND 2 THEN 1
  END,
  'a',
  'b'
)
```

###### SQLServer

```sql
choose(1, 'a', 'b')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="coalesce-function"></a>
##### 3.11.14.2. COALESCE

The `COALESCE()` function produces the first non-`NULL` value from the variadic list of arguments.

```sql
SELECT coalesce(null, null, 1);
```

```java
create.select(coalesce(null, null, 1)).fetch();
```

The result being

```text
+----------+
| coalesce |
+----------+
|        1 |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
coalesce(null, null, 1)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
coalesce(NULL, NULL, 1)
```

###### Informix

```sql
nvl(
  nvl(
    NULL,
    NULL
  ),
  1
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="decode-function"></a>
##### 3.11.14.3. DECODE

Some SQL dialects, including Db2, H2, Oracle know a more succinct, but maybe less readable `DECODE()` function with a variable number of arguments. This function works like a `NULL` safe [CASE expression](#case-expressions). jOOQ supports the `DECODE()` function and emulates it using `CASE` expressions in all dialects that do not have native support:

```sql
SELECT
  -- Oracle:
  DECODE(FIRST_NAME, 'Paulo', 'brazilian',
                     'George', 'english',
                     'unknown'),
  -- Other SQL dialects
  CASE
    WHEN FIRST_NAME IS NOT DISTINCT FROM 'Paulo'  THEN 'brazilian'
    WHEN FIRST_NAME IS NOT DISTINCT FROM 'George' THEN 'english'
    ELSE 'unknown'
  END
FROM AUTHOR
```

```java
// Use the Oracle-style DECODE() function with jOOQ.
// Note, that you will not be able to rely on type-safety
decode(
  AUTHOR.FIRST_NAME,
  "Paulo", "brazilian",
  "George", "english",
  "unknown"
);
```

See the [DISTINCT predicate](#distinct-predicate) for details about the `NULL` safe semantics.

###### Dialect support

This example using jOOQ:

```java
decode(AUTHOR.FIRST_NAME, "Paulo", "BR", "George", "EN", "unknown")
```

Translates to the following dialect specific expressions:

###### ASE, SQLDataWarehouse

```sql
CASE
  WHEN EXISTS (
    SELECT AUTHOR.FIRST_NAME x
    INTERSECT
    SELECT 'Paulo' x
  ) THEN 'BR'
  WHEN EXISTS (
    SELECT AUTHOR.FIRST_NAME x
    INTERSECT
    SELECT 'George' x
  ) THEN 'EN'
  ELSE 'unknown'
END
```

###### Aurora MySQL, MySQL

```sql
CASE
  WHEN (AUTHOR.FIRST_NAME <=> 'Paulo') THEN 'BR'
  WHEN (AUTHOR.FIRST_NAME <=> 'George') THEN 'EN'
  ELSE 'unknown'
END
```

###### Aurora Postgres, BigQuery, CockroachDB, DuckDB, Firebird, HSQLDB, Postgres, SQLServer, Snowflake, Trino, YugabyteDB

```sql
CASE
  WHEN AUTHOR.FIRST_NAME IS NOT DISTINCT FROM 'Paulo' THEN 'BR'
  WHEN AUTHOR.FIRST_NAME IS NOT DISTINCT FROM 'George' THEN 'EN'
  ELSE 'unknown'
END
```

###### ClickHouse

```sql
CASE
  WHEN arrayUniq(ARRAY(AUTHOR.FIRST_NAME, 'Paulo')) = 1 THEN 'BR'
  WHEN arrayUniq(ARRAY(AUTHOR.FIRST_NAME, 'George')) = 1 THEN 'EN'
  ELSE 'unknown'
END
```

###### DB2, Databricks, Exasol, H2, Informix, MemSQL, Oracle, Redshift, Teradata, Vertica

```sql
decode(
  AUTHOR.FIRST_NAME,
  'Paulo',
  'BR',
  'George',
  'EN',
  'unknown'
)
```

###### Hana

```sql
map(
  AUTHOR.FIRST_NAME,
  'Paulo',
  'BR',
  'George',
  'EN',
  'unknown'
)
```

###### MariaDB

```sql
decode_oracle(
  AUTHOR.FIRST_NAME,
  'Paulo',
  'BR',
  'George',
  'EN',
  'unknown'
)
```

###### Spanner

```sql
CASE
  WHEN EXISTS (
    SELECT AUTHOR.FIRST_NAME x
    INTERSECT DISTINCT
    SELECT 'Paulo' x
  ) THEN 'BR'
  WHEN EXISTS (
    SELECT AUTHOR.FIRST_NAME x
    INTERSECT DISTINCT
    SELECT 'George' x
  ) THEN 'EN'
  ELSE 'unknown'
END
```

###### SQLite

```sql
CASE
  WHEN (AUTHOR.FIRST_NAME IS 'Paulo') THEN 'BR'
  WHEN (AUTHOR.FIRST_NAME IS 'George') THEN 'EN'
  ELSE 'unknown'
END
```

###### Sybase

```sql
CASE
  WHEN EXISTS (
    SELECT AUTHOR.FIRST_NAME x
    FROM SYS.DUMMY
    INTERSECT
    SELECT 'Paulo' x
    FROM SYS.DUMMY
  ) THEN 'BR'
  WHEN EXISTS (
    SELECT AUTHOR.FIRST_NAME x
    FROM SYS.DUMMY
    INTERSECT
    SELECT 'George' x
    FROM SYS.DUMMY
  ) THEN 'EN'
  ELSE 'unknown'
END
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="iif-function"></a>
##### 3.11.14.4. IIF

The `IIF()` function checks if the first argument is `TRUE` to produce the second argument, or the third argument otherwise. It works in a similar way as the [NVL2 function](#nvl2-function) or the [CASE expression](#case-expressions)

```sql
SELECT
  iif(1 = 1, 3, 4),
  iif(1 = 2, 3, 4);
```

```java
create.select(
  iif(inline(1).eq(inline(1)), inline(3), inline(4))
  iif(inline(1).eq(inline(2)), inline(3), inline(4))).fetch();
```

The result being

```text
+-----+-----+
| iif | iif |
+-----+-----+
|   3 |   4 |
+-----+-----+
```

###### Dialect support

This example using jOOQ:

```java
iif(inline(1).eq(inline(2)), inline(3), inline(4))
```

Translates to the following dialect specific expressions:

###### Access, SQLServer

```sql
iif(1 = 2, 3, 4)
```

###### ASE, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
CASE
  WHEN 1 = 2 THEN 3
  ELSE 4
END
```

###### Aurora MySQL, ClickHouse, MariaDB, MemSQL, MySQL

```sql
if(1 = 2, 3, 4)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="nullif-function"></a>
##### 3.11.14.5. NULLIF

The `NULLIF()` function produces a `NULL` value if both its arguments are equal, otherwise it produces the first argument.

```sql
SELECT nullif(1, 1), nullif(1, 2);
```

```java
create.select(nullif(1, 1), nullif(1, 2)).fetch();
```

The result being

```text
+--------+--------+
| nullif | nullif |
+--------+--------+
|        |      1 |
+--------+--------+
```

###### Dialect support

This example using jOOQ:

```java
nullif(1, 2)
```

Translates to the following dialect specific expressions:

###### Access

```sql
iif(1 = 2, NULL, 1)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
nullif(1, 2)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="nvl-function"></a>
##### 3.11.14.6. NVL

The `NVL()` function (or also the `ISNULL()` or `IFNULL()` functions) produces the first argument if it is `NOT NULL`, otherwise the second argument. It is a special case of the [COALESCE](#coalesce-function) function, which takes any number of arguments.

```sql
SELECT nvl(null, 1);
```

```java
create.select(nvl(null, 1)).fetch();
```

The result being

```text
+-----+
| nvl |
+-----+
|   1 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
nvl(null, 1)
```

Translates to the following dialect specific expressions:

###### Access

```sql
iif(NULL IS NULL, 1, NULL)
```

###### ASE, Aurora Postgres, CockroachDB, DuckDB, Exasol, Firebird, Hana, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
coalesce(
  NULL,
  1
)
```

###### Aurora MySQL, BigQuery, ClickHouse, MariaDB, MemSQL, MySQL, SQLite, Spanner

```sql
ifnull(
  NULL,
  1
)
```

###### DB2, Databricks, H2, HSQLDB, Informix, Oracle

```sql
nvl(
  NULL,
  1
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="nvl2-function"></a>
##### 3.11.14.7. NVL2

The `NVL2()` function checks if the first argument is `NOT NULL` to produce the second argument, or the third argument otherwise. It works in a similar way as the [IIF function](#iif-function) or the [CASE expression](#case-expressions)

```sql
SELECT
  nvl2(1,    2, 3),
  nvl2(null, 2, 3);
```

```java
create.select(
  nvl2(val(1)             , 2, 3),
  nvl2(val((Integer) null), 2, 3)).fetch();
```

The result being

```text
+------+------+
| nvl2 | nvl2 |
+------+------+
|    2 |    3 |
+------+------+
```

###### Dialect support

This example using jOOQ:

```java
nvl2(val(1), 2, 3)
```

Translates to the following dialect specific expressions:

###### Access, SQLServer

```sql
iif(1 IS NOT NULL, 2, 3)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DuckDB, Firebird, Hana, MemSQL, MySQL, Postgres, SQLDataWarehouse, SQLite, Spanner, Sybase, Trino, YugabyteDB

```sql
CASE
  WHEN 1 IS NOT NULL THEN 2
  ELSE 3
END
```

###### DB2, Databricks, Exasol, H2, HSQLDB, Informix, MariaDB, Oracle, Redshift, Snowflake, Teradata, Vertica

```sql
nvl2(1, 2, 3)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="numeric-functions"></a>
#### 3.11.15. Numeric functions

In addition to the [arithmetic expressions](#arithmetic-expressions) discussed previously, jOOQ also supports a variety of numeric functions. As discussed in the chapter about [SQL dialects](#sql-dialects) numeric functions (as any function type) are mostly emulated in your database, in case they are not natively supported.

<a id="abs-function"></a>
##### 3.11.15.1. ABS

The `ABS()` function produces the absolute value of a numeric value.

```sql
SELECT abs(-5), abs(0), abs(3);
```

```java
create.select(abs(-5), abs(0), abs(3)).fetch();
```

The result being

```text
+-----+-----+-----+
| abs | abs | abs |
+-----+-----+-----+
|   5 |   0 |   3 |
+-----+-----+-----+
```

###### Dialect support

This example using jOOQ:

```java
abs(x)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
abs(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="acos-function"></a>
##### 3.11.15.2. ACOS

The `ACOS()` function calculates the arc cosine of a numeric value.

```sql
SELECT acos(0);
```

```java
create.select(acos(0)).fetch();
```

The result being

```text
+------------+
|       acos |
+------------+
| 1.57079633 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
acos(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
(atn((-x / sqr(((-x * x) + 1)))) + (2 * atn(1)))
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
acos(x)
```

###### Snowflake, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="acosh-function"></a>
##### 3.11.15.3. ACOSH

The `ACOSH()` function calculates the hyperbolic arc cosine (or inverse hyperbolic cosine) of a numeric value.

```sql
SELECT acosh(2);
```

```java
create.select(acosh(2)).fetch();
```

The result being

```text
+--------------------+
|              acosh |
+--------------------+
| 1.3169578969248166 |
+--------------------+
```

###### Dialect support

This example using jOOQ:

```java
acosh(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
log((x + sqr(((x * x) - 1))))
```

###### ASE, SQLDataWarehouse, SQLServer

```sql
log((x + sqrt((square(x) - 1))))
```

###### Aurora MySQL, DB2, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Redshift, Sybase, Vertica, YugabyteDB

```sql
ln((x + sqrt(((x * x) - 1))))
```

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, Firebird, Informix, Postgres, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
acosh(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="acot-function"></a>
##### 3.11.15.4. ACOT

The `ACOT()` function calculates the arc cotangent of a numeric value.

```sql
SELECT acot(0);
```

```java
create.select(acot(0)).fetch();
```

The result being

```text
+--------------------+
|               acot |
+--------------------+
| 1.5707963267948966 |
+--------------------+
```

###### Dialect support

This example using jOOQ:

```java
acot(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
((3.141592653589793 / 2) - atn(x))
```

###### ASE, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Sybase, Vertica, YugabyteDB

```sql
((pi() / 2) - atan(x))
```

###### BigQuery, DB2, Hana, Informix, Oracle, Spanner, Teradata

```sql
((acos(-1) / 2) - atan(x))
```

###### Snowflake, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="acoth-function"></a>
##### 3.11.15.5. ACOTH

The `ACOTH()` function calculates the hyperbolic arc cotangent (or inverse hyperbolic cotangent) of a numeric value.

```sql
SELECT acoth(2);
```

```java
create.select(acoth(2)).fetch();
```

The result being

```text
+--------------------+
|              acoth |
+--------------------+
| 0.5493061443340548 |
+--------------------+
```

###### Dialect support

This example using jOOQ:

```java
acoth(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, SQLDataWarehouse, SQLServer

```sql
(log(((x + 1) / (x - 1))) / 2)
```

###### Aurora MySQL, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Redshift, Sybase, Vertica, YugabyteDB

```sql
(ln(((x + 1) / (x - 1))) / 2)
```

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, Firebird, Informix, Postgres, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
atanh((1 / x))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="asin-function"></a>
##### 3.11.15.6. ASIN

The `ASIN()` function calculates the arc sine of a numeric value.

```sql
SELECT asin(1);
```

```java
create.select(asin(1)).fetch();
```

The result being

```text
+------------+
|       asin |
+------------+
| 1.57079633 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
asin(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
atn((x / sqr(((-x * x) + 1))))
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
asin(x)
```

###### Snowflake, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="asinh-function"></a>
##### 3.11.15.7. ASINH

The `ASINH()` function calculates the hyperbolic arc sine (or inverse hyperbolic sine) of a numeric value.

```sql
SELECT asinh(2);
```

```java
create.select(asinh(2)).fetch();
```

The result being

```text
+--------------------+
|              asinh |
+--------------------+
| 1.4436354751788103 |
+--------------------+
```

###### Dialect support

This example using jOOQ:

```java
asinh(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
log((x + sqr(((x * x) + 1))))
```

###### ASE, SQLDataWarehouse, SQLServer

```sql
log((x + sqrt((square(x) + 1))))
```

###### Aurora MySQL, DB2, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Redshift, Sybase, Vertica, YugabyteDB

```sql
ln((x + sqrt(((x * x) + 1))))
```

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, Firebird, Informix, Postgres, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
asinh(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="atan-function"></a>
##### 3.11.15.8. ATAN

The `ATAN()` function calculates the arc tangent of a numeric value.

```sql
SELECT atan(1);
```

```java
create.select(atan(1)).fetch();
```

The result being

```text
+-------------+
|        atan |
+-------------+
| 0.785398163 |
+-------------+
```

###### Dialect support

This example using jOOQ:

```java
atan(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
atn(x)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
atan(x)
```

###### Snowflake, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="atan2-function"></a>
##### 3.11.15.9. ATAN2

The `ATAN2()` function calculates the ATAN2 of a numeric value.

```sql
SELECT atan2(1, 1);
```

```java
create.select(atan2(1, 1)).fetch();
```

The result being

```text
+---------------+
|         atan2 |
+---------------+
| 0.78539816339 |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
atan2(y, x)
```

Translates to the following dialect specific expressions:

###### ASE, SQLDataWarehouse, SQLServer

```sql
atn2(y, x)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
atan2(y, x)
```

###### Access, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="atanh-function"></a>
##### 3.11.15.10. ATANH

The `ATANH()` function calculates the hyperbolic arc tangent (or inverse hyperbolic tangent) of a numeric value.

```sql
SELECT atanh(0.5);
```

```java
create.select(atanh(0.5)).fetch();
```

The result being

```text
+--------------------+
|              atanh |
+--------------------+
| 0.5493061443340548 |
+--------------------+
```

###### Dialect support

This example using jOOQ:

```java
atanh(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, SQLDataWarehouse, SQLServer

```sql
(log(((1 + x) / (1 - x))) / 2)
```

###### Aurora MySQL, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Redshift, Sybase, Vertica, YugabyteDB

```sql
(ln(((1 + x) / (1 - x))) / 2)
```

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, Firebird, Informix, Postgres, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
atanh(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="ceil-function"></a>
##### 3.11.15.11. CEIL

The `CEIL()` function rounds a numeric value to its nearest higher integer.

```sql
SELECT
  ceil(1.7),
  ceil(-1.7);
```

```java
create.select(
  ceil(1.7),
  ceil(-1.7)).fetch();
```

The result being

```text
+-------+-------+
| floor | floor |
+-------+-------+
|     2 |    -1 |
+-------+-------+
```

###### Dialect support

This example using jOOQ:

```java
ceil(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
(CLNG(x) - (x - clng(x) > 0))
```

###### ASE, H2, SQLDataWarehouse, SQLServer

```sql
ceiling(x)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
ceil(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="cos-function"></a>
##### 3.11.15.12. COS

The `COS()` function calculates the cosine of a numeric value.

```sql
SELECT cos(3.14159265359);
```

```java
create.select(cos(3.14159265359)).fetch();
```

The result being

```text
+-----+
| cos |
+-----+
|  -1 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
cos(x)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
cos(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="cosh-function"></a>
##### 3.11.15.13. COSH

The `COSH()` function calculates the hyperbolic cosine of a numeric value.

```sql
SELECT cosh(1);
```

```java
create.select(cosh(1)).fetch();
```

The result being

```text
+---------------+
|          cosh |
+---------------+
| 1.54308063482 |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
cosh(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, DuckDB, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Spanner, Sybase, Vertica, YugabyteDB

```sql
((exp((x * 2)) + 1) / (exp(x) * 2))
```

###### BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, Hana, Informix, Oracle, SQLite, Snowflake, Teradata, Trino

```sql
cosh(x)
```

###### CockroachDB

```sql
((exp(cast(
  (x * 2)
  AS decimal
)) + 1) / (exp(cast(x AS decimal)) * 2))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="cot-function"></a>
##### 3.11.15.14. COT

The `COT()` function calculates the cotangent of a numeric value.

```sql
SELECT cot(1.5707963268);
```

```java
create.select(cot(1.5707963268)).fetch();
```

The result being

```text
+-----+
| cot |
+-----+
|   0 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
cot(x)
```

Translates to the following dialect specific expressions:

###### Access, BigQuery, ClickHouse, Informix, Oracle, SQLite, Spanner, Teradata, Trino

```sql
(cos(x) / sin(x))
```

###### ASE, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Vertica, YugabyteDB

```sql
cot(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="coth-function"></a>
##### 3.11.15.15. COTH

The `COTH()` function calculates the hyperbolic cotangent of a numeric value.

```sql
SELECT coth(1);
```

```java
create.select(coth(1)).fetch();
```

The result being

```text
+--------------+
|         coth |
+--------------+
| 1.3130352855 |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
coth(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, DuckDB, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Sybase, Vertica, YugabyteDB

```sql
((exp((x * 2)) + 1) / (exp((x * 2)) - 1))
```

###### BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, Hana, Informix, Oracle, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
(1 / tanh(x))
```

###### CockroachDB

```sql
((exp(cast(
  (x * 2)
  AS decimal
)) + 1) / (exp(cast(
  (x * 2)
  AS decimal
)) - 1))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="deg-function"></a>
##### 3.11.15.16. DEG

The `DEG()` function calculates the degrees from a radian value (see also [RAD](#rad-function)).

```sql
SELECT deg(3.14159265359);
```

```java
create.select(deg(3.14159265359)).fetch();
```

The result being

```text
+-----+
| deg |
+-----+
| 180 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
deg(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
((x * 180) / 3.141592653589793)
```

###### ASE, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
degrees(x)
```

###### BigQuery

```sql
((cast(x AS bignumeric) * 180) / acos(-1))
```

###### Firebird

```sql
((cast(x AS numeric) * 180) / pi())
```

###### Hana, Spanner

```sql
((cast(x AS numeric) * 180) / acos(-1))
```

###### Oracle

```sql
((cast(x AS number) * 180) / acos(-1))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="e-function"></a>
##### 3.11.15.17. E

The `E()` function produces the Euler constant *e*, which is around `2.71828182846`

```sql
SELECT e();
```

```java
create.select(e()).fetch();
```

The result being

```text
+---------------+
| exp           |
+---------------+
| 2.71828182846 |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
e()
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
exp(1)
```

###### ClickHouse, Databricks, Trino

```sql
e()
```

###### CockroachDB

```sql
exp(cast(1 AS decimal))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="exp-function"></a>
##### 3.11.15.18. EXP

The `EXP()` function calculates e^x

```sql
SELECT exp(1);
```

```java
create.select(exp(1)).fetch();
```

The result being

```text
+---------------+
| exp           |
+---------------+
| 2.71828182846 |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
exp(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
exp(x)
```

###### CockroachDB

```sql
exp(cast(x AS decimal))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="floor-function"></a>
##### 3.11.15.19. FLOOR

The `FLOOR()` function rounds a numeric value to its nearest lower integer.

```sql
SELECT
  floor(1.7),
  floor(-1.7);
```

```java
create.select(
  floor(1.7),
  floor(-1.7)).fetch();
```

The result being

```text
+-------+-------+
| floor | floor |
+-------+-------+
|     1 |    -2 |
+-------+-------+
```

###### Dialect support

This example using jOOQ:

```java
floor(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
(cdec(x) - (x < cdec(x)))
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
floor(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="greatest-function"></a>
##### 3.11.15.20. GREATEST

The `GREATEST()` function produces the greatest value among all the arguments.

```sql
SELECT greatest(2, 3);
```

```java
create.select(greatest(2, 3)).fetch();
```

The result being

```text
+----------+
| greatest |
+----------+
|        3 |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
greatest(x, y)
```

Translates to the following dialect specific expressions:

###### Access

```sql
SWITCH(x > y, x, TRUE, y)
```

###### ASE, Informix, SQLDataWarehouse, Sybase

```sql
CASE
  WHEN x > y THEN x
  ELSE y
END
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLServer, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
greatest(x, y)
```

###### Firebird

```sql
maxvalue(x, y)
```

###### SQLite

```sql
max(x, y)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="least-function"></a>
##### 3.11.15.21. LEAST

The `LEAST()` function produces the least value among all the arguments.

```sql
SELECT least(2, 3);
```

```java
create.select(least(2, 3)).fetch();
```

The result being

```text
+-------+
| least |
+-------+
|     2 |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
least(x, y)
```

Translates to the following dialect specific expressions:

###### Access

```sql
SWITCH(x < y, x, TRUE, y)
```

###### ASE, Informix, SQLDataWarehouse, Sybase

```sql
CASE
  WHEN x < y THEN x
  ELSE y
END
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLServer, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
least(x, y)
```

###### Firebird

```sql
minvalue(x, y)
```

###### SQLite

```sql
min(x, y)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="ln-function"></a>
##### 3.11.15.22. LN

The `LN()` function calculates the natural logarithm of a numeric value.

```sql
SELECT ln(1);
```

```java
create.select(ln(1)).fetch();
```

The result being

```text
+----+
| ln |
+----+
|  0 |
+----+
```

###### Dialect support

This example using jOOQ:

```java
ln(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, SQLDataWarehouse, SQLServer

```sql
log(x)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
ln(x)
```

###### CockroachDB

```sql
ln(cast(x AS decimal))
```

###### Informix

```sql
logn(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="log-function"></a>
##### 3.11.15.23. LOG

The `LOG()` function calculates the logarithm of a numeric value, given a base.

```sql
SELECT log(8, 2);
```

```java
create.select(log(8, 2)).fetch();
```

The result being

```text
+-----+
| log |
+-----+
|   3 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
log(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, Access

```sql
(log(x) / log(y))
```

###### Aurora MySQL, Aurora Postgres, Databricks, Exasol, Firebird, H2, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, Snowflake, Trino, Vertica, YugabyteDB

```sql
log(y, x)
```

###### BigQuery, SQLDataWarehouse, SQLServer, Spanner

```sql
log(x, y)
```

###### ClickHouse, DB2, DuckDB, HSQLDB, SQLite, Sybase, Teradata

```sql
(ln(x) / ln(y))
```

###### CockroachDB

```sql
(ln(cast(x AS decimal)) / ln(cast(y AS decimal)))
```

###### Informix

```sql
(logn(x) / logn(y))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="log10-function"></a>
##### 3.11.15.24. LOG10

The `LOG10()` function calculates the logarithm of a numeric value, given base 10.

```sql
SELECT log10(100);
```

```java
create.select(log10(100)).fetch();
```

The result being

```text
+-------+
| log10 |
+-------+
|     2 |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
log10(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Postgres, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Trino, Vertica

```sql
log10(x)
```

###### CockroachDB

```sql
(ln(cast(x AS decimal)) / ln(cast(10 AS decimal)))
```

###### Hana, Oracle, Snowflake, YugabyteDB

```sql
log(10, x)
```

###### Redshift, Teradata

```sql
log(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="neg-function"></a>
##### 3.11.15.25. NEG

The `NEG()` function produces the negation of its argument.

```sql
SELECT neg(2);
```

```java
create.select(neg(2)).fetch();
```

The result being

```text
+-----+
| neg |
+-----+
|  -2 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
neg(x)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
-x
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="pi-function"></a>
##### 3.11.15.26. PI

The `PI()` function produces the pi constant *π*, which is around `3.14159265359`

```sql
SELECT pi();
```

```java
create.select(pi()).fetch();
```

The result being

```text
+---------------+
| pi            |
+---------------+
| 3.14159265359 |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
pi()
```

Translates to the following dialect specific expressions:

###### Access

```sql
3.141592653589793
```

###### ASE, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Trino, Vertica, YugabyteDB

```sql
pi()
```

###### BigQuery, DB2, Hana, Informix, Oracle, Spanner, Teradata

```sql
acos(-1)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="power-function"></a>
##### 3.11.15.27. POWER

The `POWER()` function calculates the power of two numbers.

```sql
SELECT power(2, 3);
```

```java
create.select(power(2, 3)).fetch();
```

The result being

```text
+-------+
| power |
+-------+
|     8 |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
power(x, y)
```

Translates to the following dialect specific expressions:

###### Access

```sql
(x ^ y)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
power(x, y)
```

###### ClickHouse

```sql
pow(x, y)
```

###### CockroachDB

```sql
power(
  cast(x AS decimal),
  cast(y AS decimal)
)
```

###### Snowflake

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="rad-function"></a>
##### 3.11.15.28. RAD

The `RAD()` function calculates the radian value from degrees (see also [DEG](#deg-function)).

```sql
SELECT rad(180);
```

```java
create.select(rad(180)).fetch();
```

The result being

```text
+---------------+
|           rad |
+---------------+
| 3.14159265359 |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
rad(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
((cdec(x) * 3.141592653589793) / 180)
```

###### ASE, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
radians(x)
```

###### BigQuery

```sql
((cast(x AS bignumeric) * acos(-1)) / 180)
```

###### Firebird

```sql
((cast(x AS numeric) * pi()) / 180)
```

###### Hana, Spanner

```sql
((cast(x AS numeric) * acos(-1)) / 180)
```

###### Oracle

```sql
((cast(x AS number) * acos(-1)) / 180)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="rand-function"></a>
##### 3.11.15.29. RAND

The `RAND()` function produces a random number between 0 and 1.

```sql
SELECT rand();
```

```java
create.select(rand()).fetch();
```

The result being

```text
+------+
| rand |
+------+
|  0.4 | <-- chosen by fair dice roll
+------+
```

###### Dialect support

This example using jOOQ:

```java
rand()
```

Translates to the following dialect specific expressions:

###### Access

```sql
rnd
```

###### ASE, Aurora MySQL, ClickHouse, DB2, Databricks, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, Sybase, Trino

```sql
rand()
```

###### Aurora Postgres, CockroachDB, DuckDB, Exasol, Postgres, Redshift, Vertica, YugabyteDB

```sql
random()
```

###### BigQuery, Spanner

```sql
abs((farm_fingerprint(generate_uuid()) / 9223372036854775807))
```

###### Oracle

```sql
DBMS_RANDOM.VALUE
```

###### SQLite

```sql
(abs(random()) / cast(9223372036854775808.0 AS decimal))
```

###### Teradata

```sql
(cast((random(-2147483648, 2147483647) + 2147483648) AS NUMERIC(38, 19)) / 4294967295)
```

###### Informix, Snowflake

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="round-function"></a>
##### 3.11.15.30. ROUND

The `ROUND()` function rounds a numeric value to its nearest integer, or optionally, to the nearest decimal precision.

```sql
SELECT
  round(1.7),
  round(-1.7);
```

```java
create.select(
  round(1.7),
  round(-1.7)).fetch();
```

The result being

```text
+-------+-------+
| round | round |
+-------+-------+
|     2 |    -2 |
+-------+-------+
```

###### Dialect support

This example using jOOQ:

```java
round(x)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
round(x)
```

###### ASE, SQLDataWarehouse, SQLServer, Sybase

```sql
round(x, 0)
```

###### CockroachDB

```sql
round(cast(x AS numeric))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="sign-function"></a>
##### 3.11.15.31. SIGN

The `SIGN()` function produces the sign of a numeric value, being any value of `-1, 0, 1`

```sql
SELECT sign(-5), sign(0), sign(3);
```

```java
create.select(sign(-5), sign(0), sign(3)).fetch();
```

The result being

```text
+------+------+------+
| sign | sign | sign |
+------+------+------+
|   -1 |    0 |    1 |
+------+------+------+
```

###### Dialect support

This example using jOOQ:

```java
sign(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
sgn(x)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
sign(x)
```

###### SQLite

```sql
CASE
  WHEN x > 0 THEN 1
  WHEN x < 0 THEN -1
  WHEN x = 0 THEN 0
END
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="sin-function"></a>
##### 3.11.15.32. SIN

The `SIN()` function calculates the sine of a numeric value.

```sql
SELECT sin(3.14159265359);
```

```java
create.select(sin(3.14159265359)).fetch();
```

The result being

```text
+-----+
| sin |
+-----+
|   0 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
sin(x)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
sin(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="sinh-function"></a>
##### 3.11.15.33. SINH

The `SINH()` function calculates the hyperbolic sine of a numeric value.

```sql
SELECT sinh(1);
```

```java
create.select(sinh(1)).fetch();
```

The result being

```text
+---------------+
|          sinh |
+---------------+
| 1.17520119364 |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
sinh(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, DuckDB, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Sybase, Trino, Vertica, YugabyteDB

```sql
((exp((x * 2)) - 1) / (exp(x) * 2))
```

###### BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, Hana, Informix, Oracle, SQLite, Snowflake, Spanner, Teradata

```sql
sinh(x)
```

###### CockroachDB

```sql
((exp(cast(
  (x * 2)
  AS decimal
)) - 1) / (exp(cast(x AS decimal)) * 2))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="sqrt-function"></a>
##### 3.11.15.34. SQRT

The `SQRT()` function calculates the square root of a numeric value.

```sql
SELECT sqrt(4);
```

```java
create.select(sqrt(4)).fetch();
```

The result being

```text
+------+
| sqrt |
+------+
|    2 |
+------+
```

###### Dialect support

This example using jOOQ:

```java
sqrt(x)
```

Translates to the following dialect specific expressions:

###### Access

```sql
sqr(x)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
sqrt(x)
```

###### CockroachDB

```sql
sqrt(cast(x AS decimal))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="square-function"></a>
##### 3.11.15.35. SQUARE

The `SQUARE()` function calculates the value of a number squared.

```sql
SELECT square(3);
```

```java
create.select(square(3)).fetch();
```

The result being

```text
+--------+
| square |
+--------+
|      9 |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
square(x)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
(x * x)
```

###### ASE, SQLDataWarehouse, SQLServer

```sql
square(x)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="tan-function"></a>
##### 3.11.15.36. TAN

The `TAN()` function calculates the tangent of a numeric value.

```sql
SELECT tan(3.14159265359);
```

```java
create.select(tan(3.14159265359)).fetch();
```

The result being

```text
+-----+
| tan |
+-----+
|   0 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
tan(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
tan(x)
```

###### Snowflake

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="tanh-function"></a>
##### 3.11.15.37. TANH

The `TANH()` function calculates the hyperbolic tangent of a numeric value.

```sql
SELECT tanh(1);
```

```java
create.select(tanh(1)).fetch();
```

The result being

```text
+---------------+
|          tanh |
+---------------+
| 0.76159415595 |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
tanh(x)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, DuckDB, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Sybase, Vertica, YugabyteDB

```sql
((exp((x * 2)) - 1) / (exp((x * 2)) + 1))
```

###### BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, Hana, Informix, Oracle, SQLite, Snowflake, Spanner, Teradata, Trino

```sql
tanh(x)
```

###### CockroachDB

```sql
((exp(cast(
  (x * 2)
  AS decimal
)) - 1) / (exp(cast(
  (x * 2)
  AS decimal
)) + 1))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="trunc-function"></a>
##### 3.11.15.38. TRUNC

The `TRUNC()` function rounds a numeric value to its nearest integer (or optionally, to a specific decimal precision) that is closer to zero.

```sql
SELECT
  trunc(1.7),
  trunc(-1.7);
```

```java
create.select(
  trunc(1.7),
  trunc(-1.7)).fetch();
```

The result being

```text
+-------+-------+
| trunc | trunc |
+-------+-------+
|     1 |    -1 |
+-------+-------+
```

###### Dialect support

This example using jOOQ:

```java
trunc(x)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, Vertica

```sql
date_trunc('day', x)
```

###### BigQuery

```sql
datetime_trunc(
  x,
  DAY
)
```

###### DB2, HSQLDB, Informix, Oracle

```sql
trunc(x, 'DD')
```

###### H2

```sql
PARSEDATETIME(FORMATDATETIME(x, 'yyyy-MM-dd'), 'yyyy-MM-dd')
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, Firebird, Hana, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="width-bucket-function"></a>
##### 3.11.15.39. WIDTH_BUCKET

The `WIDTH_BUCKET()` function divides a numeric range into equally sized buckets and calculates which bucket number a value is in.

```sql
SELECT
  width_bucket(0 , 0, 100, 10),
  width_bucket(15, 0, 100, 10),
  width_bucket(99, 0, 100, 10);
```

```java
create.select(
  widthBucket(val(0) , 0, 100, 10),
  widthBucket(val(15), 0, 100, 10),
  widthBucket(val(99), 0, 100, 10)).fetch();
```

The result being

```text
+--------------+--------------+--------------+
| width_bucket | width_bucket | width_bucket |
+--------------+--------------+--------------+
|            1 |            2 |           10 |
+--------------+--------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
widthBucket(val(15), 0, 100, 10)
```

Translates to the following dialect specific expressions:

###### Access

```sql
SWITCH(15 < 0, 0, 15 >= 100, (10 + 1), TRUE, ((cdec((((15 - 0) * 10) / (100 - 0))) - ((((15 - 0) * 10) / (100 - 0)) < cdec((((15 - 0) * 10) / (100 - 0))))) + 1))
```

###### ASE, Aurora MySQL, BigQuery, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Vertica

```sql
CASE
  WHEN 15 < 0 THEN 0
  WHEN 15 >= 100 THEN (10 + 1)
  ELSE (floor((((15 - 0) * 10) / (100 - 0))) + 1)
END
```

###### Aurora Postgres, ClickHouse, CockroachDB, Databricks, Oracle, Postgres, Snowflake, Teradata, Trino, YugabyteDB

```sql
width_bucket(15, 0, 100, 10)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bitwise-functions"></a>
#### 3.11.16. Bitwise functions

Most databases only support a few bitwise operations, while others ship with the full set of operators. jOOQ's API includes most bitwise operations as listed below. In order to avoid ambiguities with [conditional operators](#conditional-expressions), most bitwise functions are prefixed with "bit"

<a id="bit-and-function"></a>
##### 3.11.16.1. BIT_AND

The `BIT_AND()` function produces the bitwise `AND` operation.

```sql
SELECT bit_and(5, 4);
```

```java
create.select(bitAnd(5, 4)).fetch();
```

The result being

```text
+---------+
| bit_and |
+---------+
|       4 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
bitAnd(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Vertica, YugabyteDB

```sql
(x & y)
```

###### ClickHouse

```sql
bitAnd(x, y)
```

###### DB2, H2, HSQLDB, Hana, Informix, Oracle, Snowflake, Teradata

```sql
bitand(x, y)
```

###### Exasol

```sql
bit_and(x, y)
```

###### Firebird

```sql
bin_and(x, y)
```

###### Trino

```sql
bitwise_and(x, y)
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-count-function"></a>
##### 3.11.16.2. BIT_COUNT

The `BIT_COUNT()` function counts the number of bits in a value.

```sql
SELECT bit_count(5);
```

```java
create.select(bitCount(5)).fetch();
```

The result being

```text
+-----------+
| bit_count |
+-----------+
|         2 |
+-----------+
```

###### Dialect support

This example using jOOQ:

```java
bitCount((byte) 5)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Databricks, DuckDB, MariaDB, MemSQL, MySQL, SQLServer, Spanner

```sql
bit_count(5)
```

###### Aurora Postgres, Postgres, Redshift, SQLite, Vertica, YugabyteDB

```sql
cast(
  ((5 & 1) + ((5 & 2) >> 1) + ((5 & 4) >> 2) + ((5 & 8) >> 3) + ((5 & 16) >> 4) + ((5 & 32) >> 5) + ((5 & 64) >> 6) + ((5 & -128) >> 7))
  AS int
)
```

###### BigQuery

```sql
cast(
  ((5 & 1) + ((5 & 2) >> 1) + ((5 & 4) >> 2) + ((5 & 8) >> 3) + ((5 & 16) >> 4) + ((5 & 32) >> 5) + ((5 & 64) >> 6) + ((5 & -128) >> 7))
  AS int64
)
```

###### ClickHouse

```sql
bitCount(5)
```

###### CockroachDB

```sql
cast(
  ((5 & 1) + ((5 & 2) >> 1) + ((5 & 4) >> 2) + ((5 & 8) >> 3) + ((5 & 16) >> 4) + ((5 & 32) >> 5) + ((5 & 64) >> 6) + ((5 & -128) >> 7))
  AS int4
)
```

###### Firebird

```sql
cast(
  (bin_and(5, 1) + bin_shr(
    bin_and(5, 2),
    1
  ) + bin_shr(
    bin_and(5, 4),
    2
  ) + bin_shr(
    bin_and(5, 8),
    3
  ) + bin_shr(
    bin_and(5, 16),
    4
  ) + bin_shr(
    bin_and(5, 32),
    5
  ) + bin_shr(
    bin_and(5, 64),
    6
  ) + bin_shr(
    bin_and(5, -128),
    7
  ))
  AS integer
)
```

###### H2, HSQLDB

```sql
cast(
  (bitand(5, 1) + (bitand(5, 2) / 2) + (bitand(5, 4) / 4) + (bitand(5, 8) / 8) + (bitand(5, 16) / 16) + (bitand(5, 32) / 32) + (bitand(5, 64) / 64) + (bitand(5, -128) / -128))
  AS int
)
```

###### Hana

```sql
bitcount(5)
```

###### Informix

```sql
cast(
  (bitand(5, 1) + (bitand(5, 2) / 2) + (bitand(5, 4) / 4) + (bitand(5, 8) / 8) + (bitand(5, 16) / 16) + (bitand(5, 32) / 32) + (bitand(5, 64) / 64) + (bitand(5, -128) / -128))
  AS integer
)
```

###### Oracle

```sql
cast(
  (bitand(5, 1) + (bitand(5, 2) / 2) + (bitand(5, 4) / 4) + (bitand(5, 8) / 8) + (bitand(5, 16) / 16) + (bitand(5, 32) / 32) + (bitand(5, 64) / 64) + (bitand(5, -128) / -128))
  AS number(10)
)
```

###### Snowflake

```sql
cast(
  (bitand(5, 1) + bitshiftright(
    bitand(5, 2),
    1
  ) + bitshiftright(
    bitand(5, 4),
    2
  ) + bitshiftright(
    bitand(5, 8),
    3
  ) + bitshiftright(
    bitand(5, 16),
    4
  ) + bitshiftright(
    bitand(5, 32),
    5
  ) + bitshiftright(
    bitand(5, 64),
    6
  ) + bitshiftright(
    bitand(5, -128),
    7
  ))
  AS number(10)
)
```

###### SQLDataWarehouse, Sybase

```sql
cast(
  ((5 & 1) + ((5 & 2) / 2) + ((5 & 4) / 4) + ((5 & 8) / 8) + ((5 & 16) / 16) + ((5 & 32) / 32) + ((5 & 64) / 64) + ((5 & -128) / -128))
  AS int
)
```

###### Teradata

```sql
countset(5, 1)
```

###### Trino

```sql
cast(
  (bitwise_and(5, 1) + bitwise_right_shift(
    bitwise_and(5, 2),
    1
  ) + bitwise_right_shift(
    bitwise_and(5, 4),
    2
  ) + bitwise_right_shift(
    bitwise_and(5, 8),
    3
  ) + bitwise_right_shift(
    bitwise_and(5, 16),
    4
  ) + bitwise_right_shift(
    bitwise_and(5, 32),
    5
  ) + bitwise_right_shift(
    bitwise_and(5, 64),
    6
  ) + bitwise_right_shift(
    bitwise_and(5, -128),
    7
  ))
  AS int
)
```

###### ASE, Access, DB2, Exasol

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-get-function"></a>
##### 3.11.16.3. BIT_GET

The `BIT_GET()` function extracts the bit value at a given position:

```sql
SELECT
  bit_get(3, 0),
  bit_get(3, 2);
```

```java
create.select(
  bitGet(inline(3), 0),
  bitGet(inline(3), 2)).fetch();
```

The result being

```text
+---------+---------+
| bit_get | bit_get |
+---------+---------+
|       1 |       0 |
+---------+---------+
```

###### Dialect support

This example using jOOQ:

```java
bitGet(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, SQLDataWarehouse, Sybase

```sql
((x & (1 * cast(
  power(2, y)
  AS int
))) / cast(
  power(2, y)
  AS int
))
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLite, Spanner, Vertica, YugabyteDB

```sql
((x & (1 << y)) >> y)
```

###### ClickHouse

```sql
bitTest(x, y)
```

###### Databricks

```sql
bit_get(x, y)
```

###### DB2, Informix

```sql
(bitand(
  x,
  (1 * cast(
    power(2, y)
    AS integer
  ))
) / cast(
  power(2, y)
  AS integer
))
```

###### Exasol

```sql
CASE bit_check(x, y)
  WHEN TRUE THEN 1
  WHEN FALSE THEN 0
END
```

###### Firebird

```sql
bin_shr(
  bin_and(
    x,
    bin_shl(1, y)
  ),
  y
)
```

###### H2

```sql
CASE bitget(x, y)
  WHEN TRUE THEN 1
  WHEN FALSE THEN 0
END
```

###### HSQLDB

```sql
(bitand(
  x,
  (1 * cast(
    power(2, y)
    AS int
  ))
) / cast(
  power(2, y)
  AS int
))
```

###### Oracle

```sql
(bitand(
  x,
  (1 * cast(
    power(2, y)
    AS number(10)
  ))
) / cast(
  power(2, y)
  AS number(10)
))
```

###### Snowflake

```sql
bitshiftright(
  bitand(
    x,
    bitshiftleft(1, y)
  ),
  y
)
```

###### SQLServer

```sql
get_bit(x, y)
```

###### Teradata

```sql
getbit(x, y)
```

###### Trino

```sql
bitwise_right_shift(
  bitwise_and(
    x,
    bitwise_left_shift(1, y)
  ),
  y
)
```

###### Access, Hana

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-nand-function"></a>
##### 3.11.16.4. BIT_NAND

The `BIT_NAND()` function produces the bitwise `NAND` operation.

```sql
SELECT bit_nand(5, 4);
```

```java
create.select(bitNand(5, 4)).fetch();
```

The result being

```text
+----------+
| bit_nand |
+----------+
|       -5 |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
bitNand(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Vertica, YugabyteDB

```sql
~((x & y))
```

###### ClickHouse

```sql
bitNot(bitAnd(x, y))
```

###### DB2, H2, Hana, Informix, Snowflake, Teradata

```sql
bitnot(bitand(x, y))
```

###### Exasol

```sql
bit_not(bit_and(x, y))
```

###### Firebird

```sql
bin_not(bin_and(x, y))
```

###### HSQLDB, Oracle

```sql
((0 - bitand(x, y)) - 1)
```

###### Trino

```sql
bitwise_not(bitwise_and(x, y))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-nor-function"></a>
##### 3.11.16.5. BIT_NOR

The `BIT_NOR()` function produces the bitwise `NOR` operation.

```sql
SELECT bit_nor(5, 2);
```

```java
create.select(bitNor(5, 2)).fetch();
```

The result being

```text
+---------+
| bit_nor |
+---------+
|      -8 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
bitNor(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Vertica, YugabyteDB

```sql
~((x | y))
```

###### ClickHouse

```sql
bitNot(bitOr(x, y))
```

###### DB2, H2, Hana, Informix, Snowflake, Teradata

```sql
bitnot(bitor(x, y))
```

###### Exasol

```sql
bit_not(bit_or(x, y))
```

###### Firebird

```sql
bin_not(bin_or(x, y))
```

###### HSQLDB

```sql
((0 - bitor(x, y)) - 1)
```

###### Oracle

```sql
((0 - ((x + y) - bitand(x, y))) - 1)
```

###### Trino

```sql
bitwise_not(bitwise_or(x, y))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-not-function"></a>
##### 3.11.16.6. BIT_NOT

The `BIT_NOT()` function inverts the bits in a number, producing the 2's complement of a signed number.

```sql
SELECT bit_not(5);
```

```java
create.select(bitNot(5)).fetch();
```

The result being

```text
+---------+
| bit_not |
+---------+
|      -6 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
bitNot(x)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Vertica, YugabyteDB

```sql
~x
```

###### ClickHouse

```sql
bitNot(x)
```

###### DB2, H2, Hana, Informix, Snowflake, Teradata

```sql
bitnot(x)
```

###### Exasol

```sql
bit_not(x)
```

###### Firebird

```sql
bin_not(x)
```

###### HSQLDB, Oracle

```sql
((0 - x) - 1)
```

###### Trino

```sql
bitwise_not(x)
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-or-function"></a>
##### 3.11.16.7. BIT_OR

The `BIT_OR()` function produces the bitwise `OR` operation.

```sql
SELECT bit_or(5, 2);
```

```java
create.select(bitOr(5, 2)).fetch();
```

The result being

```text
+--------+
| bit_or |
+--------+
|      7 |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
bitOr(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Vertica, YugabyteDB

```sql
(x | y)
```

###### ClickHouse

```sql
bitOr(x, y)
```

###### DB2, H2, HSQLDB, Hana, Informix, Snowflake, Teradata

```sql
bitor(x, y)
```

###### Exasol

```sql
bit_or(x, y)
```

###### Firebird

```sql
bin_or(x, y)
```

###### Oracle

```sql
((x + y) - bitand(x, y))
```

###### Trino

```sql
bitwise_or(x, y)
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-set-function"></a>
##### 3.11.16.8. BIT_SET

The `BIT_SET()` function sets the bit value at a given position to a new value:

```sql
SELECT
  bit_set(3, 0),
  bit_set(3, 2),
  bit_set(3, 0, 0),
  bit_set(3, 2, 1);
```

```java
create.select(
  bitSet(inline(3), 0),
  bitSet(inline(3), 2),
  bitSet(inline(3), 0, 0),
  bitSet(inline(3), 2, 1)).fetch();
```

The result being

```text
+---------+---------+---------+---------+
| bit_set | bit_set | bit_set | bit_set |
+---------+---------+---------+---------+
|       3 |       7 |       2 |       7 |
+---------+---------+---------+---------+
```

###### Dialect support

This example using jOOQ:

```java
bitSet(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, SQLDataWarehouse, Sybase

```sql
(x | (1 * cast(
  power(2, y)
  AS int
)))
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLite, Spanner, Vertica, YugabyteDB

```sql
(x | (1 << y))
```

###### ClickHouse

```sql
bitOr(
  x,
  bitShiftLeft(1, y)
)
```

###### Databricks

```sql
(x | shiftleft(1, y))
```

###### DB2, Informix

```sql
bitor(
  x,
  (1 * cast(
    power(2, y)
    AS integer
  ))
)
```

###### Exasol

```sql
bit_set(x, y)
```

###### Firebird

```sql
bin_or(
  x,
  bin_shl(1, y)
)
```

###### H2

```sql
bitor(
  x,
  lshift(1, y)
)
```

###### HSQLDB

```sql
bitor(
  x,
  (1 * cast(
    power(2, y)
    AS int
  ))
)
```

###### Oracle

```sql
((x + (1 * cast(
  power(2, y)
  AS number(10)
))) - bitand(
  x,
  (1 * cast(
    power(2, y)
    AS number(10)
  ))
))
```

###### Snowflake

```sql
bitor(
  x,
  bitshiftleft(1, y)
)
```

###### SQLServer

```sql
set_bit(x, y)
```

###### Teradata

```sql
setbit(x, y)
```

###### Trino

```sql
bitwise_or(
  x,
  bitwise_left_shift(1, y)
)
```

###### Access, Hana

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-xnor-function"></a>
##### 3.11.16.9. BIT_XNOR

The `BIT_XNOR()` function produces the bitwise `XNOR` (exclusive `NOR`) operation.

```sql
SELECT bit_xnor(5, 3);
```

```java
create.select(bitXNor(5, 3)).fetch();
```

The result being

```text
+----------+
| bit_xnor |
+----------+
|       -7 |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
bitXNor(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, BigQuery, Databricks, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, Spanner, Sybase

```sql
~((x ^ y))
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, Vertica, YugabyteDB

```sql
~((x # y))
```

###### ClickHouse

```sql
bitNot(bitXor(x, y))
```

###### DB2, Hana, Informix, Snowflake, Teradata

```sql
bitnot(bitxor(x, y))
```

###### DuckDB

```sql
~xor(x, y)
```

###### Exasol

```sql
bit_not(bit_xor(x, y))
```

###### Firebird

```sql
bin_not(bin_xor(x, y))
```

###### H2

```sql
bitxnor(x, y)
```

###### HSQLDB

```sql
((0 - bitxor(x, y)) - 1)
```

###### Oracle

```sql
((0 - bitand(
  ((0 - bitand(x, y)) - 1),
  ((x + y) - bitand(x, y))
)) - 1)
```

###### SQLite

```sql
~((~((x & y)) & (x | y)))
```

###### Trino

```sql
bitwise_not(bitwise_xor(x, y))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-xor-function"></a>
##### 3.11.16.10. BIT_XOR

The `BIT_XOR()` function produces the bitwise `XOR` (exclusive `OR`) operation.

```sql
SELECT bit_xor(5, 3);
```

```java
create.select(bitXor(5, 3)).fetch();
```

The result being

```text
+---------+
| bit_xor |
+---------+
|       6 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
bitXor(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, BigQuery, Databricks, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, Spanner, Sybase

```sql
(x ^ y)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, Vertica, YugabyteDB

```sql
(x # y)
```

###### ClickHouse

```sql
bitXor(x, y)
```

###### DB2, H2, HSQLDB, Hana, Informix, Snowflake, Teradata

```sql
bitxor(x, y)
```

###### DuckDB

```sql
xor(x, y)
```

###### Exasol

```sql
bit_xor(x, y)
```

###### Firebird

```sql
bin_xor(x, y)
```

###### Oracle

```sql
bitand(
  ((0 - bitand(x, y)) - 1),
  ((x + y) - bitand(x, y))
)
```

###### SQLite

```sql
(~((x & y)) & (x | y))
```

###### Trino

```sql
bitwise_xor(x, y)
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-shl-function"></a>
##### 3.11.16.11. SHL

The `SHL()` function produces the bitwise shift left operation.

```sql
SELECT shl(1, 4);
```

```java
create.select(shl(1, 4)).fetch();
```

The result being

```text
+-----+
| shl |
+-----+
|  16 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
shl(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, HSQLDB, SQLDataWarehouse, Sybase

```sql
(x * cast(
  power(2, y)
  AS int
))
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLServer, SQLite, Spanner, Vertica, YugabyteDB

```sql
(x << y)
```

###### ClickHouse

```sql
bitShiftLeft(x, y)
```

###### Databricks, Teradata

```sql
shiftleft(x, y)
```

###### DB2, Informix

```sql
(x * cast(
  power(2, y)
  AS integer
))
```

###### Exasol

```sql
bit_lshift(x, y)
```

###### Firebird

```sql
bin_shl(x, y)
```

###### H2

```sql
lshift(x, y)
```

###### Oracle

```sql
(x * cast(
  power(2, y)
  AS number(10)
))
```

###### Snowflake

```sql
bitshiftleft(x, y)
```

###### Trino

```sql
bitwise_left_shift(x, y)
```

###### Access, Hana

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-shr-function"></a>
##### 3.11.16.12. SHR

The `SR()` function produces the bitwise shift right operation.

```sql
SELECT shr(16, 4);
```

```java
create.select(shr(16, 4)).fetch();
```

The result being

```text
+-----+
| shr |
+-----+
|   1 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
shr(x, y)
```

Translates to the following dialect specific expressions:

###### ASE, HSQLDB, SQLDataWarehouse, Sybase

```sql
(x / cast(
  power(2, y)
  AS int
))
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLServer, SQLite, Spanner, Vertica, YugabyteDB

```sql
(x >> y)
```

###### ClickHouse

```sql
bitShiftRight(x, y)
```

###### Databricks, Teradata

```sql
shiftright(x, y)
```

###### DB2, Informix

```sql
(x / cast(
  power(2, y)
  AS integer
))
```

###### Exasol

```sql
bit_rshift(x, y)
```

###### Firebird

```sql
bin_shr(x, y)
```

###### H2

```sql
rshift(x, y)
```

###### Oracle

```sql
(x / cast(
  power(2, y)
  AS number(10)
))
```

###### Snowflake

```sql
bitshiftright(x, y)
```

###### Trino

```sql
bitwise_right_shift(x, y)
```

###### Access, Hana

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="string-functions"></a>
#### 3.11.17. String functions

String formatting can be done efficiently in the database before returning results to your Java application. As discussed in the chapter about [SQL dialects](#sql-dialects) string functions (as any function type) are mostly emulated in your database, in case they are not natively supported.

<a id="ascii-function"></a>
##### 3.11.17.1. ASCII

The `ASCII()` function calculates the ASCII code of a single character.

```sql
SELECT ascii('A');
```

```java
create.select(ascii("A")).fetch();
```

The result being

```text
+-------+
| ascii |
+-------+
|  65   |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
ascii("A")
```

Translates to the following dialect specific expressions:

###### Access

```sql
asc('A')
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Teradata, Vertica, YugabyteDB

```sql
ascii('A')
```

###### Firebird

```sql
ascii_val('A')
```

###### Spanner

```sql
(to_code_points('A'))[safe_ordinal(1)]
```

###### SQLite, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bin-to-uuid-function"></a>
##### 3.11.17.2. BIN_TO_UUID

The `BIN_TO_UUID()` function converts a `BINARY(16)` representation into a `VARCHAR` or `UUID` representation. See also [UUID_TO_BIN](#uuid-to-bin-function) for the inverse function.

```sql
SELECT bin_to_uuid(binaryData);
```

```java
create.select(binToUuid(binaryData)).fetch();
```

The result being

```text
+--------------------------------------+
| bin_to_uuid                          |
+--------------------------------------+
| 1fc454e5-b9f6-4d55-b783-5987fe76cb45 |
+--------------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
binToUuid(new byte[16])
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MySQL

```sql
bin_to_uuid(X'00000000000000000000000000000000')
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
cast(
  encode(cast(E'\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000' AS bytea), 'hex')
  AS uuid
)
```

###### BigQuery, Spanner

```sql
regexp_replace(to_hex(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), '(.{8})(.{4})(.{4})(.{4})(.{12})', r'\1-\2-\3-\4-\5')
```

###### ClickHouse

```sql
UUIDNumToString(X'00000000000000000000000000000000')
```

###### CockroachDB

```sql
cast(cast(E'\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000' AS bytea) AS uuid)
```

###### ASE, Access, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-length-function"></a>
##### 3.11.17.3. BIT_LENGTH

The `BIT_LENGTH()` function calculates the length of a given string in bits.

```sql
SELECT bit_length('hello');
```

```java
create.select(bitLength("hello")).fetch();
```

The result being

```text
+------------+
| bit_length |
+------------+
|         40 |
+------------+
```

> [!TIP]
> See [BIT_LENGTH (binary)](#binary-bit-length-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
bitLength("hello")
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse, SQLServer

```sql
(8 * len('hello'))
```

###### ASE

```sql
(8 * datalength('hello'))
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MySQL, Postgres, Redshift, Snowflake, Vertica, YugabyteDB

```sql
bit_length('hello')
```

###### BigQuery, Spanner

```sql
(8 * byte_length('hello'))
```

###### ClickHouse, DB2, Hana, MemSQL, SQLite, Sybase, Teradata, Trino

```sql
(8 * length('hello'))
```

###### Oracle

```sql
(8 * lengthb('hello'))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="chr-function"></a>
##### 3.11.17.4. CHR

The `CHR()` or `CHAR()` function calculates the character representation of an ASCII code, or unicode in some dialects.

```sql
SELECT chr(64);
```

```java
create.select(chr(65)).fetch();
```

The result being

```text
+-----+
| chr |
+-----+
| A   |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
chr(65)
```

Translates to the following dialect specific expressions:

###### Access, BigQuery, CockroachDB, Databricks, DuckDB, Exasol, H2, Informix, Oracle, Postgres, Redshift, Snowflake, Teradata, Vertica

```sql
chr(65)
```

###### ASE, DB2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, SQLServer, SQLite, Sybase, YugabyteDB

```sql
char(65)
```

###### Firebird

```sql
ascii_char(65)
```

###### Spanner

```sql
code_points_to_string(ARRAY[65])
```

###### Aurora MySQL, Aurora Postgres, ClickHouse, SQLDataWarehouse, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="concat-ws-function"></a>
##### 3.11.17.5. CONCAT_WS

The `CONCAT_WS()` function (where WS = "with separator") concatenates several strings and interleaves a separator:

```sql
SELECT concat_ws(',', 'a', 'b', 'c');
```

```java
create.select(concat(",", "a", "b", "c")).fetch();
```

The result being

```text
+-----------+
| concat_ws |
+-----------+
| a,b,c     |
+-----------+
```

###### Dialect support

This example using jOOQ:

```java
concatWs(",", "a", "b")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Trino, YugabyteDB

```sql
concat_ws(',', 'a', 'b')
```

###### BigQuery, Redshift, Spanner

```sql
CASE
  WHEN ',' = '' THEN (CASE
    WHEN 'a' IS NULL THEN ''
    ELSE (',' || 'a')
  END || CASE
    WHEN 'b' IS NULL THEN ''
    ELSE (',' || 'b')
  END)
  WHEN ',' IS NOT NULL THEN ltrim(
    (CASE
      WHEN 'a' IS NULL THEN ''
      ELSE (',' || 'a')
    END || CASE
      WHEN 'b' IS NULL THEN ''
      ELSE (',' || 'b')
    END),
    ','
  )
END
```

###### DB2, Firebird, Hana, Informix, Teradata, Vertica

```sql
CASE
  WHEN ',' = '' THEN (CASE
    WHEN 'a' IS NULL THEN ''
    ELSE (',' || 'a')
  END || CASE
    WHEN 'b' IS NULL THEN ''
    ELSE (',' || 'b')
  END)
  WHEN ',' IS NOT NULL THEN trim(LEADING ',' FROM (CASE
    WHEN 'a' IS NULL THEN ''
    ELSE (',' || 'a')
  END || CASE
    WHEN 'b' IS NULL THEN ''
    ELSE (',' || 'b')
  END))
END
```

###### Oracle

```sql
CASE
  WHEN ',' IS NULL THEN (CASE
    WHEN 'a' IS NULL THEN ''
    ELSE (',' || 'a')
  END || CASE
    WHEN 'b' IS NULL THEN ''
    ELSE (',' || 'b')
  END)
  ELSE trim(LEADING ',' FROM (CASE
    WHEN 'a' IS NULL THEN ''
    ELSE (',' || 'a')
  END || CASE
    WHEN 'b' IS NULL THEN ''
    ELSE (',' || 'b')
  END))
END
```

###### ASE, Access, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="concat-function"></a>
##### 3.11.17.6. CONCAT (|| operator)

The `CONCAT()` function concatenates several strings

```sql
SELECT concat('hello', ' ', 'world');
```

```java
create.select(concat("hello", " ", "world")).fetch();
```

The result being

```text
+-------------+
| concat      |
+-------------+
| hello world |
+-------------+
```

> [!TIP]
> See [CONCAT (binary)](#binary-concat-function) and [ARRAY_CONCAT](#array-concat-function) for other versions of this function.

###### Dialect support

This example using jOOQ:

```java
concat("hello", " ", "world")
```

Translates to the following dialect specific expressions:

###### Access

```sql
('hello' & ' ' & 'world')
```

###### ASE, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
('hello' || ' ' || 'world')
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
concat('hello', ' ', 'world')
```

###### SQLDataWarehouse, SQLServer

```sql
('hello' + ' ' + 'world')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="digits-function"></a>
##### 3.11.17.7. DIGITS

The `DIGITS()` function allows for turning numbers to 0-padded string that makes sorting those strings according to numeric values easier when concatenated to other strings. The padding depends on the number's data type, precision, and scale.

```sql
SELECT digits(cast(1234.5 as decimal(8, 2)));
```

```java
create.select(digits(cast(val(1234.5), DECIMAL(8, 2)))).fetch();
```

The result being

```text
+----------+
| digits   |
+----------+
| 00123450 |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
digits(cast(val(1234.5), DECIMAL(7, 2)))
```

Translates to the following dialect specific expressions:

###### Access

```sql
(replace(space(7 - len(cstr(cdec(abs((cdec(1.2345E3) * 100)))))), ' ', '0') & cstr(cdec(abs((cdec(1.2345E3) * 100)))))
```

###### ASE

```sql
(replicate(
  '0',
  (7 - char_length(cast(
    cast(
      abs((cast(1.2345E3 AS decimal(7, 2)) * 100))
      AS decimal(7)
    )
    AS varchar(7)
  )))
) || cast(
  cast(
    abs((cast(1.2345E3 AS decimal(7, 2)) * 100))
    AS decimal(7)
  )
  AS varchar(7)
))
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
lpad(
  cast(
    cast(
      abs((cast(1.2345E3 AS decimal(7, 2)) * 100))
      AS decimal(7)
    )
    AS char(7)
  ),
  7,
  '0'
)
```

###### Aurora Postgres, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Postgres, Redshift, Teradata, Trino, Vertica, YugabyteDB

```sql
lpad(
  cast(
    cast(
      abs((cast(1.2345E3 AS decimal(7, 2)) * 100))
      AS decimal(7)
    )
    AS varchar(7)
  ),
  7,
  '0'
)
```

###### BigQuery

```sql
lpad(
  cast(
    cast(
      abs((cast(1.2345E3 AS bigdecimal) * bignumeric '100'))
      AS bigdecimal
    )
    AS string
  ),
  7,
  '0'
)
```

###### ClickHouse, DB2

```sql
digits(cast(1.2345E3 AS decimal(7, 2)))
```

###### CockroachDB

```sql
lpad(
  cast(
    cast(
      abs((cast(cast(
        1.2345E3
        AS double precision
      ) AS decimal(7, 2)) * 100E0))
      AS decimal(7)
    )
    AS string(7)
  ),
  7,
  '0'
)
```

###### H2

```sql
lpad(
  cast(
    cast(
      abs((cast(cast(
        1.2345E3
        AS double
      ) AS decimal(7, 2)) * 100))
      AS decimal(7)
    )
    AS varchar(7)
  ),
  7,
  '0'
)
```

###### Informix

```sql
lpad(
  cast(
    cast(
      abs((cast(1.2345E3 AS decimal(7, 2)) * 100))
      AS decimal(7)
    )
    AS lvarchar(7)
  ),
  7,
  '0'
)
```

###### Oracle

```sql
lpad(
  cast(
    cast(
      abs((cast(1.2345E3 AS decimal(7, 2)) * 100))
      AS decimal(7)
    )
    AS varchar2(7)
  ),
  7,
  '0'
)
```

###### Snowflake

```sql
lpad(
  cast(
    cast(
      abs((cast(1.2345E3 AS number(7, 2)) * 100))
      AS number(7)
    )
    AS varchar(7)
  ),
  7,
  '0'
)
```

###### Spanner

```sql
lpad(
  cast(
    cast(
      abs((cast(1.2345E3 AS numeric) * numeric '100'))
      AS numeric
    )
    AS string
  ),
  7,
  '0'
)
```

###### SQLDataWarehouse, SQLServer

```sql
(replicate(
  '0',
  (7 - len(cast(
    cast(
      abs((cast(1.2345E3 AS decimal(7, 2)) * cast(100 AS decimal(3))))
      AS decimal(7)
    )
    AS varchar(7)
  )))
) + cast(
  cast(
    abs((cast(1.2345E3 AS decimal(7, 2)) * cast(100 AS decimal(3))))
    AS decimal(7)
  )
  AS varchar(7)
))
```

###### SQLite

```sql
substr(replace(hex(zeroblob(7)), '00', '0'), 1, 7 - length(cast(
  cast(
    abs((cast(1.2345E3 AS decimal(7, 2)) * cast(100 AS decimal)))
    AS decimal(7)
  )
  AS varchar(7)
))) || cast(
  cast(
    abs((cast(1.2345E3 AS decimal(7, 2)) * cast(100 AS decimal)))
    AS decimal(7)
  )
  AS varchar(7)
)
```

###### Sybase

```sql
(repeat(
  '0',
  (7 - length(cast(
    cast(
      abs((cast(1.2345E3 AS decimal(7, 2)) * 100))
      AS decimal(7)
    )
    AS varchar(7)
  )))
) || cast(
  cast(
    abs((cast(1.2345E3 AS decimal(7, 2)) * 100))
    AS decimal(7)
  )
  AS varchar(7)
))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="left-function"></a>
##### 3.11.17.8. LEFT

The `LEFT()` function calculates the substring of a given string starting from the left end. See also [SUBSTRING](#substring-function), [RIGHT](#right-function)

```sql
SELECT left('hello world', 5);
```

```java
create.select(left("hello world", 5)).fetch();
```

The result being

```text
+-------+
| left  |
+-------+
| hello |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
left("hello world", 5)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Teradata, Vertica, YugabyteDB

```sql
left('hello world', 5)
```

###### Oracle, SQLite

```sql
substr('hello world', 1, 5)
```

###### Spanner, Trino

```sql
substring('hello world', 1, 5)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="length-function"></a>
##### 3.11.17.9. LENGTH

The `LENGTH()` function calculates the length of a given string.

```sql
SELECT length('hello');
```

```java
create.select(length("hello")).fetch();
```

The result being

```text
+--------+
| length |
+--------+
|      5 |
+--------+
```

> [!TIP]
> See [LENGTH (binary)](#binary-length-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
length("hello")
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse, SQLServer

```sql
len('hello')
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, Spanner, Vertica, YugabyteDB

```sql
char_length('hello')
```

###### ClickHouse, DB2, DuckDB, Hana, Oracle, SQLite, Snowflake, Sybase, Teradata, Trino

```sql
length('hello')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="lower-function"></a>
##### 3.11.17.10. LOWER

The `LOWER()` function transforms a string into lower case.

```sql
SELECT lower('HELLO');
```

```java
create.select(lower("HELLO")).fetch();
```

The result being

```text
+-------+
| lower |
+-------+
| hello |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
lower("HELLO")
```

Translates to the following dialect specific expressions:

###### Access

```sql
lcase('HELLO')
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
lower('HELLO')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="lpad-function"></a>
##### 3.11.17.11. LPAD

The `LPAD()` pads a string at the left end. See also [RPAD](#rpad-function).

```sql
SELECT lpad('hello', 10, '.');
```

```java
create.select(lpad(val("hello"), 10, '.')).fetch();
```

The result being

```text
+------------+
| lpad       |
+------------+
| .....hello |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
lpad(val("hello"), 10, '.')
```

Translates to the following dialect specific expressions:

###### Access

```sql
(replace(space(10 - len('hello')), ' ', '.') & 'hello')
```

###### ASE

```sql
(replicate(
  '.',
  (10 - char_length('hello'))
) || 'hello')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Teradata, Vertica

```sql
lpad('hello', 10, '.')
```

###### SQLDataWarehouse, SQLServer

```sql
(replicate(
  '.',
  (10 - len('hello'))
) + 'hello')
```

###### SQLite

```sql
substr(replace(hex(zeroblob(10)), '00', '.'), 1, 10 - length('hello')) || 'hello'
```

###### Sybase

```sql
(repeat(
  '.',
  (10 - length('hello'))
) || 'hello')
```

###### BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Redshift, Snowflake, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="ltrim-function"></a>
##### 3.11.17.12. LTRIM

The `LTRIM()` function trims a string from the left end, stripping it of whitespace. See also [RTRIM](#rtrim-function) and [TRIM](#trim-function).

```sql
SELECT ltrim('  hello  ');
```

```java
create.select(ltrim("  hello  ")).fetch();
```

The result being

```text
+---------+
| ltrim   |
+---------+
| hello   |
+---------+
```

> [!TIP]
> See [LTRIM (binary)](#binary-ltrim-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
ltrim("  hello  ")
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
ltrim('  hello  ')
```

###### Firebird

```sql
trim(LEADING FROM '  hello  ')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="md5-function"></a>
##### 3.11.17.13. MD5

The `MD5()` function calculates the MD5 hash of a given string.

```sql
SELECT md5('hello');
```

```java
create.select(md5("hello")).fetch();
```

The result being

```text
+----------------------------------+
| md5                              |
+----------------------------------+
| 5d41402abc4b2a76b9719d911017c592 |
+----------------------------------+
```

> [!TIP]
> See [MD5 (binary)](#binary-md5-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
md5("hello")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, MariaDB, MemSQL, MySQL, Postgres, Snowflake, Vertica, YugabyteDB

```sql
md5('hello')
```

###### Exasol

```sql
hash_md5('hello')
```

###### Oracle

```sql
lower(standard_hash('hello', 'MD5'))
```

###### Spanner

```sql
to_hex(md5('hello'))
```

###### SQLDataWarehouse

```sql
lower(convert(VARCHAR(32), hashbytes('MD5', cast('hello' AS varchar(8000))), 2))
```

###### SQLServer

```sql
lower(convert(VARCHAR(32), hashbytes('MD5', cast('hello' AS varchar(max))), 2))
```

###### ASE, Access, DB2, Firebird, H2, HSQLDB, Hana, Informix, Redshift, SQLite, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="mid-function"></a>
##### 3.11.17.14. MID

The `MID()` function is an alias for the [substring function](#substring-function)

<a id="octet-length-function"></a>
##### 3.11.17.15. OCTET_LENGTH

The `OCTET_LENGTH()` function calculates the length of a given string in bytes.

```sql
SELECT octet_length('hello');
```

```java
create.select(octetLength("hello")).fetch();
```

The result being

```text
+--------------+
| octet_length |
+--------------+
|            5 |
+--------------+
```

> [!TIP]
> See [OCTET_LENGTH (binary)](#binary-octet-length-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
octetLength("hello")
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse, SQLServer

```sql
len('hello')
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Spanner, Vertica, YugabyteDB

```sql
octet_length('hello')
```

###### ClickHouse, DB2, DuckDB, Hana, SQLite, Sybase, Teradata, Trino

```sql
length('hello')
```

###### Oracle

```sql
lengthb('hello')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="overlay-function"></a>
##### 3.11.17.16. OVERLAY

The `OVERLAY()` function takes a string and "overlays it on top of another string".

```sql
SELECT overlay('abcdefg', 'xxx', 2);
```

```java
create.select(overlay(val("abcdefg"), "xxx", 2)).fetch();
```

The result being

```text
+---------+
| overlay |
+---------+
| axxxefg |
+---------+
```

> [!TIP]
> See [OVERLAY (binary)](#binary-overlay-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
overlay(val("abcdefg"), "xxx", 2)
```

Translates to the following dialect specific expressions:

###### Access

```sql
(mid(
  'abcdefg',
  1,
  (2 - 1)
) & 'xxx' & mid(
  'abcdefg',
  (2 + len('xxx'))
))
```

###### ASE

```sql
(substring(
  'abcdefg',
  1,
  (2 - 1)
) || 'xxx' || substring(
  'abcdefg',
  (2 + char_length('xxx')),
  2147483647
))
```

###### Aurora MySQL, Exasol, H2, MariaDB, MySQL

```sql
insert(
  'abcdefg',
  2,
  char_length('xxx'),
  'xxx'
)
```

###### Aurora Postgres, CockroachDB, Databricks, Firebird, Postgres, Vertica, YugabyteDB

```sql
overlay('abcdefg' PLACING 'xxx' FROM 2)
```

###### BigQuery, HSQLDB, Redshift, Spanner

```sql
(substring(
  'abcdefg',
  1,
  (2 - 1)
) || 'xxx' || substring(
  'abcdefg',
  (2 + char_length('xxx'))
))
```

###### ClickHouse, DuckDB, Hana, Sybase, Trino

```sql
(substring(
  'abcdefg',
  1,
  (2 - 1)
) || 'xxx' || substring(
  'abcdefg',
  (2 + length('xxx'))
))
```

###### DB2

```sql
overlay('abcdefg' PLACING 'xxx' FROM 2 FOR length('xxx'))
```

###### Informix

```sql
(substr(
  'abcdefg',
  1,
  (2 - 1)
) || 'xxx' || substr(
  'abcdefg',
  (2 + char_length('xxx'))
))
```

###### MemSQL

```sql
concat(
  substring(
    'abcdefg',
    1,
    (2 - 1)
  ),
  'xxx',
  substring(
    'abcdefg',
    (2 + char_length('xxx'))
  )
)
```

###### Oracle, SQLite

```sql
(substr(
  'abcdefg',
  1,
  (2 - 1)
) || 'xxx' || substr(
  'abcdefg',
  (2 + length('xxx'))
))
```

###### Snowflake

```sql
insert(
  'abcdefg',
  2,
  length('xxx'),
  'xxx'
)
```

###### SQLDataWarehouse, SQLServer

```sql
(substring(
  'abcdefg',
  1,
  (2 - 1)
) + 'xxx' + substring(
  'abcdefg',
  (2 + len('xxx')),
  2147483647
))
```

###### Teradata

```sql
(substring('abcdefg' FROM 1 FOR (2 - 1)) || 'xxx' || substring('abcdefg' FROM (2 + length('xxx'))))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="position-function"></a>
##### 3.11.17.17. POSITION

The `POSITION()` function finds the first position of a string within another string, starting with 1.

```sql
SELECT
  position('hello', 'e'),
  position('hello', 'l', 4);
```

```java
create.select(
  position("hello", "e"),
  position("hello", "e", 4)).fetch();
```

The result being

```text
+----------+----------+
| position | position |
+----------+----------+
|        2 |        4 |
+----------+----------+
```

> [!TIP]
> See [POSITION (binary)](#binary-position-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
position("hello", "e")
```

Translates to the following dialect specific expressions:

###### ASE, SQLDataWarehouse, SQLServer

```sql
charindex('e', 'hello')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
position('e' IN 'hello')
```

###### BigQuery, Spanner

```sql
strpos('hello', 'e')
```

###### ClickHouse

```sql
position('hello', 'e')
```

###### DB2

```sql
locate('e', 'hello')
```

###### Hana, Sybase

```sql
locate('hello', 'e')
```

###### Informix, Oracle, SQLite

```sql
instr('hello', 'e')
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="regexp-replace-function"></a>
##### 3.11.17.18. REGEXP_REPLACE

The `REGEXP_REPLACE()` function searches a string for a regular expression pattern, and replaces all or the first occurrence of that string.

Vendors offer different versions of this function, so jOOQ standardises them as two synthetic functions:

- `REGEXP_REPLACE_ALL()`
- `REGEXP_REPLACE_FIRST()`

For example:

```sql
SELECT
  regexp_replace_all('hello', 'l', ''),
  regexp_replace_first('hello', 'l', '');
```

```java
create.select(
  regexpReplaceAll(val("hello"), "l", ""),
  regexpReplaceFirst(val("hello"), "l", "")).fetch();
```

The result being

```text
+--------------------+----------------------+
| regexp_replace_all | regexp_replace_first |
+--------------------+----------------------+
| heo                | helo                 |
+--------------------+----------------------+
```

###### Dialect support

This example using jOOQ:

```java
regexpReplaceAll(val("hello"), "l", "")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, BigQuery, DB2, H2, HSQLDB, MariaDB, MySQL, Oracle, Redshift, SQLServer, Snowflake, Spanner, Teradata, Vertica

```sql
regexp_replace('hello', 'l', '')
```

###### Aurora Postgres, CockroachDB, MemSQL, Postgres, YugabyteDB

```sql
regexp_replace('hello', 'l', '', 'g')
```

###### ClickHouse

```sql
replaceRegexpAll('hello', 'l', '')
```

###### Hana

```sql
replace_regexpr('l' IN 'hello' WITH '')
```

###### Informix

```sql
regex_replace('hello', 'l', '')
```

###### ASE, Access, Databricks, DuckDB, Exasol, Firebird, SQLDataWarehouse, SQLite, Sybase, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="repeat-function"></a>
##### 3.11.17.19. REPEAT

The `REPEAT()` function repeats a string a number of times.

```sql
SELECT repeat('abc', 3);
```

```java
create.select(repeat("abc", 3)).fetch();
```

The result being

```text
+-----------+
| repeat    |
+-----------+
| abcabcabc |
+-----------+
```

###### Dialect support

This example using jOOQ:

```java
repeat("abc", 3)
```

Translates to the following dialect specific expressions:

###### ASE, SQLDataWarehouse, SQLServer

```sql
replicate('abc', 3)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, MariaDB, MySQL, Postgres, Redshift, Snowflake, Spanner, Sybase, Vertica, YugabyteDB

```sql
repeat('abc', 3)
```

###### Firebird, MemSQL

```sql
rpad(
  'abc',
  (char_length('abc') * 3),
  'abc'
)
```

###### Hana, Oracle, Teradata, Trino

```sql
rpad(
  'abc',
  (length('abc') * 3),
  'abc'
)
```

###### SQLite

```sql
replace(hex(zeroblob(3)), '00', 'abc')
```

###### Access, Informix

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="replace-function"></a>
##### 3.11.17.20. REPLACE

The `REPLACE()` function replaces a substring inside of a string by another string.

```sql
SELECT replace('hello world', 'llo', 'y');
```

```java
create.select(replace(val("hello world"), "llo", "y")).fetch();
```

The result being

```text
+-----------+
| replace   |
+-----------+
| hey world |
+-----------+
```

###### Dialect support

This example using jOOQ:

```java
replace(val("hello world"), "llo", "y")
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
replace('hello world', 'llo', 'y')
```

###### ASE

```sql
str_replace('hello world', 'llo', 'y')
```

###### ClickHouse

```sql
replaceAll('hello world', 'llo', 'y')
```

###### Teradata

```sql
oreplace('hello world', 'llo', 'y')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="reverse-function"></a>
##### 3.11.17.21. REVERSE

The `REVERSE()` function reverses a string.

```sql
SELECT reverse('hello');
```

```java
create.select(reverse("hello")).fetch();
```

The result being

```text
+---------+
| reverse |
+---------+
| olleh   |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
reverse("hello")
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, HSQLDB, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Teradata, Trino, YugabyteDB

```sql
reverse('hello')
```

###### Access, DB2, Firebird, H2, Hana, Informix, MemSQL, SQLite, Sybase, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="right-function"></a>
##### 3.11.17.22. RIGHT

The `RIGHT()` function calculates the substring of a given string starting from the right end. See also [SUBSTRING](#substring-function), [LEFT](#left-function)

```sql
SELECT right('hello world', 5);
```

```java
create.select(right("hello world", 5)).fetch();
```

The result being

```text
+-----------+
| right |
+-------+
| world |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
right("hello world", 5)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Teradata, Vertica, YugabyteDB

```sql
right('hello world', 5)
```

###### Oracle, SQLite

```sql
substr(
  'hello world',
  -5
)
```

###### Spanner, Trino

```sql
substring(
  'hello world',
  -5
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="rpad-function"></a>
##### 3.11.17.23. RPAD

The `RPAD()` pads a string at the right end. See also [LPAD](#lpad-function).

```sql
SELECT rpad('hello', 10, '.');
```

```java
create.select(rpad(val("hello"), 10, '.')).fetch();
```

The result being

```text
+------------+
| rpad       |
+------------+
| hello..... |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
rpad(val("hello"), 10, '.')
```

Translates to the following dialect specific expressions:

###### Access

```sql
('hello' & replace(space(10 - len('hello')), ' ', '.'))
```

###### ASE

```sql
('hello' || replicate(
  '.',
  (10 - char_length('hello'))
))
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Teradata, Vertica

```sql
rpad('hello', 10, '.')
```

###### SQLDataWarehouse, SQLServer

```sql
('hello' + replicate(
  '.',
  (10 - len('hello'))
))
```

###### SQLite

```sql
'hello' || substr(replace(hex(zeroblob(10)), '00', '.'), 1, 10 - length('hello'))
```

###### Sybase

```sql
('hello' || repeat(
  '.',
  (10 - length('hello'))
))
```

###### BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Redshift, Snowflake, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="rtrim-function"></a>
##### 3.11.17.24. RTRIM

The `RTRIM()` function trims a string from the right end, stripping it of whitespace. See also [LTRIM](#ltrim-function) and [TRIM](#trim-function).

```sql
SELECT rtrim('  hello  ');
```

```java
create.select(rtrim("  hello  ")).fetch();
```

The result being

```text
+---------+
| rtrim   |
+---------+
|   hello |
+---------+
```

> [!TIP]
> See [RTRIM (binary)](#binary-rtrim-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
rtrim("  hello  ")
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
rtrim('  hello  ')
```

###### Firebird

```sql
trim(TRAILING FROM '  hello  ')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="space-function"></a>
##### 3.11.17.25. SPACE

The `SPACE()` function repeats a space character a number of times. This is convenience for [REPEAT](#repeat-function), as available natively in SQL Server, for example.

```sql
SELECT 'a' || space(3) || 'b';
```

```java
create.select(val("a").concat(space(3)).concat(val("b")).fetch();
```

The result being

```text
+-------+
| space |
+-------+
| a   b |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
space(3)
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, ClickHouse, DB2, Databricks, Exasol, H2, MariaDB, MySQL, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Vertica

```sql
space(3)
```

###### Aurora Postgres, BigQuery, CockroachDB, DuckDB, HSQLDB, Postgres, Redshift, Spanner, YugabyteDB

```sql
repeat(' ', 3)
```

###### Firebird, Hana, Informix, MemSQL, Oracle, Teradata, Trino

```sql
rpad(' ', 3, ' ')
```

###### SQLite

```sql
' ' || substr(replace(hex(zeroblob(3)), '00', ' '), 1, 3 - length(' '))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="split-part-function"></a>
##### 3.11.17.26. SPLIT_PART

The `SPLIT_PART()` function splits a string into substrings and retrieves the nth part, starting from 1.

```sql
SELECT split_part('a,b,c', ',', 2);
```

```java
create.select(splitPart(val("a,b,c"), ",", 2)).fetch();
```

The result being

```text
+------------+
| split_part |
+------------+
| b          |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
splitPart(val("a,b,c"), ",", 2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
substring(
  substring_index('a,b,c', ',', 2),
  CASE 2
    WHEN 1 THEN 1
    ELSE (char_length(substring_index(
      'a,b,c',
      ',',
      (2 - 1)
    )) + char_length(',') + 1)
  END
)
```

###### Aurora Postgres, CockroachDB, Databricks, Postgres, Redshift, Snowflake, Trino, Vertica, YugabyteDB

```sql
split_part('a,b,c', ',', 2)
```

###### BigQuery, Spanner

```sql
split('a,b,c', ',')[SAFE_ORDINAL(2)]
```

###### DB2, Oracle

```sql
coalesce(
  substr(
    'a,b,c',
    nullif(
      decode(
        2,
        1,
        1,
        (nullif(
          instr(
            'a,b,c',
            ',',
            1,
            nullif(
              (2 - 1),
              0
            )
          ),
          0
        ) + length(','))
      ),
      (length('a,b,c') + 1)
    ),
    coalesce(
      (nullif(
        instr('a,b,c', ',', 1, 2),
        0
      ) - decode(
        2,
        1,
        1,
        (nullif(
          instr(
            'a,b,c',
            ',',
            1,
            nullif(
              (2 - 1),
              0
            )
          ),
          0
        ) + length(','))
      )),
      ((length('a,b,c') - nullif(
        instr(
          'a,b,c',
          ',',
          1,
          nullif(
            (2 - 1),
            0
          )
        ),
        0
      )) - (length(',') - 1))
    )
  ),
  ''
)
```

###### DuckDB

```sql
(str_split('a,b,c', ','))[2]
```

###### SQLServer

```sql
coalesce(
  (
    SELECT value
    FROM string_split('a,b,c', ',', 1)
    WHERE ordinal = 2
  ),
  ''
)
```

###### Teradata

```sql
strtok('a,b,c', ',', 2)
```

###### ASE, Access, ClickHouse, Exasol, Firebird, H2, HSQLDB, Hana, Informix, SQLDataWarehouse, SQLite, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="substring-function"></a>
##### 3.11.17.27. SUBSTRING

The `SUBSTRING()` function calculates the substring of a string given a starting position and optionally, a length. See also [LEFT](#left-function), [RIGHT](#right-function).

```sql
SELECT
  substring('hello world', 7),
  substring('hello world', 7, 1);
```

```java
create.select(
  substring("hello world", 7),
  substring("hello world", 7, 1)).fetch();
```

The result being

```text
+-----------+-----------+
| substring | substring |
+-----------+-----------+
| world     | w         |
+-----------+-----------+
```

> [!TIP]
> See [SUBSTRING (binary)](#binary-substring-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
substring(val("hello world"), 7)
```

Translates to the following dialect specific expressions:

###### Access

```sql
mid('hello world', 7)
```

###### ASE, SQLDataWarehouse, SQLServer

```sql
substring('hello world', 7, 2147483647)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
substring('hello world', 7)
```

###### DB2, Informix, Oracle, SQLite

```sql
substr('hello world', 7)
```

###### Firebird, Teradata

```sql
substring('hello world' FROM 7)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="substring-index-function"></a>
##### 3.11.17.28. SUBSTRING_INDEX

The `SUBSTRING_INDEX()` function gets a substring of a string, from the beginning until the nth occurrence of a delimiter.

```sql
SELECT
  substring_index('a,b,c,d', ',', 2),
  substring_index('a,b,c,d', ',', 3);
```

```java
create.select(
  substringIndex(val("a,b,c,d"), ",", 2),
  substringIndex(val("a,b,c,d"), ",", 3)).fetch();
```

The result being

```text
+-----------------+-----------------+
| substring_index | substring_index |
+-----------------+-----------------+
| a,b             | a,b,c           |
+-----------------+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
substringIndex(val("a,b,c,d"), ",", 3)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Databricks, MariaDB, MemSQL, MySQL

```sql
substring_index('a,b,c,d', ',', 3)
```

###### BigQuery, Spanner

```sql
array_to_string(
  array_slice(
    split('a,b,c,d', ','),
    0,
    (3 - 1)
  ),
  ','
)
```

###### ClickHouse

```sql
substringIndex('a,b,c,d', ',', 3)
```

###### DB2, Oracle

```sql
coalesce(
  substr(
    'a,b,c,d',
    1,
    (nullif(
      instr('a,b,c,d', ',', 1, 3),
      0
    ) - 1)
  ),
  'a,b,c,d'
)
```

###### Vertica

```sql
coalesce(
  substring(
    'a,b,c,d',
    1,
    (nullif(
      instr('a,b,c,d', ',', 1, 3),
      0
    ) - 1)
  ),
  'a,b,c,d'
)
```

###### ASE, Access, Aurora Postgres, CockroachDB, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="to-char-function"></a>
##### 3.11.17.29. TO_CHAR

The `TO_CHAR()` function converts a value to a string value using a vendor-specific format mask.

```sql
SELECT to_char(date '2000-01-01, 'YYYY/MM/DD');
```

```java
create.select(toChar(Date.valueOf("2000-01-01"), "YYYY/MM/DD")).fetch();
```

The result being

```text
+------------+
| to_char    |
+------------+
| 2000/01/01 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
toChar(Date.valueOf("2000-01-01"), "YYYY/MM/DD")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, H2, Oracle, Postgres, Redshift

```sql
to_char(DATE '2000-01-01', 'YYYY/MM/DD')
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="to-hex-function"></a>
##### 3.11.17.30. TO_HEX

The `TO_HEX()` function translates a numeric value to its hexadecimal string counterpart.

```sql
SELECT to_hex(255);
```

```java
create.select(toHex(255)).fetch();
```

The result being

```text
+--------+
| to_hex |
+--------+
| ff     |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
toHex(255)
```

Translates to the following dialect specific expressions:

###### CockroachDB, DB2, Postgres, Redshift, Vertica, YugabyteDB

```sql
to_hex(255)
```

###### Databricks, MariaDB, MySQL

```sql
hex(255)
```

###### H2, Oracle

```sql
trim(to_char(255, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'))
```

###### SQLite

```sql
printf('%X', 255)
```

###### SQLServer

```sql
format(255, 'X')
```

###### Trino

```sql
to_base(255, 16)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, Snowflake, Spanner, Sybase, Teradata

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="translate-function"></a>
##### 3.11.17.31. TRANSLATE

The `TRANSLATE()` function translates a set of characters to another set of characters within a string, based on matching positions within the search and replacement string.

```sql
SELECT translate('1 * [2 + 3]', '[]', '()');
```

```java
create.select(translate(val("1 * [2 + 3]"), "[]", "()")).fetch();
```

The result being

```text
+-------------+
| translate   |
+-------------+
| 1 * (2 + 3) |
+-------------+
```

###### Dialect support

This example using jOOQ:

```java
translate(val("1 * [2 + 3]"), "[]", "()")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, Exasol, H2, HSQLDB, Oracle, Postgres, Redshift, SQLServer, Snowflake, Trino, Vertica, YugabyteDB

```sql
translate('1 * [2 + 3]', '[]', '()')
```

###### DB2

```sql
translate('1 * [2 + 3]', '()', '[]')
```

###### Teradata

```sql
otranslate('1 * [2 + 3]', '[]', '()')
```

###### ASE, Access, Aurora MySQL, DuckDB, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Spanner, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="trim-function"></a>
##### 3.11.17.32. TRIM

The `TRIM()` function trims a string from both ends, stripping it of whitespace. See also [LTRIM](#ltrim-function) and [RTRIM](#rtrim-function).

```sql
SELECT trim('  hello  ');
```

```java
create.select(trim("  hello  ")).fetch();
```

The result being

```text
+-------+
| trim  |
+-------+
| hello |
+-------+
```

> [!TIP]
> See [TRIM (binary)](#binary-trim-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
trim("  hello  ")
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
trim('  hello  ')
```

###### ASE, SQLDataWarehouse

```sql
ltrim(rtrim('  hello  '))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="upper-function"></a>
##### 3.11.17.33. UPPER

The `UPPER()` function transforms a string into upper case.

```sql
SELECT upper('hello');
```

```java
create.select(upper("hello")).fetch();
```

The result being

```text
+-------+
| upper |
+-------+
| HELLO |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
upper("hello")
```

Translates to the following dialect specific expressions:

###### Access

```sql
ucase('hello')
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
upper('hello')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="uuid-function"></a>
##### 3.11.17.34. UUID

The `UUID()` function generates a new random `UUID`

```sql
SELECT uuid();
```

```java
create.select(uuid()).fetch();
```

The result being

```text
+--------------------------------------+
| uuid                                 |
+--------------------------------------+
| 1fc454e5-b9f6-4d55-b783-5987fe76cb45 |
+--------------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
uuid()
```

Translates to the following dialect specific expressions:

###### Access

```sql
genguid()
```

###### ASE

```sql
newid(-1)
```

###### BigQuery, Spanner

```sql
generate_uuid()
```

###### CockroachDB, Postgres

```sql
gen_random_uuid()
```

###### Databricks, DuckDB, HSQLDB, MariaDB, MySQL, Trino

```sql
uuid()
```

###### DB2

```sql
cast(
  regexp_replace((hex(rand()) || hex(generate_unique())), '(.{8})(.{4})(.{4})(.{4})(.{12}).*', '$1-$2-$3-$4-$5')
  AS char(36)
)
```

###### Firebird

```sql
uuid_to_char(gen_uuid())
```

###### H2

```sql
random_uuid()
```

###### Hana

```sql
cast(
  replace_regexpr('(.{8})(.{4})(.{4})(.{4})(.{12}).*' IN cast(sysuuid AS char(36)) WITH '\1-\2-\3-\4-\5')
  AS char(36)
)
```

###### Oracle

```sql
cast(
  regexp_replace(rawtohex(sys_guid()), '(.{8})(.{4})(.{4})(.{4})(.{12}).*', '\1-\2-\3-\4-\5')
  AS varchar2(36)
)
```

###### Snowflake

```sql
uuid_string()
```

###### SQLite

```sql
(
  SELECT (substr(u, 1, 8) || '-' || substr(u, 9, 4) || '-' || substr(u, 13, 4) || '-' || substr(u, 17, 4) || '-' || substr(u, 21))
  FROM (
    SELECT lower(hex(randomblob(16))) u
  ) t
)
```

###### SQLServer

```sql
newid()
```

###### Vertica

```sql
uuid_generate()
```

###### Aurora MySQL, Aurora Postgres, ClickHouse, Exasol, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="uuid-to-bin-function"></a>
##### 3.11.17.35. UUID_TO_BIN

The `UUID_TO_BIN()` function converts a `VARCHAR` or `UUID` representation into a `BINARY(16)` representation. See also [BIN_TO_UUID](#bin-to-uuid-function) for the inverse function.

```sql
SELECT uuid_to_bin(
  '1fc454e5-b9f6-4d55-b783-5987fe76cb45'
);
```

```java
create.select(uuidToBin(
  UUID.fromString("1fc454e5-b9f6-4d55-b783-5987fe76cb45")
)).fetch();
```

The result being

```text
+------------------+
| uuid_to_bin      |
+------------------+
|  ÄTå¹öMU· Y þvËE |
+------------------+
```

###### Dialect support

This example using jOOQ:

```java
uuidToBin(java.util.UUID.fromString("1fc454e5-b9f6-4d55-b783-5987fe76cb45"))
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MySQL

```sql
uuid_to_bin('1fc454e5-b9f6-4d55-b783-5987fe76cb45')
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
decode(
  replace(
    cast('1fc454e5-b9f6-4d55-b783-5987fe76cb45' AS varchar),
    '-',
    ''
  ),
  'hex'
)
```

###### BigQuery, Spanner

```sql
from_hex(replace(
  cast('1fc454e5-b9f6-4d55-b783-5987fe76cb45' AS string),
  '-',
  ''
))
```

###### ClickHouse

```sql
UUIDStringToNum(cast('1fc454e5-b9f6-4d55-b783-5987fe76cb45' AS String))
```

###### CockroachDB

```sql
cast('1fc454e5-b9f6-4d55-b783-5987fe76cb45' AS bytes)
```

###### ASE, Access, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-functions"></a>
#### 3.11.18. Binary functions

Binary data often encodes binary strings, and as such, binary versions of [string functions](#string-functions) are offered by jOOQ and underlying RDBMS.

<a id="binary-bit-length-function"></a>
##### 3.11.18.1. BIT_LENGTH (binary)

The `BIT_LENGTH()` function calculates the length of a given binary string in bits.

```sql
SELECT bit_length(cast('hello' as bytea));
```

```java
create.select(binaryBitLength("hello".getBytes())).fetch();
```

The result being

```text
+------------+
| bit_length |
+------------+
|         40 |
+------------+
```

> [!TIP]
> See [BIT_LENGTH](#bit-length-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryBitLength("hello".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
bit_length(cast(E'\\150\\145\\154\\154\\157' AS bytea))
```

###### BigQuery, Spanner

```sql
(8 * byte_length(b'\x68\x65\x6C\x6C\x6F'))
```

###### Databricks

```sql
bit_length(X'68656C6C6F')
```

###### Redshift

```sql
bit_length(from_hex('68656C6C6F'))
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-concat-function"></a>
##### 3.11.18.2. CONCAT (binary, || operator)

The `CONCAT()` function concatenates several binary strings

```sql
SELECT cast('hello ' as bytea) || cast('world' as bytea);
```

```java
create.select(binaryConcat("hello ".getBytes(), "world".getBytes())).fetch();
```

The result being

```text
+-------------+
| concat      |
+-------------+
| hello world |
+-------------+
```

> [!TIP]
> See [CONCAT](#concat-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryConcat("hello ".getBytes(), "world".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
(cast(E'\\150\\145\\154\\154\\157\\040' AS bytea) || cast(E'\\167\\157\\162\\154\\144' AS bytea))
```

###### BigQuery, Spanner

```sql
(b'\x68\x65\x6C\x6C\x6F\x20' || b'\x77\x6F\x72\x6C\x64')
```

###### Databricks

```sql
(X'68656C6C6F20' || X'776F726C64')
```

###### Redshift

```sql
(from_hex('68656C6C6F20') || from_hex('776F726C64'))
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-length-function"></a>
##### 3.11.18.3. LENGTH (binary)

The `LENGTH()` function calculates the length of a given binary string.

```sql
SELECT length(cast('hello' as bytea));
```

```java
create.select(binaryLength("hello".getBytes())).fetch();
```

The result being

```text
+--------+
| length |
+--------+
|      5 |
+--------+
```

> [!TIP]
> See [LENGTH](#length-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryLength("hello".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
length(cast(E'\\150\\145\\154\\154\\157' AS bytea))
```

###### BigQuery, Spanner

```sql
length(b'\x68\x65\x6C\x6C\x6F')
```

###### Databricks

```sql
length(X'68656C6C6F')
```

###### Redshift

```sql
length(from_hex('68656C6C6F'))
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-ltrim-function"></a>
##### 3.11.18.4. LTRIM (binary)

The `LTRIM()` function trims specified bytes from a binary string from the left end. See also [RTRIM (binary)](#binary-rtrim-function) and [TRIM (binary)](#binary-trim-function).

```sql
SELECT ltrim(cast('  hello  ' as bytea), cast(' ' as bytea));
```

```java
create.select(binaryLtrim("  hello  ".getBytes(), " ".getBytes())).fetch();
```

The result being

```text
+---------+
| ltrim   |
+---------+
| hello   |
+---------+
```

> [!TIP]
> See [LTRIM](#ltrim-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryLtrim("  hello  ".getBytes(), " ".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
ltrim(cast(E'\\040\\040\\150\\145\\154\\154\\157\\040\\040' AS bytea), cast(E'\\040' AS bytea))
```

###### BigQuery, Spanner

```sql
ltrim(b'\x20\x20\x68\x65\x6C\x6C\x6F\x20\x20', b'\x20')
```

###### Databricks

```sql
ltrim(X'202068656C6C6F2020', X'20')
```

###### ASE, Access, Aurora MySQL, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-md5-function"></a>
##### 3.11.18.5. MD5 (binary)

The `MD5()` function calculates the MD5 hash of a given binary string.

```sql
SELECT md5(cast('hello' as bytea));
```

```java
create.select(binaryMd5("hello".getBytes())).fetch();
```

The result being

```text
+----------------------------------+
| md5                              |
+----------------------------------+
| 5d41402abc4b2a76b9719d911017c592 |
+----------------------------------+
```

> [!TIP]
> See [MD5](#md5-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryMd5("hello".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
md5(cast(E'\\150\\145\\154\\154\\157' AS bytea))
```

###### Databricks

```sql
md5(X'68656C6C6F')
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-octet-length-function"></a>
##### 3.11.18.6. OCTET_LENGTH (binary)

The `OCTET_LENGTH()` function calculates the length of a given binary string in bytes.

```sql
SELECT octet_length(cast('hello' as bytea));
```

```java
create.select(binaryOctetLength("hello".getBytes())).fetch();
```

The result being

```text
+--------------+
| octet_length |
+--------------+
|            5 |
+--------------+
```

> [!TIP]
> See [OCTET_LENGTH](#octet-length-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryOctetLength("hello".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
octet_length(cast(E'\\150\\145\\154\\154\\157' AS bytea))
```

###### BigQuery, Spanner

```sql
byte_length(b'\x68\x65\x6C\x6C\x6F')
```

###### Databricks

```sql
octet_length(X'68656C6C6F')
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-overlay-function"></a>
##### 3.11.18.7. OVERLAY (binary)

The `OVERLAY()` function takes a binary string and "overlays it on top of another binary string".

```sql
SELECT overlay(cast('abcdefg' as bytea), cast('xxx' as bytea), 2);
```

```java
create.select(binaryOverlay(val("abcdefg".getBytes()), "xxx".getBytes(), 2)).fetch();
```

The result being

```text
+---------+
| overlay |
+---------+
| axxxefg |
+---------+
```

> [!TIP]
> See [OVERLAY](#overlay-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryOverlay(val("abcdefg".getBytes()), "xxx".getBytes(), 2)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
overlay(cast(E'\\141\\142\\143\\144\\145\\146\\147' AS bytea) PLACING cast(E'\\170\\170\\170' AS bytea) FROM 2)
```

###### CockroachDB

```sql
((substring(
  cast(E'\\141\\142\\143\\144\\145\\146\\147' AS bytea),
  1,
  (2 - 1)
) || cast(E'\\170\\170\\170' AS bytea)) || substring(
  cast(E'\\141\\142\\143\\144\\145\\146\\147' AS bytea),
  (2 + length(cast(E'\\170\\170\\170' AS bytea)))
))
```

###### Databricks

```sql
overlay(X'61626364656667' PLACING X'787878' FROM 2)
```

###### Redshift

```sql
((substring(
  from_hex('61626364656667'),
  1,
  (2 - 1)
) || from_hex('787878')) || substring(
  from_hex('61626364656667'),
  (2 + length(from_hex('787878')))
))
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-position-function"></a>
##### 3.11.18.8. POSITION (binary)

The `POSITION()` function finds the first position of a binary string within another binary string, starting with 1.

```sql
SELECT
  position(cast('hello' as bytea), cast('e' as bytea)),
  position(cast('hello' as bytea), cast('l' as bytea), 4);
```

```java
create.select(
  binaryPosition("hello".getBytes(), "e".getBytes()),
  binaryPosition("hello".getBytes(), "e".getBytes(), 4)).fetch();
```

The result being

```text
+----------+----------+
| position | position |
+----------+----------+
|        2 |        4 |
+----------+----------+
```

> [!TIP]
> See [POSITION](#position-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryPosition("hello".getBytes(), "e".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
position(cast(E'\\145' AS bytea) IN cast(E'\\150\\145\\154\\154\\157' AS bytea))
```

###### BigQuery, Spanner

```sql
strpos(b'\x68\x65\x6C\x6C\x6F', b'\x65')
```

###### Databricks

```sql
position(X'65' IN X'68656C6C6F')
```

###### Redshift

```sql
position(from_hex('65') IN from_hex('68656C6C6F'))
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-rtrim-function"></a>
##### 3.11.18.9. RTRIM (binary)

The `RTRIM()` function trims specified bytes from a binary string from the right end. See also [LTRIM (binary)](#binary-ltrim-function) and [TRIM (binary)](#binary-trim-function).

```sql
SELECT rtrim(cast('  hello  ' as bytea), cast(' ' as bytea));
```

```java
create.select(binaryRtrim("  hello  ".getBytes(), " ".getBytes())).fetch();
```

The result being

```text
+---------+
| rtrim   |
+---------+
|   hello |
+---------+
```

> [!TIP]
> See [RTRIM](#rtrim-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryRtrim("  hello  ".getBytes(), " ".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
rtrim(cast(E'\\040\\040\\150\\145\\154\\154\\157\\040\\040' AS bytea), cast(E'\\040' AS bytea))
```

###### BigQuery, Spanner

```sql
rtrim(b'\x20\x20\x68\x65\x6C\x6C\x6F\x20\x20', b'\x20')
```

###### Databricks

```sql
rtrim(X'202068656C6C6F2020', X'20')
```

###### ASE, Access, Aurora MySQL, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-substring-function"></a>
##### 3.11.18.10. SUBSTRING (binary)

The `SUBSTRING()` function calculates the substring of a binary string given a starting position and optionally, a length.

```sql
SELECT
  substring(cast('hello world' as bytea), 7),
  substring(cast('hello world' as bytea), 7, 1);
```

```java
create.select(
  binarySubstring("hello world".getBytes(), 7),
  binarySubstring("hello world".getBytes(), 7, 1)).fetch();
```

The result being

```text
+-----------+-----------+
| substring | substring |
+-----------+-----------+
| world     | w         |
+-----------+-----------+
```

> [!TIP]
> See [SUBSTRING](#substring-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binarySubstring(val("hello world".getBytes()), 7)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
substring(cast(E'\\150\\145\\154\\154\\157\\040\\167\\157\\162\\154\\144' AS bytea), 7)
```

###### BigQuery, Spanner

```sql
substring(b'\x68\x65\x6C\x6C\x6F\x20\x77\x6F\x72\x6C\x64', 7)
```

###### Databricks

```sql
substring(X'68656C6C6F20776F726C64', 7)
```

###### Redshift

```sql
substring(from_hex('68656C6C6F20776F726C64'), 7)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-trim-function"></a>
##### 3.11.18.11. TRIM (binary)

The `TRIM()` function trims specified bytes from a binary string from both ends. See also [LTRIM (binary)](#binary-ltrim-function) and [RTRIM (binary)](#binary-rtrim-function).

```sql
SELECT trim(cast('  hello  ' as bytea), cast(' ' as bytea));
```

```java
create.select(binaryTrim("  hello  ".getBytes(), " ".getBytes())).fetch();
```

The result being

```text
+-------+
| trim  |
+-------+
| hello |
+-------+
```

> [!TIP]
> See [TRIM](#trim-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryTrim("  hello  ".getBytes(), " ".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
trim(cast(E'\\040\\040\\150\\145\\154\\154\\157\\040\\040' AS bytea), cast(E'\\040' AS bytea))
```

###### BigQuery, Spanner

```sql
trim(b'\x20\x20\x68\x65\x6C\x6C\x6F\x20\x20', b'\x20')
```

###### Databricks

```sql
trim(X'202068656C6C6F2020', X'20')
```

###### ASE, Access, Aurora MySQL, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="datetime-functions"></a>
#### 3.11.19. Datetime functions

Datetime functions are useful to calculate date time arithmetic and formatting.

Many functions in this section come with two flavours supporting both the JDBC datetime data types, and the JSR 310 types. These include:

- SQL `DATE` modelled by [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html) and JDBC's [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html)
- SQL `TIME` modelled by [`java.time.LocalTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalTime.html) and JDBC's [`java.sql.Time`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Time.html)
- SQL `TIMESTAMP` modelled by [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html) and JDBC's [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html)

Some temporal SQL data types could not be represented canonically with historic JDBC types, but only with JSR 310 types. These include:

- SQL `TIME WITH TIME ZONE` modelled by [`java.time.OffsetTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetTime.html)
- SQL `TIMESTAMP WITH TIME ZONE` modelled by any of [`java.time.Instant`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/Instant.html) (e.g. PostgreSQL), [`java.time.OffsetDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetDateTime.html) (JDBC and standard SQL), as well as [`java.time.ZonedDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/ZonedDateTime.html) (e.g. Oracle)

<a id="century-function"></a>
##### 3.11.19.1. CENTURY

Extract the `CENTURY` value from a datetime value.

The `CENTURY` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.CENTURY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#CENTURY) value as an argument.

```sql
SELECT century(DATE '2020-02-03');
```

```java
create.select(century(Date.valueOf("2020-02-03"))).fetch();
```

The result being

```text
+---------+
| century |
+---------+
|      21 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
century(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
(cdec(((sgn(datepart('yyyy', #2020/02/03 00:00:00#)) * (abs(datepart('yyyy', #2020/02/03 00:00:00#)) + 99)) / 100)) - (((sgn(datepart('yyyy', #2020/02/03 00:00:00#)) * (abs(datepart('yyyy', #2020/02/03 00:00:00#)) + 99)) / 100) < cdec(((sgn(datepart('yyyy', #2020/02/03 00:00:00#)) * (abs(datepart('yyyy', #2020/02/03 00:00:00#)) + 99)) / 100))))
```

###### ASE, Sybase

```sql
floor(((sign(datepart(yy, '2020-02-03 00:00:00.0')) * (abs(datepart(yy, '2020-02-03 00:00:00.0')) + 99)) / 100))
```

###### Aurora MySQL, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica

```sql
floor(((sign(extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00.0')) * (abs(extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00.0')) + 99)) / 100))
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
extract(CENTURY FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### BigQuery

```sql
floor(((sign(extract(YEAR FROM DATETIME '2020-02-03 00:00:00.0')) * (abs(extract(YEAR FROM DATETIME '2020-02-03 00:00:00.0')) + 99)) / 100))
```

###### ClickHouse

```sql
floor(((sign(extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00')) * (abs(extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00')) + 99)) / 100))
```

###### DB2

```sql
floor(((sign(YEAR(TIMESTAMP '2020-02-03 00:00:00.0')) * (abs(YEAR(TIMESTAMP '2020-02-03 00:00:00.0')) + 99)) / 100))
```

###### Informix

```sql
floor(((sign(YEAR(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION)) * (abs(YEAR(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION)) + 99)) / 100))
```

###### MemSQL

```sql
floor(((sign(extract(YEAR FROM {ts '2020-02-03 00:00:00.0'})) * (abs(extract(YEAR FROM {ts '2020-02-03 00:00:00.0'})) + 99)) / 100))
```

###### SQLDataWarehouse, SQLServer

```sql
floor(((sign(datepart(yy, cast('2020-02-03 00:00:00.0' AS DATETIME2))) * (abs(datepart(yy, cast('2020-02-03 00:00:00.0' AS DATETIME2))) + 99)) / 100))
```

###### SQLite

```sql
floor(((CASE
  WHEN cast(
    strftime('%Y', '2020-02-03 00:00:00.0')
    AS int
  ) > 0 THEN 1
  WHEN cast(
    strftime('%Y', '2020-02-03 00:00:00.0')
    AS int
  ) < 0 THEN -1
  WHEN cast(
    strftime('%Y', '2020-02-03 00:00:00.0')
    AS int
  ) = 0 THEN 0
END * (abs(cast(
  strftime('%Y', '2020-02-03 00:00:00.0')
  AS int
)) + 99)) / 100))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-date-function"></a>
##### 3.11.19.2. CURRENT_DATE

Get the current server time as a SQL `DATE` type (represented by [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html)).

```sql
SELECT current_date;
```

```java
create.select(currentDate()).fetch();
```

The result being something like

```text
+--------------+
| current_date |
+--------------+
| 2020-02-03   |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
currentDate()
```

Translates to the following dialect specific expressions:

###### Access

```sql
DATE()
```

###### ASE, Aurora MySQL, ClickHouse, MariaDB, MemSQL, MySQL, Snowflake

```sql
current_date()
```

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLite, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CURRENT_DATE
```

###### Informix

```sql
CURRENT YEAR TO DAY
```

###### Oracle

```sql
trunc(current_date)
```

###### SQLDataWarehouse, SQLServer

```sql
convert(DATE, current_timestamp)
```

###### Sybase

```sql
CURRENT DATE
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-localdate-function"></a>
##### 3.11.19.3. CURRENT_LOCALDATE

Get the current server time as a SQL `DATE` type (represented by [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html)).

This does the same as [CURRENT_DATE](#current-date-function) except that the client type representation uses JSR-310 types.

```sql
SELECT current_date;
```

```java
create.select(currentLocalDate()).fetch();
```

The result being something like

```text
+--------------+
| current_date |
+--------------+
| 2020-02-03   |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
currentLocalDate()
```

Translates to the following dialect specific expressions:

###### Access

```sql
DATE()
```

###### ASE, Aurora MySQL, ClickHouse, MariaDB, MemSQL, MySQL, Snowflake

```sql
current_date()
```

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLite, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CURRENT_DATE
```

###### Informix

```sql
CURRENT YEAR TO DAY
```

###### Oracle

```sql
trunc(current_date)
```

###### SQLDataWarehouse, SQLServer

```sql
convert(DATE, current_timestamp)
```

###### Sybase

```sql
CURRENT DATE
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-localdatetime-function"></a>
##### 3.11.19.4. CURRENT_LOCALDATETIME

Get the current server time as a SQL `TIMESTAMP` type (represented by [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html)).

This does the same as [CURRENT_TIMESTAMP](#current-timestamp-function) except that the client type representation uses JSR-310 types.

```sql
SELECT current_timestamp;
```

```java
create.select(currentLocalDateTime()).fetch();
```

The result being something like

```text
+-----------------------+
| current_timestamp     |
+-----------------------+
|   2020-02-03 15:30:45 |
+-----------------------+
```

###### Dialect support

This example using jOOQ:

```java
currentLocalDateTime()
```

Translates to the following dialect specific expressions:

###### Access

```sql
now()
```

###### ASE

```sql
current_bigdatetime()
```

###### Aurora MySQL, ClickHouse, MariaDB, MemSQL, MySQL, Snowflake

```sql
current_timestamp()
```

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
cast(CURRENT_TIMESTAMP AS timestamp)
```

###### BigQuery, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Teradata, Trino, Vertica

```sql
CURRENT_TIMESTAMP
```

###### DuckDB

```sql
cast(CURRENT_TIMESTAMP AS timestamp without time zone)
```

###### Informix

```sql
CURRENT YEAR TO FRACTION (5)
```

###### Sybase

```sql
CURRENT TIMESTAMP
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-localtime-function"></a>
##### 3.11.19.5. CURRENT_LOCALTIME

Get the current server time as a SQL `TIME` type (represented by [`java.time.LocalTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalTime.html)).

This does the same as [CURRENT_TIME](#current-time-function) except that the client type representation uses JSR-310 types.

```sql
SELECT current_time;
```

```java
create.select(currentLocalTime()).fetch();
```

The result being something like

```text
+--------------+
| current_time |
+--------------+
|     15:30:45 |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
currentLocalTime()
```

Translates to the following dialect specific expressions:

###### Access

```sql
TIME()
```

###### ASE, Aurora MySQL, MariaDB, MemSQL, MySQL, Snowflake

```sql
current_time()
```

###### Aurora Postgres, CockroachDB, Firebird, Postgres, YugabyteDB

```sql
cast(CURRENT_TIME AS time)
```

###### BigQuery, DB2, H2, HSQLDB, Hana, Redshift, SQLite, Spanner, Teradata, Trino, Vertica

```sql
CURRENT_TIME
```

###### ClickHouse

```sql
current_timestamp()
```

###### Databricks, Exasol

```sql
current_timestamp
```

###### DuckDB

```sql
cast(current_time AS TIME)
```

###### Informix

```sql
CURRENT HOUR TO SECOND
```

###### Oracle

```sql
cast(current_timestamp AS timestamp)
```

###### SQLDataWarehouse, SQLServer

```sql
convert(TIME, current_timestamp)
```

###### Sybase

```sql
CURRENT TIME
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-offsetdatetime-function"></a>
##### 3.11.19.6. CURRENT_OFFSETDATETIME

Get the current server time as a SQL `TIMESTAMP WITH TIME ZONE` type (represented by [`java.time.OffsetDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetDateTime.html)).

This does the same as [CURRENT_TIMESTAMP](#current-timestamp-function) except that a cast is added, and the client type representation uses JSR-310 types.

```sql
SELECT current_timestamp;
```

```java
create.select(currentOffsetDateTime()).fetch();
```

The result being something like

```text
+-----------------------+
| current_timestamp     |
+-----------------------+
|   2020-02-03 15:30:45 |
+-----------------------+
```

###### Dialect support

This example using jOOQ:

```java
currentOffsetDateTime()
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(now())
```

###### ASE

```sql
cast(
  current_bigdatetime()
  AS timestamp with time zone
)
```

###### Aurora MySQL, ClickHouse, MariaDB, MemSQL, MySQL

```sql
cast(
  current_timestamp()
  AS timestamp with time zone
)
```

###### Aurora Postgres, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, SQLite, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  CURRENT_TIMESTAMP
  AS timestamp with time zone
)
```

###### BigQuery, Databricks, Spanner

```sql
cast(
  CURRENT_TIMESTAMP
  AS timestamp
)
```

###### CockroachDB

```sql
cast(
  CURRENT_TIMESTAMP
  AS timestamptz
)
```

###### Informix

```sql
cast(
  CURRENT YEAR TO FRACTION (5)
  AS timestamp with time zone
)
```

###### Snowflake

```sql
cast(
  current_timestamp()
  AS timestamp_tz
)
```

###### SQLDataWarehouse, SQLServer

```sql
cast(
  CURRENT_TIMESTAMP
  AS datetimeoffset
)
```

###### Sybase

```sql
cast(
  CURRENT TIMESTAMP
  AS timestamp with time zone
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-offsettime-function"></a>
##### 3.11.19.7. CURRENT_OFFSETTIME

Get the current server time as a SQL `TIME WITH TIME ZONE` type (represented by [`java.time.OffsetTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetTime.html)).

This does the same as [CURRENT_TIME](#current-time-function) except that a cast is added, and the client type representation uses JSR-310 types.

```sql
SELECT current_time;
```

```java
create.select(currentOffsetTime()).fetch();
```

The result being something like

```text
+--------------+
| current_time |
+--------------+
|     15:30:45 |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
currentOffsetTime()
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(TIME())
```

###### ASE, Aurora MySQL, MariaDB, MemSQL, MySQL, Snowflake

```sql
cast(
  current_time()
  AS time with time zone
)
```

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLite, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  CURRENT_TIME
  AS time with time zone
)
```

###### ClickHouse

```sql
cast(
  current_timestamp()
  AS time with time zone
)
```

###### Databricks, Exasol

```sql
cast(
  current_timestamp
  AS time with time zone
)
```

###### DuckDB

```sql
cast(
  cast(current_time AS TIME)
  AS time with time zone
)
```

###### Informix

```sql
cast(
  CURRENT HOUR TO SECOND
  AS time with time zone
)
```

###### Oracle

```sql
cast(
  current_timestamp
  AS timestamp with time zone
)
```

###### SQLDataWarehouse, SQLServer

```sql
cast(
  convert(TIME, current_timestamp)
  AS time with time zone
)
```

###### Sybase

```sql
cast(
  CURRENT TIME
  AS time with time zone
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-time-function"></a>
##### 3.11.19.8. CURRENT_TIME

Get the current server time as a SQL `TIME` type (represented by [`java.sql.Time`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Time.html)).

```sql
SELECT current_time;
```

```java
create.select(currentTime()).fetch();
```

The result being something like

```text
+--------------+
| current_time |
+--------------+
|     15:30:45 |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
currentTime()
```

Translates to the following dialect specific expressions:

###### Access

```sql
TIME()
```

###### ASE, Aurora MySQL, MariaDB, MemSQL, MySQL, Snowflake

```sql
current_time()
```

###### Aurora Postgres, CockroachDB, Firebird, Postgres, YugabyteDB

```sql
cast(CURRENT_TIME AS time)
```

###### BigQuery, DB2, H2, HSQLDB, Hana, Redshift, SQLite, Spanner, Teradata, Trino, Vertica

```sql
CURRENT_TIME
```

###### ClickHouse

```sql
current_timestamp()
```

###### Databricks, Exasol

```sql
current_timestamp
```

###### DuckDB

```sql
cast(current_time AS TIME)
```

###### Informix

```sql
CURRENT HOUR TO SECOND
```

###### Oracle

```sql
cast(current_timestamp AS timestamp)
```

###### SQLDataWarehouse, SQLServer

```sql
convert(TIME, current_timestamp)
```

###### Sybase

```sql
CURRENT TIME
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-timestamp-function"></a>
##### 3.11.19.9. CURRENT_TIMESTAMP

Get the current server time as a SQL `TIMESTAMP` type (represented by [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html)).

```sql
SELECT current_timestamp;
```

```java
create.select(currentTimestamp()).fetch();
```

The result being something like

```text
+-----------------------+
| current_timestamp     |
+-----------------------+
|   2020-02-03 15:30:45 |
+-----------------------+
```

###### Dialect support

This example using jOOQ:

```java
currentTimestamp()
```

Translates to the following dialect specific expressions:

###### Access

```sql
now()
```

###### ASE

```sql
current_bigdatetime()
```

###### Aurora MySQL, ClickHouse, MariaDB, MemSQL, MySQL, Snowflake

```sql
current_timestamp()
```

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
cast(CURRENT_TIMESTAMP AS timestamp)
```

###### BigQuery, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Teradata, Trino, Vertica

```sql
CURRENT_TIMESTAMP
```

###### DuckDB

```sql
cast(CURRENT_TIMESTAMP AS timestamp without time zone)
```

###### Informix

```sql
CURRENT YEAR TO FRACTION (5)
```

###### Sybase

```sql
CURRENT TIMESTAMP
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="date-function"></a>
##### 3.11.19.10. DATE

Convert an ISO 8601 `DATE` string literal into a SQL `DATE` type (represented by [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html)).

```sql
SELECT CAST('2020-02-03' AS DATE);
```

```java
create.select(date("2020-02-03")).fetch();
```

The result being

```text
+------------+
| date       |
+------------+
| 2020-02-03 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
date("2020-02-03")
```

Translates to the following dialect specific expressions:

###### Access

```sql
#2020/02/03#
```

###### ASE, SQLite, Sybase

```sql
'2020-02-03'
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Teradata, Vertica

```sql
DATE '2020-02-03'
```

###### Informix

```sql
DATETIME(2020-02-03) YEAR TO DAY
```

###### MemSQL

```sql
{d '2020-02-03'}
```

###### SQLDataWarehouse, SQLServer

```sql
cast('2020-02-03' AS date)
```

###### ClickHouse, Databricks, DuckDB, Redshift, Snowflake, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="dateadd-function"></a>
##### 3.11.19.11. DATEADD

Add an interval of type [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) (number of days) or [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) ([SQL interval type](#data-type-interval)) to a date (represented by [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html)).

```sql
SELECT DATE '2020-02-03' + 3;
```

```java
create.select(dateAdd(Date.valueOf("2020-02-03"), 3)).fetch();
```

The result being

```text
+------------+
| date_add   |
+------------+
| 2020-02-06 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
dateAdd(Date.valueOf("2020-02-03"), 3)
```

Translates to the following dialect specific expressions:

###### Access

```sql
dateadd('d', 3, #2020/02/03#)
```

###### ASE, Sybase

```sql
dateadd(DAY, 3, '2020-02-03')
```

###### Aurora MySQL, BigQuery, MariaDB, MySQL, Spanner

```sql
date_add(DATE '2020-02-03', INTERVAL 3 DAY)
```

###### Aurora Postgres, ClickHouse, CockroachDB, Databricks, Exasol, H2, Oracle, Postgres, Redshift, Vertica, YugabyteDB

```sql
(DATE '2020-02-03' + 3)
```

###### DB2, HSQLDB

```sql
(DATE '2020-02-03' + (3) day)
```

###### DuckDB

```sql
cast(date_add(DATE '2020-02-03', INTERVAL 1 DAY * 3) AS DATE)
```

###### Firebird, Snowflake

```sql
dateadd(DAY, 3, DATE '2020-02-03')
```

###### Hana

```sql
add_days(DATE '2020-02-03', 3)
```

###### Informix

```sql
(DATETIME(2020-02-03) YEAR TO DAY + 3 UNITS DAY)
```

###### MemSQL

```sql
date_add({d '2020-02-03'}, INTERVAL 3 DAY)
```

###### SQLDataWarehouse, SQLServer

```sql
dateadd(DAY, 3, cast('2020-02-03' AS date))
```

###### SQLite

```sql
strftime('%Y-%m-%d %H:%M:%f', '2020-02-03', (cast(3 AS varchar) || ' day'))
```

###### Teradata

```sql
(DATE '2020-02-03' + cast(3 || ' 00:00:00' AS INTERVAL DAY TO SECOND))
```

###### Trino

```sql
date_add('day', 3, DATE '2020-02-03')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="datediff-function"></a>
##### 3.11.19.12. DATEDIFF

Subtract two SQL `DATE` types (represented by [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html)).

This function comes in two flavours:

###### MySQL 2 argument version

In MySQL, there is a 2 argument version of the `DATEDIFF()` function, where the result produces the number of days between the two dates. The argument order is in the order of the difference notation: `end_date - start_date`

```sql
SELECT DATEDIFF(
  DATE '2020-02-03',
  DATE '2020-02-01');
```

```java
create.select(dateDiff(
  Date.valueOf("2020-02-03"),
  Date.valueOf("2020-02-01"))).fetch();
```

The result being

```text
+------------+
| datediff   |
+------------+
|          2 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
dateDiff(Date.valueOf("2020-02-03"), Date.valueOf("2020-02-01"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
datediff('d', #2020/02/01#, #2020/02/03#)
```

###### ASE, Sybase

```sql
datediff(DAY, '2020-02-01', '2020-02-03')
```

###### Aurora MySQL, MariaDB, MySQL

```sql
datediff(DATE '2020-02-03', DATE '2020-02-01')
```

###### Aurora Postgres, CockroachDB, Oracle, Postgres, YugabyteDB

```sql
(DATE '2020-02-03' - DATE '2020-02-01')
```

###### BigQuery, Spanner

```sql
date_diff(DATE '2020-02-03', DATE '2020-02-01', DAY)
```

###### ClickHouse, Teradata

```sql
cast(
  (DATE '2020-02-03' - DATE '2020-02-01')
  AS integer
)
```

###### Databricks, Exasol

```sql
cast(
  (DATE '2020-02-03' - DATE '2020-02-01')
  AS int
)
```

###### DB2

```sql
(days(DATE '2020-02-03') - days(DATE '2020-02-01'))
```

###### DuckDB, Redshift

```sql
datediff('day', DATE '2020-02-01', DATE '2020-02-03')
```

###### Firebird, H2, HSQLDB, Snowflake, Vertica

```sql
datediff(DAY, DATE '2020-02-01', DATE '2020-02-03')
```

###### Hana

```sql
days_between(DATE '2020-02-01', DATE '2020-02-03')
```

###### Informix

```sql
cast(
  (DATETIME(2020-02-03) YEAR TO DAY - DATETIME(2020-02-01) YEAR TO DAY)
  AS integer
)
```

###### MemSQL

```sql
datediff({d '2020-02-03'}, {d '2020-02-01'})
```

###### SQLDataWarehouse, SQLServer

```sql
datediff(DAY, cast('2020-02-01' AS date), cast('2020-02-03' AS date))
```

###### SQLite

```sql
(strftime('%s', '2020-02-03') - strftime('%s', '2020-02-01')) / 86400
```

###### Trino

```sql
date_diff('day', DATE '2020-02-01', DATE '2020-02-03')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### SQL Server 3 argument version

In SQL Server, there is a 3 argument version of the `DATEDIFF()` function, where the result produces the number of date part periods between the two dates, with the dates being [TRUNC-ed](#date-trunc-function) to the relevant date part. The argument order is in the order of the interval notation: `[start_date, end_date]`

```sql
SELECT DATEDIFF(
  MONTH
  DATE '2020-02-03',
  DATE '2020-04-01');
```

```java
create.select(dateDiff(
  DatePart.MONTH,
  Date.valueOf("2020-02-03"),
  Date.valueOf("2020-04-01"))).fetch();
```

The result being

```text
+------------+
| datediff   |
+------------+
|          2 |
+------------+
```

Notice the truncation happening prior to calculating the difference. The result is the same as for:

```sql
SELECT DATEDIFF(
  MONTH
  DATE '2020-02-01',
  DATE '2020-04-01');
```

```java
create.select(dateDiff(
  DatePart.MONTH,
  Date.valueOf("2020-02-01"),
  Date.valueOf("2020-04-01"))).fetch();
```

###### Dialect support

This example using jOOQ:

```java
dateDiff(DatePart.MONTH, Date.valueOf("2020-02-03"), Date.valueOf("2020-04-01"))
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, Hana, MariaDB, MySQL, Oracle, Postgres, YugabyteDB

```sql
(((extract(YEAR FROM DATE '2020-04-01') - extract(YEAR FROM DATE '2020-02-03')) * 12) + (extract(MONTH FROM DATE '2020-04-01') - extract(MONTH FROM DATE '2020-02-03')))
```

###### BigQuery

```sql
date_diff(DATE '2020-04-01', DATE '2020-02-03', MONTH)
```

###### DB2

```sql
(((YEAR(DATE '2020-04-01') - YEAR(DATE '2020-02-03')) * 12) + (MONTH(DATE '2020-04-01') - MONTH(DATE '2020-02-03')))
```

###### Firebird, H2, HSQLDB, Snowflake

```sql
datediff(MONTH, DATE '2020-02-03', DATE '2020-04-01')
```

###### MemSQL

```sql
(((extract(YEAR FROM {d '2020-04-01'}) - extract(YEAR FROM {d '2020-02-03'})) * 12) + (extract(MONTH FROM {d '2020-04-01'}) - extract(MONTH FROM {d '2020-02-03'})))
```

###### Redshift

```sql
datediff('month', DATE '2020-02-03', DATE '2020-04-01')
```

###### SQLDataWarehouse, SQLServer

```sql
datediff(MONTH, cast('2020-02-03' AS date), cast('2020-04-01' AS date))
```

###### ASE, Access, ClickHouse, Databricks, DuckDB, Exasol, Informix, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="datesub-function"></a>
##### 3.11.19.13. DATESUB

Subtract an interval of type [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) (number of days) or [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) ([SQL interval type](#data-type-interval)) from a date (represented by [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html)).

```sql
SELECT DATE '2020-02-03' - 2;
```

```java
create.select(dateSub(Date.valueOf("2020-02-03"), 2)).fetch();
```

The result being

```text
+------------+
| date_sub   |
+------------+
| 2020-02-01 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
dateSub(Date.valueOf("2020-02-03"), 2)
```

Translates to the following dialect specific expressions:

###### Access

```sql
dateadd('d', -2, #2020/02/03#)
```

###### ASE, Sybase

```sql
dateadd(DAY, -2, '2020-02-03')
```

###### Aurora MySQL, MariaDB, MySQL

```sql
date_add(DATE '2020-02-03', INTERVAL -2 DAY)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
(DATE '2020-02-03' + -2)
```

###### BigQuery, Spanner

```sql
date_sub(DATE '2020-02-03', INTERVAL 2 DAY)
```

###### ClickHouse, Databricks, Exasol, H2, Oracle, Vertica

```sql
(DATE '2020-02-03' - 2)
```

###### DB2, HSQLDB

```sql
(DATE '2020-02-03' - (2) day)
```

###### DuckDB

```sql
cast(date_add(DATE '2020-02-03', INTERVAL 1 DAY * -2) AS DATE)
```

###### Firebird, Snowflake

```sql
dateadd(DAY, -2, DATE '2020-02-03')
```

###### Hana

```sql
add_days(DATE '2020-02-03', -2)
```

###### Informix

```sql
(DATETIME(2020-02-03) YEAR TO DAY - 2 UNITS DAY)
```

###### MemSQL

```sql
date_add({d '2020-02-03'}, INTERVAL -2 DAY)
```

###### SQLDataWarehouse, SQLServer

```sql
dateadd(DAY, -2, cast('2020-02-03' AS date))
```

###### SQLite

```sql
strftime('%Y-%m-%d %H:%M:%f', '2020-02-03', (cast(
  -2
  AS varchar
) || ' day'))
```

###### Teradata

```sql
(DATE '2020-02-03' - cast(2 || ' 00:00:00' AS INTERVAL DAY TO SECOND))
```

###### Trino

```sql
date_add('day', -2, DATE '2020-02-03')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="day-function"></a>
##### 3.11.19.14. DAY

Extract the `DAY` value from a datetime value.

The `DAY` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.DAY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#DAY) value as an argument.

```sql
SELECT day(DATE '2020-02-03');
```

```java
create.select(day(Date.valueOf("2020-02-03"))).fetch();
```

The result being

```text
+-----+
| day |
+-----+
|   3 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
day(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
datepart('d', #2020/02/03 00:00:00#)
```

###### ASE, Sybase

```sql
datepart(dd, '2020-02-03 00:00:00.0')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
extract(DAY FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### BigQuery

```sql
extract(DAY FROM DATETIME '2020-02-03 00:00:00.0')
```

###### ClickHouse

```sql
extract(DAY FROM TIMESTAMP '2020-02-03 00:00:00')
```

###### DB2

```sql
DAY(TIMESTAMP '2020-02-03 00:00:00.0')
```

###### Informix

```sql
DAY(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION)
```

###### MemSQL

```sql
extract(DAY FROM {ts '2020-02-03 00:00:00.0'})
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(dd, cast('2020-02-03 00:00:00.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%d', '2020-02-03 00:00:00.0')
  AS int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="day-of-year-function"></a>
##### 3.11.19.15. DAY_OF_YEAR

Extract the `DAY_OF_YEAR` value from a datetime value.

The `DAY_OF_YEAR` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.DAY_OF_YEAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#DAY_OF_YEAR) value as an argument.

```sql
SELECT day_of_year(DATE '2020-02-03');
```

```java
create.select(dayOfYear(Date.valueOf("2020-02-03"))).fetch();
```

The result being

```text
+-------------+
| day_of_year |
+-------------+
|          33 |
+-------------+
```

###### Dialect support

This example using jOOQ:

```java
dayOfYear(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### ASE, Sybase

```sql
datepart(dy, '2020-02-03 00:00:00.0')
```

###### Aurora MySQL, DB2, Hana, MariaDB, MySQL

```sql
dayofyear(TIMESTAMP '2020-02-03 00:00:00.0')
```

###### Aurora Postgres, CockroachDB, Postgres

```sql
extract(DOY FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### H2, HSQLDB

```sql
extract(DAY_OF_YEAR FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### MemSQL

```sql
dayofyear({ts '2020-02-03 00:00:00.0'})
```

###### Oracle

```sql
to_number(to_char(TIMESTAMP '2020-02-03 00:00:00.0', 'DDD'))
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(dy, cast('2020-02-03 00:00:00.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%j', '2020-02-03 00:00:00.0')
  AS int
)
```

###### Access, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, Informix, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="decade-function"></a>
##### 3.11.19.16. DECADE

Extract the `DECADE` value from a datetime value.

The `DECADE` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.DECADE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#DECADE) value as an argument.

```sql
SELECT decade(DATE '2020-02-03');
```

```java
create.select(decade(Date.valueOf("2020-02-03"))).fetch();
```

The result being

```text
+--------+
| decade |
+--------+
|    202 |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
decade(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
(cdec((datepart('yyyy', #2020/02/03 00:00:00#) / 10)) - ((datepart('yyyy', #2020/02/03 00:00:00#) / 10) < cdec((datepart('yyyy', #2020/02/03 00:00:00#) / 10))))
```

###### ASE, Sybase

```sql
floor((datepart(yy, '2020-02-03 00:00:00.0') / 10))
```

###### Aurora MySQL, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica

```sql
floor((extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00.0') / 10))
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
extract(DECADE FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### BigQuery

```sql
floor((extract(YEAR FROM DATETIME '2020-02-03 00:00:00.0') / 10))
```

###### ClickHouse

```sql
floor((extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00') / 10))
```

###### DB2

```sql
floor((YEAR(TIMESTAMP '2020-02-03 00:00:00.0') / 10))
```

###### Informix

```sql
floor((YEAR(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION) / 10))
```

###### MemSQL

```sql
floor((extract(YEAR FROM {ts '2020-02-03 00:00:00.0'}) / 10))
```

###### SQLDataWarehouse, SQLServer

```sql
floor((datepart(yy, cast('2020-02-03 00:00:00.0' AS DATETIME2)) / 10))
```

###### SQLite

```sql
floor((cast(
  strftime('%Y', '2020-02-03 00:00:00.0')
  AS int
) / 10))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="epoch-function"></a>
##### 3.11.19.17. EPOCH

Extract the `EPOCH` value from a datetime value, i.e. the number of seconds since 1970-01-01 00:00:00 UTC.

The `EPOCH` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.EPOCH`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#EPOCH) value as an argument.

```sql
SELECT epoch(TIMESTAMP '1970-01-01 00:00:15');
```

```java
create.select(epoch(Timestamp.valueOf("1970-01-01 00:00:15"))).fetch();
```

The result being

```text
+-------+
| epoch |
+-------+
|    15 |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
epoch(Timestamp.valueOf("1970-01-01 00:00:15"))
```

Translates to the following dialect specific expressions:

###### ASE, Sybase

```sql
datediff(ss, '1970-01-01 00:00:00', '1970-01-01 00:00:15.0')
```

###### Aurora MySQL, HSQLDB, MariaDB, MySQL

```sql
UNIX_TIMESTAMP(TIMESTAMP '1970-01-01 00:00:15.0')
```

###### Aurora Postgres, CockroachDB, DB2, H2, Postgres

```sql
extract(EPOCH FROM TIMESTAMP '1970-01-01 00:00:15.0')
```

###### Hana

```sql
seconds_between('1970-01-01', TIMESTAMP '1970-01-01 00:00:15.0')
```

###### MemSQL

```sql
UNIX_TIMESTAMP({ts '1970-01-01 00:00:15.0'})
```

###### Oracle

```sql
trunc((cast(TIMESTAMP '1970-01-01 00:00:15.0' AS date) - DATE '1970-01-01') * 86400)
```

###### SQLDataWarehouse, SQLServer

```sql
datediff(ss, '1970-01-01 00:00:00', cast('1970-01-01 00:00:15.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%s', '1970-01-01 00:00:15.0')
  AS int
)
```

###### Access, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, Informix, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="extract-function"></a>
##### 3.11.19.18. EXTRACT

Extract a [`org.jooq.DatePart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html) from a datetime value.

```sql
SELECT EXTRACT(MONTH FROM DATE '2020-02-03');
```

```java
create.select(extract(Date.valueOf("2020-02-03"), DatePart.MONTH)).fetch();
```

The result being

```text
+-------+
| month |
+-------+
|     2 |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
extract(Date.valueOf("2020-02-03"), DatePart.MONTH)
```

Translates to the following dialect specific expressions:

###### Access

```sql
datepart('m', #2020/02/03 00:00:00#)
```

###### ASE, Sybase

```sql
datepart(mm, '2020-02-03 00:00:00.0')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
extract(MONTH FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### BigQuery

```sql
extract(MONTH FROM DATETIME '2020-02-03 00:00:00.0')
```

###### ClickHouse

```sql
extract(MONTH FROM TIMESTAMP '2020-02-03 00:00:00')
```

###### DB2

```sql
MONTH(TIMESTAMP '2020-02-03 00:00:00.0')
```

###### Informix

```sql
MONTH(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION)
```

###### MemSQL

```sql
extract(MONTH FROM {ts '2020-02-03 00:00:00.0'})
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(mm, cast('2020-02-03 00:00:00.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%m', '2020-02-03 00:00:00.0')
  AS int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="hour-function"></a>
##### 3.11.19.19. HOUR

Extract the `HOUR` value from a datetime value.

The `HOUR` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.HOUR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#HOUR) value as an argument.

```sql
SELECT hour(TIMESTAMP '2020-02-03 15:30:45');
```

```java
create.select(hour(Timestamp.valueOf("2020-02-03 15:30:45"))).fetch();
```

The result being

```text
+------+
| hour |
+------+
|   15 |
+------+
```

###### Dialect support

This example using jOOQ:

```java
hour(Timestamp.valueOf("2020-02-03 15:30:45"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
datepart('h', #2020/02/03 15:30:45#)
```

###### ASE, Sybase

```sql
datepart(hh, '2020-02-03 15:30:45.0')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
extract(HOUR FROM TIMESTAMP '2020-02-03 15:30:45.0')
```

###### BigQuery

```sql
extract(HOUR FROM DATETIME '2020-02-03 15:30:45.0')
```

###### ClickHouse

```sql
extract(HOUR FROM TIMESTAMP '2020-02-03 15:30:45')
```

###### DB2

```sql
HOUR(TIMESTAMP '2020-02-03 15:30:45.0')
```

###### Informix

```sql
cast(DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION AS cast(DATETIME HOUR TO HOUR AS cast(CHAR(2) AS INT)))
```

###### MemSQL

```sql
extract(HOUR FROM {ts '2020-02-03 15:30:45.0'})
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(hh, cast('2020-02-03 15:30:45.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%H', '2020-02-03 15:30:45.0')
  AS int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="iso-day-of-week-function"></a>
##### 3.11.19.20. ISO_DAY_OF_WEEK

Extract the `ISO_DAY_OF_WEEK` value from a datetime value.

The `ISO_DAY_OF_WEEK` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.ISO_DAY_OF_WEEK`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#ISO_DAY_OF_WEEK) value as an argument.

```sql
SELECT iso_day_of_week(DATE '2020-02-03');
```

```java
create.select(isoDayOfWeek(Date.valueOf("2020-02-03"))).fetch();
```

The result being (Monday = 1, ..., Sunday = 7)

```text
+-----------------+
| iso_day_of_week |
+-----------------+
|               7 |
+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
isoDayOfWeek(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### ASE

```sql
(((DATEPART(dw, '2020-02-03 00:00:00.0') + @@datefirst + 5) % 7) + 1)
```

###### Aurora MySQL, Hana, MariaDB, MySQL

```sql
(weekday(TIMESTAMP '2020-02-03 00:00:00.0') + 1)
```

###### Aurora Postgres, CockroachDB, Postgres

```sql
extract(ISODOW FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### DB2

```sql
DAYOFWEEK_ISO(TIMESTAMP '2020-02-03 00:00:00.0')
```

###### H2

```sql
extract(ISO_DAY_OF_WEEK FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### HSQLDB

```sql
(mod(
  (EXTRACT(DAY_OF_WEEK FROM TIMESTAMP '2020-02-03 00:00:00.0') + 5),
  7
) + 1)
```

###### MemSQL

```sql
(weekday({ts '2020-02-03 00:00:00.0'}) + 1)
```

###### Oracle

```sql
to_number(to_char(TIMESTAMP '2020-02-03 00:00:00.0', 'D'))
```

###### SQLDataWarehouse, SQLServer

```sql
(((DATEPART(dw, cast('2020-02-03 00:00:00.0' AS DATETIME2)) + @@datefirst + 5) % 7) + 1)
```

###### SQLite

```sql
(((cast(
  strftime('%w', '2020-02-03 00:00:00.0')
  AS int
) + 6) % 7) + 1)
```

###### Sybase

```sql
(mod(
  (DATEPART(dw, '2020-02-03 00:00:00.0') + @@datefirst + 5),
  7
) + 1)
```

###### Access, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Firebird, Informix, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="localdate-function"></a>
##### 3.11.19.21. LOCALDATE

Convert an ISO 8601 `DATE` string literal into a SQL `DATE` type (represented by [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html)).

This does the same as [DATE](#date-function) except that the client type representation uses JSR-310 types.

```sql
SELECT CAST('2020-02-03' AS DATE);
```

```java
create.select(localDate("2020-02-03")).fetch();
```

The result being

```text
+------------+
| date       |
+------------+
| 2020-02-03 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
localDate("2020-02-03")
```

Translates to the following dialect specific expressions:

###### Access

```sql
#2020/02/03#
```

###### ASE, SQLite, Sybase

```sql
'2020-02-03'
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Teradata, Vertica

```sql
DATE '2020-02-03'
```

###### Informix

```sql
DATETIME(2020-02-03) YEAR TO DAY
```

###### MemSQL

```sql
{d '2020-02-03'}
```

###### SQLDataWarehouse, SQLServer

```sql
cast('2020-02-03' AS date)
```

###### ClickHouse, Databricks, DuckDB, Redshift, Snowflake, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="localdateadd-function"></a>
##### 3.11.19.22. LOCALDATEADD

Add an interval of type [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) (number of days) or [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) ([SQL interval type](#data-type-interval)) to a date (represented by [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html)).

This does the same as [DATEADD](#dateadd-function) except that the client type representation uses JSR-310 types.

```sql
SELECT DATE '2020-02-03' + 3;
```

```java
create.select(localDateAdd(LocalDate.parse("2020-02-03"), 3)).fetch();
```

The result being

```text
+------------+
| date_add   |
+------------+
| 2020-02-06 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
localDateAdd(LocalDate.parse("2020-02-03"), 3)
```

Translates to the following dialect specific expressions:

###### Access

```sql
dateadd('d', 3, #2020/02/03#)
```

###### ASE, Sybase

```sql
dateadd(DAY, 3, '2020-02-03')
```

###### Aurora MySQL, BigQuery, MariaDB, MySQL, Spanner

```sql
date_add(DATE '2020-02-03', INTERVAL 3 DAY)
```

###### Aurora Postgres, ClickHouse, CockroachDB, Databricks, Exasol, H2, Oracle, Postgres, Redshift, Vertica, YugabyteDB

```sql
(DATE '2020-02-03' + 3)
```

###### DB2, HSQLDB

```sql
(DATE '2020-02-03' + (3) day)
```

###### DuckDB

```sql
cast(date_add(DATE '2020-02-03', INTERVAL 1 DAY * 3) AS DATE)
```

###### Firebird, Snowflake

```sql
dateadd(DAY, 3, DATE '2020-02-03')
```

###### Hana

```sql
add_days(DATE '2020-02-03', 3)
```

###### Informix

```sql
(DATETIME(2020-02-03) YEAR TO DAY + 3 UNITS DAY)
```

###### MemSQL

```sql
date_add({d '2020-02-03'}, INTERVAL 3 DAY)
```

###### SQLDataWarehouse, SQLServer

```sql
dateadd(DAY, 3, cast('2020-02-03' AS date))
```

###### SQLite

```sql
strftime('%Y-%m-%d %H:%M:%f', '2020-02-03', (cast(3 AS varchar) || ' day'))
```

###### Teradata

```sql
(DATE '2020-02-03' + cast(3 || ' 00:00:00' AS INTERVAL DAY TO SECOND))
```

###### Trino

```sql
date_add('day', 3, DATE '2020-02-03')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="localdatesub-function"></a>
##### 3.11.19.23. LOCALDATESUB

Subtract an interval of type [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) (number of days) or [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) ([SQL interval type](#data-type-interval)) from a date (represented by [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html)).

This does the same as [DATESUB](#datesub-function) except that the client type representation uses JSR-310 types.

```sql
SELECT DATE '2020-02-03' + 2;
```

```java
create.select(localDateSub(Date.valueOf("2020-02-03"), 2)).fetch();
```

The result being

```text
+------------+
| date_sub   |
+------------+
| 2020-02-01 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
localDateSub(LocalDate.parse("2020-02-03"), 2)
```

Translates to the following dialect specific expressions:

###### Access

```sql
dateadd('d', -2, #2020/02/03#)
```

###### ASE, Sybase

```sql
dateadd(DAY, -2, '2020-02-03')
```

###### Aurora MySQL, MariaDB, MySQL

```sql
date_add(DATE '2020-02-03', INTERVAL -2 DAY)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
(DATE '2020-02-03' + -2)
```

###### BigQuery, Spanner

```sql
date_sub(DATE '2020-02-03', INTERVAL 2 DAY)
```

###### ClickHouse, Databricks, Exasol, H2, Oracle, Vertica

```sql
(DATE '2020-02-03' - 2)
```

###### DB2, HSQLDB

```sql
(DATE '2020-02-03' - (2) day)
```

###### DuckDB

```sql
cast(date_add(DATE '2020-02-03', INTERVAL 1 DAY * -2) AS DATE)
```

###### Firebird, Snowflake

```sql
dateadd(DAY, -2, DATE '2020-02-03')
```

###### Hana

```sql
add_days(DATE '2020-02-03', -2)
```

###### Informix

```sql
(DATETIME(2020-02-03) YEAR TO DAY - 2 UNITS DAY)
```

###### MemSQL

```sql
date_add({d '2020-02-03'}, INTERVAL -2 DAY)
```

###### SQLDataWarehouse, SQLServer

```sql
dateadd(DAY, -2, cast('2020-02-03' AS date))
```

###### SQLite

```sql
strftime('%Y-%m-%d %H:%M:%f', '2020-02-03', (cast(
  -2
  AS varchar
) || ' day'))
```

###### Teradata

```sql
(DATE '2020-02-03' - cast(2 || ' 00:00:00' AS INTERVAL DAY TO SECOND))
```

###### Trino

```sql
date_add('day', -2, DATE '2020-02-03')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="localdatetime-function"></a>
##### 3.11.19.24. LOCALDATETIME

Convert an ISO 8601 `TIMESTAMP` string literal into a SQL `TIMESTAMP` type (represented by [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html)).

This does the same as [TIMESTAMP](#timestamp-function) except that the client type representation uses JSR-310 types.

```sql
SELECT CAST('2020-02-03 15:30:45' AS TIMESTAMP);
```

```java
create.select(localDateTime("2020-02-03 15:30:45")).fetch();
```

The result being

```text
+---------------------+
| timestamp           |
+---------------------+
| 2020-02-03 15:30:45 |
+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
localDateTime("2020-02-03 15:30:45")
```

Translates to the following dialect specific expressions:

###### Access

```sql
#2020/02/03 15:30:45#
```

###### ASE, SQLite, Sybase

```sql
'2020-02-03 15:30:45.0'
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Teradata, Vertica

```sql
TIMESTAMP '2020-02-03 15:30:45.0'
```

###### BigQuery

```sql
DATETIME '2020-02-03 15:30:45.0'
```

###### Informix

```sql
DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION
```

###### MemSQL

```sql
{ts '2020-02-03 15:30:45.0'}
```

###### SQLDataWarehouse, SQLServer

```sql
cast('2020-02-03 15:30:45.0' AS DATETIME2)
```

###### ClickHouse, Databricks, DuckDB, Redshift, Snowflake, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="localdatetimeadd-function"></a>
##### 3.11.19.25. LOCALDATETIMEADD

Add an interval of type [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) (number of days) or [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) ([SQL interval type](#data-type-interval)) to a timestamp (represented by [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html)).

This does the same as [TIMESTAMPADD](#timestampadd-function) except that the client type representation uses JSR-310 types.

```sql
SELECT DATE '2020-02-03 15:30:45' + INTERVAL 3 DAYS;
```

```java
create.select(localDateTimeAdd(LocalDateTime.parse("2020-02-03T15:30:45"), 3)).fetch();
```

The result being

```text
+---------------------+
| timestamp_add       |
+---------------------+
| 2020-02-06 15:30:45 |
+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
localDateTimeAdd(LocalDateTime.parse("2020-02-03T15:30:45"), 3)
```

Translates to the following dialect specific expressions:

###### Access

```sql
dateadd('d', 3, #2020/02/03 15:30:45#)
```

###### ASE, Sybase

```sql
dateadd(DAY, 3, '2020-02-03 15:30:45.0')
```

###### Aurora MySQL, MariaDB, MySQL

```sql
date_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 3 DAY)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + 3 * INTERVAL '1 day')
```

###### BigQuery

```sql
timestamp_add(DATETIME '2020-02-03 15:30:45.0', INTERVAL 3 DAY)
```

###### ClickHouse

```sql
(TIMESTAMP '2020-02-03 15:30:45' + 3)
```

###### Databricks, Exasol, H2, Oracle, Vertica

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + 3)
```

###### DB2, HSQLDB

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + (3) day)
```

###### DuckDB

```sql
date_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 1 DAY * 3)
```

###### Firebird, Snowflake

```sql
dateadd(DAY, 3, TIMESTAMP '2020-02-03 15:30:45.0')
```

###### Hana

```sql
add_days(TIMESTAMP '2020-02-03 15:30:45.0', 3)
```

###### Informix

```sql
(DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION + 3 UNITS DAY)
```

###### MemSQL

```sql
date_add({ts '2020-02-03 15:30:45.0'}, INTERVAL 3 DAY)
```

###### Spanner

```sql
timestamp_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 3 DAY)
```

###### SQLDataWarehouse, SQLServer

```sql
dateadd(DAY, 3, cast('2020-02-03 15:30:45.0' AS DATETIME2))
```

###### SQLite

```sql
strftime('%Y-%m-%d %H:%M:%f', '2020-02-03 15:30:45.0', (cast(3 AS varchar) || ' day'))
```

###### Teradata

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + cast(3 || ' 00:00:00' AS INTERVAL DAY TO SECOND))
```

###### Trino

```sql
date_add('day', 3, TIMESTAMP '2020-02-03 15:30:45.0')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="localdatetimesub-function"></a>
##### 3.11.19.26. LOCALDATETIMESUB

Subtract an interval of type [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) (number of days) or [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) ([SQL interval type](#data-type-interval)) from a timestamp (represented by [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html)).

This does the same as [TIMESTAMPSUB](#timestampsub-function) except that the client type representation uses JSR-310 types.

```sql
SELECT DATE '2020-02-03 15:30:45' - INTERVAL 2 DAYS;
```

```java
create.select(localDateTimeSub(LocalDateTime.parse("2020-02-03T15:30:45"), 2)).fetch();
```

The result being

```text
+---------------------+
| timestamp_sub       |
+---------------------+
| 2020-02-01 15:30:45 |
+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
localDateTimeSub(LocalDateTime.parse("2020-02-03T15:30:45"), 2)
```

Translates to the following dialect specific expressions:

###### Access

```sql
dateadd('d', -2, #2020/02/03 15:30:45#)
```

###### ASE, Sybase

```sql
dateadd(DAY, -2, '2020-02-03 15:30:45.0')
```

###### Aurora MySQL, MariaDB, MySQL

```sql
date_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL -2 DAY)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + -2 * INTERVAL '1 day')
```

###### BigQuery

```sql
timestamp_sub(DATETIME '2020-02-03 15:30:45.0', INTERVAL 2 DAY)
```

###### ClickHouse

```sql
(TIMESTAMP '2020-02-03 15:30:45' - 2)
```

###### Databricks, Exasol, H2, Oracle, Vertica

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' - 2)
```

###### DB2, HSQLDB

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' - (2) day)
```

###### DuckDB

```sql
date_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 1 DAY * -2)
```

###### Firebird, Snowflake

```sql
dateadd(DAY, -2, TIMESTAMP '2020-02-03 15:30:45.0')
```

###### Hana

```sql
add_days(TIMESTAMP '2020-02-03 15:30:45.0', -2)
```

###### Informix

```sql
(DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION - 2 UNITS DAY)
```

###### MemSQL

```sql
date_add({ts '2020-02-03 15:30:45.0'}, INTERVAL -2 DAY)
```

###### Spanner

```sql
timestamp_sub(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 2 DAY)
```

###### SQLDataWarehouse, SQLServer

```sql
dateadd(DAY, -2, cast('2020-02-03 15:30:45.0' AS DATETIME2))
```

###### SQLite

```sql
strftime('%Y-%m-%d %H:%M:%f', '2020-02-03 15:30:45.0', (cast(
  -2
  AS varchar
) || ' day'))
```

###### Teradata

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' - cast(2 || ' 00:00:00' AS INTERVAL DAY TO SECOND))
```

###### Trino

```sql
date_add('day', -2, TIMESTAMP '2020-02-03 15:30:45.0')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="localtime-function"></a>
##### 3.11.19.27. LOCALTIME

Convert an ISO 8601 `TIME` string literal into a SQL `TIME` type (represented by [`java.time.LocalTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalTime.html)).

This does the same as [TIME](#time-function) except that the client type representation uses JSR-310 types.

```sql
SELECT CAST('15:30:45' AS TIME);
```

```java
create.select(localTime("15:30:45")).fetch();
```

The result being

```text
+----------+
| time     |
+----------+
| 15:30:45 |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
localTime("15:30:45")
```

Translates to the following dialect specific expressions:

###### Access, MemSQL

```sql
{t '15:30:45'}
```

###### ASE, SQLite, Sybase

```sql
'15:30:45'
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Postgres, Teradata, Vertica

```sql
TIME '15:30:45'
```

###### Informix

```sql
DATETIME(15:30:45) HOUR TO SECOND
```

###### Oracle

```sql
TIMESTAMP '1970-01-01 15:30:45'
```

###### SQLDataWarehouse, SQLServer

```sql
cast(cast('15:30:45' AS time) AS time)
```

###### ClickHouse, Databricks, DuckDB, Exasol, Redshift, Snowflake, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="millennium-function"></a>
##### 3.11.19.28. MILLENNIUM

Extract the `MILLENNIUM` value from a datetime value.

The `MILLENNIUM` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.MILLENNIUM`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#MILLENNIUM) value as an argument.

```sql
SELECT millennium(DATE '2020-02-03');
```

```java
create.select(millennium(Date.valueOf("2020-02-03"))).fetch();
```

The result being

```text
+------------+
| millennium |
+------------+
|          3 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
millennium(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
(cdec(((sgn(datepart('yyyy', #2020/02/03 00:00:00#)) * (abs(datepart('yyyy', #2020/02/03 00:00:00#)) + 999)) / 1000)) - (((sgn(datepart('yyyy', #2020/02/03 00:00:00#)) * (abs(datepart('yyyy', #2020/02/03 00:00:00#)) + 999)) / 1000) < cdec(((sgn(datepart('yyyy', #2020/02/03 00:00:00#)) * (abs(datepart('yyyy', #2020/02/03 00:00:00#)) + 999)) / 1000))))
```

###### ASE, Sybase

```sql
floor(((sign(datepart(yy, '2020-02-03 00:00:00.0')) * (abs(datepart(yy, '2020-02-03 00:00:00.0')) + 999)) / 1000))
```

###### Aurora MySQL, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica

```sql
floor(((sign(extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00.0')) * (abs(extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00.0')) + 999)) / 1000))
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
extract(MILLENNIUM FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### BigQuery

```sql
floor(((sign(extract(YEAR FROM DATETIME '2020-02-03 00:00:00.0')) * (abs(extract(YEAR FROM DATETIME '2020-02-03 00:00:00.0')) + 999)) / 1000))
```

###### ClickHouse

```sql
floor(((sign(extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00')) * (abs(extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00')) + 999)) / 1000))
```

###### DB2

```sql
floor(((sign(YEAR(TIMESTAMP '2020-02-03 00:00:00.0')) * (abs(YEAR(TIMESTAMP '2020-02-03 00:00:00.0')) + 999)) / 1000))
```

###### Informix

```sql
floor(((sign(YEAR(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION)) * (abs(YEAR(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION)) + 999)) / 1000))
```

###### MemSQL

```sql
floor(((sign(extract(YEAR FROM {ts '2020-02-03 00:00:00.0'})) * (abs(extract(YEAR FROM {ts '2020-02-03 00:00:00.0'})) + 999)) / 1000))
```

###### SQLDataWarehouse, SQLServer

```sql
floor(((sign(datepart(yy, cast('2020-02-03 00:00:00.0' AS DATETIME2))) * (abs(datepart(yy, cast('2020-02-03 00:00:00.0' AS DATETIME2))) + 999)) / 1000))
```

###### SQLite

```sql
floor(((CASE
  WHEN cast(
    strftime('%Y', '2020-02-03 00:00:00.0')
    AS int
  ) > 0 THEN 1
  WHEN cast(
    strftime('%Y', '2020-02-03 00:00:00.0')
    AS int
  ) < 0 THEN -1
  WHEN cast(
    strftime('%Y', '2020-02-03 00:00:00.0')
    AS int
  ) = 0 THEN 0
END * (abs(cast(
  strftime('%Y', '2020-02-03 00:00:00.0')
  AS int
)) + 999)) / 1000))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="minute-function"></a>
##### 3.11.19.29. MINUTE

Extract the `MINUTE` value from a datetime value.

The `MINUTE` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.MINUTE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#MINUTE) value as an argument.

```sql
SELECT minute(TIMESTAMP '2020-02-03 15:30:45');
```

```java
create.select(minute(Timestamp.valueOf("2020-02-03 15:30:45"))).fetch();
```

The result being

```text
+--------+
| minute |
+--------+
|     30 |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
minute(Timestamp.valueOf("2020-02-03 15:30:45"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
datepart('n', #2020/02/03 15:30:45#)
```

###### ASE, Sybase

```sql
datepart(mi, '2020-02-03 15:30:45.0')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
extract(MINUTE FROM TIMESTAMP '2020-02-03 15:30:45.0')
```

###### BigQuery

```sql
extract(MINUTE FROM DATETIME '2020-02-03 15:30:45.0')
```

###### ClickHouse

```sql
extract(MINUTE FROM TIMESTAMP '2020-02-03 15:30:45')
```

###### DB2

```sql
MINUTE(TIMESTAMP '2020-02-03 15:30:45.0')
```

###### Informix

```sql
cast(DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION AS cast(DATETIME MINUTE TO MINUTE AS cast(CHAR(2) AS INT)))
```

###### MemSQL

```sql
extract(MINUTE FROM {ts '2020-02-03 15:30:45.0'})
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(mi, cast('2020-02-03 15:30:45.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%M', '2020-02-03 15:30:45.0')
  AS int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="month-function"></a>
##### 3.11.19.30. MONTH

Extract the `MONTH` value from a datetime value.

The `MONTH` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.MONTH`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#MONTH) value as an argument.

```sql
SELECT month(DATE '2020-02-03');
```

```java
create.select(month(Date.valueOf("2020-02-03"))).fetch();
```

The result being

```text
+-------+
| month |
+-------+
|     2 |
+-------+
```

###### Dialect support

This example using jOOQ:

```java
month(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
datepart('m', #2020/02/03 00:00:00#)
```

###### ASE, Sybase

```sql
datepart(mm, '2020-02-03 00:00:00.0')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
extract(MONTH FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### BigQuery

```sql
extract(MONTH FROM DATETIME '2020-02-03 00:00:00.0')
```

###### ClickHouse

```sql
extract(MONTH FROM TIMESTAMP '2020-02-03 00:00:00')
```

###### DB2

```sql
MONTH(TIMESTAMP '2020-02-03 00:00:00.0')
```

###### Informix

```sql
MONTH(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION)
```

###### MemSQL

```sql
extract(MONTH FROM {ts '2020-02-03 00:00:00.0'})
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(mm, cast('2020-02-03 00:00:00.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%m', '2020-02-03 00:00:00.0')
  AS int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="quarter-function"></a>
##### 3.11.19.31. QUARTER

Extract the `QUARTER` value from a datetime value.

The `QUARTER` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.QUARTER`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#QUARTER) value as an argument.

```sql
SELECT quarter(DATE '2020-02-03');
```

```java
create.select(quarter(Date.valueOf("2020-02-03"))).fetch();
```

The result being

```text
+---------+
| quarter |
+---------+
|       1 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
quarter(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
(cdec(((datepart('m', #2020/02/03 00:00:00#) + 2) / 3)) - (((datepart('m', #2020/02/03 00:00:00#) + 2) / 3) < cdec(((datepart('m', #2020/02/03 00:00:00#) + 2) / 3))))
```

###### ASE, Sybase

```sql
datepart(qq, '2020-02-03 00:00:00.0')
```

###### Aurora MySQL, DB2, H2, HSQLDB, MariaDB, MySQL

```sql
quarter(TIMESTAMP '2020-02-03 00:00:00.0')
```

###### Aurora Postgres, CockroachDB, Firebird, Postgres, Snowflake, Spanner, YugabyteDB

```sql
extract(QUARTER FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### BigQuery

```sql
extract(QUARTER FROM DATETIME '2020-02-03 00:00:00.0')
```

###### ClickHouse

```sql
floor(((extract(MONTH FROM TIMESTAMP '2020-02-03 00:00:00') + 2) / 3))
```

###### Databricks, DuckDB, Exasol, Hana, Redshift, Teradata, Trino, Vertica

```sql
floor(((extract(MONTH FROM TIMESTAMP '2020-02-03 00:00:00.0') + 2) / 3))
```

###### Informix

```sql
floor(((MONTH(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION) + 2) / 3))
```

###### MemSQL

```sql
quarter({ts '2020-02-03 00:00:00.0'})
```

###### Oracle

```sql
to_number(to_char(TIMESTAMP '2020-02-03 00:00:00.0', 'Q'))
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(qq, cast('2020-02-03 00:00:00.0' AS DATETIME2))
```

###### SQLite

```sql
floor(((cast(
  strftime('%m', '2020-02-03 00:00:00.0')
  AS int
) + 2) / 3))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="second-function"></a>
##### 3.11.19.32. SECOND

Extract the `SECOND` value from a datetime value.

The `SECOND` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.SECOND`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#SECOND) value as an argument.

```sql
SELECT second(TIMESTAMP '2020-02-03 15:30:45');
```

```java
create.select(second(Timestamp.valueOf("2020-02-03 15:30:45"))).fetch();
```

The result being

```text
+--------+
| second |
+--------+
|     45 |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
second(Timestamp.valueOf("2020-02-03 15:30:45"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
datepart('s', #2020/02/03 15:30:45#)
```

###### ASE, Sybase

```sql
datepart(ss, '2020-02-03 15:30:45.0')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
extract(SECOND FROM TIMESTAMP '2020-02-03 15:30:45.0')
```

###### BigQuery

```sql
extract(SECOND FROM DATETIME '2020-02-03 15:30:45.0')
```

###### ClickHouse

```sql
extract(SECOND FROM TIMESTAMP '2020-02-03 15:30:45')
```

###### DB2

```sql
SECOND(TIMESTAMP '2020-02-03 15:30:45.0')
```

###### Informix

```sql
cast(DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION AS cast(DATETIME SECOND TO SECOND AS cast(CHAR(2) AS INT)))
```

###### MemSQL

```sql
extract(SECOND FROM {ts '2020-02-03 15:30:45.0'})
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(ss, cast('2020-02-03 15:30:45.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%S', '2020-02-03 15:30:45.0')
  AS int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="time-function"></a>
##### 3.11.19.33. TIME

Convert an ISO 8601 `TIME` string literal into a SQL `TIME` type (represented by [`java.sql.Time`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Time.html)).

```sql
SELECT CAST('15:30:45' AS TIME);
```

```java
create.select(time("15:30:45")).fetch();
```

The result being

```text
+----------+
| time     |
+----------+
| 15:30:45 |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
time("15:30:45")
```

Translates to the following dialect specific expressions:

###### Access, MemSQL

```sql
{t '15:30:45'}
```

###### ASE, SQLite, Sybase

```sql
'15:30:45'
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Postgres, Teradata, Vertica

```sql
TIME '15:30:45'
```

###### Informix

```sql
DATETIME(15:30:45) HOUR TO SECOND
```

###### Oracle

```sql
TIMESTAMP '1970-01-01 15:30:45'
```

###### SQLDataWarehouse, SQLServer

```sql
cast(cast('15:30:45' AS time) AS time)
```

###### ClickHouse, Databricks, DuckDB, Exasol, Redshift, Snowflake, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="timestamp-function"></a>
##### 3.11.19.34. TIMESTAMP

Convert an ISO 8601 `TIMESTAMP` string literal into a SQL `TIMESTAMP` type (represented by [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html)).

```sql
SELECT CAST('2020-02-03 15:30:45' AS TIMESTAMP);
```

```java
create.select(timestamp("2020-02-03 15:30:45")).fetch();
```

The result being

```text
+---------------------+
| timestamp           |
+---------------------+
| 2020-02-03 15:30:45 |
+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
timestamp("2020-02-03 15:30:45")
```

Translates to the following dialect specific expressions:

###### Access

```sql
#2020/02/03 15:30:45#
```

###### ASE, SQLite, Sybase

```sql
'2020-02-03 15:30:45.0'
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Teradata, Vertica

```sql
TIMESTAMP '2020-02-03 15:30:45.0'
```

###### BigQuery

```sql
DATETIME '2020-02-03 15:30:45.0'
```

###### Informix

```sql
DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION
```

###### MemSQL

```sql
{ts '2020-02-03 15:30:45.0'}
```

###### SQLDataWarehouse, SQLServer

```sql
cast('2020-02-03 15:30:45.0' AS DATETIME2)
```

###### ClickHouse, Databricks, DuckDB, Redshift, Snowflake, Spanner, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="timestampadd-function"></a>
##### 3.11.19.35. TIMESTAMPADD

Add an interval of type [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) (number of days) or [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) ([SQL interval type](#data-type-interval)) to a timestamp (represented by [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html)).

```sql
SELECT DATE '2020-02-03 15:30:45' + INTERVAL 3 DAYS;
```

```java
create.select(timestampAdd(Timestamp.valueOf("2020-02-03 15:30:45"), 3)).fetch();
```

The result being

```text
+---------------------+
| timestamp_add       |
+---------------------+
| 2020-02-06 15:30:45 |
+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
timestampAdd(Timestamp.valueOf("2020-02-03 15:30:45"), 3)
```

Translates to the following dialect specific expressions:

###### Access

```sql
dateadd('d', 3, #2020/02/03 15:30:45#)
```

###### ASE, Sybase

```sql
dateadd(DAY, 3, '2020-02-03 15:30:45.0')
```

###### Aurora MySQL, MariaDB, MySQL

```sql
date_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 3 DAY)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + 3 * INTERVAL '1 day')
```

###### BigQuery

```sql
timestamp_add(DATETIME '2020-02-03 15:30:45.0', INTERVAL 3 DAY)
```

###### ClickHouse

```sql
(TIMESTAMP '2020-02-03 15:30:45' + 3)
```

###### Databricks, Exasol, H2, Oracle, Vertica

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + 3)
```

###### DB2, HSQLDB

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + (3) day)
```

###### DuckDB

```sql
date_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 1 DAY * 3)
```

###### Firebird, Snowflake

```sql
dateadd(DAY, 3, TIMESTAMP '2020-02-03 15:30:45.0')
```

###### Hana

```sql
add_days(TIMESTAMP '2020-02-03 15:30:45.0', 3)
```

###### Informix

```sql
(DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION + 3 UNITS DAY)
```

###### MemSQL

```sql
date_add({ts '2020-02-03 15:30:45.0'}, INTERVAL 3 DAY)
```

###### Spanner

```sql
timestamp_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 3 DAY)
```

###### SQLDataWarehouse, SQLServer

```sql
dateadd(DAY, 3, cast('2020-02-03 15:30:45.0' AS DATETIME2))
```

###### SQLite

```sql
strftime('%Y-%m-%d %H:%M:%f', '2020-02-03 15:30:45.0', (cast(3 AS varchar) || ' day'))
```

###### Teradata

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + cast(3 || ' 00:00:00' AS INTERVAL DAY TO SECOND))
```

###### Trino

```sql
date_add('day', 3, TIMESTAMP '2020-02-03 15:30:45.0')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="timestampsub-function"></a>
##### 3.11.19.36. TIMESTAMPSUB

Subtract an interval of type [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) (number of days) or [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) ([SQL interval type](#data-type-interval)) from a timestamp (represented by [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html)).

```sql
SELECT DATE '2020-02-03 15:30:45' - INTERVAL 2 DAYS;
```

```java
create.select(timestampSub(Timestamp.valueOf("2020-02-03 15:30:45"), 2)).fetch();
```

The result being

```text
+---------------------+
| timestamp_sub       |
+---------------------+
| 2020-02-01 15:30:45 |
+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
timestampSub(Timestamp.valueOf("2020-02-03 15:30:45"), 2)
```

Translates to the following dialect specific expressions:

###### Access

```sql
dateadd('d', -2, #2020/02/03 15:30:45#)
```

###### ASE, Sybase

```sql
dateadd(DAY, -2, '2020-02-03 15:30:45.0')
```

###### Aurora MySQL, MariaDB, MySQL

```sql
date_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL -2 DAY)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' + -2 * INTERVAL '1 day')
```

###### BigQuery

```sql
timestamp_sub(DATETIME '2020-02-03 15:30:45.0', INTERVAL 2 DAY)
```

###### ClickHouse

```sql
(TIMESTAMP '2020-02-03 15:30:45' - 2)
```

###### Databricks, Exasol, H2, Oracle, Vertica

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' - 2)
```

###### DB2, HSQLDB

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' - (2) day)
```

###### DuckDB

```sql
date_add(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 1 DAY * -2)
```

###### Firebird, Snowflake

```sql
dateadd(DAY, -2, TIMESTAMP '2020-02-03 15:30:45.0')
```

###### Hana

```sql
add_days(TIMESTAMP '2020-02-03 15:30:45.0', -2)
```

###### Informix

```sql
(DATETIME(2020-02-03 15:30:45.0) YEAR TO FRACTION - 2 UNITS DAY)
```

###### MemSQL

```sql
date_add({ts '2020-02-03 15:30:45.0'}, INTERVAL -2 DAY)
```

###### Spanner

```sql
timestamp_sub(TIMESTAMP '2020-02-03 15:30:45.0', INTERVAL 2 DAY)
```

###### SQLDataWarehouse, SQLServer

```sql
dateadd(DAY, -2, cast('2020-02-03 15:30:45.0' AS DATETIME2))
```

###### SQLite

```sql
strftime('%Y-%m-%d %H:%M:%f', '2020-02-03 15:30:45.0', (cast(
  -2
  AS varchar
) || ' day'))
```

###### Teradata

```sql
(TIMESTAMP '2020-02-03 15:30:45.0' - cast(2 || ' 00:00:00' AS INTERVAL DAY TO SECOND))
```

###### Trino

```sql
date_add('day', -2, TIMESTAMP '2020-02-03 15:30:45.0')
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="to-date-function"></a>
##### 3.11.19.37. TO_DATE

Parse a string value to a SQL `DATE` type (represented by [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html)) using a vendor specific formatting pattern.

The pattern is not translated by jOOQ for vendor agnosticism and may need to be adapted depending on the SQL dialect you're using.

```sql
SELECT TO_DATE('20200203', 'YYYYMMDD');
```

```java
create.select(toDate("20200203", "YYYYMMDD")).fetch();
```

The result being

```text
+------------+
| to_date    |
+------------+
| 2020-02-03 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
toDate("20200203", "YYYYMMDD")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, DB2, Databricks, Exasol, HSQLDB, Oracle, Postgres, Vertica, YugabyteDB

```sql
to_date('20200203', 'YYYYMMDD')
```

###### SQLDataWarehouse, SQLServer

```sql
convert(
  date,
  '20200203',
  112
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, CockroachDB, DuckDB, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="to-localdate-function"></a>
##### 3.11.19.38. TO_LOCALDATE

Parse a string value to a SQL `DATE` type (represented by [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html)) using a vendor specific formatting pattern.

The pattern is not translated by jOOQ for vendor agnosticism and may need to be adapted depending on the SQL dialect you're using.

This does the same as [TO_DATE](#to-date-function) except that the client type representation uses JSR-310 types.

```sql
SELECT TO_DATE('20200203', 'YYYYMMDD');
```

```java
create.select(toLocalDate("20200203", "YYYYMMDD")).fetch();
```

The result being

```text
+------------+
| to_date    |
+------------+
| 2020-02-03 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
toLocalDate("20200203", "YYYYMMDD")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, HSQLDB, Oracle, Postgres, Vertica

```sql
to_date('20200203', 'YYYYMMDD')
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="to-localdatetime-function"></a>
##### 3.11.19.39. TO_LOCALDATETIME

Parse a string value to a SQL `TIMESTAMP` type (represented by [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html)) using a vendor specific formatting pattern.

The pattern is not translated by jOOQ for vendor agnosticism and may need to be adapted depending on the SQL dialect you're using.

This does the same as [TO_TIMESTAMP](#to-timestamp-function) except that the client type representation uses JSR-310 types.

```sql
SELECT TO_TIMESTAMP('20200203153045', 'YYYYMMDDHH24MISS');
```

```java
create.select(toLocalDateTime("20200203153045", "YYYYMMDDHH24MISS")).fetch();
```

The result being

```text
+---------------------+
| to_timestamp        |
+---------------------+
| 2020-02-03 15:30:45 |
+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
toLocalDateTime("20200203153045", "YYYYMMDDHH24MISS")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, HSQLDB, Oracle, Postgres, Vertica

```sql
to_timestamp('20200203153045', 'YYYYMMDDHH24MISS')
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="to-timestamp-function"></a>
##### 3.11.19.40. TO_TIMESTAMP

Parse a string value to a SQL `TIMESTAMP` type (represented by [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html)) using a vendor specific formatting pattern.

The pattern is not translated by jOOQ for vendor agnosticism and may need to be adapted depending on the SQL dialect you're using.

```sql
SELECT TO_TIMESTAMP('20200203153045', 'YYYYMMDDHH24MISS');
```

```java
create.select(toTimestamp("20200203153045", "YYYYMMDDHH24MISS")).fetch();
```

The result being

```text
+---------------------+
| to_timestamp        |
+---------------------+
| 2020-02-03 15:30:45 |
+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
toTimestamp("20200203153045", "YYYYMMDDHH24MISS")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DB2, Databricks, Exasol, HSQLDB, Oracle, Postgres, SQLDataWarehouse, SQLServer, Vertica, YugabyteDB

```sql
to_timestamp('20200203153045', 'YYYYMMDDHH24MISS')
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DuckDB, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="date-trunc-function"></a>
##### 3.11.19.41. TRUNC

Truncate a datetime value to the precision of a certain [`org.jooq.DatePart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html), or [`DatePart.DAY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#DAY) by default.

```sql
SELECT TRUNC(DATE '2020-02-03', 'YYYY');
```

```java
create.select(trunc(Date.valueOf("2020-02-03", DatePart.YEAR))).fetch();
```

The result being

```text
+------------+
| trunc      |
+------------+
| 2020-01-01 |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
trunc(Date.valueOf("2020-02-03"), DatePart.YEAR)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, Vertica

```sql
date_trunc('year', DATE '2020-02-03')
```

###### BigQuery

```sql
date_trunc(
  DATE '2020-02-03',
  YEAR
)
```

###### DB2, Oracle

```sql
trunc(DATE '2020-02-03', 'YYYY')
```

###### H2

```sql
PARSEDATETIME(FORMATDATETIME(DATE '2020-02-03', 'yyyy'), 'yyyy')
```

###### HSQLDB

```sql
trunc(DATE '2020-02-03', 'YY')
```

###### Informix

```sql
trunc(DATETIME(2020-02-03) YEAR TO DAY, 'YEAR')
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, DuckDB, Exasol, Firebird, Hana, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="year-function"></a>
##### 3.11.19.42. YEAR

Extract the `YEAR` value from a datetime value.

The `YEAR` function is a short version of the [EXTRACT](#extract-function), passing a [`DatePart.YEAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DatePart.html#YEAR) value as an argument.

```sql
SELECT year(DATE '2020-02-03');
```

```java
create.select(year(Date.valueOf("2020-02-03"))).fetch();
```

The result being

```text
+------+
| year |
+------+
| 2020 |
+------+
```

###### Dialect support

This example using jOOQ:

```java
year(Date.valueOf("2020-02-03"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
datepart('yyyy', #2020/02/03 00:00:00#)
```

###### ASE, Sybase

```sql
datepart(yy, '2020-02-03 00:00:00.0')
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00.0')
```

###### BigQuery

```sql
extract(YEAR FROM DATETIME '2020-02-03 00:00:00.0')
```

###### ClickHouse

```sql
extract(YEAR FROM TIMESTAMP '2020-02-03 00:00:00')
```

###### DB2

```sql
YEAR(TIMESTAMP '2020-02-03 00:00:00.0')
```

###### Informix

```sql
YEAR(DATETIME(2020-02-03 00:00:00.0) YEAR TO FRACTION)
```

###### MemSQL

```sql
extract(YEAR FROM {ts '2020-02-03 00:00:00.0'})
```

###### SQLDataWarehouse, SQLServer

```sql
datepart(yy, cast('2020-02-03 00:00:00.0' AS DATETIME2))
```

###### SQLite

```sql
cast(
  strftime('%Y', '2020-02-03 00:00:00.0')
  AS int
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-functions"></a>
#### 3.11.20. ARRAY functions

The SQL standard specifies an `ARRAY` data type, which allows for nesting collections of scalar values and even [ROW expressions](#row-value-expressions).

In order to operate on `ARRAY` data types, a few functions are made available by jOOQ.

<a id="array-all-match-function"></a>
##### 3.11.20.1. ARRAY_ALL_MATCH

The `ARRAY_ALL_MATCH` function allows for checking if all array elements match a given predicate.

> [!TIP]
> A few SQL dialects, including ClickHouse, DuckDB, and Trino have introduced higher order functions with a lambda syntax to help implement features like this one. jOOQ can map a Java lambda to a SQL lambda, and emulate the feature using standard SQL functionality (using [UNNEST](#array-and-cursor-unnesting) and [ARRAY_AGG](#array-agg-function)) if the function isn't available.

```sql
SELECT array_all_match(ARRAY[1, 2, 2, 3], e -> e > 0)
```

```java
create.select(arrayAllMatch(array(1, 2, 2, 3), e -> e.gt(0))).fetch();
```

The result would look like this:

```text
+-----------------+
| array_all_match |
+-----------------+
| true            |
+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayAllMatch(array(1, 2, 2, 3), e -> e.gt(0))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, HSQLDB, Postgres

```sql
(NOT EXISTS (
  SELECT 1
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
  WHERE NOT (e > 0)
))
```

###### BigQuery

```sql
(NOT EXISTS (
  SELECT 1
  FROM UNNEST(ARRAY[1, 2, 2, 3]) AS e WITH OFFSET AS o
  WHERE NOT (e > 0)
))
```

###### ClickHouse

```sql
arrayAll(
  e -> e > 0,
  ARRAY(1, 2, 2, 3)
)
```

###### Databricks

```sql
aggregate(
  ARRAY(1, 2, 2, 3),
  TRUE,
  e -> e > 0
)
```

###### Trino

```sql
all_match(
  ARRAY[1, 2, 2, 3],
  e -> e > 0
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-any-match-function"></a>
##### 3.11.20.2. ARRAY_ANY_MATCH

The `ARRAY_ANY_MATCH` function allows for checking if any of the array elements match a given predicate.

> [!TIP]
> A few SQL dialects, including ClickHouse, DuckDB, and Trino have introduced higher order functions with a lambda syntax to help implement features like this one. jOOQ can map a Java lambda to a SQL lambda, and emulate the feature using standard SQL functionality (using [UNNEST](#array-and-cursor-unnesting) and [ARRAY_AGG](#array-agg-function)) if the function isn't available.

```sql
SELECT array_any_match(ARRAY[1, 2, 2, 3], e -> e > 2)
```

```java
create.select(arrayAnyMatch(array(1, 2, 2, 3), e -> e.gt(2))).fetch();
```

The result would look like this:

```text
+-----------------+
| array_any_match |
+-----------------+
| true            |
+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayAnyMatch(array(1, 2, 2, 3), e -> e.gt(2))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, HSQLDB, Postgres

```sql
EXISTS (
  SELECT 1
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
  WHERE e > 2
)
```

###### BigQuery

```sql
EXISTS (
  SELECT 1
  FROM UNNEST(ARRAY[1, 2, 2, 3]) AS e WITH OFFSET AS o
  WHERE e > 2
)
```

###### ClickHouse

```sql
arrayExists(
  e -> e > 2,
  ARRAY(1, 2, 2, 3)
)
```

###### Databricks

```sql
exists(
  ARRAY(1, 2, 2, 3),
  e -> e > 2
)
```

###### Trino

```sql
any_match(
  ARRAY[1, 2, 2, 3],
  e -> e > 2
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-append-function"></a>
##### 3.11.20.3. ARRAY_APPEND (|| operator)

The `ARRAY_APPEND` function allows for concatenating an element to the end of an array (see also [ARRAY_PREPEND](#array-prepend-function) and [ARRAY_CONCAT](#array-concat-function)):

```sql
SELECT ARRAY[1, 2] || 3
```

```java
create.select(arrayAppend(array(1, 2), 3)).fetch();
```

The result would look like this:

```text
+--------------+
| array_append |
+--------------+
| [1, 2, 3]    |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayAppend(array(1, 2), 3)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, YugabyteDB

```sql
array_append(
  ARRAY[1, 2],
  3
)
```

###### BigQuery, H2, HSQLDB, Spanner, Trino

```sql
(ARRAY[1, 2] || ARRAY[3])
```

###### ClickHouse

```sql
arrayPushBack(
  ARRAY(1, 2),
  3
)
```

###### Databricks

```sql
array_append(
  ARRAY(1, 2),
  3
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-concat-function"></a>
##### 3.11.20.4. ARRAY_CONCAT (|| operator)

The `ARRAY_CONCAT` (or `ARRAY_CAT`) function allows for concatenating arrays (see also [ARRAY_APPEND](#array-append-function) and [ARRAY_PREPEND](#array-prepend-function) for API to concatenate single values with arrays):

```sql
SELECT ARRAY[1, 2] || ARRAY[3, 4]
```

```java
create.select(arrayConcat(array(1, 2), array(3, 4))).fetch();
```

The result would look like this:

```text
+--------------+
| array_concat |
+--------------+
| [1, 2, 3, 4] |
+--------------+
```

> [!TIP]
> See [CONCAT](#concat-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
arrayConcat(array(1, 2), array(3, 4))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DuckDB, H2, HSQLDB, Postgres, Spanner, Trino, YugabyteDB

```sql
(ARRAY[1, 2] || ARRAY[3, 4])
```

###### ClickHouse

```sql
arrayConcat(
  ARRAY(1, 2),
  ARRAY(3, 4)
)
```

###### Databricks

```sql
(ARRAY(1, 2) || ARRAY(3, 4))
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-contains-function"></a>
##### 3.11.20.5. ARRAY_CONTAINS

The `ARRAY_CONTAINS` function allows for checking if an array contains a specific element:

```sql
SELECT array_contains(ARRAY[1, 2, 2, 3], 2)
```

```java
create.select(arrayContains(array(1, 2, 2, 3), val(2))).fetch();
```

The result would look like this:

```text
+-----------------+
| array_contains  |
+-----------------+
| true            |
+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayContains(array(1, 2, 2, 3), val(2))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
ARRAY[1, 2, 2, 3] @> ARRAY[2]
```

###### BigQuery

```sql
EXISTS (
  SELECT 1
  FROM UNNEST(ARRAY[1, 2, 2, 3]) AS e WITH OFFSET AS o
  WHERE e = 2
)
```

###### ClickHouse

```sql
has(
  ARRAY(1, 2, 2, 3),
  2
)
```

###### Databricks

```sql
array_contains(
  ARRAY(1, 2, 2, 3),
  2
)
```

###### DuckDB

```sql
list_contains(
  ARRAY[1, 2, 2, 3],
  2
)
```

###### H2

```sql
array_contains(
  ARRAY[1, 2, 2, 3],
  2
)
```

###### HSQLDB

```sql
(position_array(2 IN ARRAY[1, 2, 2, 3]) > 0)
```

###### Spanner

```sql
array_includes(
  ARRAY[1, 2, 2, 3],
  2
)
```

###### Trino

```sql
contains(
  ARRAY[1, 2, 2, 3],
  2
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-filter-function"></a>
##### 3.11.20.6. ARRAY_FILTER

The `ARRAY_FILTER` function allows for filtering elements of an array given a predicate.

> [!TIP]
> A few SQL dialects, including ClickHouse, DuckDB, and Trino have introduced higher order functions with a lambda syntax to help implement features like this one. jOOQ can map a Java lambda to a SQL lambda, and emulate the feature using standard SQL functionality (using [UNNEST](#array-and-cursor-unnesting) and [ARRAY_AGG](#array-agg-function)) if the function isn't available.

```sql
SELECT array_filter(ARRAY[1, 2, 2, 3], e -> mod(e, 2) = 0)
```

```java
create.select(arrayFilter(array(1, 2, 2, 3), e -> e.mod(2).eq(0))).fetch();
```

The result would look like this:

```text
+--------------+
| array_filter |
+--------------+
| [ 2, 2 ]     |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayFilter(array(1, 2, 2, 3), e -> e.mod(2).eq(0))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
(
  SELECT coalesce(
    array_agg(e),
    cast(ARRAY[] AS int[])
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
  WHERE mod(e, 2) = 0
)
```

###### BigQuery

```sql
(
  SELECT coalesce(
    array_agg(e ORDER BY o),
    cast(ARRAY[] AS array<int64>)
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) AS e WITH OFFSET AS o
  WHERE mod(e, 2) = 0
)
```

###### ClickHouse

```sql
arrayFilter(
  e -> mod(e, 2) = 0,
  ARRAY(1, 2, 2, 3)
)
```

###### CockroachDB

```sql
(
  SELECT coalesce(
    array_agg(e),
    cast(ARRAY[] AS int4[])
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
  WHERE mod(e, 2) = 0
)
```

###### Databricks

```sql
filter(
  ARRAY(1, 2, 2, 3),
  e -> (e % 2) = 0
)
```

###### DuckDB

```sql
array_filter(
  ARRAY[1, 2, 2, 3],
  LAMBDA e: (e % 2) = 0
)
```

###### H2, HSQLDB

```sql
(
  SELECT coalesce(
    array_agg(e),
    cast(ARRAY[] AS int array)
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
  WHERE mod(e, 2) = 0
)
```

###### Trino

```sql
filter(
  ARRAY[1, 2, 2, 3],
  e -> mod(e, 2) = 0
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-get-function"></a>
##### 3.11.20.7. ARRAY_GET

The `ARRAY_GET` function allows for accessing array elements by 1-based ordinal.

```sql
SELECT (ARRAY[1, 2])[1]
```

```java
create.select(arrayGet(array(1, 2), 1)).fetch();
```

The result would look like this:

```text
+-----------+
| array_get |
+-----------+
|         1 |
+-----------+
```

###### Dialect support

This example using jOOQ:

```java
arrayGet(array(1, 2), 1)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, Postgres, YugabyteDB

```sql
(ARRAY[1, 2])[1]
```

###### BigQuery, Spanner

```sql
(ARRAY[1, 2])[safe_ordinal(1)]
```

###### ClickHouse

```sql
(ARRAY(1, 2))[1]
```

###### Databricks

```sql
(ARRAY(1, 2))[(1 - 1)]
```

###### HSQLDB

```sql
CASE
  WHEN cardinality(ARRAY[1, 2]) >= 1 THEN (ARRAY[1, 2])[1]
END
```

###### Trino

```sql
element_at(
  ARRAY[1, 2],
  1
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-map-function"></a>
##### 3.11.20.8. ARRAY_MAP

The `ARRAY_MAP` function allows for mapping array elements of an array to another value.

> [!TIP]
> A few SQL dialects, including ClickHouse, DuckDB, and Trino have introduced higher order functions with a lambda syntax to help implement features like this one. jOOQ can map a Java lambda to a SQL lambda, and emulate the feature using standard SQL functionality (using [UNNEST](#array-and-cursor-unnesting) and [ARRAY_AGG](#array-agg-function)) if the function isn't available.

```sql
SELECT array_map(ARRAY[1, 2, 2, 3], e -> square(e))
```

```java
create.select(arrayMap(array(1, 2, 2, 3), DSL::square)).fetch();
```

The result would look like this:

```text
+----------------+
| array_map      |
+----------------+
| [ 1, 4, 4, 9 ] |
+----------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayMap(array(1, 2, 2, 3), DSL::square)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
(
  SELECT coalesce(
    array_agg((e * e)),
    cast(ARRAY[] AS int[])
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
)
```

###### BigQuery

```sql
(
  SELECT coalesce(
    array_agg((e * e) ORDER BY o),
    cast(ARRAY[] AS array<int64>)
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) AS e WITH OFFSET AS o
)
```

###### ClickHouse

```sql
arrayMap(
  e -> (e * e),
  ARRAY(1, 2, 2, 3)
)
```

###### CockroachDB

```sql
(
  SELECT coalesce(
    array_agg((e * e)),
    cast(ARRAY[] AS int4[])
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
)
```

###### Databricks

```sql
transform(
  ARRAY(1, 2, 2, 3),
  e -> (e * e)
)
```

###### DuckDB

```sql
array_transform(
  ARRAY[1, 2, 2, 3],
  LAMBDA e: (e * e)
)
```

###### H2, HSQLDB

```sql
(
  SELECT coalesce(
    array_agg((e * e)),
    cast(ARRAY[] AS int array)
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
)
```

###### Trino

```sql
transform(
  ARRAY[1, 2, 2, 3],
  e -> (e * e)
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-none-match-function"></a>
##### 3.11.20.9. ARRAY_NONE_MATCH

The `ARRAY_NONE_MATCH` function allows for checking if none of the array elements match a given predicate.

> [!TIP]
> A few SQL dialects, including ClickHouse, DuckDB, and Trino have introduced higher order functions with a lambda syntax to help implement features like this one. jOOQ can map a Java lambda to a SQL lambda, and emulate the feature using standard SQL functionality (using [UNNEST](#array-and-cursor-unnesting) and [ARRAY_AGG](#array-agg-function)) if the function isn't available.

```sql
SELECT array_none_match(ARRAY[1, 2, 2, 3], e -> e > 2)
```

```java
create.select(arrayNoneMatch(array(1, 2, 2, 3), e -> e.gt(2))).fetch();
```

The result would look like this:

```text
+------------------+
| array_none_match |
+------------------+
| false            |
+------------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayNoneMatch(array(1, 2, 2, 3), e -> e.gt(2))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, H2, HSQLDB, Postgres

```sql
(NOT EXISTS (
  SELECT 1
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
  WHERE e > 2
))
```

###### BigQuery

```sql
(NOT EXISTS (
  SELECT 1
  FROM UNNEST(ARRAY[1, 2, 2, 3]) AS e WITH OFFSET AS o
  WHERE e > 2
))
```

###### Databricks

```sql
NOT (exists(
  ARRAY(1, 2, 2, 3),
  e -> e > 2
))
```

###### Trino

```sql
none_match(
  ARRAY[1, 2, 2, 3],
  e -> e > 2
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-overlap-function"></a>
##### 3.11.20.10. ARRAY_OVERLAP

The `ARRAY_OVERLAP` function allows for checking if two arrays overlap:

```sql
SELECT ARRAY[1, 2] && ARRAY[3, 4]
```

```java
create.select(arrayOverlap(array(1, 2), array(2, 3))).fetch();
```

The result would look like this:

```text
+---------------+
| array_overlap |
+---------------+
| true          |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayOverlap(array(1, 2), array(2, 3))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
(ARRAY[1, 2] && ARRAY[2, 3])
```

###### Databricks

```sql
arrays_overlap(
  ARRAY(1, 2),
  ARRAY(2, 3)
)
```

###### DuckDB

```sql
array_length(array_intersect(
  ARRAY[1, 2],
  ARRAY[2, 3]
)) > 0
```

###### H2

```sql
EXISTS (
  SELECT *
  FROM UNNEST(ARRAY[1, 2]) array_table (COLUMN_VALUE)
  INTERSECT
  SELECT *
  FROM UNNEST(ARRAY[2, 3]) array_table (COLUMN_VALUE)
)
```

###### HSQLDB

```sql
EXISTS (
  SELECT *
  FROM UNNEST(ARRAY[1, 2]) array_table (COLUMN_VALUE)
  INTERSECT ALL
  SELECT *
  FROM UNNEST(ARRAY[2, 3]) array_table (COLUMN_VALUE)
)
```

###### Spanner

```sql
EXISTS (
  SELECT *
  FROM (
    SELECT null COLUMN_VALUE
    FROM UNNEST([STRUCT(1 AS dual)]) AS dual
    WHERE FALSE
    UNION ALL
    SELECT *
    FROM UNNEST(ARRAY[1, 2]) array_table
  ) array_table
  INTERSECT ALL
  SELECT *
  FROM (
    SELECT null COLUMN_VALUE
    FROM UNNEST([STRUCT(1 AS dual)]) AS dual
    WHERE FALSE
    UNION ALL
    SELECT *
    FROM UNNEST(ARRAY[2, 3]) array_table
  ) array_table
)
```

###### Trino

```sql
arrays_overlap(
  ARRAY[1, 2],
  ARRAY[2, 3]
)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-prepend-function"></a>
##### 3.11.20.11. ARRAY_PREPEND (|| operator)

The `ARRAY_PREPEND` function allows for concatenating an element to the beginning of an array (see also [ARRAY_APPEND](#array-append-function) and [ARRAY_CONCAT](#array-concat-function)):

```sql
SELECT 1 || ARRAY[2, 3]
```

```java
create.select(arrayPrepend(1, array(2, 3))).fetch();
```

The result would look like this:

```text
+--------------.+
| array_prepend |
+---------------+
| [1, 2, 3]     |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayPrepend(1, array(2, 3))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, YugabyteDB

```sql
array_prepend(
  1,
  ARRAY[2, 3]
)
```

###### BigQuery, H2, HSQLDB, Spanner, Trino

```sql
(ARRAY[1] || ARRAY[2, 3])
```

###### ClickHouse

```sql
arrayPushFront(
  ARRAY(2, 3),
  1
)
```

###### Databricks

```sql
array_prepend(
  ARRAY(2, 3),
  1
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-remove-function"></a>
##### 3.11.20.12. ARRAY_REMOVE

The `ARRAY_REMOVE` function allows for removing all occurrences of an element from an array:

```sql
SELECT array_remove(ARRAY[1, 2, 2, 3], 2)
```

```java
create.select(arrayRemove(array(1, 2, 2, 3), 2)).fetch();
```

The result would look like this:

```text
+--------------+
| array_remove |
+--------------+
| [1, 3]       |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayRemove(array(1, 2, 2, 3), 2)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, Trino, YugabyteDB

```sql
array_remove(
  ARRAY[1, 2, 2, 3],
  2
)
```

###### BigQuery

```sql
(
  SELECT coalesce(
    array_agg(e ORDER BY o),
    cast(ARRAY[] AS array<int64>)
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) AS e WITH OFFSET AS o
  WHERE e <> 2
)
```

###### Databricks

```sql
array_remove(
  ARRAY(1, 2, 2, 3),
  2
)
```

###### DuckDB

```sql
array_filter(
  ARRAY[1, 2, 2, 3],
  LAMBDA e: e <> 2
)
```

###### H2, HSQLDB

```sql
(
  SELECT coalesce(
    array_agg(e),
    cast(ARRAY[] AS int array)
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
  WHERE e <> 2
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-replace-function"></a>
##### 3.11.20.13. ARRAY_REPLACE

The `ARRAY_REPLACE` function allows for replacing all occurrences of an element by another value in an array:

```sql
SELECT array_replace(ARRAY[1, 2, 2, 3], 2, -1)
```

```java
create.select(arrayReplace(array(1, 2, 2, 3), val(2), val(-1))).fetch();
```

The result would look like this:

```text
+----------------+
| array_replace  |
+----------------+
| [1, -1, -1, 3] |
+----------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayReplace(array(1, 2, 2, 3), val(2), val(-1))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
array_replace(
  ARRAY[1, 2, 2, 3],
  2,
  -1
)
```

###### BigQuery

```sql
(
  SELECT coalesce(
    array_agg(
      CASE
        WHEN e IS NOT DISTINCT FROM 2 THEN -1
        ELSE e
      END
     ORDER BY o),
    cast(ARRAY[] AS array<int64>)
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) AS e WITH OFFSET AS o
)
```

###### Databricks

```sql
array_replace(
  ARRAY(1, 2, 2, 3),
  2,
  -1
)
```

###### DuckDB

```sql
array_transform(
  ARRAY[1, 2, 2, 3],
  LAMBDA e: CASE
    WHEN e IS NOT DISTINCT FROM 2 THEN -1
    ELSE e
  END
)
```

###### H2, HSQLDB

```sql
(
  SELECT coalesce(
    array_agg(
      CASE
        WHEN e IS NOT DISTINCT FROM 2 THEN -1
        ELSE e
      END
    ),
    cast(ARRAY[] AS int array)
  )
  FROM UNNEST(ARRAY[1, 2, 2, 3]) t (e)
)
```

###### Trino

```sql
transform(
  ARRAY[1, 2, 2, 3],
  e -> CASE
    WHEN e IS NOT DISTINCT FROM 2 THEN -1
    ELSE e
  END
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-reverse-function"></a>
##### 3.11.20.14. ARRAY_REVERSE

The `ARRAY_REVERSE` function allows for replacing all reversing the order of elements in an array:

```sql
SELECT array_reverse(ARRAY[1, 2, 3])
```

```java
create.select(arrayReverse(array(1, 2, 3))).fetch();
```

The result would look like this:

```text
+---------------+
| array_reverse |
+---------------+
| [3, 2, 1]     |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
arrayReverse(array(1, 2, 3))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, HSQLDB

```sql
CASE
  WHEN ARRAY[1, 2, 3] IS NULL THEN ARRAY[1, 2, 3]
  WHEN cardinality(ARRAY[1, 2, 3]) = 0 THEN ARRAY[1, 2, 3]
  ELSE (
    SELECT array_agg(e ORDER BY o DESC)
    FROM UNNEST(ARRAY[1, 2, 3]) WITH ORDINALITY t (e, o)
  )
END
```

###### BigQuery, Postgres, Spanner

```sql
array_reverse(ARRAY[1, 2, 3])
```

###### Databricks

```sql
CASE
  WHEN ARRAY(1, 2, 3) IS NULL THEN ARRAY(1, 2, 3)
  WHEN cardinality(ARRAY(1, 2, 3)) = 0 THEN ARRAY(1, 2, 3)
  ELSE (
    SELECT array_agg(e ORDER BY o DESC)
    FROM (
      SELECT
        array_table.COLUMN_VALUE,
        row_number() OVER (
          ORDER BY (
            SELECT 1
          )
        ) ordinal
      FROM EXPLODE(ARRAY(1, 2, 3)) array_table (COLUMN_VALUE)
    ) t (e, o)
  )
END
```

###### DuckDB

```sql
CASE
  WHEN ARRAY[1, 2, 3] IS NULL THEN ARRAY[1, 2, 3]
  WHEN array_length(ARRAY[1, 2, 3]) = 0 THEN ARRAY[1, 2, 3]
  ELSE (
    SELECT array_agg(e ORDER BY o DESC)
    FROM (
      SELECT
        array_table.COLUMN_VALUE,
        row_number() OVER () ordinal
      FROM UNNEST(ARRAY[1, 2, 3]) array_table (COLUMN_VALUE)
    ) t (e, o)
  )
END
```

###### Trino

```sql
reverse(ARRAY[1, 2, 3])
```

###### ASE, Access, Aurora MySQL, ClickHouse, CockroachDB, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-constructor"></a>
##### 3.11.20.15. ARRAY constructor

In order to construct an ad-hoc `ARRAY` type from within a SQL query, the `ARRAY` constructor can be used.

```sql
SELECT ARRAY[1, 2]
```

```java
create.select(array(1, 2)).fetch();
```

The result would look like this:

```text
+----------+
| array    |
+----------+
| [ 1, 2 ] |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
array(1, 2)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DuckDB, H2, HSQLDB, Postgres, Spanner, Trino, YugabyteDB

```sql
ARRAY[1, 2]
```

###### ClickHouse, Databricks

```sql
ARRAY(1, 2)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-constructor-subquery"></a>
##### 3.11.20.16. ARRAY constructor from subquery

In order to construct an ad-hoc `ARRAY` type from a subquery, the `ARRAY` constructor can be used.

```sql
SELECT
  AUTHOR.ID,
  ARRAY(
    SELECT ID
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  )
FROM AUTHOR
```

```java
create.select(
  AUTHOR.ID,
  array(
    select(BOOK.ID)
    .from(BOOK)
    .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))))
  .from(AUTHOR)
  .fetch();
```

Unlike [ARRAY_AGG](#array-agg-function), this `ARRAY` constructor does not act as an aggregate function, and thus does not produce aggregate semantics, such as requiring an explicit (or producing an implicit) [GROUP BY clause](#group-by-clause).

The result would look like this:

```text
+----+----------+
| ID |          |
+----+----------+
|  1 | [ 1, 2 ] |
|  2 | [ 3, 4 ] |
+----+----------+
```

###### Dialect support

This example using jOOQ:

```java
array(select(val(1)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DuckDB, Postgres, Spanner, YugabyteDB

```sql
ARRAY(
  SELECT 1
)
```

###### Databricks, H2

```sql
(
  SELECT array_agg(t.c)
  FROM (
    SELECT 1
  ) t (c)
)
```

###### HSQLDB

```sql
ARRAY(
  SELECT 1
  FROM (VALUES (1)) AS dual (dual)
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="cardinality-function"></a>
##### 3.11.20.17. CARDINALITY

The `CARDINALITY` function allows for getting the size of an array.

```sql
SELECT CARDINALITY(ARRAY[1, 2])
```

```java
create.select(cardinality(array(1, 2))).fetch();
```

The result would look like this:

```text
+-------------+
| cardinality |
+-------------+
|           2 |
+-------------+
```

###### Dialect support

This example using jOOQ:

```java
cardinality(array(1, 2))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, HSQLDB, Postgres, Trino, YugabyteDB

```sql
cardinality(ARRAY[1, 2])
```

###### BigQuery, DuckDB, Spanner

```sql
array_length(ARRAY[1, 2])
```

###### ClickHouse

```sql
length(ARRAY(1, 2))
```

###### Databricks

```sql
cardinality(ARRAY(1, 2))
```

###### ASE, Access, Aurora MySQL, CockroachDB, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-functions"></a>
#### 3.11.21. JSON functions

jOOQ 3.12 introduced support for the [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) and [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html) types, which are used to wrap string based JSON documents in a type safe way. With these types, there are also a few standard JSON functions that have been added to the API. This section describes scalar functions, but there are also [conditions](#conditional-expressions), [aggregate functions](#aggregate-functions), and [table valued functions](#table-expressions) for JSON usage.

Most functions are overloaded with a `JSON` and `JSONB` variant to make the distinction explicit for dialects where this matters. For simplicity, and because most dialects do not make a distinction, this manual will only document the `JSON` version of each function.

<a id="json-array-function"></a>
##### 3.11.21.1. JSON_ARRAY

The `JSON_ARRAY` function is used to produce simple JSON arrays from scalar values, without aggregation(see also [JSON_ARRAYAGG](#json-arrayagg-function)).

```sql
SELECT json_array(author.first_name, author.last_name)
FROM author
 
```

```java
create.select(jsonArray(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME))
      .from(AUTHOR)
      .fetch();
```

The result would look like this:

```text
+----------------------+
| json_array           |
+----------------------+
| ["Paulo", "Coelho"]  |
| ["George", "Orwell"] |
+----------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArray(val(1), val(2))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
json_build_array(cast(1 AS int), cast(2 AS int))
```

###### BigQuery, DB2, DuckDB, H2, MariaDB, MySQL, Oracle, SQLServer, SQLite, Spanner

```sql
json_array(1, 2)
```

###### ClickHouse

```sql
toJSONString(tuple(1, 2))
```

###### CockroachDB

```sql
json_build_array(cast(1 AS int4), cast(2 AS int4))
```

###### Databricks

```sql
to_json(ARRAY(
  cast(1 AS variant),
  cast(2 AS variant)
))
```

###### Snowflake

```sql
array_construct(coalesce(
  to_variant(1),
  parse_json('null')
), coalesce(
  to_variant(2),
  parse_json('null')
))
```

###### Trino

```sql
cast(
  ARRAY[
    cast(1 AS json),
    cast(2 AS json)
  ]
  AS json
)
```

###### ASE, Access, Aurora MySQL, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-array-function-absent-on-null"></a>
###### 3.11.21.1.1. ABSENT ON NULL

The `JSON_ARRAY` function has a `ABSENT ON NULL` clause to indicate that `NULL` values should not be contained in the output JSON array. Instead, the value should be removed from the array if it is `NULL`:

```sql
SELECT json_array(
  language.cd, language.description
  ABSENT ON NULL
)
FROM language
```

```java
create.select(jsonArray(
          LANGUAGE.CD,
          LANGUAGE.DESCRIPTION)
          .absentOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+------------------+
| json_array       |
+------------------+
| ["EN","English"] |
| ["DE"]           |
+------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArray(LANGUAGE.CD, LANGUAGE.DESCRIPTION).absentOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
(
  SELECT json_agg(t.a)
  FROM (
    VALUES
      (LANGUAGE.CD),
      (LANGUAGE.DESCRIPTION)
  ) t (a)
  WHERE t.a IS NOT NULL
)
```

###### BigQuery, Spanner

```sql
json_strip_nulls(json_array(LANGUAGE.CD, LANGUAGE.DESCRIPTION))
```

###### DB2

```sql
(
  SELECT json_array(
    LANGUAGE.CD, LANGUAGE.DESCRIPTION
    ABSENT ON NULL
  )
  FROM SYSIBM.DUAL
)
```

###### DuckDB

```sql
cast(
  array_filter(
    ARRAY[
      cast(LANGUAGE.CD AS json),
      cast(LANGUAGE.DESCRIPTION AS json)
    ],
    LAMBDA e: e IS NOT NULL
  )
  AS json
)
```

###### H2, Oracle

```sql
json_array(
  LANGUAGE.CD, LANGUAGE.DESCRIPTION
  ABSENT ON NULL
)
```

###### MariaDB

```sql
coalesce(
  (
    SELECT json_merge_preserve(
      '[]',
      concat(
        '[',
        group_concat(json_extract(value, '$') SEPARATOR ','),
        ']'
      )
    )
    FROM JSON_TABLE(
      json_array(LANGUAGE.CD, LANGUAGE.DESCRIPTION),
      '$[*]'
      COLUMNS (value json PATH '$')
    ) t
    WHERE (
      value <> 'null'
      AND rand() IS NOT NULL
    )
  ),
  json_array()
)
```

###### Snowflake

```sql
array_construct_compact(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
```

###### SQLite

```sql
(
  SELECT json_group_array(value) FILTER (WHERE (
    value IS NOT NULL
    AND key IS NOT NULL
  ))
  FROM json_tree(json_array(LANGUAGE.CD, LANGUAGE.DESCRIPTION))
)
```

###### Trino

```sql
cast(
  filter(
    ARRAY[
      cast(
        cast(LANGUAGE.CD AS varchar)
        AS json
      ),
      cast(LANGUAGE.DESCRIPTION AS json)
    ],
    e -> e IS NOT NULL
  )
  AS json
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-array-function-null-on-null"></a>
###### 3.11.21.1.2. NULL ON NULL

The `JSON_ARRAY` function has a `NULL ON NULL` clause to indicate that `NULL` values be included in the output JSON array:

```sql
SELECT json_array(
  language.cd, language.description
  NULL ON NULL
)
FROM language
```

```java
create.select(jsonArray(
          LANGUAGE.CD, LANGUAGE.DESCRIPTION)
          .nullOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+------------------+
| json_array       |
+------------------+
| ["EN","English"] |
| ["DE", null]     |
+------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArray(LANGUAGE.CD, LANGUAGE.DESCRIPTION).nullOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
json_build_array(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
```

###### BigQuery, DuckDB, MariaDB, MySQL, SQLite, Spanner

```sql
json_array(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
```

###### ClickHouse

```sql
toJSONString(tuple(LANGUAGE.CD, LANGUAGE.DESCRIPTION))
```

###### Databricks

```sql
to_json(ARRAY(
  cast(LANGUAGE.CD AS variant),
  cast(LANGUAGE.DESCRIPTION AS variant)
))
```

###### DB2

```sql
(
  SELECT json_array(
    LANGUAGE.CD, LANGUAGE.DESCRIPTION
    NULL ON NULL
  )
  FROM SYSIBM.DUAL
)
```

###### H2, Oracle, SQLServer

```sql
json_array(
  LANGUAGE.CD, LANGUAGE.DESCRIPTION
  NULL ON NULL
)
```

###### Snowflake

```sql
array_construct(coalesce(
  to_variant(LANGUAGE.CD),
  parse_json('null')
), coalesce(
  to_variant(LANGUAGE.DESCRIPTION),
  parse_json('null')
))
```

###### Trino

```sql
cast(
  ARRAY[
    cast(
      cast(LANGUAGE.CD AS varchar)
      AS json
    ),
    cast(LANGUAGE.DESCRIPTION AS json)
  ]
  AS json
)
```

###### ASE, Access, Aurora MySQL, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-array-length-function"></a>
##### 3.11.21.2. JSON_ARRAY_LENGTH

The `JSON_ARRAY_LENGTH` function is used to count the number of elements in a [JSON_ARRAY](#json-array-function).

```sql
SELECT
  json_array_length(json_array(1, 2))
```

```java
create.select(jsonArrayLength(jsonArray(1, 2)))
      .fetch();
```

The result would look like this:

```text
+-------------------+
| json_array_length |
+-------------------+
|                 1 |
+-------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArrayLength(val(json("[1,2]")))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
json_array_length(cast('[1,2]' AS json))
```

###### BigQuery

```sql
array_length(json_query_array('[1,2]', '$'))
```

###### ClickHouse

```sql
JSONArrayLength('[1,2]')
```

###### Databricks

```sql
json_array_length('[1,2]')
```

###### DuckDB

```sql
json_array_length(JSON '[1,2]')
```

###### MariaDB

```sql
json_length(json_extract('[1,2]', '$'))
```

###### MySQL

```sql
json_length(cast('[1,2]' AS json))
```

###### Oracle

```sql
(
  SELECT count(*)
  FROM JSON_TABLE(
    '[1,2]',
    '$[*]'
    COLUMNS (x varchar2(4000) PATH '$')
  )
)
```

###### SQLite

```sql
json_array_length(JSON('[1,2]'))
```

###### SQLServer

```sql
(
  SELECT count(*)
  FROM openjson('[1,2]')
)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-array-query-function"></a>
##### 3.11.21.3. JSON_ARRAY from query

The `JSON_ARRAY` function is used to produce simple JSON arrays from the result of a single column query.

```sql
SELECT json_array(SELECT id FROM author)
 
```

```java
create.select(jsonArray(select(AUTHOR.ID).from(AUTHOR)))
      .fetch();
```

The result would look like this:

```text
+------------+
| json_array |
+------------+
| [1,2,3,4]  |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArray(select(AUTHOR.ID).from(AUTHOR))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
coalesce(
  json_array(
    SELECT AUTHOR.ID
    FROM AUTHOR
    RETURNING json
  ),
  cast('[]' AS json)
)
```

###### BigQuery, ClickHouse, DB2, H2, Oracle

```sql
json_array(
  SELECT AUTHOR.ID
  FROM AUTHOR
)
```

###### CockroachDB, YugabyteDB

```sql
coalesce(
  (
    SELECT json_agg(a)
    FROM (
      SELECT AUTHOR.ID
      FROM AUTHOR
    ) t (a)
  ),
  cast('[]' AS json)
)
```

###### Databricks

```sql
(
  SELECT to_json(array_agg(a))
  FROM (
    SELECT AUTHOR.ID
    FROM AUTHOR
  ) t (a)
)
```

###### DuckDB

```sql
coalesce(
  (
    SELECT to_json(array_agg(a))
    FROM (
      SELECT AUTHOR.ID
      FROM AUTHOR
    ) t (a)
  ),
  JSON '[]'
)
```

###### MariaDB

```sql
ifnull(
  (
    SELECT json_merge_preserve(
      '[]',
      concat(
        '[',
        group_concat(a SEPARATOR ','),
        ']'
      )
    )
    FROM (
      SELECT AUTHOR.ID a
      FROM AUTHOR
    ) t
  ),
  json_extract('[]', '$')
)
```

###### MySQL

```sql
ifnull(
  (
    SELECT json_merge_preserve(
      '[]',
      concat(
        '[',
        group_concat(a SEPARATOR ','),
        ']'
      )
    )
    FROM (
      SELECT AUTHOR.ID
      FROM AUTHOR
    ) t (a)
  ),
  cast('[]' AS json)
)
```

###### Snowflake

```sql
(
  SELECT array_agg(coalesce(
    to_variant(a),
    parse_json('null')
  ))
  FROM (
    SELECT AUTHOR.ID
    FROM AUTHOR
  ) t (a)
)
```

###### Spanner

```sql
(
  SELECT to_json(
    coalesce(
      array_agg(a), cast(ARRAY[] AS array<int64>)
    )
  )
  FROM (
    SELECT AUTHOR.ID a
    FROM AUTHOR
  ) t
)
```

###### SQLite

```sql
(
  SELECT json_group_array(a)
  FROM (
    SELECT AUTHOR.ID a
    FROM AUTHOR
  ) t
)
```

###### SQLServer

```sql
coalesce(
  (
    SELECT json_arrayagg(a)
    FROM (
      SELECT AUTHOR.ID
      FROM AUTHOR
    ) t (a)
  ),
  '[]'
)
```

###### Trino

```sql
coalesce(
  (
    SELECT cast(array_agg(a) AS json)
    FROM (
      SELECT AUTHOR.ID
      FROM AUTHOR
    ) t (a)
  ),
  json_parse('[]')
)
```

###### ASE, Access, Aurora MySQL, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-array-query-function-absent-on-null"></a>
###### 3.11.21.3.1. ABSENT ON NULL

The `JSON_ARRAY` from query function has a `ABSENT ON NULL` clause to indicate that `NULL` values should not be contained in the output JSON array. Instead, the value should be removed from the array if it is `NULL`:

```sql
SELECT json_array(
  SELECT language.description FROM language
  ABSENT ON NULL
)
```

```java
create.select(jsonArray(
          select(LANGUAGE.CD).from(LANGUAGE))
          .absentOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+-------------+
| json_array  |
+-------------+
| ["English"] |
+-------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArray(select(LANGUAGE.DESCRIPTION).from(LANGUAGE)).absentOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
coalesce(
  json_array(
    SELECT LANGUAGE.DESCRIPTION
    FROM LANGUAGE
    RETURNING json
  ),
  cast('[]' AS json)
)
```

###### BigQuery, DB2, H2, Oracle

```sql
json_array(
  SELECT LANGUAGE.DESCRIPTION
  FROM LANGUAGE
)
```

###### CockroachDB, YugabyteDB

```sql
coalesce(
  (
    SELECT json_agg(a)
    FROM (
      SELECT LANGUAGE.DESCRIPTION
      FROM LANGUAGE
    ) t (a)
  ),
  cast('[]' AS json)
)
```

###### DuckDB

```sql
coalesce(
  (
    SELECT to_json(array_agg(a))
    FROM (
      SELECT LANGUAGE.DESCRIPTION
      FROM LANGUAGE
    ) t (a)
  ),
  JSON '[]'
)
```

###### MariaDB

```sql
ifnull(
  (
    SELECT json_merge_preserve(
      '[]',
      concat(
        '[',
        group_concat(json_quote(a) SEPARATOR ','),
        ']'
      )
    )
    FROM (
      SELECT LANGUAGE.DESCRIPTION a
      FROM LANGUAGE
    ) t
  ),
  json_extract('[]', '$')
)
```

###### Snowflake

```sql
(
  SELECT array_agg(coalesce(
    to_variant(a),
    parse_json('null')
  ))
  FROM (
    SELECT LANGUAGE.DESCRIPTION
    FROM LANGUAGE
  ) t (a)
)
```

###### Spanner

```sql
(
  SELECT to_json(
    coalesce(
      array_agg(a), cast(ARRAY[] AS array<string>)
    )
  )
  FROM (
    SELECT LANGUAGE.DESCRIPTION a
    FROM LANGUAGE
  ) t
)
```

###### SQLite

```sql
(
  SELECT json_group_array(a)
  FROM (
    SELECT LANGUAGE.DESCRIPTION a
    FROM LANGUAGE
  ) t
)
```

###### Trino

```sql
coalesce(
  (
    SELECT cast(array_agg(a) AS json)
    FROM (
      SELECT LANGUAGE.DESCRIPTION
      FROM LANGUAGE
    ) t (a)
  ),
  json_parse('[]')
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-array-query-function-null-on-null"></a>
###### 3.11.21.3.2. NULL ON NULL

The `JSON_ARRAY` from query function has a `NULL ON NULL` clause to indicate that `NULL` values should be included in the output JSON array:

```sql
SELECT json_array(
  SELECT language.description FROM language
  NULL ON NULL
)
FROM language
```

```java
create.select(jsonObject(
          select(LANGUAGE.CD).from(LANGUAGE))
          .nullOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+------------------+
| json_array       |
+------------------+
| ["English",null] |
+------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArray(select(LANGUAGE.DESCRIPTION).from(LANGUAGE)).nullOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
coalesce(
  json_array(
    SELECT LANGUAGE.DESCRIPTION
    FROM LANGUAGE
    RETURNING json
  ),
  cast('[]' AS json)
)
```

###### BigQuery, ClickHouse, DB2, H2, Oracle

```sql
json_array(
  SELECT LANGUAGE.DESCRIPTION
  FROM LANGUAGE
)
```

###### CockroachDB, YugabyteDB

```sql
coalesce(
  (
    SELECT json_agg(a)
    FROM (
      SELECT LANGUAGE.DESCRIPTION
      FROM LANGUAGE
    ) t (a)
  ),
  cast('[]' AS json)
)
```

###### Databricks

```sql
(
  SELECT to_json(array_agg(a))
  FROM (
    SELECT LANGUAGE.DESCRIPTION
    FROM LANGUAGE
  ) t (a)
)
```

###### DuckDB

```sql
coalesce(
  (
    SELECT to_json(array_agg(a))
    FROM (
      SELECT LANGUAGE.DESCRIPTION
      FROM LANGUAGE
    ) t (a)
  ),
  JSON '[]'
)
```

###### MariaDB

```sql
ifnull(
  (
    SELECT json_merge_preserve(
      '[]',
      concat(
        '[',
        group_concat(json_quote(a) SEPARATOR ','),
        ']'
      )
    )
    FROM (
      SELECT LANGUAGE.DESCRIPTION a
      FROM LANGUAGE
    ) t
  ),
  json_extract('[]', '$')
)
```

###### MySQL

```sql
ifnull(
  (
    SELECT json_merge_preserve(
      '[]',
      concat(
        '[',
        group_concat(json_quote(a) SEPARATOR ','),
        ']'
      )
    )
    FROM (
      SELECT LANGUAGE.DESCRIPTION
      FROM LANGUAGE
    ) t (a)
  ),
  cast('[]' AS json)
)
```

###### Snowflake

```sql
(
  SELECT array_agg(coalesce(
    to_variant(a),
    parse_json('null')
  ))
  FROM (
    SELECT LANGUAGE.DESCRIPTION
    FROM LANGUAGE
  ) t (a)
)
```

###### Spanner

```sql
(
  SELECT to_json(
    coalesce(
      array_agg(a), cast(ARRAY[] AS array<string>)
    )
  )
  FROM (
    SELECT LANGUAGE.DESCRIPTION a
    FROM LANGUAGE
  ) t
)
```

###### SQLite

```sql
(
  SELECT json_group_array(a)
  FROM (
    SELECT LANGUAGE.DESCRIPTION a
    FROM LANGUAGE
  ) t
)
```

###### SQLServer

```sql
coalesce(
  (
    SELECT json_arrayagg(a)
    FROM (
      SELECT LANGUAGE.DESCRIPTION
      FROM LANGUAGE
    ) t (a)
  ),
  '[]'
)
```

###### Trino

```sql
coalesce(
  (
    SELECT cast(array_agg(a) AS json)
    FROM (
      SELECT LANGUAGE.DESCRIPTION
      FROM LANGUAGE
    ) t (a)
  ),
  json_parse('[]')
)
```

###### ASE, Access, Aurora MySQL, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-attribute-access"></a>
##### 3.11.21.4. JSON_GET_ATTRIBUTE

JSON object attributes can be accessed by key as follows:

```sql
SELECT
  '{"a":"b"}'::json->'a'
```

```java
create.select(jsonGetAttribute(json("{\"a\":\"b\"}"), "a"))
      .fetch();
```

The result would look like this:

```text
+--------------------+
| json_get_attribute |
+--------------------+
| "b"                |
+--------------------+
```

The API is PostgreSQL inspired, and as such, there are two ways of accessing attributes:

- `->` or with [`jsonGetAttribute()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonGetAttribute(org.jooq.Field,java.lang.String)) / [`jsonbGetAttribute()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonbGetAttribute(org.jooq.Field,java.lang.String)): To produce a [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) or [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html) value
- `->>` or with [`jsonGetAttributeAsText()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonGetAttributeAsText(org.jooq.Field,java.lang.String)) / [`jsonbGetAttributeAsText()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonbGetAttributeAsText(org.jooq.Field,java.lang.String)): To produce a [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) value (see [JSON_GET_ATTRIBUTE_AS_TEXT](#json-attribute-access-as-text))

###### Dialect support

This example using jOOQ:

```java
jsonGetAttribute(json("{\"a\":1}"), "a")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
(cast('{"a":1}' AS json)->'a')
```

###### BigQuery

```sql
('{"a":1}')['a']
```

###### ClickHouse

```sql
JSONExtractRaw('{"a":1}', 'a')
```

###### DB2

```sql
coalesce(
  coalesce(
    json_query(
      '{"a":1}',
      ('$.' || cast('a' AS varchar(3998)))
    ),
    CASE
      WHEN json_value(
        '{"a":1}',
        ('$.' || cast('a' AS varchar(3998)))
        DEFAULT 'empty' ON EMPTY
      ) IS NULL THEN 'null'
    END
  ),
  nvl2(
    json_query(
      '{"a":1}',
      ('$.' || cast('a' AS varchar(3998))) EMPTY ARRAY ON EMPTY
    ),
    NULL,
    'null'
  )
)
```

###### DuckDB

```sql
(JSON '{"a":1}'->'a')
```

###### MariaDB

```sql
json_extract(
  json_extract('{"a":1}', '$'),
  concat('$.', 'a')
)
```

###### MySQL

```sql
json_extract(
  cast('{"a":1}' AS json),
  concat('$.', 'a')
)
```

###### Oracle

```sql
json_query(
  '{"a":1}',
  '$.a'
)
```

###### Snowflake

```sql
get(parse_json('{"a":1}'), 'a')
```

###### Spanner

```sql
(JSON '{"a":1}')['a']
```

###### SQLite

```sql
(JSON('{"a":1}')->'a')
```

###### Trino

```sql
json_extract(
  json_parse('{"a":1}'),
  ('$.' || 'a')
)
```

###### ASE, Access, Aurora MySQL, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLServer, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-attribute-access-as-text"></a>
##### 3.11.21.5. JSON_GET_ATTRIBUTE_AS_TEXT

JSON object attributes can be accessed by key as follows:

```sql
SELECT
  '{"a":"b"}'::json->'a'
```

```java
create.select(jsonGetAttributeAsText(json("{\"a\":\"b\"}"), "a"))
      .fetch();
```

The result would look like this:

```text
+----------------------------+
| json_get_attribute_as_text |
+----------------------------+
| b                          |
+----------------------------+
```

The API is PostgreSQL inspired, and as such, there are two ways of accessing attributes:

- `->` or with [`jsonGetAttribute()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonGetAttribute(org.jooq.Field,java.lang.String)) / [`jsonbGetAttribute()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonbGetAttribute(org.jooq.Field,java.lang.String)): To produce a [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) or [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html) value (see [JSON_GET_ATTRIBUTE](#json-attribute-access))
- `->>` or with [`jsonGetAttributeAsText()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonGetAttributeAsText(org.jooq.Field,java.lang.String)) / [`jsonbGetAttributeAsText()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonbGetAttributeAsText(org.jooq.Field,java.lang.String)): To produce a [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) value

###### Dialect support

This example using jOOQ:

```java
jsonGetAttributeAsText(json("{\"a\":1}"), "a")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
(cast('{"a":1}' AS json)->>'a')
```

###### BigQuery

```sql
coalesce(
  json_value(
    ('{"a":1}')['a'],
    '$'
  ),
  nullif(
    to_json_string(('{"a":1}')['a']),
    'null'
  )
)
```

###### ClickHouse

```sql
JSONExtractString('{"a":1}', 'a')
```

###### Databricks

```sql
get_json_object(
  '{"a":1}',
  ('$.' || 'a')
)
```

###### DB2

```sql
coalesce(
  json_value(
    '{"a":1}',
    ('$.' || cast('a' AS varchar(3998)))
  ),
  json_query(
    '{"a":1}',
    ('$.' || cast('a' AS varchar(3998)))
  )
)
```

###### DuckDB

```sql
(JSON '{"a":1}'->>'a')
```

###### MariaDB

```sql
json_unquote(nullif(
  cast(
    json_extract(
      json_extract('{"a":1}', '$'),
      concat('$.', 'a')
    )
    AS char
  ),
  'null'
))
```

###### MySQL

```sql
json_unquote(nullif(
  json_extract(
    cast('{"a":1}' AS json),
    concat('$.', 'a')
  ),
  cast('null' AS json)
))
```

###### Oracle

```sql
coalesce(
  json_value(
    '{"a":1}',
    '$.a'
  ),
  nullif(
    json_query(
      '{"a":1}',
      '$.a'
    ),
    'null'
  )
)
```

###### Spanner

```sql
coalesce(
  json_value(
    (JSON '{"a":1}')['a'],
    '$'
  ),
  nullif(
    to_json_string((JSON '{"a":1}')['a']),
    'null'
  )
)
```

###### SQLite

```sql
json_extract(
  JSON('{"a":1}'),
  ('$.' || 'a')
)
```

###### SQLServer

```sql
coalesce(
  json_query(
    '{"a":1}',
    ('$.' + 'a')
  ),
  json_value(
    '{"a":1}',
    ('$.' + 'a')
  )
)
```

###### Trino

```sql
coalesce(
  json_extract_scalar(
    json_parse('{"a":1}'),
    ('$.' || 'a')
  ),
  json_format(nullif(
    json_extract(
      json_parse('{"a":1}'),
      ('$.' || 'a')
    ),
    json_parse('null')
  ))
)
```

###### ASE, Access, Aurora MySQL, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-element-access"></a>
##### 3.11.21.6. JSON_GET_ELEMENT

JSON array elements can be accessed by (zero based) index as follows:

```sql
SELECT
  '["a","b","c"]'::json->1
```

```java
create.select(jsonGetElement(json("[\"a\",\"b\",\"c\"]"), 1))
      .fetch();
```

The result would look like this:

```text
+------------------+
| json_get_element |
+------------------+
| "b"              |
+------------------+
```

The API is PostgreSQL inspired, and as such, there are two ways of accessing elements:

- `->` or with [`jsonGetElement()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonGetElement(org.jooq.Field,int)) / [`jsonbGetElement()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonbGetElement(org.jooq.Field,int)): To produce a [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) or [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html) value
- `->>` or with [`jsonGetElementAsText()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonGetElementAsText(org.jooq.Field,int)) / [`jsonbGetElementAsText()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonbGetElementAsText(org.jooq.Field,int)): To produce a [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) value (see [JSON_GET_ELEMENT_AS_TEXT](#json-element-access-as-text))

###### Dialect support

This example using jOOQ:

```java
jsonGetElement(json("[1,2,3]"), 1)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
(cast('[1,2,3]' AS json)->1)
```

###### BigQuery

```sql
('[1,2,3]')[1]
```

###### ClickHouse

```sql
JSONExtractRaw(
  '[1,2,3]',
  (1 + 1)
)
```

###### DB2

```sql
coalesce(
  json_query(
    '[1,2,3]',
    ('$.' || cast(1 AS varchar(3998)))
  ),
  CASE
    WHEN json_value(
      '[1,2,3]',
      ('$.' || cast(1 AS varchar(3998)))
      DEFAULT 'empty' ON EMPTY
    ) IS NULL THEN 'null'
  END
)
```

###### DuckDB

```sql
(JSON '[1,2,3]'->1)
```

###### MariaDB

```sql
json_extract(
  json_extract('[1,2,3]', '$'),
  concat(
    '$[',
    cast(1 AS char),
    ']'
  )
)
```

###### MySQL

```sql
json_extract(
  cast('[1,2,3]' AS json),
  concat(
    '$[',
    cast(1 AS char),
    ']'
  )
)
```

###### Oracle

```sql
json_query(
  '[1,2,3]',
  '$[1]'
)
```

###### Snowflake

```sql
get(parse_json('[1,2,3]'), 1)
```

###### Spanner

```sql
(JSON '[1,2,3]')[1]
```

###### SQLite

```sql
(JSON('[1,2,3]')->1)
```

###### Trino

```sql
json_extract(
  json_parse('[1,2,3]'),
  ('$[' || cast(1 AS varchar) || ']')
)
```

###### ASE, Access, Aurora MySQL, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLServer, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-element-access-as-text"></a>
##### 3.11.21.7. JSON_GET_ELEMENT_AS_TEXT

JSON array elements can be accessed by (zero based) index as follows:

```sql
SELECT
  '["a","b","c"]'::json->1
```

```java
create.select(jsonGetElement(json("[\"a\",\"b\",\"c\"]"), 1))
      .fetch();
```

The result would look like this:

```text
+--------------------------+
| json_get_element_as_text |
+--------------------------+
| b                        |
+--------------------------+
```

The API is PostgreSQL inspired, and as such, there are two ways of accessing elements:

- `->` or with [`jsonGetElement()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonGetElement(org.jooq.Field,int)) / [`jsonbGetElement()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonbGetElement(org.jooq.Field,int)): To produce a [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) or [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html) value (see [JSON_GET_ELEMENT](#json-element-access))
- `->>` or with [`jsonGetElementAsText()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonGetElementAsText(org.jooq.Field,int)) / [`jsonbGetElementAsText()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#jsonbGetElementAsText(org.jooq.Field,int)): To produce a [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) value

###### Dialect support

This example using jOOQ:

```java
jsonGetElement(json("[1,2,3]"), 1)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
(cast('[1,2,3]' AS json)->1)
```

###### BigQuery

```sql
('[1,2,3]')[1]
```

###### ClickHouse

```sql
JSONExtractRaw(
  '[1,2,3]',
  (1 + 1)
)
```

###### DB2

```sql
coalesce(
  json_query(
    '[1,2,3]',
    ('$.' || cast(1 AS varchar(3998)))
  ),
  CASE
    WHEN json_value(
      '[1,2,3]',
      ('$.' || cast(1 AS varchar(3998)))
      DEFAULT 'empty' ON EMPTY
    ) IS NULL THEN 'null'
  END
)
```

###### DuckDB

```sql
(JSON '[1,2,3]'->1)
```

###### MariaDB

```sql
json_extract(
  json_extract('[1,2,3]', '$'),
  concat(
    '$[',
    cast(1 AS char),
    ']'
  )
)
```

###### MySQL

```sql
json_extract(
  cast('[1,2,3]' AS json),
  concat(
    '$[',
    cast(1 AS char),
    ']'
  )
)
```

###### Oracle

```sql
json_query(
  '[1,2,3]',
  '$[1]'
)
```

###### Snowflake

```sql
get(parse_json('[1,2,3]'), 1)
```

###### Spanner

```sql
(JSON '[1,2,3]')[1]
```

###### SQLite

```sql
(JSON('[1,2,3]')->1)
```

###### Trino

```sql
json_extract(
  json_parse('[1,2,3]'),
  ('$[' || cast(1 AS varchar) || ']')
)
```

###### ASE, Access, Aurora MySQL, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLServer, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-insert-function"></a>
##### 3.11.21.8. JSON_INSERT

The MySQL style `JSON_INSERT` function is a function that adds but doesn't replace ([JSON_REPLACE](#json-replace-function)) a value in a JSON document, given a JSON path.

```sql
SELECT
  JSON_INSERT('{"a":1}', '$.a', 2),
  JSON_INSERT('{"a":1}', '$.b', 2)
```

```java
create.select(
           jsonInsert(val(json("{\"a\":1}")), "$.a", 2),
           jsonInsert(val(json("{\"a\":1}")), "$.b", 2)).fetch();
```

The result would look like this:

```text
+-------------+---------------+
| json_insert | json_insert   |
+-------------+---------------+
| {"a":1}     | {"a":1,"b":2} |
+-------------+---------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonInsert(val(json("{\"a\":2}")), "$.a", 2)
```

Translates to the following dialect specific expressions:

###### BigQuery

```sql
json_array_insert('{"a":2}', '$.a', 2)
```

###### MariaDB

```sql
json_insert(json_extract('{"a":2}', '$'), '$.a', 2)
```

###### MySQL

```sql
json_insert(cast('{"a":2}' AS json), '$.a', 2)
```

###### Oracle

```sql
json_transform('{"a":2}', INSERT '$.a' = 2 IGNORE ON EXISTING)
```

###### Spanner

```sql
json_array_insert(JSON '{"a":2}', '$.a', 2)
```

###### SQLite

```sql
json_insert(JSON('{"a":2}'), '$.a', 2)
```

###### SQLServer

```sql
CASE
  WHEN coalesce(
    json_query('{"a":2}', '$.a'),
    json_value('{"a":2}', '$.a')
  ) IS NOT NULL THEN '{"a":2}'
  ELSE json_modify(
    json_modify('{"a":2}', '$.a', ''),
    ('strict ' + '$.a'),
    2
  )
END
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Postgres, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-key-exists-function"></a>
##### 3.11.21.9. JSON_KEY_EXISTS

The `JSON_KEY_EXISTS` function is a non-standard JSON function inspired by PostgreSQL's `JSONB_EXISTS` function or `?` operator, which can be used to check for the existence of a key in a [JSON object](#json-object-function).

```sql
SELECT json_key_exists(json_object(
  KEY 'a' VALUE 1
), 'a')
```

```java
create.select(jsonKeyExists(jsonObject(
          key("a").value(1)), "a"))
      .fetch();
```

The result would look like this:

```text
+-----------------+
| json_key_exists |
+-----------------+
| true            |
+-----------------+
```

This is simply a less powerful version of the standard SQL [JSON_EXISTS](#json-exists-predicate) predicate, which can work with JSON paths, not just key names.

###### Dialect support

This example using jOOQ:

```java
jsonKeyExists(jsonObject(key("a").value(1)), "a")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
(cast(
  json_build_object('a', cast(1 AS int))
  AS jsonb
) ?? 'a')
```

###### BigQuery, Spanner

```sql
(json_object('a', 1))['a'] IS NOT NULL
```

###### ClickHouse

```sql
JSONExtractRaw(
  toJSONString(map('a', 1)),
  'a'
) IS NOT NULL
```

###### CockroachDB

```sql
(json_build_object('a', cast(1 AS int4)) ?? 'a')
```

###### DB2

```sql
coalesce(
  coalesce(
    json_query(
      json_object(KEY 'a' VALUE 1),
      ('$.' || cast('a' AS varchar(3998)))
    ),
    CASE
      WHEN json_value(
        json_object(KEY 'a' VALUE 1),
        ('$.' || cast('a' AS varchar(3998)))
        DEFAULT 'empty' ON EMPTY
      ) IS NULL THEN 'null'
    END
  ),
  nvl2(
    json_query(
      json_object(KEY 'a' VALUE 1),
      ('$.' || cast('a' AS varchar(3998))) EMPTY ARRAY ON EMPTY
    ),
    NULL,
    'null'
  )
) IS NOT NULL
```

###### DuckDB, SQLite

```sql
(json_object('a', 1)->'a') IS NOT NULL
```

###### MariaDB, MySQL

```sql
json_extract(
  json_object('a', 1),
  concat('$.', 'a')
) IS NOT NULL
```

###### Oracle

```sql
json_query(
  json_object(KEY 'a' VALUE 1),
  '$.a'
) IS NOT NULL
```

###### Snowflake

```sql
get(
  object_construct_keep_null('a', 1),
  'a'
) IS NOT NULL
```

###### Trino

```sql
json_extract(
  cast(
    map_from_entries(ARRAY[row(
      'a',
      cast(1 AS json)
    )])
    AS json
  ),
  ('$.' || 'a')
) IS NOT NULL
```

###### ASE, Access, Aurora MySQL, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLServer, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-keys-function"></a>
##### 3.11.21.10. JSON_KEYS

The `JSON_KEYS` function is a non-standard JSON function inspired by MySQL's `JSON_KEYS` function, which can be used to extract keys of a [JSON object](#json-object-function) into an [JSON array](#json-array-function).

```sql
SELECT json_keys(json_object(
  KEY 'a' VALUE 1
  KEY 'b' VALUE 2
))
```

```java
create.select(jsonKeys(jsonObject(
          key("a").value(1),
          key("b").value(2))))
      .fetch();
```

The result would look like this:

```text
+-----------+
| json_keys |
+-----------+
| ["a","b"] |
+-----------+
```

###### Dialect support

This example using jOOQ:

```java
jsonKeys(jsonObject(key("a").value(1), key("b").value(2)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
(
  SELECT coalesce(
    json_agg(j),
    json_build_array()
  )
  FROM json_object_keys(json_build_object(
    'a', cast(1 AS int),
    'b', cast(2 AS int)
  )) as j(j)
)
```

###### ClickHouse

```sql
toJSONString(JSONExtractKeys(jsonMergePatch(
  toJSONString(map('a', 1)),
  toJSONString(map('b', 2))
)))
```

###### CockroachDB

```sql
(
  SELECT coalesce(
    json_agg(j),
    json_build_array()
  )
  FROM json_object_keys(json_build_object(
    'a', cast(1 AS int4),
    'b', cast(2 AS int4)
  )) as j(j)
)
```

###### Databricks

```sql
to_json(json_object_keys(to_json(map_from_entries(ARRAY(
  struct(
    'a',
    cast(1 AS variant)
  ),
  struct(
    'b',
    cast(2 AS variant)
  )
)))))
```

###### DuckDB

```sql
to_json(json_keys(json_object(
  'a', 1,
  'b', 2
)))
```

###### MariaDB

```sql
json_keys(json_merge_preserve(
  '{}',
  json_object('a', 1),
  json_object('b', 2)
))
```

###### MySQL

```sql
json_keys(json_object(
  'a', 1,
  'b', 2
))
```

###### Oracle

```sql
json_keys(json_object(
  KEY 'a' VALUE 1,
  KEY 'b' VALUE 2
))
```

###### Snowflake

```sql
object_keys(object_construct_keep_null(
  'a', 1,
  'b', 2
))
```

###### SQLite

```sql
(
  SELECT json_group_array(key)
  FROM json_each(json_object(
    'a', 1,
    'b', 2
  ))
)
```

###### Trino

```sql
cast(
  map_keys(cast(cast(
    map_from_entries(ARRAY[
      row(
        'a',
        cast(1 AS json)
      ),
      row(
        'b',
        cast(2 AS json)
      )
    ])
    AS json
  ) as map(varchar, json)))
  AS json
)
```

###### ASE, Access, Aurora MySQL, BigQuery, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLServer, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-object-function"></a>
##### 3.11.21.11. JSON_OBJECT

The `JSON_OBJECT` function is used to produce simple JSON objects from scalar values, without aggregation(see also [JSON_OBJECTAGG](#json-objectagg-function))

```sql
SELECT json_object(
  KEY 'firstName' VALUE author.first_name,
  KEY 'lastName'  VALUE author.last_name
)
FROM author
```

```java
create.select(jsonObject(
          key("firstName").value(AUTHOR.FIRST_NAME),
          key("lastName").value(AUTHOR.LAST_NAME)))
      .from(AUTHOR)
      .fetch();
```

The result would look like this:

```text
+--------------------------------------------+
| json_object                                |
+--------------------------------------------+
| {"firstName":"Paulo","lastName":"Coelho"}  |
| {"firstName":"George","lastName":"Orwell"} |
+--------------------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonObject("firstName", AUTHOR.FIRST_NAME)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
json_build_object('firstName', AUTHOR.FIRST_NAME)
```

###### BigQuery, DuckDB, MariaDB, MySQL, SQLite, Spanner

```sql
json_object('firstName', AUTHOR.FIRST_NAME)
```

###### ClickHouse

```sql
toJSONString(map('firstName', AUTHOR.FIRST_NAME))
```

###### Databricks

```sql
to_json(map_from_entries(ARRAY(struct(
  'firstName',
  cast(AUTHOR.FIRST_NAME AS variant)
))))
```

###### DB2, H2, Oracle

```sql
json_object(KEY 'firstName' VALUE AUTHOR.FIRST_NAME)
```

###### Snowflake

```sql
object_construct_keep_null('firstName', AUTHOR.FIRST_NAME)
```

###### SQLServer

```sql
json_object('firstName': AUTHOR.FIRST_NAME)
```

###### Trino

```sql
cast(
  map_from_entries(ARRAY[row(
    'firstName',
    cast(AUTHOR.FIRST_NAME AS json)
  )])
  AS json
)
```

###### ASE, Access, Aurora MySQL, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-object-function-absent-on-null"></a>
###### 3.11.21.11.1. ABSENT ON NULL

The `JSON_OBJECT` function has a `ABSENT ON NULL` clause to indicate that `NULL` values should not be contained in the output JSON document. Instead, the key should be removed from the document if the value is `NULL`:

```sql
SELECT json_object(
  KEY 'cd' VALUE language.cd,
  KEY 'desc' VALUE language.description
  ABSENT ON NULL
)
FROM language
```

```java
create.select(jsonObject(
          key("cd").value(LANGUAGE.CD),
          key("desc").value(LANGUAGE.DESCRIPTION))
          .absentOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+------------------------------+
| json_object                  |
+------------------------------+
| {"cd":"EN","desc":"English"} |
| {"cd":"DE"}                  |
+------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonObject("description", LANGUAGE.DESCRIPTION).absentOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
json_strip_nulls(json_build_object('description', LANGUAGE.DESCRIPTION))
```

###### BigQuery, Spanner

```sql
json_strip_nulls(json_object('description', LANGUAGE.DESCRIPTION))
```

###### DB2, H2, Oracle

```sql
json_object(
  KEY 'description' VALUE LANGUAGE.DESCRIPTION
  ABSENT ON NULL
)
```

###### DuckDB

```sql
cast(
  map_from_entries(array_filter(
    ARRAY[row(
      'description',
      cast(LANGUAGE.DESCRIPTION AS json)
    )],
    LAMBDA e: e[2] IS NOT NULL
  ))
  AS json
)
```

###### MariaDB

```sql
json_object('description', LANGUAGE.DESCRIPTION)
```

###### MySQL

```sql
(
  SELECT coalesce(
    json_objectagg(jt.k, json_extract(
      j.o,
      concat('$."', jt.k, '"')
    )),
    json_object()
  )
  FROM
    (
      SELECT json_object('description', LANGUAGE.DESCRIPTION) o
    ) j,
    JSON_TABLE(
      json_keys(j.o),
      '$[*]'
      COLUMNS (k text PATH '$')
    ) jt
  WHERE json_extract(
    j.o,
    concat('$."', jt.k, '"')
  ) <> cast('null' AS json)
)
```

###### Snowflake

```sql
object_construct('description', LANGUAGE.DESCRIPTION)
```

###### SQLite

```sql
(
  SELECT json_group_object(key, value) FILTER (WHERE (
    value IS NOT NULL
    AND key IS NOT NULL
  ))
  FROM json_tree(json_object('description', LANGUAGE.DESCRIPTION))
)
```

###### SQLServer

```sql
json_object(
  'description': LANGUAGE.DESCRIPTION
  ABSENT ON NULL
)
```

###### Trino

```sql
cast(
  map_from_entries(filter(
    ARRAY[row(
      'description',
      cast(LANGUAGE.DESCRIPTION AS json)
    )],
    e -> e[2] IS NOT NULL
  ))
  AS json
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-object-function-null-on-null"></a>
###### 3.11.21.11.2. NULL ON NULL

The `JSON_OBJECT` function has a `NULL ON NULL` clause to indicate that `NULL` values should be included in the output JSON document:

```sql
SELECT json_object(
  KEY 'cd' VALUE language.cd,
  KEY 'desc' VALUE language.description
  NULL ON NULL
)
FROM language
```

```java
create.select(jsonObject(
          key("cd").value(LANGUAGE.CD),
          key("desc").value(LANGUAGE.DESCRIPTION))
          .nullOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+------------------------------+
| json_object                  |
+------------------------------+
| {"cd":"EN","desc":"English"} |
| {"cd":"DE","desc":null}      |
+------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonObject("description", LANGUAGE.DESCRIPTION).nullOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
json_build_object('description', LANGUAGE.DESCRIPTION)
```

###### BigQuery, DuckDB, MariaDB, MySQL, SQLite, Spanner

```sql
json_object('description', LANGUAGE.DESCRIPTION)
```

###### ClickHouse

```sql
toJSONString(map('description', LANGUAGE.DESCRIPTION))
```

###### Databricks

```sql
to_json(map_from_entries(ARRAY(struct(
  'description',
  cast(LANGUAGE.DESCRIPTION AS variant)
))))
```

###### DB2, H2, Oracle

```sql
json_object(
  KEY 'description' VALUE LANGUAGE.DESCRIPTION
  NULL ON NULL
)
```

###### Snowflake

```sql
object_construct_keep_null('description', LANGUAGE.DESCRIPTION)
```

###### SQLServer

```sql
json_object(
  'description': LANGUAGE.DESCRIPTION
  NULL ON NULL
)
```

###### Trino

```sql
cast(
  map_from_entries(ARRAY[row(
    'description',
    cast(LANGUAGE.DESCRIPTION AS json)
  )])
  AS json
)
```

###### ASE, Access, Aurora MySQL, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-query-function"></a>
##### 3.11.21.12. JSON_QUERY

The `JSON_QUERY` function is used to extract document (non-scalar) content from JSON documents using a JSON path expression.

```sql
SELECT json_query(
  '{"a":[1,2,3]}',
  '$.a'
)
FROM dual
```

```java
create.select(jsonQuery(
          val(JSON.valueOf("{\"a\":[1,2,3]}")),
          "$.a"
      )
      .fetch();
```

The result would look like this:

```text
+------------+
| json_query |
+------------+
| [1,2,3]    |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonQuery(val(json("[1,2]")), "$[*]")
```

Translates to the following dialect specific expressions:

###### BigQuery, Databricks, Oracle, SQLServer

```sql
json_query('[1,2]', '$[*]')
```

###### ClickHouse

```sql
JSON_QUERY('[1,2]', '$[*]')
```

###### DB2

```sql
coalesce(
  json_query('[1,2]', '$[*]'),
  CASE
    WHEN json_value('[1,2]', '$[*]' DEFAULT 'empty' ON EMPTY) IS NULL THEN 'null'
  END
)
```

###### DuckDB

```sql
json_extract(JSON '[1,2]', '$[*]')
```

###### MariaDB

```sql
json_extract(json_extract('[1,2]', '$'), '$[*]')
```

###### MySQL

```sql
json_extract(cast('[1,2]' AS json), '$[*]')
```

###### Postgres

```sql
json_query(cast('[1,2]' AS json), '$[*]')
```

###### Spanner

```sql
json_query(JSON '[1,2]', '$[*]')
```

###### SQLite

```sql
(JSON('[1,2]')->'$[*]')
```

###### YugabyteDB

```sql
jsonb_path_query_first(
  cast('[1,2]' AS jsonb),
  cast('$[*]' as jsonpath)
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, CockroachDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-remove-function"></a>
##### 3.11.21.13. JSON_REMOVE

The MySQL style `JSON_REMOVE` function is a function that removes a value from a JSON document, given a JSON path.

```sql
SELECT
  JSON_REMOVE('{"a":1}', '$.a'),
  JSON_REMOVE('{"a":1}', '$.b')
```

```java
create.select(
           jsonRemove(val(json("{\"a\":1}")), "$.a"),
           jsonRemove(val(json("{\"a\":1}")), "$.b")).fetch();
```

The result would look like this:

```text
+-------------+-------------+
| json_remove | json_remove |
+-------------+-------------+
| {}          | {"a":1}     |
+-------------+-------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonRemove(val(json("{\"a\":1}")), "$.a")
```

Translates to the following dialect specific expressions:

###### BigQuery

```sql
json_remove('{"a":1}', '$.a')
```

###### MariaDB

```sql
json_remove(json_extract('{"a":1}', '$'), '$.a')
```

###### MySQL

```sql
json_remove(cast('{"a":1}' AS json), '$.a')
```

###### Oracle

```sql
json_transform('{"a":1}', REMOVE '$.a')
```

###### Spanner

```sql
json_remove(JSON '{"a":1}', '$.a')
```

###### SQLite

```sql
json_remove(JSON('{"a":1}'), '$.a')
```

###### SQLServer

```sql
json_modify('{"a":1}', '$.a', NULL)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Postgres, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-replace-function"></a>
##### 3.11.21.14. JSON_REPLACE

The MySQL style `JSON_REPLACE` function is a function that does not add add (like [JSON_INSERT](#json-insert-function)) but replaces a value in a JSON document, given a JSON path.

```sql
SELECT
  JSON_REPLACE('{"a":1}', '$.a', 2),
  JSON_REPLACE('{"a":1}', '$.b', 2)
```

```java
create.select(
           jsonReplace(val(json("{\"a\":1}")), "$.a", 2),
           jsonReplace(val(json("{\"a\":1}")), "$.b", 2)).fetch();
```

The result would look like this:

```text
+--------------+--------------+
| json_replace | json_replace |
+--------------+--------------+
| {"a":2}      | {"a":1}      |
+--------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonReplace(val(json("{\"a\":1}")), "$.a", 2)
```

Translates to the following dialect specific expressions:

###### MariaDB

```sql
json_replace(json_extract('{"a":1}', '$'), '$.a', 2)
```

###### MySQL

```sql
json_replace(cast('{"a":1}' AS json), '$.a', 2)
```

###### Oracle

```sql
json_transform('{"a":1}', REPLACE '$.a' = 2)
```

###### SQLite

```sql
json_replace(JSON('{"a":1}'), '$.a', 2)
```

###### SQLServer

```sql
CASE
  WHEN coalesce(
    json_query('{"a":1}', '$.a'),
    json_value('{"a":1}', '$.a')
  ) IS NULL THEN '{"a":1}'
  ELSE json_modify(
    json_modify('{"a":1}', '$.a', ''),
    ('strict ' + '$.a'),
    2
  )
END
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Postgres, Redshift, SQLDataWarehouse, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-set-function"></a>
##### 3.11.21.15. JSON_SET

The MySQL style `JSON_SET` function is a function that adds (like [JSON_INSERT](#json-insert-function)) or replaces ([JSON_REPLACE](#json-replace-function)) a value in a JSON document, given a JSON path.

```sql
SELECT
  JSON_SET('{"a":1}', '$.a', 2),
  JSON_SET('{"a":1}', '$.b', 2)
```

```java
create.select(
           jsonSet(val(json("{\"a\":1}")), "$.a", 2),
           jsonSet(val(json("{\"a\":1}")), "$.b", 2)).fetch();
```

The result would look like this:

```text
+----------+---------------+
| json_set | json_set      |
+----------+---------------+
| {"a":2}  | {"a":1,"b":2} |
+----------+---------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonSet(val(json("{\"a\":1}")), "$.a", 2)
```

Translates to the following dialect specific expressions:

###### BigQuery

```sql
json_set('{"a":1}', '$.a', 2)
```

###### MariaDB

```sql
json_set(json_extract('{"a":1}', '$'), '$.a', 2)
```

###### MySQL

```sql
json_set(cast('{"a":1}' AS json), '$.a', 2)
```

###### Oracle

```sql
json_transform('{"a":1}', SET '$.a' = 2)
```

###### Spanner

```sql
json_set(JSON '{"a":1}', '$.a', 2)
```

###### SQLite

```sql
json_set(JSON('{"a":1}'), '$.a', 2)
```

###### SQLServer

```sql
json_modify(
  json_modify('{"a":1}', '$.a', ''),
  ('strict ' + '$.a'),
  2
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Postgres, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-value-function"></a>
##### 3.11.21.16. JSON_VALUE

The `JSON_VALUE` function is used to extract scalar content from JSON documents using a JSON path expression.

```sql
SELECT json_value(
  '{"a":[1,2,3]}',
  '$.a[1]'
)
FROM dual
```

```java
create.select(jsonValue(
          val(JSON.valueOf("{\"a\":[1,2,3]}")),
          "$.a[1]"
      )
      .fetch();
```

The result would look like this:

```text
+------------+
| json_value |
+------------+
| 2          |
+------------+
```

If the value does not matter, but you just want to check for a value's existence, use the [JSON_EXISTS predicate](#json-exists-predicate).

###### Dialect support

This example using jOOQ:

```java
jsonValue(val(json("[1,2]")), "$[*]")
```

Translates to the following dialect specific expressions:

###### BigQuery, DB2, Databricks, Oracle

```sql
json_value('[1,2]', '$[*]')
```

###### ClickHouse

```sql
JSON_VALUE('[1,2]', '$[*]')
```

###### DuckDB

```sql
json_extract_string(JSON '[1,2]', '$[*]')
```

###### MariaDB

```sql
json_value(json_extract('[1,2]', '$'), '$[*]')
```

###### MySQL

```sql
json_extract(cast('[1,2]' AS json), '$[*]')
```

###### Postgres, YugabyteDB

```sql
jsonb_path_query_first(
  cast('[1,2]' AS jsonb),
  cast('$[*]' as jsonpath)
)
```

###### Spanner

```sql
json_value(JSON '[1,2]', '$[*]')
```

###### SQLite

```sql
json_extract(JSON('[1,2]'), '$[*]')
```

###### SQLServer

```sql
(
  SELECT c
  FROM openjson('[1,2]', '$') WITH (c varchar(max) '$[*]')
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, CockroachDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-functions"></a>
#### 3.11.22. XML functions

jOOQ 3.14 introduced support for the [`org.jooq.XML`](https://www.jooq.org/javadoc/3.22.x/org/jooq/XML.html) type, which are used to wrap string based XML documents in a type safe way. With this type, there are also a few standard XML functions that have been added to the API. This section describes scalar functions, but there are also [conditions](#conditional-expressions), [aggregate functions](#aggregate-functions), and [table valued functions](#table-expressions) for XML usage.

Notice that XML is case sensitive in all dialects, but SQL identifiers may not be. jOOQ by default produces quoted identifiers (see the [RenderQuotedNames Setting](#settings-name-style)), which maintains the case you provide in Java.

<a id="xml-attributes-function"></a>
##### 3.11.22.1. XMLATTRIBUTES

The `XMLATTRIBUTES()` function is used to create attributes inside of [XMLELEMENT()](#xml-element-function).

```sql
SELECT xmlelement(
  NAME element,
  xmlattributes('value' AS attr)
)
```

```java
create.select(xmlelement("element",
        xmlattributes(val("value").as("attr"))
      ))
      .fetch();
```

The result would look like this:

```text
+-------------------------+
| xmlelement              |
+-------------------------+
| <element attr="value"/> |
+-------------------------+
```

###### Dialect support

This example using jOOQ:

```java
xmlelement("e", xmlattributes(val("value").as("attr")))
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres, Teradata

```sql
xmlelement(
  NAME e,
  xmlattributes('value' AS attr)
)
```

###### SQLServer

```sql
(
  SELECT
    1 tag,
    NULL parent,
    'value' [e!1!attr]
  FOR XML EXPLICIT, TYPE
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-comment-function"></a>
##### 3.11.22.2. XMLCOMMENT

The `XMLCOMMENT()` function is used to create comments inside XML documents, at arbitrary positions.

```sql
SELECT xmlcomment('comment')
 
```

```java
create.select(xmlcomment("comment"))
      .fetch();
```

The result would look like this:

```text
+----------------+
| xmlcomment     |
+----------------+
| <!--comment--> |
+----------------+
```

###### Dialect support

This example using jOOQ:

```java
xmlcomment("comment")
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres, Teradata

```sql
xmlcomment('comment')
```

###### SQLServer

```sql
cast(
  ('<!--' + 'comment' + '-->')
  AS xml
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-concat-function"></a>
##### 3.11.22.3. XMLCONCAT

The `XMLCONCAT()` function is used to concatenate two XML fragments of arbitrary type

```sql
SELECT xmlconcat(
  xmlelement(NAME e1),
  xmlelement(NAME e2)
)
```

```java
create.select(xmlconcat(
         xmlelement("e1"),
         xmlelement("e2")))
      .fetch();
```

The result would look like this:

```text
+------------+
| xmlconcat  |
+------------+
| <e1/><e2/> |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
xmlconcat(xmlelement("e1"), xmlelement("e2"))
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres, Teradata

```sql
xmlconcat(
  xmlelement(NAME e1),
  xmlelement(NAME e2)
)
```

###### SQLServer

```sql
(
  SELECT
    (
      SELECT
        1 tag,
        NULL parent,
        NULL [e1!1]
      FOR XML EXPLICIT, TYPE
    ),
    (
      SELECT
        1 tag,
        NULL parent,
        NULL [e2!1]
      FOR XML EXPLICIT, TYPE
    )
  FOR XML PATH (''), TYPE
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-document-function"></a>
##### 3.11.22.4. XMLDOCUMENT

The `XMLDOCUMENT()` function is used to produce an XML document from document contents, useful in dialects where this is required in some cases.

```sql
SELECT xmldocument(xmlelement(NAME e1))
FROM sysibm.dual
```

```java
create.select(xmldocument(xmlelement("e1")))
      .fetch();
```

The result would look like this:

```text
+--------------+
| xmldocument  |
+--------------+
| <e1/>        |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
xmldocument(xmlelement("e1"))
```

Translates to the following dialect specific expressions:

###### DB2, Teradata

```sql
xmldocument(xmlelement(NAME e1))
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-element-function"></a>
##### 3.11.22.5. XMLELEMENT

The `XMLELEMENT()` function is used to create XML elements, possibly with attributes (see [XMLATTRIBUTES()](#xml-attributes-function))

```sql
SELECT
  xmlelement(NAME e1) AS e1,
  xmlelement(NAME e2, xmlattributes('1' AS a)) AS e2,
  xmlelement(NAME e3, 'text-content') AS e3,
  xmlelement(NAME e4, xmlelement(NAME nested)) AS e4
 
```

```java
create.select(
         xmlelement("e1").as("e1"),
         xmlelement("e2", xmlattributes(val("1").as("a"))).as("e2"),
         xmlelement("e3", val("text-content")).as("e3"),
         xmlelement("e4", xmlelement("nested")).as("e4"))
      .fetch();
```

The result would look like this:

```text
+-------+-------------+-----------------------+--------------------+
| e1    | e2          | e3                    | e4                 |
+-------+-------------+-----------------------+--------------------+
| <e1/> | <e2 a="1"/> | <e3>text-content</e3> | <e4><nested/></e4> |
+-------+-------------+-----------------------+--------------------+
```

###### Dialect support

This example using jOOQ:

```java
xmlelement("e1", val("text-content"))
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres, Teradata

```sql
xmlelement(NAME e1, 'text-content')
```

###### SQLServer

```sql
(
  SELECT
    1 tag,
    NULL parent,
    'text-content' [e1!1]
  FOR XML EXPLICIT, TYPE
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-forest-function"></a>
##### 3.11.22.6. XMLFOREST

The `XMLFOREST()` function is used to create XML forests from other elements

```sql
SELECT xmlforest(
  xmlelement(NAME e1) AS w1,
  xmlelement(NAME e2) AS w2
)
```

```java
create.select(xmlforest(
         xmlelement("e1").as("w1"),
         xmlelement("e2").as("w2")))
      .fetch();
```

The result would look like this:

```text
+------------------------------+
| xmlforest                    |
+------------------------------+
| <w1><e1/></w1><w2><e2/></w2> |
+------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
xmlforest(xmlelement("e1").as("w1"), xmlelement("e2").as("w2"))
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres, Teradata

```sql
xmlforest(
  xmlelement(NAME e1) AS w1,
  xmlelement(NAME e2) AS w2
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-parse-function"></a>
##### 3.11.22.7. XMLPARSE

The `XMLPARSE()` function allows for explicit parsing of XML documents or elements for further processing, when implicit conversion from strings is not possible, or when it leads to more clarity.

```sql
SELECT
  xmlparse(document '<d/>') AS d,
  xmlparse(element '<e/>') AS e
 
```

```java
create.select(
         xmlparseDocument("<d/>").as("d"),
         xmlparseElement("<e/>").as("e"))
      .fetch();
```

The result would look like this:

```text
+------+------+
| d    | e    |
+------+------+
| <d/> | <e/> |
+------+------+
```

###### Dialect support

This example using jOOQ:

```java
xmlparseDocument("<d/>")
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres

```sql
xmlparse(DOCUMENT '<d/>')
```

###### Teradata

```sql
xmlparse(DOCUMENT '<d/>' PRESERVE WHITESPACE)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-pi-function"></a>
##### 3.11.22.8. XMLPI

The `XMLPI()` function produces XML processing instructions.

```sql
SELECT xmlpi(NAME "php")
 
```

```java
create.select(xmlpi("php"))
      .fetch();
```

The result would look like this:

```text
+---------+
| xmlpi   |
+---------+
| <?php?> |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
xmlpi("php")
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres, Teradata

```sql
xmlpi(NAME php)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-query-function"></a>
##### 3.11.22.9. XMLQUERY

The `XMLQUERY()` function allows for extracting content from an XML document using XQuery or XPath

```sql
SELECT xmlquery('/doc/x'
  PASSING xmlparse(DOCUMENT '<doc><x>content</x></doc>')
  RETURNING CONTENT
)
FROM dual
```

```java
create.select(xmlquery("/doc/x")
        .passing(
            XML.xml("<doc><x>content</x></doc>")
        ))
      .fetch();
```

The result would look like this:

```text
+----------+
| xmlquery |
+----------+
| content  |
+----------+
```

###### Dialect support

This example using jOOQ:

```java
xmlquery("/doc/x").passing(xml("<doc><x>content</x></doc>"))
```

Translates to the following dialect specific expressions:

###### DB2

```sql
xmlquery(
  '/doc/x'
  PASSING xmlparse(DOCUMENT '<doc><x>content</x></doc>')
)
```

###### Oracle

```sql
xmlquery(
  '/doc/x'
  PASSING xmltype.createxml('<doc><x>content</x></doc>')
  RETURNING CONTENT
)
```

###### Postgres

```sql
(SELECT xmlagg(x)
FROM UNNEST(xpath('/doc/x', cast('<doc><x>content</x></doc>' AS xml))) t (x))
```

###### SQLServer

```sql
cast('<doc><x>content</x></doc>' AS xml).QUERY('/doc/x')
```

###### Teradata

```sql
xmlquery(
  '/doc/x'
  PASSING '<doc><x>content</x></doc>'
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-serialize-function"></a>
##### 3.11.22.10. XMLSERIALIZE

The `XMLSERIALIZE()` function allows for serializing XML content into a string type

```sql
SELECT xmlserialize(CONTENT xmlelement(NAME 'a') AS VARCHAR)
FROM dual
```

```java
create.select(xmlserializeContent(xmlelement("a"), VARCHAR))
      .fetch();
```

The result would look like this:

```text
+--------------+
| xmlserialize |
+--------------+
| <a/>         |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
xmlserializeContent(xmlelement("a"), VARCHAR(1000))
```

Translates to the following dialect specific expressions:

###### DB2, Postgres, Teradata

```sql
xmlserialize(CONTENT xmlelement(NAME a) AS varchar(1000))
```

###### Oracle

```sql
xmlserialize(CONTENT xmlelement(NAME a) AS varchar2(1000))
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="connect-by-functions"></a>
#### 3.11.23. CONNECT BY functions

The [CONNECT BY clause](#connect-by-clause) is a vendor specific clause used for hierarchical SQL, in the context of which a few `CONNECT BY` specific functions, operators, and pseudo fields are available. These functions allow for retrieving recursion state and collect paths within the recursion.

<a id="connect-by-iscycle-function"></a>
##### 3.11.23.1. CONNECT_BY_ISCYCLE

The `CONNECT_BY_ISCYCLE` pseudo column allows for detecting if the current row has a child which is also the row's ancestor.

```sql
SELECT
  child,
  parent,
  sys_connect_by_path(child, '/'),
  connect_by_iscycle
FROM (
  VALUES
    (1, null),
    (2, 1),
    (3, 2),
    (2, 3)
) AS t (child, parent)
START WITH
  parent IS NULL
CONNECT BY NOCYCLE
  PRIOR child = parent;
```

```java
Field<Integer> child = field("child", INTEGER);
Field<Integer> parent = field("parent", INTEGER);

create.select(
            child,
            parent,
            sysConnectByPath(child, "/"),
            connectByIsCycle())
      .from(values(
            row(val(1), val(null, INTEGER)),
            row(2, 1),
            row(3, 2),
            row(2, 3)).as(table("t"), child, parent))
      .startWith(parent.isNull())
      .connectByNoCycle(prior(child).eq(parent))
      .fetch();
```

The result being, for example

```text
+-------+--------+--------+--------------------+
| child | parent | path   | connect_by_iscycle |
+-------+--------+--------+--------------------+
| 1     |        | /1     | 0                  |
| 2     | 1      | /1/2   | 0                  |
| 3     | 2      | /1/2/3 | 1                  |
+-------+--------+--------+--------------------+
```

###### Dialect support

This example using jOOQ:

```java
connectByIsCycle()
```

Translates to the following dialect specific expressions:

###### Exasol, Informix, Oracle

```sql
connect_by_iscycle
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="connect-by-isleaf-function"></a>
##### 3.11.23.2. CONNECT_BY_ISLEAF

The `CONNECT_BY_ISLEAF` pseudo column allows for detecting if the current row has no children in the hierachy (a "leaf" in a tree).

```sql
SELECT
  child,
  parent,
  sys_connect_by_path(child, '/'),
  connect_by_isleaf
FROM (
  VALUES
    (1, null),
    (2, 1),
    (3, 2),
    (4, 1)
) AS t (child, parent)
START WITH
  parent IS NULL
CONNECT BY NOCYCLE
  PRIOR child = parent;
```

```java
Field<Integer> child = field("child", INTEGER);
Field<Integer> parent = field("parent", INTEGER);

ctx.select(
            child,
            parent,
            sysConnectByPath(child, "/"),
            connectByIsLeaf())
      .from(values(
            row(val(1), val(null, INTEGER)),
            row(2, 1),
            row(3, 2),
            row(4, 1)).as(table("t"), child, parent))
      .startWith(parent.isNull())
      .connectByNoCycle(prior(child).eq(parent))
      .fetch();
```

The result being, for example

```text
+-------+--------+---------------------+-------------------+
| child | parent | sys_connect_by_path | connect_by_isleaf |
+-------+--------+---------------------+-------------------+
|     1 | {null} | /1                  | false             |
|     2 |      1 | /1/2                | false             |
|     3 |      2 | /1/2/3              | true              |
|     4 |      1 | /1/4                | true              |
+-------+--------+---------------------+-------------------+
```

###### Dialect support

This example using jOOQ:

```java
connectByIsLeaf()
```

Translates to the following dialect specific expressions:

###### Exasol, Informix, Oracle

```sql
connect_by_isleaf
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="connect-by-root-operator"></a>
##### 3.11.23.3. CONNECT_BY_ROOT

The `CONNECT_BY_ROOT` operator allows for accessing a row's hierarchy root row and evaluate an expression on that root row.

```sql
SELECT
  child,
  parent,
  sys_connect_by_path(child, '/'),
  connectByRoot(child)
FROM (
  VALUES
    (1, null),
    (2, 1),
    (3, null),
    (4, 3)
) AS t (child, parent)
START WITH
  parent IS NULL
CONNECT BY NOCYCLE
  PRIOR child = parent;
```

```java
Field<Integer> child = field("child", INTEGER);
Field<Integer> parent = field("parent", INTEGER);

create.select(
            child,
            parent,
            sysConnectByPath(child, "/"),
            connectByRoot(child))
      .from(values(
            row(val(1), val(null, INTEGER)),
            row(2, 1),
            row(val(3), val(null, INTEGER)),
            row(4, 3)).as(table("t"), child, parent))
      .startWith(parent.isNull())
      .connectByNoCycle(prior(child).eq(parent))
      .fetch();
```

The result being, for example

```text
+-------+--------+---------------------+-----------------+
| child | parent | sys_connect_by_path | connect_by_root |
+-------+--------+---------------------+-----------------+
|     1 | {null} | /1                  |               1 |
|     2 |      1 | /1/2                |               1 |
|     3 | {null} | /3                  |               3 |
|     4 |      3 | /3/4                |               3 |
+-------+--------+---------------------+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
connectByRoot(AUTHOR.ID)
```

Translates to the following dialect specific expressions:

###### Exasol, Informix, Oracle, Snowflake

```sql
connect_by_root AUTHOR.ID
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="level-function"></a>
##### 3.11.23.4. LEVEL

The `LEVEL` pseudo column allows for accessing the hierarchy level of the current row, or in other words, the depth of the current row in the hierarchy's tree.

```sql
SELECT
  child,
  parent,
  sys_connect_by_path(child, '/'),
  level
FROM (
  VALUES
    (1, null),
    (2, 1),
    (3, 2),
    (4, 1)
) AS t (child, parent)
START WITH
  parent IS NULL
CONNECT BY NOCYCLE
  PRIOR child = parent;
```

```java
Field<Integer> child = field("child", INTEGER);
Field<Integer> parent = field("parent", INTEGER);

ctx.select(
            child,
            parent,
            sysConnectByPath(child, "/"),
            level())
      .from(values(
            row(val(1), val(null, INTEGER)),
            row(2, 1),
            row(3, 2),
            row(4, 1)).as(table("t"), child, parent))
      .startWith(parent.isNull())
      .connectByNoCycle(prior(child).eq(parent))
      .fetch();
```

The result being, for example

```text
+-------+--------+---------------------+-------+
| child | parent | sys_connect_by_path | level |
+-------+--------+---------------------+-------+
|     1 | {null} | /1                  |     1 |
|     2 |      1 | /1/2                |     2 |
|     3 |      2 | /1/2/3              |     3 |
|     4 |      1 | /1/4                |     2 |
+-------+--------+---------------------+-------+
```

###### Dialect support

This example using jOOQ:

```java
level()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, YugabyteDB

```sql
level
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, Databricks, DuckDB, Hana, MemSQL, Spanner, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="prior-operator"></a>
##### 3.11.23.5. PRIOR

The `PRIOR` operator allows for specifying an expression from the parent (the "prior") row in the hierarchy. This can be used mainly in the [CONNECT BY](#connect-by-clause) clause itself.

```sql
SELECT
  child,
  parent,
  sys_connect_by_path(child, '/')
FROM (
  VALUES
    (1, null),
    (2, 1),
    (3, 2)
) AS t (child, parent)
START WITH
  parent IS NULL
CONNECT BY NOCYCLE
  PRIOR child = parent;
```

```java
Field<Integer> child = field("child", INTEGER);
Field<Integer> parent = field("parent", INTEGER);

ctx.select(
            child,
            parent,
            sysConnectByPath(child, "/"))
      .from(values(
            row(val(1), val(null, INTEGER)),
            row(2, 1),
            row(3, 2)).as(table("t"), child, parent))
      .startWith(parent.isNull())
      .connectByNoCycle(prior(child).eq(parent))
      .fetch();
```

The result being, for example

```text
+-------+--------+---------------------+
| child | parent | sys_connect_by_path |
+-------+--------+---------------------+
|     1 | {null} | /1                  |
|     2 |      1 | /1/2                |
|     3 |      2 | /1/2/3              |
+-------+--------+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
prior(AUTHOR.ID)
```

Translates to the following dialect specific expressions:

###### Exasol, Informix, Oracle, Redshift, Snowflake

```sql
PRIOR AUTHOR.ID
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="sys-connect-by-path-function"></a>
##### 3.11.23.6. SYS_CONNECT_BY_PATH

The `SYS_CONNECT_BY_PATH` function allows for recursively generating a string for each element in the path leading to the current row in the hierarchy.

```sql
SELECT
  child,
  parent,
  sys_connect_by_path(child, '/')
FROM (
  VALUES
    (1, null),
    (2, 1),
    (3, 2)
) AS t (child, parent)
START WITH
  parent IS NULL
CONNECT BY NOCYCLE
  PRIOR child = parent;
```

```java
Field<Integer> child = field("child", INTEGER);
Field<Integer> parent = field("parent", INTEGER);

ctx.select(
            child,
            parent,
            sysConnectByPath(child, "/"))
      .from(values(
            row(val(1), val(null, INTEGER)),
            row(2, 1),
            row(3, 2)).as(table("t"), child, parent))
      .startWith(parent.isNull())
      .connectByNoCycle(prior(child).eq(parent))
      .fetch();
```

The result being, for example

```text
+-------+--------+---------------------+
| child | parent | sys_connect_by_path |
+-------+--------+---------------------+
|     1 | {null} | /1                  |
|     2 |      1 | /1/2                |
|     3 |      2 | /1/2/3              |
+-------+--------+---------------------+
```

###### Dialect support

This example using jOOQ:

```java
sysConnectByPath(AUTHOR.ID, "/")
```

Translates to the following dialect specific expressions:

###### Exasol, Informix, Oracle, Snowflake

```sql
sys_connect_by_path(AUTHOR.ID, '/')
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="system-functions"></a>
#### 3.11.24. System functions

Some system functions are supported by jOOQ.

<a id="current-catalog-function"></a>
##### 3.11.24.1. CURRENT_CATALOG

The `CURRENT_CATALOG()` function produces the dialect dependent expression to produce the current default catalog for the JDBC connection.

```sql
SELECT current_catalog;
```

```java
create.select(currentCatalog()).fetch();
```

The result being, for example

```text
+-----------------+
| current_catalog |
+-----------------+
| my_database     |
+-----------------+
```

> [!TIP]
> In some dialects, the schema and the catalog is the same thing, in case of which this function produces the same value as [CURRENT_SCHEMA](#current-schema-function)

###### Dialect support

This example using jOOQ:

```java
currentCatalog()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
database()
```

###### Aurora Postgres, CockroachDB, Databricks, Postgres, Snowflake, YugabyteDB

```sql
current_database()
```

###### ClickHouse

```sql
currentDatabase()
```

###### Firebird, SQLite

```sql
''
```

###### Informix

```sql
dbinfo('dbname')
```

###### SQLDataWarehouse, SQLServer

```sql
db_name()
```

###### Trino

```sql
current_catalog
```

###### ASE, Access, BigQuery, DB2, DuckDB, Exasol, H2, HSQLDB, Hana, Oracle, Redshift, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-schema-function"></a>
##### 3.11.24.2. CURRENT_SCHEMA

The `CURRENT_SCHEMA()` function produces the dialect dependent expression to produce the current default schema for the JDBC connection.

```sql
SELECT current_schema;
```

```java
create.select(currentSchema()).fetch();
```

The result being, for example

```text
+----------------+
| current_schema |
+----------------+
| public         |
+----------------+
```

> [!TIP]
> In some dialects, the schema and the catalog is the same thing, in case of which this function produces the same value as [CURRENT_CATALOG](#current-catalog-function)

###### Dialect support

This example using jOOQ:

```java
currentSchema()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
database()
```

###### Aurora Postgres, CockroachDB, DB2, HSQLDB, Postgres, YugabyteDB

```sql
current_schema
```

###### ClickHouse

```sql
currentDatabase()
```

###### Databricks, Snowflake, Vertica

```sql
current_schema()
```

###### Firebird, SQLite

```sql
''
```

###### H2

```sql
schema()
```

###### Oracle

```sql
user
```

###### SQLDataWarehouse, SQLServer

```sql
schema_name()
```

###### Teradata

```sql
database
```

###### ASE, Access, BigQuery, DuckDB, Exasol, Hana, Informix, Redshift, Spanner, Sybase, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="current-user-function"></a>
##### 3.11.24.3. CURRENT_USER

The `CURRENT_USER()` function produces the dialect dependent expression to produce the currently connected user for the JDBC connection.

```sql
SELECT current_user;
```

```java
create.select(currentUser()).fetch();
```

The result being, for example

```text
+--------------+
| current_user |
+--------------+
| sa           |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
currentUser()
```

Translates to the following dialect specific expressions:

###### ASE, Informix, Oracle

```sql
user
```

###### Aurora MySQL, Databricks, H2, MariaDB, MemSQL, MySQL, Snowflake

```sql
current_user()
```

###### Aurora Postgres, CockroachDB, DB2, Firebird, HSQLDB, Hana, Postgres, SQLDataWarehouse, SQLServer, Sybase, Teradata, YugabyteDB

```sql
current_user
```

###### ClickHouse

```sql
currentUser()
```

###### SQLite

```sql
''
```

###### Access, BigQuery, DuckDB, Exasol, Redshift, Spanner, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="spatial-functions"></a>
#### 3.11.25. Spatial functions

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A few databases have implemented the ISO/IEC 13249-3 SQL standard spatial extensions (or vendor specific adaptations thereof) to calculate geometric or geographic sets.

These extensions are very useful, and SQL is a perfect match for them. Starting with jOOQ 3.16, we support quite a few of these spatial functions, [spatial aggregate and window functions](#aggregate-functions), [spatial predicates](#spatial-predicates), and more.

Before moving on with the following chapters of the jOOQ manual, get yourself acquainted with the various standards around spatial data, the [WKT (Well-known text representation of geometry)](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry), and other related topics, to see how a polygon like:

```text
POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))
```

... can produce the equivalent:

```text
-- Geometry (WKT): polygon ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))
```

<a id="st-area-function"></a>
##### 3.11.25.1. ST_Area

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function calculates the area of a polygonal geometry.

```java
create.select(stArea(stGeomFromText("POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))"))).fetch();
```

The result being, for example

```text
+---------+
| ST_Area |
+---------+
| 4       |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
stArea(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_area(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_area(geometry, tol => null)
```

###### SQLServer

```sql
geometry.STArea()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-astext-function"></a>
##### 3.11.25.2. ST_AsText

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function produces the [WKT (Well-known text representation of geometry)](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry).

```java
create.select(stAsText(stGeomFromText("POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))"))).fetch();
```

The result being, for example

```text
+-------------------------------------------+
| ST_GeomFromText                           |
+-------------------------------------------+
| POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1)) |
+-------------------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
stAsText(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_astext(geometry)
```

###### Oracle

```sql
(geometry).Get_WKT()
```

###### SQLServer

```sql
geometry.STAsText()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-boundary-function"></a>
##### 3.11.25.3. ST_Boundary

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function calculates the boundary of a geometry.

```java
create.select(stBoundary(stGeomFromText("LINESTRING(0 0, 1 0, 1 1)"))).fetch();
```

The result being, for example

```text
+---------------------------+
| ST_Boundary               |
+---------------------------+
| MULTIPOINT ((0 0), (1 1)) |
+---------------------------+
```

Or, visually:

```text
-- Geometry (WKT): multipoint ((-2 -2), (2 2))
-- Background (WKT): linestring (-2 -2, 2 -2, 2 2)
```

###### Dialect support

This example using jOOQ:

```java
stBoundary(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, Postgres, Redshift

```sql
st_boundary(geometry)
```

###### Oracle

```sql
sdo_geometry(st_geometry(geometry).st_boundary().get_wkt())
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-centroid-function"></a>
##### 3.11.25.4. ST_Centroid

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function calculates the geometric center of mass of a geometry.

```java
create.select(stCentroid(stGeomFromText("POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))"))).fetch();
```

The result being, for example

```text
+-------------+
| ST_Centroid |
+-------------+
| POINT (0 0) |
+-------------+
```

Or, visually:

```text
-- Geometry (WKT): point (0 0)
-- Background (WKT): polygon ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))
```

###### Dialect support

This example using jOOQ:

```java
stCentroid(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_centroid(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_centroid(geometry, tol => null)
```

###### SQLServer

```sql
geometry.STCentroid()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-difference-function"></a>
##### 3.11.25.5. ST_Difference

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function subtracts a geometry from another.

```java
create.select(stDifference(
  stGeomFromText("POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))"),
  stGeomFromText("POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))"),
)).fetch();
```

The result being, for example

```text
+----------------------------------------------------+
| ST_Difference                                      |
+----------------------------------------------------+
| POLYGON ((-1 1, 0 1, 0 0, 1 0, 1 -1, -1 -1, -1 1)) |
+----------------------------------------------------+
```

Or, visually:

```text
-- Geometry (WKT): polygon ((-1 1, 0 1, 0 0, 1 0, 1 -1, -1 -1, -1 1))
-- Background (WKT): polygon ((0 0, 2 0, 2 2, 0 2, 0 0))
```

###### Dialect support

This example using jOOQ:

```java
stDifference(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Snowflake

```sql
st_difference(geometry1, geometry2)
```

###### Oracle

```sql
sdo_geom.sdo_difference(geometry1, geometry2, tol => null)
```

###### SQLServer

```sql
geometry1.STDifference(geometry2)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-dimension-function"></a>
##### 3.11.25.6. ST_Dimension

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function produces the dimension of a spatial value.

```java
create.select(
  stDimension(stGeomFromText("POINT (0 0)")),
  stDimension(stGeomFromText("LINESTRING (0 0, 1 1)")),
  stDimension(stGeomFromText("POLYGON ((0 0, 1 1, 1 0, 0 0))"))
)).fetch();
```

The result being, for example

```text
+--------------+--------------+--------------+
| ST_Dimension | ST_Dimension | ST_Dimension |
+--------------+--------------+--------------+
|            0 |            1 |            2 |
+--------------+--------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
stDimension(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_dimension(geometry)
```

###### SQLServer

```sql
geometry.STDimension()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Oracle, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-distance-function"></a>
##### 3.11.25.7. ST_Distance

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function calculates the distance between two geometries.

```java
create.select(stDistance(
  stGeomFromText("POINT (0 0)"),
  stGeomFromText("POINT (1 0)"),
)).fetch();
```

The result being, for example

```text
+-------------+
| ST_Distance |
+-------------+
| 1.0         |
+-------------+
```

###### Dialect support

This example using jOOQ:

```java
stDistance(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_distance(geometry1, geometry2)
```

###### Oracle

```sql
sdo_geom.sdo_distance(geometry1, geometry2, tol => null)
```

###### SQLServer

```sql
geometry1.STDistance(geometry2)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-endpoint-function"></a>
##### 3.11.25.8. ST_EndPoint

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the last point of a linestring.

```java
create.select(stEndPoint(stGeomFromText("LINESTRING (0 0, 1 1, 2 0, 3 1)"))).fetch();
```

The result being, for example

```text
+-------------+
| ST_EndPoint |
+-------------+
| POINT (3 1) |
+-------------+
```

Or, visually:

```text
-- Geometry (WKT): point (3 1)
-- Background (WKT): linestring (0 0, 1 1, 2 0, 3 1)
```

###### Dialect support

This example using jOOQ:

```java
stEndPoint(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_endpoint(geometry)
```

###### Oracle

```sql
sdo_lrs.geom_segment_end_pt(geometry)
```

###### SQLServer

```sql
geometry.STEndPoint()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-exteriorring-function"></a>
##### 3.11.25.9. ST_ExteriorRing

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns a linestring corresponding to the exterior ring of a polygon geometry.

```java
create.select(stExteriorRing(
  stGeomFromText("""
    POLYGON (
      (-3 -3, 3 -3, 3 3, -3 3, -3 -3),
      (-2 -2, 2 -2, 2 2, -2 2, -2 -2),
      (-1 -1, 1 -1, 1 1, -1 1, -1 -1)
    )
  """)
)).fetch();
```

The result being, for example

```text
+--------------------------------------------+
| ST_ExteriorRing                            |
+--------------------------------------------+
| LINESTRING (-3 -3, 3 -3, 3 3, -3 3, -3 -3) |
+--------------------------------------------+
```

Or, visually:

```text
-- Geometry (WKT): polygon ((-3 -3, 3 -3, 3 3, -3 3, -3 -3))
-- Background (WKT): polygon ((-2 -2, 2 -2, 2 2, -2 2, -2 -2), (-1 -1, 1 -1, 1 1, -1 1, -1 -1))
```

###### Dialect support

This example using jOOQ:

```java
stExteriorRing(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_exteriorring(geometry)
```

###### Oracle

```sql
st_polygon(geometry).st_exteriorring()
```

###### SQLServer

```sql
geometry.STExteriorRing()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-geometryn-function"></a>
##### 3.11.25.10. ST_GeometryN

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the N-th geometry (1-based) from a geometry that contains multiple nested geometries.

```java
create.select(stGeometryN(stGeomFromText("MULTIPOINT ((-1 -1), (1 -1), (1 1), (-1 1))"), 2)).fetch();
```

The result being, for example

```text
+--------------+
| ST_GeometryN |
+--------------+
| POINT (1 -1) |
+--------------+
```

Or, visually:

```text
-- Geometry (WKT): point (1 -1)
-- Background (WKT): multipoint ((-1 -1), (1 1), (-1 1))
```

To get the total number of geometries, use [ST_NumGeometries](#st-numgeometries-function).

###### Dialect support

This example using jOOQ:

```java
stGeometryN(geometry, 2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_geometryn(geometry, 2)
```

###### Oracle

```sql
sdo_util.extract(geometry, 2)
```

###### SQLServer

```sql
geometry.STGeometryN(2)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-geometrytype-function"></a>
##### 3.11.25.11. ST_GeometryType

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the type name of a geometry (which may be vendor specific).

```java
create.select(stGeometryType(stGeomFromText("POINT (1 1)"))).fetch();
```

The result being, for example

```text
+-----------------+
| ST_GeometryType |
+-----------------+
| ST_Point        |
+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
stGeometryType(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_geometrytype(geometry)
```

###### Oracle

```sql
decode(
  mod(
    (geometry).sdo_gtype,
    100
  ),
  1,
  'POINT',
  2,
  'LINE',
  3,
  'POLYGON',
  4,
  'COLLECTION',
  5,
  'MULTIPOINT',
  6,
  'MULTILINE',
  7,
  'MULTIPOLYGON',
  8,
  'SOLID',
  9,
  'MULTISOLID',
  'UNKNOWN_GEOMETRY'
)
```

###### SQLServer

```sql
geometry.STGeometryType()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-geomfromtext-function"></a>
##### 3.11.25.12. ST_GeomFromText

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function parses a [WKT (Well-known text representation of geometry)](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry).

```java
create.select(stGeomFromText("POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))")).fetch();
```

The result being, for example

```text
+-------------------------------------------+
| ST_GeomFromText                           |
+-------------------------------------------+
| POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1)) |
+-------------------------------------------+
```

... which is a simple square:

```text
-- Geometry (WKT): polygon ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))
```

###### Dialect support

This example using jOOQ:

```java
stGeomFromText("POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_geomfromtext('POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))', 0)
```

###### DuckDB

```sql
st_geomfromtext('POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))')
```

###### Oracle

```sql
sdo_geometry(wkt => 'POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))', srid => NULL)
```

###### SQLServer

```sql
geometry::STGeomFromText('POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))', 0)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-interiorringn-function"></a>
##### 3.11.25.13. ST_InteriorRingN

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns a linestring corresponding to the Nth interior ring (1-based) of a polygon geometry.

```java
create.select(stInteriorRingN(
  stGeomFromText("""
    POLYGON (
      (-3 -3, 3 -3, 3 3, -3 3, -3 -3),
      (-2 -2, 2 -2, 2 2, -2 2, -2 -2),
      (-1 -1, 1 -1, 1 1, -1 1, -1 -1)
    )
  """)
), 1).fetch();
```

The result being, for example

```text
+--------------------------------------------+
| ST_InteriorRingN                           |
+--------------------------------------------+
| LINESTRING (-2 -2, 2 -2, 2 2, -2 2, -2 -2) |
+--------------------------------------------+
```

Or, visually:

```text
-- Geometry (WKT): polygon ((-2 -2, 2 -2, 2 2, -2 2, -2 -2))
-- Background (WKT): polygon ((-3 -3, 3 -3, 3 3, -3 3, -3 -3), (-1 -1, 1 -1, 1 1, -1 1, -1 -1))
```

To get the total number of interior rings, use [ST_NumInteriorRings](#st-numinteriorrings-function).

###### Dialect support

This example using jOOQ:

```java
stInteriorRingN(geometry, 1)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_interiorringn(geometry, 1)
```

###### Oracle

```sql
st_polygon(geometry).st_interiorringn(1)
```

###### SQLServer

```sql
geometry.STInteriorRingN(1)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-intersection-function"></a>
##### 3.11.25.14. ST_Intersection

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function intersects two geometries.

```java
create.select(stIntersection(
  stGeomFromText("POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))"),
  stGeomFromText("POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))"),
)).fetch();
```

The result being, for example

```text
+-------------------------------------+
| ST_Difference                       |
+-------------------------------------+
| POLYGON ((1 1, 1 0, 0 0, 0 1, 1 1)) |
+-------------------------------------+
```

Or, visually:

```text
-- Geometry (WKT): polygon ((1 1, 1 0, 0 0, 0 1, 1 1))
-- Background (WKT): polygon ((-1 -1, 1 -1, 1 1, -1 1, -1 -1), (0 0, 2 0, 2 2, 0 2, 0 0))
```

###### Dialect support

This example using jOOQ:

```java
stIntersection(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_intersection(geometry1, geometry2)
```

###### Oracle

```sql
sdo_geom.sdo_intersection(geometry1, geometry2, tol => null)
```

###### SQLServer

```sql
geometry1.STIntersection(geometry2)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-length-function"></a>
##### 3.11.25.15. ST_Length

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the length of a geometry.

```java
create.select(stLength(stGeomFromText("LINESTRING (0 0, 0 1, 1 1, 1 2)"))).fetch();
```

The result being, for example

```text
+---------------------------------+
| ST_Length                       |
+---------------------------------+
| 3                               |
+---------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
stLength(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_length(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_length(geometry, tol => null)
```

###### SQLServer

```sql
geometry.STLength()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-numgeometries-function"></a>
##### 3.11.25.16. ST_NumGeometries

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the number of interior rings of a polygon geometry.

```java
create.select(stNumGeometries(stGeomFromText("MULTIPOINT ((-1 -1), (1 -1), (1 1), (-1 1))"))).fetch();
```

The result being, for example

```text
+------------------+
| ST_NumGeometries |
+------------------+
| 4                |
+------------------+
```

To access the Nth geometry (1-based), use [ST_GeometryN](#st-geometryn-function).

###### Dialect support

This example using jOOQ:

```java
stNumGeometries(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_numgeometries(geometry)
```

###### Oracle

```sql
sdo_util.getnumelem(geometry)
```

###### SQLServer

```sql
geometry.STNumGeometries()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-numinteriorrings-function"></a>
##### 3.11.25.17. ST_NumInteriorRings

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the number of interior rings of a polygon geometry.

```java
create.select(stNumInteriorRings(
  stGeomFromText("""
    POLYGON (
      (-3 -3, 3 -3, 3 3, -3 3, -3 -3),
      (-2 -2, 2 -2, 2 2, -2 2, -2 -2),
      (-1 -1, 1 -1, 1 1, -1 1, -1 -1)
    )
  """)
)).fetch();
```

The result being, for example

```text
+---------------------+
| ST_NumInteriorRings |
+---------------------+
| 2                   |
+---------------------+
```

To access the Nth interior ring (1-based), use [ST_InteriorRingN](#st-interiorringn-function).

###### Dialect support

This example using jOOQ:

```java
stNumInteriorRings(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, MySQL, Postgres, Snowflake

```sql
st_numinteriorring(geometry)
```

###### DuckDB

```sql
st_ninteriorrings(geometry)
```

###### MariaDB, Redshift

```sql
st_numinteriorrings(geometry)
```

###### Oracle

```sql
(
  SELECT (nullif(
    count(*),
    0
  ) - 1)
  FROM table(sdo_util.extract_all(geometry))
)
```

###### SQLServer

```sql
geometry.STNumInteriorRing()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-numpoints-function"></a>
##### 3.11.25.18. ST_NumPoints

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the number of points on a linestring geometry.

```java
create.select(stNumPoints(stGeomFromText("LINESTRING (0 0, 0 1, 1 1, 1 2)"))).fetch();
```

The result being, for example

```text
+--------------+
| ST_NumPoints |
+--------------+
| 4            |
+--------------+
```

To access the Nth point (1-based), use [ST_PointN](#st-pointn-function).

###### Dialect support

This example using jOOQ:

```java
stNumPoints(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_numpoints(geometry)
```

###### Oracle

```sql
st_curve(geometry).st_numpoints()
```

###### SQLServer

```sql
geometry.STNumPoints()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-perimeter-function"></a>
##### 3.11.25.19. ST_Perimeter

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the perimeter of an areal geometry.

```java
create.select(stPointN(stGeomFromText("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"))).fetch();
```

The result being, for example

```text
+--------------+
| ST_Perimeter |
+--------------+
|            4 |
+--------------+
```

###### Dialect support

This example using jOOQ:

```java
stPerimeter(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, Postgres, Redshift, Snowflake

```sql
st_perimeter(geometry)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-pointn-function"></a>
##### 3.11.25.20. ST_PointN

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the Nth point (1-based) of a linestring geometry.

```java
create.select(stPointN(stGeomFromText("LINESTRING (0 0, 0 1, 1 1, 1 2)"), 2)).fetch();
```

The result being, for example

```text
+-------------+
| ST_PointN   |
+-------------+
| POINT (0 1) |
+-------------+
```

Or, visually:

```text
-- Geometry (WKT): point (0 1)
-- Background (WKT): linestring (0 0, 0 1, 1 1, 1 2)
```

To get the total number of points, use [ST_NumPoints](#st-numpoints-function).

###### Dialect support

This example using jOOQ:

```java
stPointN(geometry, 2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_pointn(geometry, 2)
```

###### Oracle

```sql
sdo_geometry(st_curve(geometry).st_pointn(2).get_wkt())
```

###### SQLServer

```sql
geometry.STPointN(2)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-srid-function"></a>
##### 3.11.25.21. ST_SRID

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the SRID of a geometry.

```java
create.select(stSrid(stGeomFromText("POINT (1 0)", 4326))).fetch();
```

The result being, for example

```text
+---------+
| ST_SRID |
+---------+
| 4326    |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
stSrid(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_srid(geometry)
```

###### Oracle

```sql
(geometry).sdo_srid
```

###### SQLServer

```sql
geometry.STSrid
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-startpoint-function"></a>
##### 3.11.25.22. ST_StartPoint

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function returns the first point of a linestring.

```java
create.select(stStartPoint(stGeomFromText("LINESTRING (0 0, 1 1, 2 0, 3 1)"))).fetch();
```

The result being, for example

```text
+---------------+
| ST_StartPoint |
+---------------+
| POINT (0 0)   |
+---------------+
```

Or, visually:

```text
-- Geometry (WKT): point (0 0)
-- Background (WKT): linestring (0 0, 1 1, 2 0, 3 1)
```

###### Dialect support

This example using jOOQ:

```java
stStartPoint(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_startpoint(geometry)
```

###### Oracle

```sql
sdo_lrs.geom_segment_start_pt(geometry)
```

###### SQLServer

```sql
geometry.STStartPoint()
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-transform-function"></a>
##### 3.11.25.23. ST_Transform

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function transforms a spatial value between different spatial reference systems.

```java
create.select(stTransform(stGeomFromText("POINT (1 1)", 2249), 4326)).fetch();
```

The result being, for example

```text
+----------------------------------------------+
| ST_Transform                                 |
+----------------------------------------------+
| POINT (-73.65138770881771 34.24438954333329) |
+----------------------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
stTransform(geometry, 4326)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_transform(geometry, 4326)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-union-function"></a>
##### 3.11.25.24. ST_Union

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function combines a geometry with another.

```java
create.select(stUnion(
  stGeomFromText("POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1 -1))"),
  stGeomFromText("POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))"),
)).fetch();
```

The result being, for example

```text
+--------------------------------------------------------------+
| ST_Union                                                     |
+--------------------------------------------------------------+
| POLYGON ((1 -1, -1 -1, -1 1, 0 1, 0 2, 2 2, 2 0, 1 0, 1 -1)) |
+--------------------------------------------------------------+
```

Or, visually:

```text
-- Geometry (WKT): polygon ((1 -1, -1 -1, -1 1, 0 1, 0 2, 2 2, 2 0, 1 0, 1 -1))
-- Background (WKT): geometrycollection(polygon ((-1 -1, 1 -1, 1 1, -1 1, -1 -1)), polygon ((0 0, 2 0, 2 2, 0 2, 0 0)))
```

###### Dialect support

This example using jOOQ:

```java
stUnion(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_union(geometry1, geometry2)
```

###### CockroachDB

```sql
(
  SELECT st_union(v)
  FROM (
    VALUES
      (geometry1),
      (geometry2)
  ) t (v)
)
```

###### Oracle

```sql
sdo_geom.sdo_union(geometry1, geometry2, tol => null)
```

###### SQLServer

```sql
geometry1.STUnion(geometry2)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-x-function"></a>
##### 3.11.25.25. ST_X

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the X coordinate of a point.

```java
create.select(stX(stGeomFromText("POINT (1 0)"))).fetch();
```

The result being, for example

```text
+------+
| ST_X |
+------+
| 1    |
+------+
```

###### Dialect support

This example using jOOQ:

```java
stX(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_x(geometry)
```

###### Oracle

```sql
(geometry).sdo_point.x
```

###### SQLServer

```sql
geometry.STX
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-xmax-function"></a>
##### 3.11.25.26. ST_XMax

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the maximum X coordinate of a geometry.

```java
create.select(stXMax(stGeomFromText("POLYGON ((-1 0, 1 0, 1 2, -1 2, -1 0))"))).fetch();
```

The result being, for example

```text
+---------+
| ST_XMAX |
+---------+
|       1 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
stXMax(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake

```sql
st_xmax(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_max_mbr_ordinate(geometry, 1)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-xmin-function"></a>
##### 3.11.25.27. ST_XMin

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the minimum X coordinate of a geometry.

```java
create.select(stXMin(stGeomFromText("POLYGON ((-1 0, 1 0, 1 2, -1 2, -1 0))"))).fetch();
```

The result being, for example

```text
+---------+
| ST_XMIN |
+---------+
|      -1 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
stXMin(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake

```sql
st_xmin(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_min_mbr_ordinate(geometry, 1)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-y-function"></a>
##### 3.11.25.28. ST_Y

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the Y coordinate of a point.

```java
create.select(stY(stGeomFromText("POINT (0 1)"))).fetch();
```

The result being, for example

```text
+------+
| ST_Y |
+------+
| 1    |
+------+
```

###### Dialect support

This example using jOOQ:

```java
stY(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_y(geometry)
```

###### Oracle

```sql
(geometry).sdo_point.y
```

###### SQLServer

```sql
geometry.STY
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-ymax-function"></a>
##### 3.11.25.29. ST_YMax

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the maximum Y coordinate of a geometry.

```java
create.select(stYMax(stGeomFromText("POLYGON ((-1 0, 1 0, 1 2, -1 2, -1 0))"))).fetch();
```

The result being, for example

```text
+---------+
| ST_YMAX |
+---------+
|       1 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
stYMax(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake

```sql
st_ymax(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_max_mbr_ordinate(geometry, 2)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-ymin-function"></a>
##### 3.11.25.30. ST_YMin

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the minimum Y coordinate of a geometry.

```java
create.select(stYMin(stGeomFromText("POLYGON ((-1 0, 1 0, 1 2, -1 2, -1 0))"))).fetch();
```

The result being, for example

```text
+---------+
| ST_YMIN |
+---------+
|       0 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
stYMin(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake

```sql
st_ymin(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_min_mbr_ordinate(geometry, 2)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-z-function"></a>
##### 3.11.25.31. ST_Z

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the Z coordinate of a point.

```java
create.select(stZ(stGeomFromText("POINT (0 0 1)"))).fetch();
```

The result being, for example

```text
+------+
| ST_Z |
+------+
| 1    |
+------+
```

###### Dialect support

This example using jOOQ:

```java
stZ(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, Redshift, Snowflake

```sql
st_z(geometry)
```

###### Oracle

```sql
(geometry).sdo_point.z
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-zmax-function"></a>
##### 3.11.25.32. ST_ZMax

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the maximum Z coordinate of a geometry.

```java
create.select(stZMax(stGeomFromText("POLYGON ((-1 0 -5, 1 0 0, 1 2 5, -1 2 0, -1 0 -5))"))).fetch();
```

The result being, for example

```text
+---------+
| ST_ZMAX |
+---------+
|       5 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
stZMax(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, Postgres, Redshift

```sql
st_zmax(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_max_mbr_ordinate(geometry, 3)
```

###### ASE, Access, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-zmin-function"></a>
##### 3.11.25.33. ST_ZMin

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This function extracts the minimum Z coordinate of a geometry.

```java
create.select(stZMin(stGeomFromText("POLYGON ((-1 0 -5, 1 0 0, 1 2 5, -1 2 0, -1 0 -5))"))).fetch();
```

The result being, for example

```text
+---------+
| ST_ZMIN |
+---------+
|      -5 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
stZMin(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, Postgres, Redshift

```sql
st_zmin(geometry)
```

###### Oracle

```sql
sdo_geom.sdo_min_mbr_ordinate(geometry, 3)
```

###### ASE, Access, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="aggregate-functions"></a>
#### 3.11.26. Aggregate functions

Aggregate functions work like Java [`java.util.stream.Collector`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collector.html), as they aggregate data from a group of data into a new data structure.

This section will first explain concepts common to many aggregate functions, and then proceed to explaining individual aggregate functions supported by jOOQ.

<a id="aggregate-grouping"></a>
##### 3.11.26.1. Grouping

Aggregate functions aggregate data from groups of data into individual values. There are three main ways of forming such groups:

- A [GROUP BY](#group-by-clause) clause is used to define the groups for which data is aggregated
- No [GROUP BY](#group-by-clause) clause is defined, which means that all data from a [SELECT statement](#select-statement) (or subquery) is aggregated into a single row
- All aggregate functions can be used as [window functions](#window-functions), in case of which they will aggregate the data of the specified window

###### Aggregation with GROUP BY

In the presence of [GROUP BY](#group-by-clause), a [SELECT statement](#select-statement) transforms the output of its [FROM clause](#from-clause) into a new "virtual" set of tuples containing:

- The column expressions of the `GROUP BY` clause. In the overall data set, the values of these column expressions is unique.
- A set of data corresponding to each row produced by the `GROUP BY` clause. This data set can be aggregated per group using aggregate functions.

Using `GROUP BY` means that a new set of rules need to be observed in the rest of the query:

- Clauses that [logically precede](https://blog.jooq.org/a-beginners-guide-to-the-true-order-of-sql-operations/) [GROUP BY](#group-by-clause) are not affected. These include, for example, [FROM](#from-clause) and [WHERE](#where-clause)
- All other clauses (e.g. [HAVING](#having-clause), [WINDOW](#window-clause), [SELECT](#select-clause), or [ORDER BY](#order-by-clause)) may now only reference expressions built from the expressions in the `GROUP BY` clause, or aggregations on any other expression

An example:

```sql
SELECT AUTHOR_ID, count(*)
FROM BOOK
GROUP BY AUTHOR_ID;
```

```java
create.select(BOOK.AUTHOR_ID, count())
      .from(BOOK)
      .groupBy(BOOK.AUTHOR_ID).fetch();
```

Producing:

```text
+-----------+-------+
| AUTHOR_ID | count |
+-----------+-------+
|         1 |     2 |
|         2 |     2 |
+-----------+-------+
```

Per the rules imposed by `GROUP BY`, it would not be possible, for example, to project the `BOOK.TITLE` column, because it is not defined per author. An author has written many books, so we don't know what a `BOOK.TITLE` is supposed to mean. Only an aggregation, such as [LISTAGG](#listagg-function) or [ARRAY_AGG](#array-agg-function) can reference `BOOK.TITLE` as an argument.

###### Aggregation without GROUP BY

In the absence of [GROUP BY](#group-by-clause), a [SELECT statement](#select-statement) that contains at least one aggregate function in any of its clauses (e.g. [HAVING](#having-clause), [WINDOW](#window-clause), [SELECT](#select-clause), or [ORDER BY](#order-by-clause)) will proceed to aggregating the entire data into a single row. There is an implied "empty grouping", i.e. a grouping that has no `GROUP BY` columns. These two are the same things:

```sql
SELECT count(*) FROM BOOK;
SELECT count(*) FROM BOOK GROUP BY ();
```

See also [GROUPING SETS](#group-by-grouping-sets) for more details about this empty `GROUP BY` syntax.

For example, using our [sample database](#sample-database), which has 4 books with IDs 1-4, we can write:

```sql
SELECT count(*), sum(ID)
FROM BOOK
```

```java
create.select(count(), sum(BOOK.ID))
      .from(BOOK).fetch();
```

Producing:

```text
+----------+---------+
| count(*) | sum(ID) |
+----------+---------+
|        4 |      10 |
+----------+---------+
```

No other columns from the tables in the [FROM clause](#from-clause) may be projected by the [SELECT clause](#select-clause), because they would not be defined for this single group. For example, no specific `BOOK.TITLE` is defined for the aggregated value of all books. Only an aggregation, such as [LISTAGG](#listagg-function) or [ARRAY_AGG](#array-agg-function) can reference `BOOK.TITLE` as an argument.

However, any expression whose components do not depend on content of the group is allowed. For example, it is possible to combine aggregate functions and constant expressions like this:

```sql
SELECT count(*) + sum(ID) + 1
FROM BOOK
```

```java
create.select(count().plus(sum(BOOK.ID)).plus(1))
      .from(BOOK).fetch();
```

Producing:

```text
+------+
| plus |
+------+
|   15 |
+------+
```

<a id="aggregate-distinct"></a>
##### 3.11.26.2. Distinctness

A useful thing to do when aggregating data is to remove duplicate input first, prior to aggregation. A few aggregate functions support a `DISTINCT` keyword for that purpose. For example, we can query

```sql
SELECT
  count(AUTHOR_ID),
  count(DISTINCT AUTHOR_ID),
  group_concat(AUTHOR_ID),
  group_concat(DISTINCT AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         count(BOOK.AUTHOR_ID),
         countDistinct(BOOK.AUTHOR_ID),
         groupConcat(BOOK.AUTHOR_ID),
         groupConcatDistinct(BOOK.AUTHOR_ID))
      .from(BOOK).fetch();
```

Producing:

```text
+-------+----------------+--------------+-----------------------+
| count | count_distinct | group_concat | group_concat_distinct |
+-------+----------------+--------------+-----------------------+
|     4 |              2 | 1, 1, 2, 2   | 1, 2                  |
+-------+----------------+--------------+-----------------------+
```

If `DISTINCT` is available through the jOOQ API, it is always appended to the aggregate function name, such as `count()` and `countDistinct()`. `sum()` and `sumDistinct()`, etc.

<a id="aggregate-filter"></a>
##### 3.11.26.3. Filtering

The SQL standard specifies an optional `FILTER` clause, that can be appended to all [aggregate functions](#aggregate-functions) including aggregated [window functions](#window-functions). This is very useful, for example, to implement "pivot" tables, such as the following:

```sql
SELECT
  count(*),
  count(*) FILTER (WHERE TITLE LIKE 'A%'),
  count(*) FILTER (WHERE TITLE LIKE '%A%')
FROM BOOK
```

```java
create.select(
         count(),
         count().filterWhere(BOOK.TITLE.like("A%")),
         count().filterWhere(BOOK.TITLE.like("%A%")))
      .from(BOOK)
```

Producing:

```text
+-------+-------+-------+
| count | count | count |
+-------+-------+-------+
|     4 |     1 |     2 |
+-------+-------+-------+
```

Or, with [GROUP BY](#group-by-clause):

```sql
SELECT
  AUTHOR_ID,
  count(*),
  count(*) FILTER (WHERE TITLE LIKE 'A%'),
  count(*) FILTER (WHERE TITLE LIKE '%A%')
FROM BOOK
GROUP BY AUTHOR_ID
```

```java
create.select(
         BOOK.AUTHOR_ID,
         count(),
         count().filterWhere(BOOK.TITLE.like("A%")),
         count().filterWhere(BOOK.TITLE.like("%A%")))
      .from(BOOK)
      .groupBy(BOOK.AUTHOR_ID)
```

Producing:

```text
+-----------+-------+-------+-------+
| AUTHOR_ID | count | count | count |
+-----------+-------+-------+-------+
|         1 |     2 |     1 |     1 |
|         2 |     2 |     0 |     1 |
+-----------+-------+-------+-------+
```

It is usually a good idea to [calculate multiple aggregate functions in a single query](https://blog.jooq.org/how-to-calculate-multiple-aggregate-functions-in-a-single-query/), if this is possible, and `FILTER` helps here.

Only a few dialects implement native support for the `FILTER` clause. In all other databases, jOOQ emulates the clause using a [CASE expression](#case-expressions). Aggregate functions exclude `NULL` values from aggregation.

###### Dialect support

This example using jOOQ:

```java
count().filterWhere(BOOK.TITLE.like("A%"))
```

Translates to the following dialect specific expressions:

###### Access

```sql
count(SWITCH(BOOK.TITLE LIKE 'A%', 1))
```

###### ASE, Aurora MySQL, DB2, Exasol, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, Sybase, Teradata, Vertica

```sql
count(CASE
  WHEN BOOK.TITLE LIKE 'A%' THEN 1
END)
```

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Firebird, H2, HSQLDB, Postgres, SQLite, Trino, YugabyteDB

```sql
count(*) FILTER (WHERE BOOK.TITLE LIKE 'A%')
```

###### BigQuery

```sql
countif((BOOK.TITLE LIKE 'A%'))
```

###### ClickHouse

```sql
count() FILTER (WHERE BOOK.TITLE LIKE 'A%')
```

###### Snowflake

```sql
count_if((BOOK.TITLE LIKE 'A%'))
```

###### Spanner

```sql
countif((BOOK.TITLE LIKE 'A%') HAVING MAX nullif(
  (BOOK.TITLE LIKE 'A%'),
  FALSE
))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="aggregate-order-by"></a>
##### 3.11.26.4. Ordering

Some aggregate functions allow for ordering their inputs to produce an ordered output. These aggregate functions allow for specifying an optional `ORDER BY` clause in their argument list. This is not to be confused with the [WITHIN GROUP (ORDER BY ..)](#aggregate-within-group) clause, which is required for ordering inputs to produce a single, unordered output.

This makes a lot of sense with aggregations that produce the aggregated values in a nested or formatted data structure, such as, for example:

- [ARRAY_AGG](#array-agg-function), which aggregates data into an array.
- [COLLECT](#collect-function), which aggregates data into a nested table (Oracle).
- [JSON_ARRAYAGG](#json-arrayagg-function), which aggregates data into a JSON array.
- [LISTAGG](#listagg-function), which aggregates data into a string. The standard `LISTAGG` function, unfortunately, inconsistently uses the [WITHIN GROUP](#aggregate-within-group) syntax. MySQL's `GROUP_CONCAT` is more consistent with the rest.
- [XMLAGG](#xml-agg-function), which aggregates data into an XML element.

An example using [ARRAY_AGG](#array-agg-function) could look like this:

```sql
SELECT
  array_agg(ID),
  array_agg(ID ORDER BY ID DESC)
FROM BOOK
```

```java
create.select(
         arrayAgg(BOOK.ID),
         arrayAgg(BOOK.ID).orderBy(BOOK.ID.desc()))
      .from(BOOK)
```

Producing:

```text
+--------------+--------------+
| array_agg    | array_agg    |
+--------------+--------------+
| [1, 3, 4, 2] | [4, 3, 2, 1] |
+--------------+--------------+
```

> [!TIP]
> Notice that in the absence of an explicit `ORDER BY` clause, as always, the ordering is non deterministic.

<a id="aggregate-within-group"></a>
##### 3.11.26.5. Ordering WITHIN GROUP

Some aggregate functions allow for ordering their inputs to produce an ordered output. These aggregate functions allow for specifying a mandatory `WITHIN GROUP (ORDER BY ..)` clause after the function. This is not to be confused with the [aggregate ORDER BY](#aggregate-order-by) clause, which allows for optionally ordering inputs to produce ordered output

Standard SQL talks about "ordered set aggregate functions" which come in three flavours

- Hypothetical set functions: Functions that check for the position of a hypothetical value inside of an ordered set. These include [RANK](#rank-function), [DENSE_RANK](#dense-rank-function), [PERCENT_RANK](#percent-rank-function), [CUME_DIST](#cume-dist-function).
- Inverse distribution functions: Functions calculating a percentile over an ordered set, including [PERCENTILE_CONT](#percentile-cont-function), [PERCENTILE_DISC](#percentile-disc-function), or [MODE](#mode-function).
- [LISTAGG](#listagg-function), which is inconsistently using the `WITHIN GROUP` syntax, as it is used to order the output of the function, and isn't mandatory in all dialects.

An example for the [PERCENTILE_CONT](#percentile-cont-function) inverse distribution function is this:

```sql
SELECT
  percentile_cont(0.5) WITHIN GROUP (ORDER BY ID)
FROM BOOK
```

```java
create.select(
         percentileCont(0.5).withinGroupOrderBy(BOOK.ID))
      .from(BOOK)
```

Producing the median BOOK.ID value:

```text
+-----------------+
| percentile_cont |
+-----------------+
|             2.5 |
+-----------------+
```

<a id="aggregate-keep"></a>
##### 3.11.26.6. Keeping

Oracle allows for restricting other aggregate functions using the `KEEP()` clause, which is supported by jOOQ. In Oracle, some aggregate functions (e.g. [MIN](#min-function), [MAX](#max-function), [SUM](#sum-function), [AVG](#avg-function), [COUNT](#count-function), `VARIANCE`, or `STDDEV`) can be restricted by this clause, hence [`org.jooq.AggregateFunction`](https://www.jooq.org/javadoc/3.22.x/org/jooq/AggregateFunction.html) also allows for specifying it. Here is an example using this clause:

```sql
SUM(BOOK.AMOUNT_SOLD)
  KEEP(DENSE_RANK FIRST ORDER BY BOOK.AUTHOR_ID)
```

```java
sum(BOOK.AMOUNT_SOLD)
  .keepDenseRankFirstOrderBy(BOOK.AUTHOR_ID)
```

<a id="any-value-function"></a>
##### 3.11.26.7. ANY_VALUE

The `ANY_VALUE()` aggregate function produces any random value from the group, non-deterministically

```sql
SELECT any_value(ID)
FROM BOOK
```

```java
create.select(anyValue(BOOK.ID))
      .from(BOOK)
```

Producing (for example):

```text
+-----------+
| any_value |
+-----------+
|         3 |
+-----------+
```

###### Dialect support

This example using jOOQ:

```java
anyValue(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, SQLDataWarehouse, SQLServer, SQLite, Sybase, Teradata, Vertica, YugabyteDB

```sql
min(BOOK.ID)
```

###### Aurora MySQL, BigQuery, Databricks, DuckDB, H2, MemSQL, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner

```sql
any_value(BOOK.ID)
```

###### ClickHouse

```sql
any(BOOK.ID)
```

###### Trino

```sql
arbitrary(BOOK.ID)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="approx-count-distinct-function"></a>
##### 3.11.26.8. APPROX_COUNT_DISTINCT

The `APPROX_COUNT_DISTINCT()` aggregate function produces an approximatively equivalent value to the [COUNT(DISTINCT ..)](#count-function) function, using a faster approximative counting algorithm.

```sql
SELECT approx_count_distinct(LANGUAGE_ID)
FROM BOOK
```

```java
create.select(approxCountDistinct(BOOK.LANGUAGE_ID))
      .from(BOOK)
```

Producing (for example):

```text
+-----------------------+
| approx_count_distinct |
+-----------------------+
|                     3 |
+-----------------------+
```

If the function is not supported natively, jOOQ will just fall back to the slower, exact [COUNT(DISTINCT ..)](#count-function) function, instead.

> [!TIP]
> For consistency with [COUNT(DISTINCT ..)](#count-function), this function returns a [`java.lang.Integer`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Integer.html) value. To support larger [`java.lang.Long`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Long.html) result values, use [`DSL.approxCountLargeDistinct()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#approxCountLargeDistinct(org.jooq.Field)) instead.

###### Dialect support

This example using jOOQ:

```java
anyValue(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, SQLDataWarehouse, SQLServer, SQLite, Sybase, Teradata, Vertica, YugabyteDB

```sql
min(BOOK.ID)
```

###### Aurora MySQL, BigQuery, Databricks, DuckDB, H2, MemSQL, MySQL, Oracle, Postgres, Redshift, Snowflake, Spanner

```sql
any_value(BOOK.ID)
```

###### ClickHouse

```sql
any(BOOK.ID)
```

###### Trino

```sql
arbitrary(BOOK.ID)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="approx-percentile-cont-function"></a>
##### 3.11.26.9. APPROX_PERCENTILE_CONT

The `APPROX_PERCENTILE_CONT()` approximative aggregate function is an [ordered set function](#aggregate-within-group) that calculates a given continuous percentile of all input values using a faster, approximative algorithm than the exact [PERCENTILE_CONT](#percentile-cont-function) version. If a RDBMS supports the exact version, but not the approximative one, the exact version is used. If a RDBMS does not support the continuous version, the [APPROX_PERCENTILE_DISC](#approx-percentile-disc-function) (discrete) version is used.

```sql
SELECT
  approx_percentile_cont(0.00) WITHIN GROUP (ORDER BY ID),
  approx_percentile_cont(0.25) WITHIN GROUP (ORDER BY ID),
  approx_percentile_cont(0.50) WITHIN GROUP (ORDER BY ID),
  approx_percentile_cont(0.75) WITHIN GROUP (ORDER BY ID),
  approx_percentile_cont(1.00) WITHIN GROUP (ORDER BY ID)
FROM BOOK
```

```java
create.select(
         approxPercentileCont(0.00).withinGroupOrderBy(BOOK.ID),
         approxPercentileCont(0.25).withinGroupOrderBy(BOOK.ID),
         approxPercentileCont(0.50).withinGroupOrderBy(BOOK.ID),
         approxPercentileCont(0.75).withinGroupOrderBy(BOOK.ID),
         approxPercentileCont(1.00).withinGroupOrderBy(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+------+------+------+------+------+
| 0.00 | 0.25 | 0.50 | 0.75 | 1.00 |
+------+------+------+------+------+
|    1 | 1.75 |  2.5 | 3.25 |    4 |
+------+------+------+------+------+
```

###### Dialect support

This example using jOOQ:

```java
approxPercentileCont(0.00).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
percentile_cont(cast(0E0 AS double precision)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### BigQuery

```sql
approx_quantiles(BOOK.ID, 100)[OFFSET(cast(
  (0E0 * 100)
  AS int64
))]
```

###### ClickHouse

```sql
quantileTDigest(0E0)(BOOK.ID)
```

###### Databricks

```sql
approx_percentile(BOOK.ID, 0E0)
```

###### DB2

```sql
percentile_cont(cast(0E0 AS double)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### DuckDB

```sql
approx_quantile(BOOK.ID, cast(0E0 AS real))
```

###### Exasol, MariaDB, Teradata

```sql
percentile_cont(0E0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### H2

```sql
percentile_cont(cast(
  0E0
  AS double
)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### MemSQL, Snowflake, Trino

```sql
approx_percentile(0E0, BOOK.ID)
```

###### Oracle

```sql
approx_percentile(0E0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### Redshift

```sql
APPROXIMATE percentile_cont(0E0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### SQLDataWarehouse, SQLServer

```sql
approx_percentile_cont(cast(0E0 AS float)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, CockroachDB, Firebird, HSQLDB, Hana, Informix, MySQL, SQLite, Spanner, Sybase, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="approx-percentile-disc-function"></a>
##### 3.11.26.10. APPROX_PERCENTILE_DISC

The `APPROX_PERCENTILE_DISC()` approximative aggregate function is an [ordered set function](#aggregate-within-group) that calculates a given discrete percentile of all input values using a faster, approximative algorithm than the exact [PERCENTILE_DISC](#percentile-disc-function) version. If a RDBMS supports the exact version, but not the approximative one, the exact version is used.

```sql
SELECT
  approx_percentile_disc(0.00) WITHIN GROUP (ORDER BY ID),
  approx_percentile_disc(0.25) WITHIN GROUP (ORDER BY ID),
  approx_percentile_disc(0.50) WITHIN GROUP (ORDER BY ID),
  approx_percentile_disc(0.75) WITHIN GROUP (ORDER BY ID),
  approx_percentile_disc(1.00) WITHIN GROUP (ORDER BY ID)
FROM BOOK
```

```java
create.select(
         approxPercentileDisc(0.00).withinGroupOrderBy(BOOK.ID),
         approxPercentileDisc(0.25).withinGroupOrderBy(BOOK.ID),
         approxPercentileDisc(0.50).withinGroupOrderBy(BOOK.ID),
         approxPercentileDisc(0.75).withinGroupOrderBy(BOOK.ID),
         approxPercentileDisc(1.00).withinGroupOrderBy(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+------+------+------+------+------+
| 0.00 | 0.25 | 0.50 | 0.75 | 1.00 |
+------+------+------+------+------+
|    1 |    1 |    2 |    3 |    4 |
+------+------+------+------+------+
```

###### Dialect support

This example using jOOQ:

```java
approxPercentileDisc(0.00).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
percentile_disc(cast(0E0 AS double precision)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### BigQuery

```sql
approx_quantiles(BOOK.ID, 100)[OFFSET(cast(
  (0E0 * 100)
  AS int64
))]
```

###### ClickHouse

```sql
quantileTDigest(0E0)(BOOK.ID)
```

###### Databricks

```sql
approx_percentile(BOOK.ID, 0E0)
```

###### DB2

```sql
percentile_disc(cast(0E0 AS double)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### DuckDB

```sql
approx_quantile(BOOK.ID, cast(0E0 AS real))
```

###### Exasol, MariaDB, Teradata

```sql
percentile_disc(0E0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### H2

```sql
percentile_disc(cast(
  0E0
  AS double
)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### MemSQL, Snowflake, Trino

```sql
approx_percentile(0E0, BOOK.ID)
```

###### Oracle

```sql
approx_percentile(0E0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### Redshift

```sql
APPROXIMATE percentile_disc(0E0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### SQLDataWarehouse, SQLServer

```sql
approx_percentile_disc(cast(0E0 AS float)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, CockroachDB, Firebird, HSQLDB, Hana, Informix, MySQL, SQLite, Spanner, Sybase, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="array-agg-function"></a>
##### 3.11.26.11. ARRAY_AGG

The `ARRAY_AGG` aggregate function aggregates grouped values into an array. It supports being used with an [ORDER BY](#aggregate-order-by) clause.

```sql
SELECT
  array_agg(ID)
  array_agg(ID ORDER BY ID DESC)
FROM BOOK
```

```java
create.select(
         arrayAgg(BOOK.ID),
         arrayAgg(BOOK.ID).orderBy(BOOK.ID.desc()))
      .from(BOOK)
```

Producing:

```text
+--------------+--------------+
| array_agg    | array_agg    |
+--------------+--------------+
| [1, 3, 4, 2] | [4, 3, 2, 1] |
+--------------+--------------+
```

Unlike the [MULTISET_AGG function](#multiset-agg-function), this:

- Produces an array, instead of a [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) type
- Allows for projecting only a single column (though that column may contain a [nested record](#nested-records))

###### Dialect support

This example using jOOQ:

```java
arrayAgg(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, H2, HSQLDB, Postgres, Spanner, Trino, YugabyteDB

```sql
array_agg(BOOK.ID)
```

###### ClickHouse

```sql
groupArray(BOOK.ID)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="avg-function"></a>
##### 3.11.26.12. AVG

The `AVG()` aggregate function calculates the average value of all input values

```sql
SELECT avg(ID)
FROM BOOK
```

```java
create.select(avg(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+-----+
| avg |
+-----+
| 2.5 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
avg(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
avg(BOOK.ID)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-listagg-function"></a>
##### 3.11.26.13. LISTAGG (binary)

The binary `LISTAGG()` aggregate function aggregates data into a binary string. It uses the [WITHIN GROUP](#aggregate-within-group) syntax.

```sql
SELECT
  listagg(ID) WITHIN GROUP (ORDER BY ID),
  listagg(ID, '; ') WITHIN GROUP (ORDER BY ID),
FROM BOOK
```

```java
create.select(
         binaryListAgg(BOOK.ID).withinGroupOrderBy(BOOK.ID),
         binaryListAgg(BOOK.ID, "; ".getBytes()).withinGroupOrderBy(BOOK.ID))
      .from(BOOK).fetch();
```

Producing:

```text
+------------------+------------------+
| listagg          | listagg          |
+------------------+------------------+
| MSwgMiwgMywgNA== | MTsgMjsgMzsgNA== |
+------------------+------------------+
```

> [!TIP]
> See [LISTAGG](#listagg-function) for a text version of this function.

###### Dialect support

This example using jOOQ:

```java
binaryListAgg(BOOK.AUTHOR_ID, ",".getBytes()).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres

```sql
string_agg(cast(
  cast(BOOK.AUTHOR_ID AS varchar)
  AS bytea
), cast(E'\\054' AS bytea) ORDER BY BOOK.ID)
```

###### BigQuery, Spanner

```sql
string_agg(cast(
  cast(BOOK.AUTHOR_ID AS string)
  AS bytes
), b'\x2C' ORDER BY BOOK.ID)
```

###### CockroachDB

```sql
string_agg(cast(
  cast(BOOK.AUTHOR_ID AS string)
  AS bytes
), cast(E'\\054' AS bytea) ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, ClickHouse, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-and-agg-function"></a>
##### 3.11.26.14. BIT_AND_AGG

An aggregate function to perform the equivalent of the [BIT_AND function](#bit-and-function) on a data set. In other words, the resulting bits are:

- `1` at position `p` if the argument is `1` at position `p` for every row in the group.
- `0` at position `p` if the argument is `0` at position `p` for at least one row in the group.

As with most aggregate functions, `NULL` values are not aggregated.

```sql
SELECT
  bit_and_agg(ID),
  bit_and_agg(AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         bitAndAgg(BOOK.ID),
         bitAndAgg(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+-------------+-------------+
| bit_and_agg | bit_and_agg |
+-------------+-------------+
|           0 |           0 |
+-------------+-------------+
```

###### Dialect support

This example using jOOQ:

```java
bitAndAgg(BOOK.ID.coerce(TINYINT))
```

Translates to the following dialect specific expressions:

###### ASE, MemSQL, SQLDataWarehouse, SQLServer, SQLite

```sql
(CASE min(
  CASE (BOOK.ID & 1)
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 2)
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 4)
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 8)
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 16)
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 32)
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 64)
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & -128)
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)
```

###### Aurora MySQL, Aurora Postgres, H2, Oracle, Snowflake

```sql
bit_and_agg(BOOK.ID)
```

###### BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MySQL, Postgres, Redshift, Spanner, Sybase, YugabyteDB

```sql
bit_and(BOOK.ID)
```

###### ClickHouse

```sql
groupBitAnd(BOOK.ID)
```

###### DB2, HSQLDB, Hana, Informix, Teradata

```sql
(CASE min(
  CASE bitand(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)
```

###### Exasol

```sql
(CASE min(
  CASE bit_and(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)
```

###### Firebird

```sql
(CASE min(
  CASE bin_and(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)
```

###### Trino

```sql
bitwise_and_agg(BOOK.ID)
```

###### Vertica

```sql
hex_to_integer(to_hex(bit_and(hex_to_binary(to_hex(BOOK.ID)))))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-nand-agg-function"></a>
##### 3.11.26.15. BIT_NAND_AGG

An aggregate function to perform the equivalent of the [BIT_NAND function](#bit-nand-function) on a data set. In other words, the resulting bits are:

- `0` at position `p` if the argument is `1` at position `p` for every row in the group.
- `1` at position `p` if the argument is `0` at position `p` for at least one row in the group.

As with most aggregate functions, `NULL` values are not aggregated.

```sql
SELECT
  bit_nand_agg(ID),
  bit_nand_agg(AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         bitNandAgg(BOOK.ID),
         bitNandAgg(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+--------------+--------------+
| bit_nand_agg | bit_nand_agg |
+--------------+--------------+
|           -1 |           -1 |
+--------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
bitNandAgg(BOOK.ID.coerce(TINYINT))
```

Translates to the following dialect specific expressions:

###### ASE, MemSQL, SQLDataWarehouse, SQLServer, SQLite

```sql
~((CASE min(
  CASE (BOOK.ID & 1)
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 2)
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 4)
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 8)
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 16)
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 32)
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & 64)
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE (BOOK.ID & -128)
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END))
```

###### Aurora MySQL, Aurora Postgres

```sql
~(bit_and_agg(BOOK.ID))
```

###### BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MySQL, Postgres, Redshift, Spanner, Sybase, YugabyteDB

```sql
~(bit_and(BOOK.ID))
```

###### ClickHouse

```sql
bitNot(groupBitAnd(BOOK.ID))
```

###### DB2, Hana, Informix, Teradata

```sql
bitnot((CASE min(
  CASE bitand(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END))
```

###### Exasol

```sql
bit_not((CASE min(
  CASE bit_and(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE bit_and(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END))
```

###### Firebird

```sql
bin_not((CASE min(
  CASE bin_and(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE bin_and(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END))
```

###### H2

```sql
bit_nand_agg(BOOK.ID)
```

###### HSQLDB

```sql
((0 - (CASE min(
  CASE bitand(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE min(
  CASE bitand(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)) - 1)
```

###### Oracle

```sql
((0 - bit_and_agg(BOOK.ID)) - 1)
```

###### Snowflake

```sql
bitnot(bit_and_agg(BOOK.ID))
```

###### Trino

```sql
bitwise_not(bitwise_and_agg(BOOK.ID))
```

###### Vertica

```sql
~(hex_to_integer(to_hex(bit_and(hex_to_binary(to_hex(BOOK.ID))))))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-nor-agg-function"></a>
##### 3.11.26.16. BIT_NOR_AGG

An aggregate function to perform the equivalent of the [BIT_NOR function](#bit-nor-function) on a data set. In other words, the resulting bits are:

- `0` at position `p` if the argument is `1` at position `p` for at least one row in the group.
- `1` at position `p` if the argument is `0` at position `p` for every row in the group.

As with most aggregate functions, `NULL` values are not aggregated.

```sql
SELECT
  bit_nor_agg(ID),
  bit_nor_agg(AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         bitNorAgg(BOOK.ID),
         bitNorAgg(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+-------------+--------------+
| bit_nor_agg | bit_nor_agg  |
+-------------+--------------+
|          -8 |           -4 |
+-------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
bitNorAgg(BOOK.ID.coerce(TINYINT))
```

Translates to the following dialect specific expressions:

###### ASE, MemSQL, Redshift, SQLDataWarehouse, SQLServer, SQLite

```sql
~((CASE max(
  CASE (BOOK.ID & 1)
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 2)
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 4)
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 8)
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 16)
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 32)
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 64)
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & -128)
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END))
```

###### Aurora MySQL, Aurora Postgres

```sql
~(bit_or_agg(BOOK.ID))
```

###### BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MySQL, Postgres, Spanner, Sybase, YugabyteDB

```sql
~(bit_or(BOOK.ID))
```

###### ClickHouse

```sql
bitNot(groupBitOr(BOOK.ID))
```

###### DB2, Hana, Informix, Teradata

```sql
bitnot((CASE max(
  CASE bitand(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END))
```

###### Exasol

```sql
bit_not((CASE max(
  CASE bit_and(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END))
```

###### Firebird

```sql
bin_not((CASE max(
  CASE bin_and(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END))
```

###### H2

```sql
bit_nor_agg(BOOK.ID)
```

###### HSQLDB

```sql
((0 - (CASE max(
  CASE bitand(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)) - 1)
```

###### Oracle

```sql
((0 - bit_or_agg(BOOK.ID)) - 1)
```

###### Snowflake

```sql
bitnot(bit_or_agg(BOOK.ID))
```

###### Trino

```sql
bitwise_not(bitwise_or_agg(BOOK.ID))
```

###### Vertica

```sql
~(hex_to_integer(to_hex(bit_or(hex_to_binary(to_hex(BOOK.ID))))))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-or-agg-function"></a>
##### 3.11.26.17. BIT_OR_AGG

An aggregate function to perform the equivalent of the [BIT_OR function](#bit-or-function) on a data set. In other words, the resulting bits are:

- `1` at position `p` if the argument is `1` at position `p` for at least one row in the group.
- `0` at position `p` if the argument is `0` at position `p` for every row in the group.

As with most aggregate functions, `NULL` values are not aggregated.

```sql
SELECT
  bit_or_agg(ID),
  bit_or_agg(AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         bitOrAgg(BOOK.ID),
         bitOrAgg(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+------------+------------+
| bit_or_agg | bit_or_agg |
+------------+------------+
|          7 |          3 |
+------------+------------+
```

###### Dialect support

This example using jOOQ:

```java
bitOrAgg(BOOK.ID.coerce(TINYINT))
```

Translates to the following dialect specific expressions:

###### ASE, MemSQL, Redshift, SQLDataWarehouse, SQLServer, SQLite

```sql
(CASE max(
  CASE (BOOK.ID & 1)
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 2)
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 4)
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 8)
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 16)
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 32)
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & 64)
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE (BOOK.ID & -128)
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)
```

###### Aurora MySQL, Aurora Postgres, H2, Oracle, Snowflake

```sql
bit_or_agg(BOOK.ID)
```

###### BigQuery, CockroachDB, Databricks, DuckDB, MariaDB, MySQL, Postgres, Spanner, Sybase, YugabyteDB

```sql
bit_or(BOOK.ID)
```

###### ClickHouse

```sql
groupBitOr(BOOK.ID)
```

###### DB2, HSQLDB, Hana, Informix, Teradata

```sql
(CASE max(
  CASE bitand(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE bitand(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)
```

###### Exasol

```sql
(CASE max(
  CASE bit_and(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE bit_and(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)
```

###### Firebird

```sql
(CASE max(
  CASE bin_and(
    BOOK.ID,
    1
  )
    WHEN 0 THEN 0
    WHEN 1 THEN 1
  END
)
  WHEN 1 THEN 1
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    2
  )
    WHEN 0 THEN 0
    WHEN 2 THEN 2
  END
)
  WHEN 2 THEN 2
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    4
  )
    WHEN 0 THEN 0
    WHEN 4 THEN 4
  END
)
  WHEN 4 THEN 4
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    8
  )
    WHEN 0 THEN 0
    WHEN 8 THEN 8
  END
)
  WHEN 8 THEN 8
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    16
  )
    WHEN 0 THEN 0
    WHEN 16 THEN 16
  END
)
  WHEN 16 THEN 16
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    32
  )
    WHEN 0 THEN 0
    WHEN 32 THEN 32
  END
)
  WHEN 32 THEN 32
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    64
  )
    WHEN 0 THEN 0
    WHEN 64 THEN 64
  END
)
  WHEN 64 THEN 64
  WHEN 0 THEN 0
END + CASE max(
  CASE bin_and(
    BOOK.ID,
    -128
  )
    WHEN 0 THEN 0
    WHEN -128 THEN -128
  END
)
  WHEN -128 THEN -128
  WHEN 0 THEN 0
END)
```

###### Trino

```sql
bitwise_or_agg(BOOK.ID)
```

###### Vertica

```sql
hex_to_integer(to_hex(bit_or(hex_to_binary(to_hex(BOOK.ID)))))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-xor-agg-function"></a>
##### 3.11.26.18. BIT_XOR_AGG

An aggregate function to perform the equivalent of the [BIT_XOR function](#bit-xor-function) on a data set. In other words, the resulting bits are:

- `1` at position `p` if the argument is `1` at position `p` for an odd number of rows in the group.
- `0` at position `p` if the argument is `0` at position `p` for an even number of rows in the group.

As with most aggregate functions, `NULL` values are not aggregated.

```sql
SELECT
  bit_xor_agg(ID),
  bit_xor_agg(AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         bitXorAgg(BOOK.ID),
         bitXorAgg(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+-------------+-------------+
| bit_xor_agg | bit_xor_agg |
+-------------+-------------+
|           4 |           0 |
+-------------+-------------+
```

###### Dialect support

This example using jOOQ:

```java
bitXorAgg(BOOK.ID.coerce(TINYINT))
```

Translates to the following dialect specific expressions:

###### ASE, Redshift, SQLDataWarehouse, SQLServer

```sql
(CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 1) = 1 THEN 1
  END) % 2) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 2) = 2 THEN 1
  END) % 2) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 4) = 4 THEN 1
  END) % 2) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 8) = 8 THEN 1
  END) % 2) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 16) = 16 THEN 1
  END) % 2) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 32) = 32 THEN 1
  END) % 2) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 64) = 64 THEN 1
  END) % 2) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & -128) = -128 THEN 1
  END) % 2) = 1 THEN -128
  ELSE 0
END)
```

###### Aurora MySQL, Oracle, Snowflake

```sql
bit_xor_agg(BOOK.ID)
```

###### Aurora Postgres, CockroachDB, YugabyteDB

```sql
(CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 1) = 1),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 2) = 2),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 4) = 4),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 8) = 8),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 16) = 16),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 32) = 32),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 64) = 64),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & -128) = -128),
    2
  ) = 1 THEN -128
  ELSE 0
END)
```

###### BigQuery, Databricks, DuckDB, MariaDB, MySQL, Postgres, Spanner, Sybase

```sql
bit_xor(BOOK.ID)
```

###### ClickHouse

```sql
groupBitXor(BOOK.ID)
```

###### DB2, Hana, Informix

```sql
(CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        1
      ) = 1 THEN 1
    END),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        2
      ) = 2 THEN 1
    END),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        4
      ) = 4 THEN 1
    END),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        8
      ) = 8 THEN 1
    END),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        16
      ) = 16 THEN 1
    END),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        32
      ) = 32 THEN 1
    END),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        64
      ) = 64 THEN 1
    END),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        -128
      ) = -128 THEN 1
    END),
    2
  ) = 1 THEN -128
  ELSE 0
END)
```

###### Exasol

```sql
(CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        1
      ) = 1 THEN 1
    END),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        2
      ) = 2 THEN 1
    END),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        4
      ) = 4 THEN 1
    END),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        8
      ) = 8 THEN 1
    END),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        16
      ) = 16 THEN 1
    END),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        32
      ) = 32 THEN 1
    END),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        64
      ) = 64 THEN 1
    END),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        -128
      ) = -128 THEN 1
    END),
    2
  ) = 1 THEN -128
  ELSE 0
END)
```

###### Firebird

```sql
(CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      1
    ) = 1),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      2
    ) = 2),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      4
    ) = 4),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      8
    ) = 8),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      16
    ) = 16),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      32
    ) = 32),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      64
    ) = 64),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      -128
    ) = -128),
    2
  ) = 1 THEN -128
  ELSE 0
END)
```

###### H2, HSQLDB

```sql
(CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      1
    ) = 1),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      2
    ) = 2),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      4
    ) = 4),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      8
    ) = 8),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      16
    ) = 16),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      32
    ) = 32),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      64
    ) = 64),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      -128
    ) = -128),
    2
  ) = 1 THEN -128
  ELSE 0
END)
```

###### MemSQL

```sql
(CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 1) = 1 THEN 1
    END),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 2) = 2 THEN 1
    END),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 4) = 4 THEN 1
    END),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 8) = 8 THEN 1
    END),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 16) = 16 THEN 1
    END),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 32) = 32 THEN 1
    END),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 64) = 64 THEN 1
    END),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & -128) = -128 THEN 1
    END),
    2
  ) = 1 THEN -128
  ELSE 0
END)
```

###### SQLite

```sql
(CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 1) = 1) % 2) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 2) = 2) % 2) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 4) = 4) % 2) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 8) = 8) % 2) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 16) = 16) % 2) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 32) = 32) % 2) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 64) = 64) % 2) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & -128) = -128) % 2) = 1 THEN -128
  ELSE 0
END)
```

###### Teradata

```sql
(CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      1
    ) = 1 THEN 1
  END) MOD 2) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      2
    ) = 2 THEN 1
  END) MOD 2) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      4
    ) = 4 THEN 1
  END) MOD 2) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      8
    ) = 8 THEN 1
  END) MOD 2) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      16
    ) = 16 THEN 1
  END) MOD 2) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      32
    ) = 32 THEN 1
  END) MOD 2) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      64
    ) = 64 THEN 1
  END) MOD 2) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      -128
    ) = -128 THEN 1
  END) MOD 2) = 1 THEN -128
  ELSE 0
END)
```

###### Trino

```sql
(CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      1
    ) = 1),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      2
    ) = 2),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      4
    ) = 4),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      8
    ) = 8),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      16
    ) = 16),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      32
    ) = 32),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      64
    ) = 64),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      -128
    ) = -128),
    2
  ) = 1 THEN -128
  ELSE 0
END)
```

###### Vertica

```sql
hex_to_integer(to_hex(bit_xor(hex_to_binary(to_hex(BOOK.ID)))))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bit-xnor-agg-function"></a>
##### 3.11.26.19. BIT_XNOR_AGG

An aggregate function to perform the equivalent of the [BIT_XNOR function](#bit-xnor-function) on a data set. In other words, the resulting bits are:

- `0` at position `p` if the argument is `1` at position `p` for an odd number of rows in the group.
- `1` at position `p` if the argument is `0` at position `p` for an even number of rows in the group.

As with most aggregate functions, `NULL` values are not aggregated.

```sql
SELECT
  bit_xnor_agg(ID),
  bit_xnor_agg(AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         bitXNorAgg(BOOK.ID),
         bitXNorAgg(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+--------------+--------------+
| bit_xnor_agg | bit_xnor_agg |
+--------------+--------------+
|           -5 |           -1 |
+--------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
bitXNorAgg(BOOK.ID.coerce(TINYINT))
```

Translates to the following dialect specific expressions:

###### ASE, Redshift, SQLDataWarehouse, SQLServer

```sql
~((CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 1) = 1 THEN 1
  END) % 2) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 2) = 2 THEN 1
  END) % 2) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 4) = 4 THEN 1
  END) % 2) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 8) = 8 THEN 1
  END) % 2) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 16) = 16 THEN 1
  END) % 2) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 32) = 32 THEN 1
  END) % 2) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & 64) = 64 THEN 1
  END) % 2) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN (BOOK.ID & -128) = -128 THEN 1
  END) % 2) = 1 THEN -128
  ELSE 0
END))
```

###### Aurora MySQL

```sql
~(bit_xor_agg(BOOK.ID))
```

###### Aurora Postgres, CockroachDB, YugabyteDB

```sql
~((CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 1) = 1),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 2) = 2),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 4) = 4),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 8) = 8),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 16) = 16),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 32) = 32),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & 64) = 64),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE (BOOK.ID & -128) = -128),
    2
  ) = 1 THEN -128
  ELSE 0
END))
```

###### BigQuery, Databricks, DuckDB, MariaDB, MySQL, Postgres, Spanner, Sybase

```sql
~(bit_xor(BOOK.ID))
```

###### ClickHouse

```sql
bitNot(groupBitXor(BOOK.ID))
```

###### DB2, Hana, Informix

```sql
bitnot((CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        1
      ) = 1 THEN 1
    END),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        2
      ) = 2 THEN 1
    END),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        4
      ) = 4 THEN 1
    END),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        8
      ) = 8 THEN 1
    END),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        16
      ) = 16 THEN 1
    END),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        32
      ) = 32 THEN 1
    END),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        64
      ) = 64 THEN 1
    END),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bitand(
        BOOK.ID,
        -128
      ) = -128 THEN 1
    END),
    2
  ) = 1 THEN -128
  ELSE 0
END))
```

###### Exasol

```sql
bit_not((CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        1
      ) = 1 THEN 1
    END),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        2
      ) = 2 THEN 1
    END),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        4
      ) = 4 THEN 1
    END),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        8
      ) = 8 THEN 1
    END),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        16
      ) = 16 THEN 1
    END),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        32
      ) = 32 THEN 1
    END),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        64
      ) = 64 THEN 1
    END),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN bit_and(
        BOOK.ID,
        -128
      ) = -128 THEN 1
    END),
    2
  ) = 1 THEN -128
  ELSE 0
END))
```

###### Firebird

```sql
bin_not((CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      1
    ) = 1),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      2
    ) = 2),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      4
    ) = 4),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      8
    ) = 8),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      16
    ) = 16),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      32
    ) = 32),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      64
    ) = 64),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bin_and(
      BOOK.ID,
      -128
    ) = -128),
    2
  ) = 1 THEN -128
  ELSE 0
END))
```

###### H2

```sql
bit_xnor_agg(BOOK.ID)
```

###### HSQLDB

```sql
((0 - (CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      1
    ) = 1),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      2
    ) = 2),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      4
    ) = 4),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      8
    ) = 8),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      16
    ) = 16),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      32
    ) = 32),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      64
    ) = 64),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitand(
      BOOK.ID,
      -128
    ) = -128),
    2
  ) = 1 THEN -128
  ELSE 0
END)) - 1)
```

###### MemSQL

```sql
~((CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 1) = 1 THEN 1
    END),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 2) = 2 THEN 1
    END),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 4) = 4 THEN 1
    END),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 8) = 8 THEN 1
    END),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 16) = 16 THEN 1
    END),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 32) = 32 THEN 1
    END),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & 64) = 64 THEN 1
    END),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(CASE
      WHEN (BOOK.ID & -128) = -128 THEN 1
    END),
    2
  ) = 1 THEN -128
  ELSE 0
END))
```

###### Oracle

```sql
((0 - bit_xor_agg(BOOK.ID)) - 1)
```

###### Snowflake

```sql
bitnot(bit_xor_agg(BOOK.ID))
```

###### SQLite

```sql
~((CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 1) = 1) % 2) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 2) = 2) % 2) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 4) = 4) % 2) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 8) = 8) % 2) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 16) = 16) % 2) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 32) = 32) % 2) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & 64) = 64) % 2) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN (count(*) FILTER (WHERE (BOOK.ID & -128) = -128) % 2) = 1 THEN -128
  ELSE 0
END))
```

###### Teradata

```sql
bitnot((CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      1
    ) = 1 THEN 1
  END) MOD 2) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      2
    ) = 2 THEN 1
  END) MOD 2) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      4
    ) = 4 THEN 1
  END) MOD 2) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      8
    ) = 8 THEN 1
  END) MOD 2) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      16
    ) = 16 THEN 1
  END) MOD 2) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      32
    ) = 32 THEN 1
  END) MOD 2) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      64
    ) = 64 THEN 1
  END) MOD 2) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN (count(CASE
    WHEN bitand(
      BOOK.ID,
      -128
    ) = -128 THEN 1
  END) MOD 2) = 1 THEN -128
  ELSE 0
END))
```

###### Trino

```sql
bitwise_not((CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      1
    ) = 1),
    2
  ) = 1 THEN 1
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      2
    ) = 2),
    2
  ) = 1 THEN 2
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      4
    ) = 4),
    2
  ) = 1 THEN 4
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      8
    ) = 8),
    2
  ) = 1 THEN 8
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      16
    ) = 16),
    2
  ) = 1 THEN 16
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      32
    ) = 32),
    2
  ) = 1 THEN 32
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      64
    ) = 64),
    2
  ) = 1 THEN 64
  ELSE 0
END + CASE
  WHEN mod(
    count(*) FILTER (WHERE bitwise_and(
      BOOK.ID,
      -128
    ) = -128),
    2
  ) = 1 THEN -128
  ELSE 0
END))
```

###### Vertica

```sql
~(hex_to_integer(to_hex(bit_xor(hex_to_binary(to_hex(BOOK.ID))))))
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bool-and-function"></a>
##### 3.11.26.20. BOOL_AND

The `BOOL_AND()` aggregate function calculates the boolean conjunction of all the boolean values in the aggregated group. In other words, this is:

- `TRUE` if the argument is `TRUE` for every row in the group.
- `FALSE` if at the argument is `FALSE` for at least one row in the group.

As with most aggregate functions, `NULL` values are not aggregated, so three valued logic does not apply here.

```sql
SELECT
  bool_and(ID < 4),
  bool_and(ID < 5)
FROM BOOK
```

```java
create.select(
         boolAnd(BOOK.ID.lt(4)),
         boolAnd(BOOK.ID.lt(5)))
      .from(BOOK)
```

Producing:

```text
+----------+----------+
| bool_and | bool_and |
+----------+----------+
| false    | true     |
+----------+----------+
```

###### Dialect support

This example using jOOQ:

```java
boolAnd(BOOK.ID.lt(4))
```

Translates to the following dialect specific expressions:

###### Access

```sql
(min(
  SWITCH(BOOK.ID < 4, 1, TRUE, 0)
) = 1)
```

###### ASE, DB2, SQLDataWarehouse, SQLServer, Sybase, Teradata

```sql
CASE
  WHEN min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN 1
  WHEN NOT (min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN 0
END
```

###### Aurora MySQL, ClickHouse, Firebird, H2, HSQLDB, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLite

```sql
(min(
  CASE
    WHEN BOOK.ID < 4 THEN 1
    ELSE 0
  END
) = 1)
```

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Postgres, Trino, Vertica, YugabyteDB

```sql
bool_and((BOOK.ID < 4))
```

###### BigQuery, Spanner

```sql
logical_and((BOOK.ID < 4))
```

###### Exasol

```sql
every((BOOK.ID < 4))
```

###### Hana

```sql
CASE
  WHEN min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN TRUE
  WHEN NOT (min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN FALSE
END
```

###### Informix

```sql
CASE
  WHEN min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN cast('t' AS boolean)
  WHEN NOT (min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN cast('f' AS boolean)
END
```

###### Snowflake

```sql
booland_agg((BOOK.ID < 4))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="bool-or-function"></a>
##### 3.11.26.21. BOOL_OR

The `BOOL_OR()` aggregate function calculates the boolean disjunction of all the boolean values in the aggregated group. In other words, this is:

- `FALSE` if the argument is `FALSE` for every row in the group.
- `TRUE` if at the argument is `TRUE` for at least one row in the group.

As with most aggregate functions, `NULL` values are not aggregated, so three valued logic does not apply here.

```sql
SELECT
  bool_or(ID >= 4),
  bool_or(ID >= 5)
FROM BOOK
```

```java
create.select(
         boolOr(BOOK.ID.ge(4)),
         boolOr(BOOK.ID.ge(5)))
      .from(BOOK)
```

Producing:

```text
+---------+---------+
| bool_or | bool_or |
+---------+---------+
| true    | false   |
+---------+---------+
```

###### Dialect support

This example using jOOQ:

```java
boolOr(BOOK.ID.ge(4))
```

Translates to the following dialect specific expressions:

###### Access

```sql
(max(
  SWITCH(BOOK.ID >= 4, 1, TRUE, 0)
) = 1)
```

###### ASE, DB2, SQLDataWarehouse, SQLServer, Sybase, Teradata

```sql
CASE
  WHEN max(
    CASE
      WHEN BOOK.ID >= 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN 1
  WHEN NOT (max(
    CASE
      WHEN BOOK.ID >= 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN 0
END
```

###### Aurora MySQL, ClickHouse, Firebird, H2, HSQLDB, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLite

```sql
(max(
  CASE
    WHEN BOOK.ID >= 4 THEN 1
    ELSE 0
  END
) = 1)
```

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Postgres, Trino, Vertica, YugabyteDB

```sql
bool_or((BOOK.ID >= 4))
```

###### BigQuery, Spanner

```sql
logical_or((BOOK.ID >= 4))
```

###### Exasol

```sql
any((BOOK.ID >= 4))
```

###### Hana

```sql
CASE
  WHEN max(
    CASE
      WHEN BOOK.ID >= 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN TRUE
  WHEN NOT (max(
    CASE
      WHEN BOOK.ID >= 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN FALSE
END
```

###### Informix

```sql
CASE
  WHEN max(
    CASE
      WHEN BOOK.ID >= 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN cast('t' AS boolean)
  WHEN NOT (max(
    CASE
      WHEN BOOK.ID >= 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN cast('f' AS boolean)
END
```

###### Snowflake

```sql
boolor_agg((BOOK.ID >= 4))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="collect-function"></a>
##### 3.11.26.22. COLLECT

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The `COLLECT()` aggregate function is Oracle's vendor specific version of the standard SQL [ARRAY_AGG](#array-agg-function) function. It produces a structurally typed array, which is implemented behind the scenes as a nominally typed, system-generated array. It supports being used with an [ORDER BY](#aggregate-order-by) clause.

The following example is using an auxiliary data type and casting the `COLLECT()` result to that type.

```sql
CREATE TYPE NUMBERS AS TABLE OF NUMBER(10);
SELECT CAST(collect(ID ORDER BY ID) AS NUMBERS);
FROM BOOK;
```

```java
create.select(
         collect(BOOK.ID, NumbersRecord.class).orderBy(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+--------------+
| collect      |
+--------------+
| [1, 2, 3, 4] |
+--------------+
```

<a id="count-function"></a>
##### 3.11.26.23. COUNT

The `COUNT()` aggregate function comes in two flavours:

- `COUNT(*)`: This version counts the number of tuples in a group, regardless of any contents, including `NULL` values.
- `COUNT(expression)`: This version counts the number of non-`NULL` expression evaluations per group.

The second version can be used to emulate the [FILTER](#aggregate-filter) clause as the argument expression effectively filters out `NULL` values. Alternatively, in the case of a [LEFT JOIN](#join-clause), the outer joined rows can be counted using an expression on the primary key, because `COUNT(*)` always produces at least one row.

```sql
SELECT
  AUTHOR.ID,
  count(*),
  count(BOOK.ID)
FROM AUTHOR
LEFT JOIN BOOK
ON BOOK.AUTHOR_ID = AUTHOR.ID
```

```java
create.select(
         AUTHOR.ID,
         count(),
         count(BOOK.ID))
      .from(AUTHOR)
      .leftJoin(BOOK)
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
```

Producing (assuming the presence of an author with ID = 3, but without books):

```text
+----+----------+----------------+
| ID | count(*) | count(BOOK.ID) |
+----+----------+----------------+
|  1 |        2 |              2 |
|  2 |        2 |              2 |
|  3 |        1 |              0 |
+----+----------+----------------+
```

> [!TIP]
> For historic reasons, this function returns a [`java.lang.Integer`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Integer.html) value. To support larger [`java.lang.Long`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Long.html) result values, use [`DSL.countLarge()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#countLarge()) instead.

###### Dialect support

This example using jOOQ:

```java
count(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
count(BOOK.ID)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="cume-dist-function"></a>
##### 3.11.26.24. CUME_DIST

The `CUME_DIST()` [hypothetical set function](#aggregate-within-group) calculates the cumulative distribution of the hypothetical value, i.e. the relative rank from 1/N to 1 ([PERCENT_RANK](#percent-rank-function) produces values from 0 to 1)

```sql
SELECT
  cume_dist(0) WITHIN GROUP (ORDER BY ID),
  cume_dist(2) WITHIN GROUP (ORDER BY ID),
  cume_dist(4) WITHIN GROUP (ORDER BY ID)
FROM BOOK
```

```java
create.select(
         cumeDist(val(0)).withinGroupOrderBy(BOOK.ID),
         cumeDist(val(2)).withinGroupOrderBy(BOOK.ID),
         cumeDist(val(4)).withinGroupOrderBy(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+--------------+--------------+--------------+
| cume_dist(0) | cume_dist(2) | cume_dist(4) |
+--------------+--------------+--------------+
|          0.2 |          0.6 |          1.0 |
+--------------+--------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
cumeDist(val(0)).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, Oracle, Postgres, YugabyteDB

```sql
cume_dist(0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="dense-rank-function"></a>
##### 3.11.26.25. DENSE_RANK

The `DENSE_RANK()` [hypothetical set function](#aggregate-within-group) calculates the rank without gaps of the hypothetical value, i.e. dense ranks will be 1, 1, 1, 2, 3, 3, 4 ([RANK](#rank-function) produces values with gaps, e.g. 1, 1, 1, 4, 5, 5, 7)

```sql
SELECT
  dense_rank(0) WITHIN GROUP (ORDER BY AUTHOR_ID),
  dense_rank(1) WITHIN GROUP (ORDER BY AUTHOR_ID),
  dense_rank(2) WITHIN GROUP (ORDER BY AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         denseRank(val(0)).withinGroupOrderBy(BOOK.AUTHOR_ID),
         denseRank(val(2)).withinGroupOrderBy(BOOK.AUTHOR_ID),
         denseRank(val(4)).withinGroupOrderBy(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+---------------+---------------+---------------+
| dense_rank(0) | dense_rank(1) | dense_rank(2) |
+---------------+---------------+---------------+
|             1 |             1 |             2 |
+---------------+---------------+---------------+
```

###### Dialect support

This example using jOOQ:

```java
denseRank(val(0)).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, Oracle, Postgres, YugabyteDB

```sql
dense_rank(0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="every-function"></a>
##### 3.11.26.26. EVERY

The `EVERY()` aggregate function is the standard SQL version of the [BOOL_AND](#bool-and-function) function.

```sql
SELECT
  every(ID < 4),
  every(ID < 5)
FROM BOOK
```

```java
create.select(
         every(BOOK.ID.lt(4)),
         every(BOOK.ID.lt(5)))
      .from(BOOK)
```

Producing:

```text
+---------------+---------------+
| every(ID < 4) | every(ID < 5) |
+---------------+---------------+
| false         | true          |
+---------------+---------------+
```

###### Dialect support

This example using jOOQ:

```java
every(BOOK.ID.lt(4))
```

Translates to the following dialect specific expressions:

###### Access

```sql
(min(
  SWITCH(BOOK.ID < 4, 1, TRUE, 0)
) = 1)
```

###### ASE, DB2, SQLDataWarehouse, SQLServer, Sybase, Teradata

```sql
CASE
  WHEN min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN 1
  WHEN NOT (min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN 0
END
```

###### Aurora MySQL, ClickHouse, Firebird, H2, HSQLDB, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLite

```sql
(min(
  CASE
    WHEN BOOK.ID < 4 THEN 1
    ELSE 0
  END
) = 1)
```

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Postgres, Trino, Vertica, YugabyteDB

```sql
bool_and((BOOK.ID < 4))
```

###### BigQuery, Spanner

```sql
logical_and((BOOK.ID < 4))
```

###### Exasol

```sql
every((BOOK.ID < 4))
```

###### Hana

```sql
CASE
  WHEN min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN TRUE
  WHEN NOT (min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN FALSE
END
```

###### Informix

```sql
CASE
  WHEN min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1 THEN cast('t' AS boolean)
  WHEN NOT (min(
    CASE
      WHEN BOOK.ID < 4 THEN 1
      ELSE 0
    END
  ) = 1) THEN cast('f' AS boolean)
END
```

###### Snowflake

```sql
booland_agg((BOOK.ID < 4))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="group-concat-function"></a>
##### 3.11.26.27. GROUP_CONCAT

The `GROUP_CONCAT()` aggregate function is the MySQL version of the standard SQL [LISTAGG](#listagg-function) function, to concatenate aggregate data into a string. It supports being used with an [ORDER BY](#aggregate-order-by) clause, which uses the expected syntax, unlike `LISTAGG()`, which uses the [WITHIN GROUP](#aggregate-within-group) syntax.

```sql
SELECT
  group_concat(ID),
  group_concat(ID ORDER BY ID),
  group_concat(ID SEPARATOR '; '),
  group_concat(ID ORDER BY ID SEPARATOR '; '),
FROM BOOK
```

```java
create.select(
         groupConcat(BOOK.ID),
         groupConcat(BOOK.ID).orderBy(BOOK.ID),
         groupConcat(BOOK.ID).separator("; "),
         groupConcat(BOOK.ID).orderBy(BOOK.ID).separator("; "))
      .from(BOOK).fetch();
```

Producing:

```text
+--------------+--------------+--------------+--------------+
| group_concat | group_concat | group_concat | group_concat |
+--------------+--------------+--------------+--------------+
| 1, 3, 4, 2   | 1, 2, 3, 4   | 1; 3; 4; 2   | 1; 2; 3; 4   |
+--------------+--------------+--------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
groupConcat(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, H2, HSQLDB, MariaDB, MemSQL, MySQL

```sql
group_concat(BOOK.ID SEPARATOR ',')
```

###### Aurora Postgres, DuckDB, Hana, Postgres

```sql
string_agg(cast(BOOK.ID AS varchar), ',')
```

###### BigQuery, CockroachDB, Spanner

```sql
string_agg(cast(BOOK.ID AS string), ',')
```

###### DB2, Exasol, Oracle, Redshift

```sql
listagg(BOOK.ID, ',')
```

###### SQLite

```sql
group_concat(BOOK.ID, ',')
```

###### SQLServer

```sql
string_agg(cast(BOOK.ID AS varchar(max)), ',')
```

###### Sybase

```sql
list(cast(BOOK.ID AS varchar), ',')
```

###### Teradata

```sql
substring(xmlserialize(CONTENT xmlagg((',' || cast(BOOK.ID AS varchar(32000)))) AS varchar(32000)) FROM 2)
```

###### Trino

```sql
listagg(cast(BOOK.ID AS varchar), ',')
```

###### ASE, Access, ClickHouse, Databricks, Firebird, Informix, SQLDataWarehouse, Snowflake, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-arrayagg-function"></a>
##### 3.11.26.28. JSON_ARRAYAGG

A data set can be aggregated into a [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) or [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html) array using `JSON_ARRAYAGG`

```sql
SELECT json_arrayagg(author.id)
FROM author
 
```

```java
create.select(jsonArrayAgg(AUTHOR.ID))
      .from(AUTHOR)
      .fetch();
```

The result would look like this:

```text
+---------------+
| json_arrayagg |
+---------------+
| [1,2]         |
+---------------+
```

###### Ordering aggregation contents

When aggregating data into an array or JSON array, ordering may be relevant. For this, use the `ORDER BY` clause in `JSON_ARRAYAGG`

```sql
SELECT json_arrayagg(author.id ORDER BY author.id DESC)
FROM author
 
```

```java
create.select(jsonArrayAgg(AUTHOR.ID).orderBy(AUTHOR.ID.desc())
      .from(AUTHOR)
      .fetch();
```

The result would look like this:

```text
+---------------+
| json_arrayagg |
+---------------+
| [2,1]         |
+---------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArrayAgg(AUTHOR.ID)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, H2, Oracle, SQLDataWarehouse, SQLServer

```sql
json_arrayagg(AUTHOR.ID)
```

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
json_agg(AUTHOR.ID)
```

###### BigQuery, Spanner

```sql
to_json(
  coalesce(
    array_agg(AUTHOR.ID), cast(ARRAY[] AS array<int64>)
  )
)
```

###### ClickHouse

```sql
toJSONString(groupArray(AUTHOR.ID))
```

###### Databricks, DuckDB

```sql
to_json(array_agg(AUTHOR.ID))
```

###### DB2

```sql
cast(
  ('[' || listagg(
    AUTHOR.ID,
    ','
  ) || ']')
  AS varchar(32672)
)
```

###### MariaDB, MySQL

```sql
json_merge_preserve(
  '[]',
  concat(
    '[',
    group_concat(AUTHOR.ID SEPARATOR ','),
    ']'
  )
)
```

###### Snowflake

```sql
array_agg(coalesce(
  to_variant(AUTHOR.ID),
  parse_json('null')
))
```

###### SQLite

```sql
json_group_array(AUTHOR.ID)
```

###### Trino

```sql
cast(array_agg(AUTHOR.ID) AS json)
```

###### ASE, Access, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-arrayagg-function-absent-on-null"></a>
###### 3.11.26.28.1. ABSENT ON NULL

The `JSON_ARRAYAGG` function has a `ABSENT ON NULL` clause to indicate that `NULL` values should not be contained in the output JSON array. Instead, the values should be removed from the array if they are `NULL`:

```sql
SELECT json_arrayagg(
  language.description
  ABSENT ON NULL
)
FROM language
```

```java
create.select(jsonArrayAgg(
          LANGUAGE.DESCRIPTION)
          .absentOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+---------------+
| json_arrayagg |
+---------------+
| ["English"]   |
+---------------+
```

The effect is similar to that of the [FILTER clause](#aggregate-filter).

###### Dialect support

This example using jOOQ:

```java
jsonArrayAgg(LANGUAGE.DESCRIPTION).absentOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, H2, Oracle, SQLDataWarehouse, SQLServer

```sql
json_arrayagg(LANGUAGE.DESCRIPTION ABSENT ON NULL)
```

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
json_agg(LANGUAGE.DESCRIPTION) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL)
```

###### BigQuery, Spanner

```sql
json_strip_nulls(to_json(
  coalesce(
    array_agg(LANGUAGE.DESCRIPTION), cast(ARRAY[] AS array<string>)
  )
))
```

###### DuckDB

```sql
to_json(array_agg(LANGUAGE.DESCRIPTION) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL))
```

###### MariaDB, MySQL

```sql
json_merge_preserve(
  '[]',
  concat(
    '[',
    group_concat(json_quote(LANGUAGE.DESCRIPTION) SEPARATOR ','),
    ']'
  )
)
```

###### Snowflake

```sql
array_agg(LANGUAGE.DESCRIPTION)
```

###### SQLite

```sql
json_group_array(LANGUAGE.DESCRIPTION) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL)
```

###### Trino

```sql
cast(array_agg(LANGUAGE.DESCRIPTION) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL) AS json)
```

###### ASE, Access, ClickHouse, DB2, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-arrayagg-function-null-on-null"></a>
###### 3.11.26.28.2. NULL ON NULL

The `JSON_ARRAYAGG` function has a `NULL ON NULL` clause to indicate that `NULL` values should be included in the output JSON array:

```sql
SELECT json_arrayagg(
  language.description
  NULL ON NULL
)
FROM language
```

```java
create.select(jsonArrayAgg(
          LANGUAGE.DESCRIPTION)
          .nullOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+------------------+
| json_arrayagg    |
+------------------+
| ["English",null] |
+------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonArrayAgg(LANGUAGE.DESCRIPTION).nullOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, H2, Oracle, SQLDataWarehouse, SQLServer

```sql
json_arrayagg(LANGUAGE.DESCRIPTION NULL ON NULL)
```

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
json_agg(LANGUAGE.DESCRIPTION)
```

###### DuckDB

```sql
to_json(array_agg(LANGUAGE.DESCRIPTION))
```

###### MariaDB, MySQL

```sql
json_merge_preserve(
  '[]',
  concat(
    '[',
    group_concat(coalesce(
      json_quote(LANGUAGE.DESCRIPTION),
      'null'
    ) SEPARATOR ','),
    ']'
  )
)
```

###### Snowflake

```sql
array_agg(coalesce(
  to_variant(LANGUAGE.DESCRIPTION),
  parse_json('null')
))
```

###### Spanner

```sql
to_json(
  coalesce(
    array_agg(LANGUAGE.DESCRIPTION), cast(ARRAY[] AS array<string>)
  )
)
```

###### SQLite

```sql
json_group_array(LANGUAGE.DESCRIPTION)
```

###### Trino

```sql
cast(array_agg(LANGUAGE.DESCRIPTION) AS json)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-objectagg-function"></a>
##### 3.11.26.29. JSON_OBJECTAGG

A data set can be aggregated into a [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) or [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html) object using `JSON_OBJECTAGG`

```sql
SELECT json_objectagg(
  CAST(author.id AS varchar(100)),
  first_name
)
FROM author
 
```

```java
create.select(jsonObjectAgg(
         cast(AUTHOR.ID, VARCHAR(100)),
         AUTHOR.FIRST_NAME
      ))
      .from(AUTHOR)
      .fetch();
```

The result would look like this:

```text
+----------------------------+
| json_objectagg             |
+----------------------------+
| {"1":"George","2":"Paulo"} |
+----------------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonObjectAgg(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
json_object_agg(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
```

###### BigQuery, Spanner

```sql
json_object(
  array_agg(AUTHOR.FIRST_NAME),
  array_agg(AUTHOR.LAST_NAME)
)
```

###### CockroachDB

```sql
(('{' || string_agg(regexp_replace(cast(
  json_build_object(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
  AS string
), '^\{(.*)\}$', '\1', 'g'), ',') || '}'))
```

###### Databricks

```sql
to_json(map_from_entries(array_agg(STRUCT(AUTHOR.FIRST_NAME, cast(AUTHOR.LAST_NAME AS variant)))))
```

###### DB2

```sql
(('{' || listagg(
  regexp_replace(cast(
    json_object(KEY AUTHOR.FIRST_NAME VALUE AUTHOR.LAST_NAME)
    AS varchar(32672)
  ), '^\{(.*)\}$', '\1'),
  ','
) || '}'))
```

###### DuckDB

```sql
to_json(map_from_entries(array_agg(ROW(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME))))
```

###### H2, Oracle

```sql
json_objectagg(KEY AUTHOR.FIRST_NAME VALUE AUTHOR.LAST_NAME)
```

###### MariaDB, MySQL

```sql
json_objectagg(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
```

###### Snowflake

```sql
object_agg(coalesce(
  to_variant(AUTHOR.FIRST_NAME),
  parse_json('null')
), coalesce(
  to_variant(AUTHOR.LAST_NAME),
  parse_json('null')
))
```

###### SQLite

```sql
json_group_object(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
```

###### SQLServer

```sql
json_objectagg(AUTHOR.FIRST_NAME: AUTHOR.LAST_NAME)
```

###### Trino

```sql
cast(map(array_agg(AUTHOR.FIRST_NAME), array_agg(AUTHOR.LAST_NAME)) AS json)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-objectagg-function-absent-on-null"></a>
###### 3.11.26.29.1. ABSENT ON NULL

The `JSON_OBJECTAGG` function has a `ABSENT ON NULL` clause to indicate that `NULL` values should not be contained in the output JSON document. Instead, the key should be removed from the document if the value is `NULL`:

```sql
SELECT json_objectagg(
  language.cd, language.description
  ABSENT ON NULL
)
FROM language
```

```java
create.select(jsonObject(
          LANGUAGE.CD, LANGUAGE.DESCRIPTION)
          .absentOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+------------------+
| json_objectagg   |
+------------------+
| {"EN":"English"} |
+------------------+
```

The effect is similar to that of the [FILTER clause](#aggregate-filter).

###### Dialect support

This example using jOOQ:

```java
jsonObjectAgg(LANGUAGE.CD, LANGUAGE.DESCRIPTION).absentOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
json_object_agg(LANGUAGE.CD, LANGUAGE.DESCRIPTION) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL)
```

###### BigQuery, Spanner

```sql
json_strip_nulls(json_object(
  array_agg(LANGUAGE.CD),
  array_agg(LANGUAGE.DESCRIPTION)
))
```

###### CockroachDB

```sql
(('{' || string_agg(regexp_replace(cast(
  CASE
    WHEN LANGUAGE.DESCRIPTION IS NULL THEN cast(NULL AS json)
    ELSE json_build_object(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
  END
  AS string
), '^\{(.*)\}$', '\1', 'g'), ',') || '}'))
```

###### DB2

```sql
(('{' || listagg(
  regexp_replace(cast(
    CASE
      WHEN LANGUAGE.DESCRIPTION IS NULL THEN NULL
      ELSE json_object(KEY LANGUAGE.CD VALUE LANGUAGE.DESCRIPTION)
    END
    AS varchar(32672)
  ), '^\{(.*)\}$', '\1'),
  ','
) || '}'))
```

###### DuckDB

```sql
to_json(map_from_entries(array_agg(ROW(LANGUAGE.CD, LANGUAGE.DESCRIPTION)) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL)))
```

###### H2, Oracle

```sql
json_objectagg(KEY LANGUAGE.CD VALUE LANGUAGE.DESCRIPTION ABSENT ON NULL)
```

###### MariaDB

```sql
(concat(
  '{',
  group_concat(regexp_replace(cast(
    CASE
      WHEN LANGUAGE.DESCRIPTION IS NULL THEN NULL
      ELSE json_object(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
    END
    AS char
  ), '^\\{(.*)\\}$', '\\1') SEPARATOR ','),
  '}'
))
```

###### MySQL

```sql
(concat(
  '{',
  group_concat(regexp_replace(cast(
    CASE
      WHEN LANGUAGE.DESCRIPTION IS NULL THEN NULL
      ELSE json_object(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
    END
    AS char
  ), '^\\{(.*)\\}$', '$1') SEPARATOR ','),
  '}'
))
```

###### Snowflake

```sql
object_agg(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
```

###### SQLite

```sql
json_group_object(LANGUAGE.CD, LANGUAGE.DESCRIPTION) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL)
```

###### SQLServer

```sql
json_objectagg(LANGUAGE.CD: LANGUAGE.DESCRIPTION ABSENT ON NULL)
```

###### Trino

```sql
cast(map(array_agg(cast(LANGUAGE.CD AS varchar)) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL), array_agg(LANGUAGE.DESCRIPTION) FILTER (WHERE LANGUAGE.DESCRIPTION IS NOT NULL)) AS json)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-objectagg-function-null-on-null"></a>
###### 3.11.26.29.2. NULL ON NULL

The `JSON_OBJECTAGG` function has a `NULL ON NULL` clause to indicate that `NULL` values should be included in the output JSON document:

```sql
SELECT json_objectagg(
  language.cd, language.description
  NULL ON NULL
)
FROM language
```

```java
create.select(jsonObject(
          LANGUAGE.CD, LANGUAGE.DESCRIPTION)
          .nullOnNull())
      .from(LANGUAGE)
      .fetch();
```

The result would look like this:

```text
+----------------------------+
| json_objectagg             |
+----------------------------+
| {"EN":"English","DE":null} |
+----------------------------+
```

###### Dialect support

This example using jOOQ:

```java
jsonObjectAgg(LANGUAGE.CD, LANGUAGE.DESCRIPTION).nullOnNull()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
json_object_agg(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
```

###### BigQuery, Spanner

```sql
json_object(
  array_agg(LANGUAGE.CD),
  array_agg(LANGUAGE.DESCRIPTION)
)
```

###### CockroachDB

```sql
(('{' || string_agg(regexp_replace(cast(
  json_build_object(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
  AS string
), '^\{(.*)\}$', '\1', 'g'), ',') || '}'))
```

###### DB2

```sql
(('{' || listagg(
  regexp_replace(cast(
    json_object(KEY LANGUAGE.CD VALUE LANGUAGE.DESCRIPTION)
    AS varchar(32672)
  ), '^\{(.*)\}$', '\1'),
  ','
) || '}'))
```

###### DuckDB

```sql
to_json(map_from_entries(array_agg(ROW(LANGUAGE.CD, LANGUAGE.DESCRIPTION))))
```

###### H2, Oracle

```sql
json_objectagg(KEY LANGUAGE.CD VALUE LANGUAGE.DESCRIPTION NULL ON NULL)
```

###### MariaDB, MySQL

```sql
json_objectagg(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
```

###### Snowflake

```sql
object_agg(coalesce(
  to_variant(LANGUAGE.CD),
  parse_json('null')
), coalesce(
  to_variant(LANGUAGE.DESCRIPTION),
  parse_json('null')
))
```

###### SQLite

```sql
json_group_object(LANGUAGE.CD, LANGUAGE.DESCRIPTION)
```

###### SQLServer

```sql
json_objectagg(LANGUAGE.CD: LANGUAGE.DESCRIPTION NULL ON NULL)
```

###### Trino

```sql
cast(map(array_agg(cast(LANGUAGE.CD AS varchar)), array_agg(LANGUAGE.DESCRIPTION)) AS json)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="listagg-function"></a>
##### 3.11.26.30. LISTAGG

The `LISTAGG()` aggregate function aggregates data into a string. It uses the [WITHIN GROUP](#aggregate-within-group) syntax.

```sql
SELECT
  listagg(ID) WITHIN GROUP (ORDER BY ID),
  listagg(ID, '; ') WITHIN GROUP (ORDER BY ID),
FROM BOOK
```

```java
create.select(
         listAgg(BOOK.ID).withinGroupOrderBy(BOOK.ID),
         listAgg(BOOK.ID, "; ").withinGroupOrderBy(BOOK.ID))
      .from(BOOK).fetch();
```

Producing:

```text
+------------+--------------+
| listagg    | listagg      |
+------------+--------------+
| 1, 2, 3, 4 | 1; 2; 3; 4   |
+------------+--------------+
```

> [!TIP]
> See [LISTAGG (binary)](#binary-listagg-function) for a binary version of this function.

###### Dialect support

This example using jOOQ:

```java
listAgg(BOOK.AUTHOR_ID, ",").withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, H2, HSQLDB, MariaDB, MemSQL, MySQL

```sql
group_concat(BOOK.AUTHOR_ID ORDER BY BOOK.ID SEPARATOR ',')
```

###### Aurora Postgres, DuckDB, Hana, Postgres

```sql
string_agg(cast(BOOK.AUTHOR_ID AS varchar), ',' ORDER BY BOOK.ID)
```

###### BigQuery, CockroachDB, Spanner

```sql
string_agg(cast(BOOK.AUTHOR_ID AS string), ',' ORDER BY BOOK.ID)
```

###### DB2, Exasol, Oracle, Redshift

```sql
listagg(BOOK.AUTHOR_ID, ',') WITHIN GROUP (ORDER BY BOOK.ID)
```

###### SQLite

```sql
group_concat(BOOK.AUTHOR_ID ORDER BY BOOK.ID, ',')
```

###### SQLServer

```sql
string_agg(cast(BOOK.AUTHOR_ID AS varchar(max)), ',') WITHIN GROUP (ORDER BY BOOK.ID)
```

###### Sybase

```sql
list(cast(BOOK.AUTHOR_ID AS varchar), ',' ORDER BY BOOK.ID)
```

###### Teradata

```sql
substring(xmlserialize(CONTENT xmlagg((',' || cast(BOOK.AUTHOR_ID AS varchar(32000))) ORDER BY BOOK.ID) AS varchar(32000)) FROM 2)
```

###### Trino

```sql
listagg(cast(BOOK.AUTHOR_ID AS varchar), ',') WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, ClickHouse, Databricks, Firebird, Informix, SQLDataWarehouse, Snowflake, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="max-function"></a>
##### 3.11.26.31. MAX

The `MAX()` aggregate function calculates the maximum value of all input values

```sql
SELECT max(ID)
FROM BOOK
```

```java
create.select(max(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+-----+
| max |
+-----+
|   4 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
max(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
max(BOOK.ID)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="max-by-function"></a>
##### 3.11.26.32. MAX_BY

The `MAX_BY()` aggregate function calculates a `value` at the row containing the maximum value of all `by` values. This works the same way as the Oracle specific [KEEP clause](#aggregate-keep).

```sql
SELECT max_by(AUTHOR_ID, ID)
FROM BOOK
```

```java
create.select(maxBy(BOOK.AUTHOR_ID, BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+--------+
| max_by |
+--------+
|      2 |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
maxBy(BOOK.AUTHOR_ID, BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, H2, Postgres, YugabyteDB

```sql
(array_agg(BOOK.AUTHOR_ID ORDER BY BOOK.ID DESC))[1]
```

###### BigQuery, Databricks, DuckDB, Snowflake, Trino

```sql
max_by(BOOK.AUTHOR_ID, BOOK.ID)
```

###### ClickHouse

```sql
argMax(BOOK.AUTHOR_ID, BOOK.ID)
```

###### Hana

```sql
last_value(BOOK.AUTHOR_ID ORDER BY BOOK.ID)
```

###### HSQLDB

```sql
CASE
  WHEN cardinality(array_agg(BOOK.AUTHOR_ID ORDER BY BOOK.ID DESC)) >= 1 THEN (array_agg(BOOK.AUTHOR_ID ORDER BY BOOK.ID DESC))[1]
END
```

###### Oracle

```sql
max(BOOK.AUTHOR_ID) KEEP (DENSE_RANK LAST ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="median-function"></a>
##### 3.11.26.33. MEDIAN

The `MEDIAN()` aggregate function calculates the median value of all input values. `MEDIAN(x)` is equivalent to standard SQL `PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY x)`, see [PERCENTILE_CONT](#percentile-cont-function).

```sql
SELECT median(ID)
FROM BOOK
```

```java
create.select(median(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+--------+
| median |
+--------+
|    2.5 |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
median(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, Teradata, YugabyteDB

```sql
percentile_cont(0.5) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### BigQuery

```sql
percentile_cont(BOOK.ID, bignumeric '0.5')
```

###### ClickHouse, DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, Oracle, Redshift, Snowflake, Sybase

```sql
median(BOOK.ID)
```

###### ASE, Access, Aurora MySQL, CockroachDB, Firebird, Informix, MemSQL, MySQL, SQLDataWarehouse, SQLServer, SQLite, Spanner, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="min-function"></a>
##### 3.11.26.34. MIN

The `MIN()` aggregate function calculates the minimum value of all input values

```sql
SELECT min(ID)
FROM BOOK
```

```java
create.select(min(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+-----+
| min |
+-----+
|   1 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
min(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
min(BOOK.ID)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="min-by-function"></a>
##### 3.11.26.35. MIN_BY

The `MIN_BY()` aggregate function calculates a `value` at the row containing the minimum value of all `by` values. This works the same way as the Oracle specific [KEEP clause](#aggregate-keep).

```sql
SELECT min_by(AUTHOR_ID, ID)
FROM BOOK
```

```java
create.select(minBy(BOOK.AUTHOR_ID, BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+--------+
| min_by |
+--------+
|      1 |
+--------+
```

###### Dialect support

This example using jOOQ:

```java
minBy(BOOK.AUTHOR_ID, BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, H2, Postgres, YugabyteDB

```sql
(array_agg(BOOK.AUTHOR_ID ORDER BY BOOK.ID))[1]
```

###### BigQuery, Databricks, DuckDB, Snowflake, Trino

```sql
min_by(BOOK.AUTHOR_ID, BOOK.ID)
```

###### ClickHouse

```sql
argMin(BOOK.AUTHOR_ID, BOOK.ID)
```

###### Hana

```sql
first_value(BOOK.AUTHOR_ID ORDER BY BOOK.ID)
```

###### HSQLDB

```sql
CASE
  WHEN cardinality(array_agg(BOOK.AUTHOR_ID ORDER BY BOOK.ID)) >= 1 THEN (array_agg(BOOK.AUTHOR_ID ORDER BY BOOK.ID))[1]
END
```

###### Oracle

```sql
min(BOOK.AUTHOR_ID) KEEP (DENSE_RANK FIRST ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, DB2, Exasol, Firebird, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="mode-function"></a>
##### 3.11.26.36. MODE (ordered)

The `MODE()` aggregate function calculates the statistical mode of all input values, i.e. the value that appears most in the data set. There can be several modes, in case of which the first one, given an ordering, will be chosen.

```sql
SELECT mode() WITHIN GROUP (ORDER BY BOOK.AUTHOR_ID)
FROM BOOK
```

```java
create.select(mode().withinGroupOrderBy(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+------+
| mode |
+------+
|    1 |
+------+
```

See also [MODE (unordered)](#mode-function).

###### Dialect support

This example using jOOQ:

```java
mode().withinGroupOrderBy(BOOK.AUTHOR_ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DuckDB, H2, Postgres, YugabyteDB

```sql
mode() WITHIN GROUP (ORDER BY BOOK.AUTHOR_ID)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="mode-function-unordered"></a>
##### 3.11.26.37. MODE (unordered)

The `MODE()` aggregate function calculates the statistical mode of all input values, i.e. the value that appears most in the data set. Unlike the [MODE (ordered)](#mode-function) variant of this function, this unordered variant does not allow for chosing among tied modes.

```sql
SELECT mode(BOOK.LANGUAGE_ID)
FROM BOOK
```

```java
create.select(mode(BOOK.LANGUAGE_ID))
      .from(BOOK)
```

Producing:

```text
+------+
| mode |
+------+
|    1 |
+------+
```

See also [MODE (ordered)](#mode-function).

###### Dialect support

This example using jOOQ:

```java
mode(BOOK.LANGUAGE_ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, DuckDB, H2, Postgres

```sql
mode() WITHIN GROUP (ORDER BY BOOK.LANGUAGE_ID)
```

###### Databricks, Snowflake

```sql
mode(BOOK.LANGUAGE_ID)
```

###### Oracle

```sql
stats_mode(BOOK.LANGUAGE_ID)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="multiset-agg-function"></a>
##### 3.11.26.38. MULTISET_AGG

The synthetic `MULTISET_AGG()` aggregate function collects group contents into a nested collection, just like the [MULTISET value constructor](#multiset-value-constructor) (learn about [other synthetic sql syntaxes](#synthetic-sql-clauses)).

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  MULTISET_AGG(
    BOOK.ID,
    BOOK.TITLE,
    LANGUAGE.CD
  )
FROM AUTHOR
JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID
JOIN LANGUAGE ON BOOK.LANGUAGE_ID = LANGUAGE.ID
GROUP BY
  AUTHOR.ID,
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME
ORDER BY AUTHOR.ID
```

```java
create.select(
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME,
          multisetAgg(
              BOOK.ID,
              BOOK.TITLE,
              BOOK.language().CD
          ).as("books"))
      .from(AUTHOR)
      .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
      .groupBy(
          AUTHOR.ID,
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME)
      .orderBy(AUTHOR.ID)
      .fetch()
```

The result being:

```text
+----------+---------+---------------------------------------+
|first_name|last_name|books                                  |
+----------+---------+---------------------------------------+
|George    |Orwell   |[(2, Animal Farm, en), (1, 1984, en)]  |
|Paulo     |Coelho   |[(4, Brida, de), (3, O Alquimista, pt)]|
+----------+---------+---------------------------------------+
```

Unlike the [ARRAY_AGG function](#array-agg-function), this:

- Produces a more convenient [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) type, instead of an array
- Allows for projecting multiple columns in a type safe way, instead of just a single column

###### Dialect support

This example using jOOQ:

```java
multisetAgg(BOOK.ID, BOOK.TITLE)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
jsonb_agg(jsonb_build_array(BOOK.ID, BOOK.TITLE))
```

###### BigQuery, Spanner

```sql
to_json(
  coalesce(
    array_agg(json_array(BOOK.ID, BOOK.TITLE)), cast(ARRAY[] AS array<json>)
  )
)
```

###### Databricks

```sql
array_agg(STRUCT (
  coalesce(BOOK.ID),
  coalesce(BOOK.TITLE)
))
```

###### DB2

```sql
xmlelement(
  NAME result,
  xmlagg(xmlelement(
    NAME record,
    xmlelement(NAME v0, BOOK.ID),
    xmlelement(
      NAME v1,
      xmlattributes(
        CASE
          WHEN BOOK.TITLE IS NULL THEN 'true'
        END AS "xsi:nil"
      ),
      BOOK.TITLE
    )
  ))
)
```

###### DuckDB

```sql
array_agg(ROW (BOOK.ID, BOOK.TITLE))
```

###### H2

```sql
json_arrayagg(json_array(
  BOOK.ID, BOOK.TITLE
  NULL ON NULL
))
```

###### MariaDB, MySQL

```sql
json_merge_preserve(
  '[]',
  concat(
    '[',
    group_concat(json_array(BOOK.ID, BOOK.TITLE) SEPARATOR ','),
    ']'
  )
)
```

###### Oracle

```sql
json_arrayagg(json_array(
  BOOK.ID, BOOK.TITLE
  NULL ON NULL
  RETURNING clob
) FORMAT JSON RETURNING clob)
```

###### Snowflake

```sql
array_agg(array_construct(coalesce(
  to_variant(BOOK.ID),
  parse_json('null')
), coalesce(
  to_variant(BOOK.TITLE),
  parse_json('null')
)))
```

###### SQLite

```sql
json_group_array(json_array(BOOK.ID, BOOK.TITLE))
```

###### Teradata

```sql
xmlelement(
  NAME "result",
  xmlagg(xmlelement(
    NAME record,
    xmlelement(NAME v0, BOOK.ID),
    xmlelement(
      NAME v1,
      xmlattributes(
        CASE
          WHEN BOOK.TITLE IS NULL THEN 'true'
        END AS nil
      ),
      BOOK.TITLE
    )
  ))
)
```

###### Trino

```sql
cast(array_agg(cast(
  ARRAY[
    cast(BOOK.ID AS json),
    cast(BOOK.TITLE AS json)
  ]
  AS json
)) AS json)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Exasol, Firebird, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, SQLServer, Sybase, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="percent-rank-function"></a>
##### 3.11.26.39. PERCENT_RANK

The `PERCENT_RANK()` [hypothetical set function](#aggregate-within-group) calculates the percent rank of the hypothetical value, i.e. the relative rank from 0 to 1 ([CUME_DIST](#cume-dist-function) produces values from 1/N to 1)

```sql
SELECT
  percent_rank(0) WITHIN GROUP (ORDER BY ID),
  percent_rank(2) WITHIN GROUP (ORDER BY ID),
  percent_rank(4) WITHIN GROUP (ORDER BY ID)
FROM BOOK
```

```java
create.select(
         percentRank(val(0)).withinGroupOrderBy(BOOK.ID),
         percentRank(val(2)).withinGroupOrderBy(BOOK.ID),
         percentRank(val(4)).withinGroupOrderBy(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+-----------------+-----------------+-----------------+
| percent_rank(0) | percent_rank(2) | percent_rank(4) |
+-----------------+-----------------+-----------------+
|             0.0 |            0.25 |            0.75 |
+-----------------+-----------------+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
percentRank(val(0)).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, Oracle, Postgres, YugabyteDB

```sql
percent_rank(0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="percentile-cont-function"></a>
##### 3.11.26.40. PERCENTILE_CONT

The `PERCENTILE_CONT()` aggregate function is an [ordered set function](#aggregate-within-group) that calculates a given continuous percentile of all input values. A special kind of percentile is the [MEDIAN](#median-function), corresponding to the 50% percentile.

```sql
SELECT
  percentile_cont(0.00) WITHIN GROUP (ORDER BY ID),
  percentile_cont(0.25) WITHIN GROUP (ORDER BY ID),
  percentile_cont(0.50) WITHIN GROUP (ORDER BY ID),
  percentile_cont(0.75) WITHIN GROUP (ORDER BY ID),
  percentile_cont(1.00) WITHIN GROUP (ORDER BY ID)
FROM BOOK
```

```java
create.select(
         percentileCont(0.00).withinGroupOrderBy(BOOK.ID),
         percentileCont(0.25).withinGroupOrderBy(BOOK.ID),
         percentileCont(0.50).withinGroupOrderBy(BOOK.ID),
         percentileCont(0.75).withinGroupOrderBy(BOOK.ID),
         percentileCont(1.00).withinGroupOrderBy(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+------+------+------+------+------+
| 0.00 | 0.25 | 0.50 | 0.75 | 1.00 |
+------+------+------+------+------+
|    1 | 1.75 |  2.5 | 3.25 |    4 |
+------+------+------+------+------+
```

###### Dialect support

This example using jOOQ:

```java
percentileCont(0.00).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
percentile_cont(cast(0E0 AS double precision)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### BigQuery

```sql
percentile_cont(BOOK.ID, 0E0)
```

###### ClickHouse

```sql
quantile(0E0)(BOOK.ID)
```

###### Databricks, DuckDB, Exasol, MariaDB, MemSQL, Oracle, Redshift, Snowflake, Teradata

```sql
percentile_cont(0E0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### DB2

```sql
percentile_cont(cast(0E0 AS double)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### H2

```sql
percentile_cont(cast(
  0E0
  AS double
)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### SQLDataWarehouse, SQLServer

```sql
percentile_cont(cast(0E0 AS float)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, CockroachDB, Firebird, HSQLDB, Hana, Informix, MySQL, SQLite, Spanner, Sybase, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="percentile-disc-function"></a>
##### 3.11.26.41. PERCENTILE_DISC

The `PERCENTILE_DISC()` aggregate function is an [ordered set function](#aggregate-within-group) that calculates a given discrete percentile of all input values.

```sql
SELECT
  percentile_disc(0.00) WITHIN GROUP (ORDER BY ID),
  percentile_disc(0.25) WITHIN GROUP (ORDER BY ID),
  percentile_disc(0.50) WITHIN GROUP (ORDER BY ID),
  percentile_disc(0.75) WITHIN GROUP (ORDER BY ID),
  percentile_disc(1.00) WITHIN GROUP (ORDER BY ID)
FROM BOOK
```

```java
create.select(
         percentileDisc(0.00).withinGroupOrderBy(BOOK.ID),
         percentileDisc(0.25).withinGroupOrderBy(BOOK.ID),
         percentileDisc(0.50).withinGroupOrderBy(BOOK.ID),
         percentileDisc(0.75).withinGroupOrderBy(BOOK.ID),
         percentileDisc(1.00).withinGroupOrderBy(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+------+------+------+------+------+
| 0.00 | 0.25 | 0.50 | 0.75 | 1.00 |
+------+------+------+------+------+
|    1 |    1 |    2 |    3 |    4 |
+------+------+------+------+------+
```

###### Dialect support

This example using jOOQ:

```java
percentileDisc(0.00).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
percentile_disc(cast(0E0 AS double precision)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### BigQuery

```sql
percentile_disc(BOOK.ID, 0E0)
```

###### ClickHouse

```sql
quantileExactLow(0E0)(BOOK.ID)
```

###### Databricks, DuckDB, Exasol, MariaDB, MemSQL, Oracle, Redshift, Snowflake, Teradata

```sql
percentile_disc(0E0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### DB2

```sql
percentile_disc(cast(0E0 AS double)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### H2

```sql
percentile_disc(cast(
  0E0
  AS double
)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### SQLDataWarehouse, SQLServer

```sql
percentile_disc(cast(0E0 AS float)) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, CockroachDB, Firebird, HSQLDB, Hana, Informix, MySQL, SQLite, Spanner, Sybase, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="product-function"></a>
##### 3.11.26.42. PRODUCT

The `PRODUCT()` aggregate function is an aggregate function that calculates the product of all values in the group, similar to how the [SUM](#sum-function) function calculates the sum.

```sql
SELECT product(ID)
FROM BOOK
```

```java
create.select(product(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+---------+
| product |
+---------+
|      24 |
+---------+
```

###### Dialect support

This example using jOOQ:

```java
product(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Access

```sql
(SWITCH(sum(
  SWITCH(BOOK.ID = 0, 1)
) > 0, 0, (sum(
  SWITCH(BOOK.ID < 0, -1)
) MOD 2) < 0, -1, TRUE, 1) * exp(sum(log(abs(iif(BOOK.ID = 0, NULL, BOOK.ID))))))
```

###### ASE

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > 0 THEN 0
  WHEN (sum(
    CASE
      WHEN BOOK.ID < 0 THEN -1
    END
  ) % 2) < 0 THEN -1
  ELSE 1
END * exp(sum(log(abs(nullif(BOOK.ID, 0))))))
```

###### Aurora MySQL, Aurora Postgres, ClickHouse, DB2, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Snowflake, Sybase, Trino, Vertica, YugabyteDB

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > 0 THEN 0
  WHEN mod(
    sum(
      CASE
        WHEN BOOK.ID < 0 THEN -1
      END
    ),
    2
  ) < 0 THEN -1
  ELSE 1
END * exp(sum(ln(abs(nullif(BOOK.ID, 0))))))
```

###### BigQuery

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > bignumeric '0' THEN 0
  WHEN mod(
    sum(
      CASE
        WHEN BOOK.ID < 0 THEN -1
      END
    ),
    2
  ) < bignumeric '0' THEN -1
  ELSE 1
END * exp(sum(ln(abs(nullif(BOOK.ID, 0))))))
```

###### CockroachDB

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > 0E0 THEN 0
  WHEN mod(
    sum(
      CASE
        WHEN BOOK.ID < 0 THEN -1
      END
    ),
    2
  ) < 0E0 THEN -1
  ELSE 1
END * exp(sum(ln(cast(
  abs(nullif(BOOK.ID, 0))
  AS numeric
)))))
```

###### Databricks, Redshift

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > 0 THEN 0
  WHEN (sum(
    CASE
      WHEN BOOK.ID < 0 THEN -1
    END
  ) % 2) < 0 THEN -1
  ELSE 1
END * exp(sum(ln(abs(nullif(BOOK.ID, 0))))))
```

###### DuckDB, SQLServer

```sql
product(BOOK.ID)
```

###### Exasol

```sql
mul(BOOK.ID)
```

###### Informix

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > 0 THEN 0
  WHEN mod(
    sum(
      CASE
        WHEN BOOK.ID < 0 THEN -1
      END
    ),
    2
  ) < 0 THEN -1
  ELSE 1
END * exp(sum(logn(abs(nullif(BOOK.ID, 0))))))
```

###### Spanner

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > numeric '0' THEN 0
  WHEN mod(
    sum(
      CASE
        WHEN BOOK.ID < 0 THEN -1
      END
    ),
    2
  ) < numeric '0' THEN -1
  ELSE 1
END * exp(sum(ln(abs(nullif(BOOK.ID, 0))))))
```

###### SQLDataWarehouse

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > cast(0 AS decimal(1)) THEN 0
  WHEN (sum(
    CASE
      WHEN BOOK.ID < 0 THEN -1
    END
  ) % 2) < cast(0 AS decimal(1)) THEN -1
  ELSE 1
END * exp(sum(log(abs(nullif(BOOK.ID, 0))))))
```

###### Teradata

```sql
(CASE
  WHEN sum(
    CASE BOOK.ID
      WHEN 0 THEN 1
    END
  ) > 0 THEN 0
  WHEN (sum(
    CASE
      WHEN BOOK.ID < 0 THEN -1
    END
  ) MOD 2) < 0 THEN -1
  ELSE 1
END * exp(sum(ln(abs(nullif(BOOK.ID, 0))))))
```

###### SQLite

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="rank-function"></a>
##### 3.11.26.43. RANK

The `RANK()` [hypothetical set function](#aggregate-within-group) calculates the rank with gaps of the hypothetical value, i.e. ranks will be 1, 1, 1, 4, 5, 5, 7 ([DENSE_RANK](#dense-rank-function) produces values without gaps, e.g. 1, 1, 1, 2, 3, 3, 4)

```sql
SELECT
  rank(0) WITHIN GROUP (ORDER BY AUTHOR_ID),
  rank(1) WITHIN GROUP (ORDER BY AUTHOR_ID),
  rank(2) WITHIN GROUP (ORDER BY AUTHOR_ID)
FROM BOOK
```

```java
create.select(
         rank(val(0)).withinGroupOrderBy(BOOK.AUTHOR_ID),
         rank(val(2)).withinGroupOrderBy(BOOK.AUTHOR_ID),
         rank(val(4)).withinGroupOrderBy(BOOK.AUTHOR_ID))
      .from(BOOK)
```

Producing:

```text
+---------+---------+---------+
| rank(0) | rank(1) | rank(2) |
+---------+---------+---------+
|       1 |       1 |       3 |
+---------+---------+---------+
```

###### Dialect support

This example using jOOQ:

```java
rank(val(0)).withinGroupOrderBy(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, H2, Oracle, Postgres, YugabyteDB

```sql
rank(0) WITHIN GROUP (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="sum-function"></a>
##### 3.11.26.44. SUM

The `SUM()` aggregate function calculates the sum of all values per group.

```sql
SELECT sum(ID)
FROM BOOK
```

```java
create.select(sum(BOOK.ID))
      .from(BOOK)
```

Producing:

```text
+-----+
| sum |
+-----+
|  10 |
+-----+
```

###### Dialect support

This example using jOOQ:

```java
sum(BOOK.ID)
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
sum(BOOK.ID)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-agg-function"></a>
##### 3.11.26.45. XMLAGG

A data set can be aggregated into a [`org.jooq.XML`](https://www.jooq.org/javadoc/3.22.x/org/jooq/XML.html) element using `XMLAGG`

```sql
SELECT xmlelement(
  NAME ids,
  xmlagg(xmlelement(NAME id, id))
)
FROM author
```

```java
create.select(xmlelement("ids",
        xmlagg(xmlelement("id", AUTHOR.ID))
      ))
      .from(AUTHOR)
      .fetch();
```

The result would look like this:

```text
+---------------------------------+
| xmlelement                      |
+---------------------------------+
| <ids><id>1</id><id>2</id></ids> |
+---------------------------------+
```

###### Ordering aggregation contents

When aggregating data into XML, ordering may be relevant. For this, use the `ORDER BY` clause in `XMLAGG`

```sql
SELECT xmlelement(
  NAME ids,
  xmlagg(xmlelement(NAME id, id) ORDER BY id DESC)
)
FROM author
```

```java
create.select(xmlelement("ids",
        xmlagg(xmlelement("id", AUTHOR.ID))
          .orderBy(AUTHOR.ID.desc())))
      .from(AUTHOR)
      .fetch();
```

The result would look like this:

```text
+---------------------------------+
| xmlelement                      |
+---------------------------------+
| <ids><id>2</id><id>1</id></ids> |
+---------------------------------+
```

###### Dialect support

This example using jOOQ:

```java
xmlagg(xmlelement("id", AUTHOR.ID))
```

Translates to the following dialect specific expressions:

###### DB2, Oracle, Postgres, Teradata

```sql
xmlagg(xmlelement(NAME id, AUTHOR.ID))
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-functions"></a>
#### 3.11.27. Window functions

A window function calculates an aggregate or ranking value over a subset of data (the window) relative to the projected row.

This has numerous powerful applications, for example, cumulative sums or sliding averages:

```sql
SELECT
  id,

  -- A sliding average over 3 rows, including the current row
  avg(amount) OVER (ORDER BY id ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING),
  amount,

  -- A cumulative sum over all previous rows
  sum(amount) OVER (ORDER BY id)
FROM (VALUES
  (1, 10.0),
  (2, 15.0),
  (3, 20.0),
  (4, 25.0),
  (5, 30.0),
  (6, 35.0)
) AS t (id, amount)
```

The result being

```text
+----+-----------------+--------+-----------------+
| id | sliding average | amount |  cumulative sum |
+----+-----------------+--------+-----------------+
|  1 |  12.5           |   10.0 | --\        10.0 |
|  2 |  15.0           |   15.0 |   |        25.0 |
|  3 |  20.0           |   20.0 |   |        45.0 |
|  4 |  25.0       /-- |   25.0 |   |        70.0 |
|  5 |  30.0 = AVG +   |   30.0 | --+ SUM = 100.0 |
|  6 |  32.5       \-- |   35.0 |           135.0 |
+----+-----------------+--------+-----------------+
```

As this illustration shows, the aggregation happens over a window that is defined relative to the row on which it is calculated:

- In the `AVG` case, the window moves along with the row, always looking 1 row behind and 1 row ahead (if applicable), spanning anything between 1-3 rows, and calculating the average over those, forming a sliding average.
- In the `SUM` case, the window always starts at the beginning of the data set, and sums up all the rows up to the current row, forming a cumulative sum.

The details of how this powerful feature works will be illustrated over the next pages, where the various clauses, including the [PARTITION BY clause](#window-partition), the [ORDER BY clause](#window-order), and the [frame clause](#window-frame) are explained.

<a id="window-partition"></a>
##### 3.11.27.1. PARTITION BY

Just like the [GROUP BY clause](#group-by-clause), the `PARTITION BY` clause divides the data set into mutually exclusive groups / partitions.

This is best illustrated by example, where we fetch all the books and the total number of books per author of a book:

```sql
SELECT
  BOOK.ID,
  BOOK.AUTHOR_ID,
  count(*) OVER (PARTITION BY BOOK.AUTHOR_ID)
FROM
  BOOK
```

```java
create.select(
         BOOK.ID,
         BOOK.AUTHOR_ID,
         count().over(partitionBy(BOOK.AUTHOR_ID)))
      .from(BOOK)
      .fetch();
```

Producing:

```text
+----+-----------+-------+
| id | author_id | count |
+----+-----------+-------+
|  1 |         1 |     2 |
|  2 |         1 |     2 |
|  3 |         2 |     2 |
|  4 |         2 |     2 |
+----+-----------+-------+
```

Just like ordinary aggregate functions that aggregate all data per `GROUP` produced by the [GROUP BY clause](#group-by-clause), the `PARTITION BY` clause allows for grouping data, but without transforming the entire result set. As such, this kind of grouping can be much more convenient, especially in reporting, as the original data set isn't modified, only a new column is added.

> [!TIP]
> If you omit the `PARTITION BY` clause, then the entire data set forms a single partition.

###### Dialect support

This example using jOOQ:

```java
count().over(partitionBy(BOOK.AUTHOR_ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
count(*) OVER (PARTITION BY BOOK.AUTHOR_ID)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-order"></a>
##### 3.11.27.2. ORDER BY

The `ORDER BY` clause allows for ordering a window, which may be required by a window function to produce a deterministic result.

There are 2 reasons to order window functions:

- The window function requires it (e.g. [ROW_NUMBER](#window-row-number)).
- The window has a [explicit or implicit window frame](#window-frame).

While the [window frame ordering](#window-frame) will be discussed later, it is easy to see how `ROW_NUMBER` relies on ordering in an example:

```sql
SELECT
  BOOK.ID,
  row_number() OVER (ORDER BY id DESC)
FROM
  BOOK
```

```java
create.select(
         BOOK.ID,
         rowNumber().over(orderBy(BOOK.ID.desc())))
      .from(BOOK)
      .fetch();
```

Producing:

```text
+----+------------+
| id | row_number |
+----+------------+
|  1 |          4 |
|  2 |          3 |
|  3 |          2 |
|  4 |          1 |
+----+------------+
```

> [!TIP]
> If you omit the `ORDER BY` clause (and if that's supported in a window function), then no [frame clause](#window-frame) is implied, and thus the entire [window partition](#window-partition) is being considered.

###### Dialect support

This example using jOOQ:

```java
rowNumber().over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
row_number() OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-frame"></a>
##### 3.11.27.3. ROWS, RANGE, GROUPS (frame clause)

When a window specification contains a [ORDER BY clause](#window-order), then a window frame may be explicit or implicit, with [aggregate window functions](#window-aggregate). In short, a window frame limits the size of the window in both directions, from the current row.

For example:

- A cumulative sum can be achieved by framing the window to include all `PRECEDING` rows.
- A sliding average can be achieved by framing the window to include a certain number of `PRECEDING` rows as well as `FOLLOWING` rows.

A frame can be limited in 3 modes:

- `ROWS`: This limits the frame by an exact number of rows, similar to the [LIMIT clause](#limit-clause). For example, `ROWS 3 PRECEDING` will include the 3 preceding rows and the current row in the window.
- `RANGE`: This limits the frame logically by a value range, e.g. `RANGE 3 PRECEDING` will include the a value range of `[current value - 3, current value]` and the current row in the window. This only works for types with well defined ranges, including numeric and temporal types.
- `GROUPS`: This limits the frame logically by a distinct value count range, e.g. `GROUPS 3 PRECEDING` will include the rows containing the 3 preceding distinct values and the current row in the window.

Notice how in the above examples, the current row is always included by default. It can be excluded using [the window exclusion clause](#window-exclude).

###### Complete syntax

The complete syntax is best illustrated using a grammar:

```text
frame = ( 'ROWS' | 'RANGE' | 'GROUPS' ) (
    frameBound
  | 'BETWEEN' frameBound AND frameBound
);

frameBound = ( 'UNBOUNDED' | value ) ( 'PRECEDING' | 'FOLLOWING' ) | 'CURRENT ROW'
;
```

In the above short form where only a single `frameBound` is provided (e.g. `ROWS 3 PRECEDING`), then `ROWS BETWEEN frameBound AND CURRENT ROW` is implied.

###### Example

This is again best explained by example:

```sql
SELECT
  ID,
  PUBLISHED_IN,

  -- The 2 preceding rows and the current row
  COUNT(*) OVER (ORDER BY PUBLISHED_IN ROWS 2 PRECEDING),

  -- The 42 preceding years and the current row
  COUNT(*) OVER (ORDER BY PUBLISHED_IN RANGE 42 PRECEDING),

  -- The 1 preceding groups of years and the current row
  trunc(PUBLISHED_IN, -1),
  COUNT(*) OVER (ORDER BY trunc(PUBLISHED_IN, -1)
    GROUPS 1 PRECEDING)
FROM
  BOOK
ORDER BY published_in
```

```java
create.select(
         BOOK.ID,
         BOOK.PUBLISHED_IN,

         // The 2 preceding rows and the current row
         count().over(orderBy(BOOK.PUBLISHED_IN).rowsPreceding(2)),

         // The 42 preceding years and the current row
         count().over(orderBy(BOOK.PUBLISHED_IN).rangePreceding(42)),

         // The 1 preceding groups of years and the current row
         trunc(BOOK.PUBLISHED_IN, -1),
         count().over(orderBy(trunc(BOOK.PUBLISHED_IN, -1))
                .groupsPreceding(1)))
      .from(BOOK)
      .orderBy(BOOK.PUBLISHED_IN)
      .fetch();
```

Producing:

```text
+----+--------------+-------+-------+-------+--------+
| id | published_in | rows | range | decade | groups |
+----+--------------+------+-------+--------+--------+
|  2 |         1945 |    1 |     1 |   1940 |      2 |
|  1 |         1948 |    2 |     2 |   1940 |      2 |
|  3 |         1988 |    3 |     2 |   1980 |      3 |
|  4 |         1990 |    3 |     3 |   1990 |      2 |
+----+--------------+------+-------+--------+--------+
```

As you can see:

- `ROWS`: All rows have between 0 and 2 preceding rows, plus the current row.
- `RANGE`: While `1990` has 2 preceding rows within 42 years (plus the rows with the same value as the current row), the other years have less rows in that time span.
- `GROUPS`: The decade of the `1980`s have 2 rows belonging to the previous 1 group of decades (plus the rows with the same value as the current row).

This certainly requires a bit of practice. While the `ROWS` clause is straightforward, the `RANGE` and `GROUPS` clauses are a bit more tricky to understand, although they're much more powerful.

> [!TIP]
> If you omit the frame clause, but have an [ORDER BY clause](#window-order), then the `RANGE UNBOUNDED PRECEDING` frame is implicit for [aggregate window functions](#window-aggregate). Without `ORDER BY`, `RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING` is implicit, i.e. the entire window partition.

###### Dialect support

This example using jOOQ:

```java
count().over(orderBy(BOOK.ID).rowsPreceding(3))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
count(*) OVER (
  ORDER BY BOOK.ID
  ROWS 3 PRECEDING
)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Hana, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-exclude"></a>
##### 3.11.27.4. EXCLUDE

While poorly supported by most dialects, this standard SQL extension to the [window frame clause](#window-frame) can be quite handy to govern the exclusion of the current `ROW`, `GROUP`, or `TIES`.

Options include:

- `EXCLUDE CURRENT ROW`: Only the current row is excluded from the window
- `EXCLUDE GROUP`: The rows belonging to the current row's group are excluded from the window
- `EXCLUDE TIES`: The rows tied with the current row are excluded from the window
- `EXCLUDE NO OTHERS`: The default.

###### Dialect support

This example using jOOQ:

```java
count().over(orderBy(BOOK.ID).rowsPreceding(3).excludeCurrentRow())
```

Translates to the following dialect specific expressions:

###### CockroachDB, DuckDB, Exasol, H2, Oracle, Postgres, SQLite, Trino, YugabyteDB

```sql
count(*) OVER (
  ORDER BY BOOK.ID
  ROWS 3 PRECEDING EXCLUDE CURRENT ROW
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, DB2, Databricks, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Sybase, Teradata, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-nulls"></a>
##### 3.11.27.5. NULL treatment

Some window functions may offer a special `NULL` treatment clause, which allows for excluding `NULL` values from being considered for the evaluation of the function.

These include:

- [LEAD](#window-lead)
- [LAG](#window-lag)
- [FIRST_VALUE](#window-first-value)
- [LAST_VALUE](#window-last-value)
- [NTH_VALUE](#window-nth-value)

Possible clause values include:

- `IGNORE NULLS`: `NULL` values are not considered for the evaluation of the function.
- `RESPECT NULLS`: The default.

An example illustrates the utility of this optional clause

```sql
SELECT
  id,
  amount,
  lead(amount) OVER (ORDER BY id) AS respect_nulls,
  lead(amount) IGNORE NULLS OVER (ORDER BY id) AS ignore_nulls
FROM (VALUES
  (1, 10.0),
  (2, 15.0),
  (3, 20.0),
  (4, null),
  (5, 30.0),
  (6, 35.0)
) AS t (id, amount)
```

The result being

```text
+----+--------+---------------+--------------+
| ID | AMOUNT | RESPECT_NULLS | IGNORE_NULLS |
+----+--------+---------------+--------------+
|  1 |     10 |            15 |           15 |
|  2 |     15 |            20 |           20 |
|  3 |     20 |               |           30 | <-- difference here
|  4 |        |            30 |           30 |
|  5 |     30 |            35 |           35 |
|  6 |     35 |               |              |
+----+--------+---------------+--------------+
```

If you will, the `IGNORE NULLS` clause allows for skipping all rows containing `NULL` values until the next non-`NULL` value is found. Such a function may still return `NULL` if no next row is found in the window, e.g. the last row in the above example!

###### Dialect support

This example using jOOQ:

```java
lead(BOOK.ID).ignoreNulls().over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### BigQuery, DuckDB, Vertica

```sql
lead(BOOK.ID IGNORE NULLS) OVER (ORDER BY BOOK.ID)
```

###### Databricks, Exasol, H2, Informix, Oracle, Redshift, SQLServer, Snowflake, Teradata, Trino

```sql
lead(BOOK.ID) IGNORE NULLS OVER (ORDER BY BOOK.ID)
```

###### DB2

```sql
lead(BOOK.ID, 'IGNORE NULLS') OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, Firebird, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, SQLDataWarehouse, SQLite, Spanner, Sybase, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-first-last"></a>
##### 3.11.27.6. FROM FIRST, FROM LAST

The [NTH_VALUE](#window-nth-value) window function has an additional clause that allows for specifying whether the `N`th value should be searched from the `FIRST` or the `LAST` row in the window.

Possible clause values include:

- `FROM FIRST`: The default.
- `FROM LAST`: `N` is counted from the `LAST` row, backwards.

###### Dialect support

This example using jOOQ:

```java
nthValue(BOOK.ID, 2).fromLast().over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### DB2, Exasol, Firebird, H2, Oracle, Snowflake

```sql
nth_value(BOOK.ID, 2) FROM LAST OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-nested-aggregate"></a>
##### 3.11.27.7. Nested aggregate functions

Ordinary [aggregate functions](#aggregate-functions) are evaluated before [window functions](#window-functions), logically, in [SQL's logical order of operations](https://blog.jooq.org/a-beginners-guide-to-the-true-order-of-sql-operations/).

This means that when window functions are computed, the value of aggregate functions is already defined. This allows for some impressive looking expressions, like:

```sql
SELECT
  AUTHOR_ID,
  COUNT(*) AS BOOKS,
  SUM(COUNT(*)) OVER () AS ALL_BOOKS
FROM
  BOOK
GROUP BY AUTHOR_ID
```

```java
create.select(
         BOOK.AUTHOR_ID,
         count().as("books"),
         sum(count()).over().as("all_books"))
     .from(BOOK)
     .groupBy(BOOK.AUTHOR_ID)
     .fetch();
```

Producing:

```text
+-----------+-------+-----------+
| author_id | books | all_books |
+-----------+-------+-----------+
|         1 |     2 |         4 |
|         2 |     2 |         4 |
+-----------+-------+-----------+
```

In this example, the aggregate value of `COUNT(*)` can again be aggregated using `SUM(COUNT(*)) OVER (...)`.

> [!TIP]
> It is, however, not possible to nest window functions in window functions, just like aggregate functions cannot be nested in aggregate functions.

<a id="window-aggregate"></a>
##### 3.11.27.8. Window aggregation

Every [aggregate function](#aggregate-functions) can be turned into a window function simply by appending the `OVER()` clause.

For example:

- `COUNT(*) OVER ()`
- `SUM(x) OVER ()`
- `MAX(x) OVER ()`
- ...

This also includes [user-defined aggregate functions](#user-defined-aggregate-functions)!

<a id="window-ordered-aggregate"></a>
##### 3.11.27.9. Window ordered aggregate

Some aggregate functions already specify ordering for their aggregation. These include:

- [ordered aggregate functions](#aggregate-order-by)
- [ordered set aggregate functions](#aggregate-within-group) (subtle difference, see those sections)

In principle, there's nothing preventing users from ordering an ordered aggregate window function twice. While few dialects actually support this, here's how it would look:

```sql
SELECT
  ID,
  array_agg(ID ORDER BY ID DESC) OVER (),
  array_agg(ID ORDER BY ID DESC)
    OVER (ORDER BY ID)
FROM
  BOOK
```

```java
create.select(
         BOOK.ID,
         arrayAgg(BOOK.ID.desc()).orderBy(BOOK.ID).over(),
         arrayAgg(BOOK.ID.desc()).orderBy(BOOK.ID)
           .over(orderBy(BOOK.ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+-----------+-----------+
| ID | ARRAY_AGG | ARRAY_AGG |
+----+-----------+-----------+
|  1 | [4,3,2,1] | [1]       |
|  2 | [4,3,2,1] | [2,1]     |
|  3 | [4,3,2,1] | [3,2,1]   |
|  4 | [4,3,2,1] | [4,3,2,1] |
+----+-----------+-----------+
```

While the aggregation itself lists the values in descending order, the window specification may or may not sort the values, meaning that if it does, the [window frame](#window-frame) only includes the preceding rows, whereas otherwise, all the rows are included.

<a id="window-row-number"></a>
##### 3.11.27.10. ROW_NUMBER

`ROW_NUMBER` assigns a series of unique, consecutive numbers to each row in the partition.

```sql
SELECT
  LANGUAGE_ID,
  row_number() OVER (ORDER BY LANGUAGE_ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.LANGUAGE_ID,
         rowNumber().over(orderBy(BOOK.LANGUAGE_ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+-------------+------------+
| language_id | row_number |
+-------------+------------+
|           1 |          1 |
|           1 |          2 |
|           2 |          3 |
|           4 |          4 |
+-------------+------------+
```

> [!TIP]
> [See this article for a comparison between `ROW_NUMBER`, `RANK`, and `DENSE_RANK`](https://blog.jooq.org/the-difference-between-row_number-rank-and-dense_rank/)

###### Dialect support

This example using jOOQ:

```java
rowNumber().over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
row_number() OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-rank"></a>
##### 3.11.27.11. RANK

`RANK` assigns a series of rankings, which are different from [ROW_NUMBER](#window-row-number).

- The same rank is assigned to tied rows
- Ranks are skipped after tied rows

This works similarly as ranks in a sports event, when two athletes are ranked first, the next one is ranked third.

```sql
SELECT
  LANGUAGE_ID,
  rank() OVER (ORDER BY LANGUAGE_ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.LANGUAGE_ID,
         rank().over(orderBy(BOOK.LANGUAGE_ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+-------------+------+
| language_id | rank |
+-------------+------+
|           1 |    1 |
|           1 |    1 | <-- Tied rows are both ranked first
|           2 |    3 | <-- The next rank is 3 as 2 is skipped
|           4 |    4 |
+-------------+------+
```

> [!TIP]
> [See this article for a comparison between `ROW_NUMBER`, `RANK`, and `DENSE_RANK`](https://blog.jooq.org/the-difference-between-row_number-rank-and-dense_rank/)

###### Dialect support

This example using jOOQ:

```java
rank().over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
rank() OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-dense-rank"></a>
##### 3.11.27.12. DENSE_RANK

`DENSE_RANK` assigns a series of "dense" rankings (where dense means, no gaps), which are different from [RANK](#window-rank).

- The same rank is assigned to tied rows
- Ranks are not skipped after tied rows

```sql
SELECT
  LANGUAGE_ID,
  dense_rank() OVER (ORDER BY LANGUAGE_ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.LANGUAGE_ID,
         denseRank().over(orderBy(BOOK.LANGUAGE_ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+-------------+------------+
| language_id | dense_rank |
+-------------+------------+
|           1 |          1 |
|           1 |          1 | <-- Tied rows are both ranked first
|           2 |          2 | <-- The next rank is 2 as no ranks are skipped
|           4 |          3 |
+-------------+------------+
```

> [!TIP]
> [See this article for a comparison between `ROW_NUMBER`, `RANK`, and `DENSE_RANK`](https://blog.jooq.org/the-difference-between-row_number-rank-and-dense_rank/)

###### Dialect support

This example using jOOQ:

```java
denseRank().over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
dense_rank() OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-percent-rank"></a>
##### 3.11.27.13. PERCENT_RANK

`PERCENT_RANK` works like [RANK](#window-rank), but assigns ranks between `0` and `1`

```sql
SELECT
  LANGUAGE_ID,
  percent_rank() OVER (ORDER BY LANGUAGE_ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.LANGUAGE_ID,
         percentRank().over(orderBy(BOOK.LANGUAGE_ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+-------------+--------------+
| language_id | percent_rank |
+-------------+--------------+
|           1 |            0 |
|           1 |            0 | <-- Tied rows are both ranked first
|           2 | 0.6666666667 |
|           4 |            1 |
+-------------+--------------+
```

###### Dialect support

This example using jOOQ:

```java
percentRank().over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
percent_rank() OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, ClickHouse, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-cume-dist"></a>
##### 3.11.27.14. CUME_DIST

`CUME_DIST` (or cumulative distribution) works like [PERCENT_RANK](#window-percent-rank), but assigns ranks between `1/N` and `1`

```sql
SELECT
  LANGUAGE_ID,
  cume_dist() OVER (ORDER BY LANGUAGE_ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.LANGUAGE_ID,
         cumeDist().over(orderBy(BOOK.LANGUAGE_ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+-------------+-----------+
| language_id | cume_dist |
+-------------+-----------+
|           1 |       0.5 |
|           1 |       0.5 | <-- Tied rows are both ranked first
|           2 |      0.75 |
|           4 |         1 |
+-------------+-----------+
```

###### Dialect support

This example using jOOQ:

```java
cumeDist().over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cume_dist() OVER (ORDER BY BOOK.ID)
```

###### MemSQL

```sql
(cast(
  count(*) OVER (
    ORDER BY BOOK.ID
    RANGE UNBOUNDED PRECEDING
  )
  AS decimal
) / count(*) OVER (
  ORDER BY BOOK.ID
  RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
))
```

###### ASE, Access, Aurora MySQL, ClickHouse, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-is-first"></a>
##### 3.11.27.15. IS_FIRST

The `IS_FIRST` window function allows for checking if a row is among the first `N` rows within a window using [ROW_NUMBER](#window-row-number) semantics.

For example:

```sql
SELECT
  ID,
  is_first(2) OVER (ORDER BY ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.ID,
         isFirst(2).over(orderBy(BOOK.ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+----------+
| id | is_first |
+----+----------+
|  1 | true     |
|  2 | true     |
|  3 | false    |
|  4 | false    |
+----+----------+
```

###### Dialect support

This example using jOOQ:

```java
isFirst(2).over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Trino, Vertica, YugabyteDB

```sql
(row_number() OVER (ORDER BY BOOK.ID) <= 2)
```

###### DB2, SQLDataWarehouse, SQLServer, Sybase, Teradata

```sql
CASE
  WHEN row_number() OVER (ORDER BY BOOK.ID) <= 2 THEN 1
  WHEN NOT (row_number() OVER (ORDER BY BOOK.ID) <= 2) THEN 0
END
```

###### Hana

```sql
CASE
  WHEN row_number() OVER (ORDER BY BOOK.ID) <= 2 THEN TRUE
  WHEN NOT (row_number() OVER (ORDER BY BOOK.ID) <= 2) THEN FALSE
END
```

###### Informix

```sql
CASE
  WHEN row_number() OVER (ORDER BY BOOK.ID) <= 2 THEN cast('t' AS boolean)
  WHEN NOT (row_number() OVER (ORDER BY BOOK.ID) <= 2) THEN cast('f' AS boolean)
END
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-ntile"></a>
##### 3.11.27.16. NTILE

The `NTILE` window function allows for dividing a window into `N` buckets of equal size (e.g. when `N = 4`, then you'll get quartiles), and computes the bucket number for each row.

For example:

```sql
SELECT
  ID,
  ntile(2) OVER (ORDER BY ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.ID,
         ntile(2).over(orderBy(BOOK.ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+-------+
| id | ntile |
+----+-------+
|  1 |     1 |
|  2 |     1 |
|  3 |     2 |
|  4 |     2 |
+----+-------+
```

###### Dialect support

This example using jOOQ:

```java
ntile(2).over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Trino, Vertica, YugabyteDB

```sql
ntile(2) OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner, Sybase, Teradata

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-lead"></a>
##### 3.11.27.17. LEAD

The `LEAD` window function allows for getting the value of an expression evaluated on the next row, or the nth next row if an offset is given.

```sql
SELECT
  ID,
  lead(ID) OVER (ORDER BY ID),
  lead(ID, 2) OVER (ORDER BY ID),
  lead(ID, 2, -1) OVER (ORDER BY ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.ID,
         lead(BOOK.ID).over(orderBy(BOOK.ID)),
         lead(BOOK.ID, 2).over(orderBy(BOOK.ID)),
         lead(BOOK.ID, 2, -1).over(orderBy(BOOK.ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+------+------+------+
| id | lead | lead | lead |
+----+------+------+------+
|  1 |    2 |    3 |    3 |
|  2 |    3 |    4 |    4 |
|  3 |    4 |      |   -1 |
|  4 |      |      |   -1 |
+----+------+------+------+
```

Notes:

- The [window frame clause](#window-frame) has no effect on `LEAD`.
- `LEAD` supports the optional [NULL treatment clause](#window-nulls).

###### Dialect support

This example using jOOQ:

```java
lead(BOOK.ID).over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
lead(BOOK.ID) OVER (ORDER BY BOOK.ID)
```

###### ClickHouse

```sql
leadInFrame(BOOK.ID) OVER (
  ORDER BY BOOK.ID
  RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-lag"></a>
##### 3.11.27.18. LAG

The `LAG` window function allows for getting the value of an expression evaluated on the previous row, or the nth previous row if an offset is given.

```sql
SELECT
  ID,
  lag(ID) OVER (ORDER BY ID),
  lag(ID, 2) OVER (ORDER BY ID),
  lag(ID, 2, -1) OVER (ORDER BY ID)
FROM
  BOOK;
```

```java
create.select(
         BOOK.ID,
         lag(BOOK.ID).over(orderBy(BOOK.ID)),
         lag(BOOK.ID, 2).over(orderBy(BOOK.ID)),
         lag(BOOK.ID, 2, -1).over(orderBy(BOOK.ID)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+------+------+------+
| id |  lag |  lag |  lag |
+----+------+------+------+
|  1 |      |      |   -1 |
|  2 |    1 |      |   -1 |
|  3 |    2 |    1 |    1 |
|  4 |    3 |    2 |    2 |
+----+------+------+------+
```

- The [window frame clause](#window-frame) has no effect on `LAG`.
- `LAG` supports the optional [NULL treatment clause](#window-nulls).

###### Dialect support

This example using jOOQ:

```java
lag(BOOK.ID).over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
lag(BOOK.ID) OVER (ORDER BY BOOK.ID)
```

###### ClickHouse

```sql
lagInFrame(BOOK.ID) OVER (
  ORDER BY BOOK.ID
  RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-first-value"></a>
##### 3.11.27.19. FIRST_VALUE

The `FIRST_VALUE` window function allows for getting the value of an expression evaluated on the first row of the window.

```sql
SELECT
  ID,
  first_value(ID) OVER (ORDER BY ID),
  first_value(ID) OVER (ORDER BY ID ROWS 1 PRECEDING)
FROM
  BOOK;
```

```java
create.select(
         BOOK.ID,
         firstValue(BOOK.ID).over(orderBy(BOOK.ID)),
         firstValue(BOOK.ID).over(orderBy(BOOK.ID).rowsPreceding(1)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+-------------+-------------+
| id | first_value | first_value |
+----+-------------+-------------+
|  1 |           1 |           1 |
|  2 |           1 |           1 |
|  3 |           1 |           2 |
|  4 |           1 |           3 |
+----+-------------+-------------+
```

- The [window frame clause](#window-frame) is applied to `FIRST_VALUE`.
- `FIRST_VALUE` supports the optional [NULL treatment clause](#window-nulls).

###### Dialect support

This example using jOOQ:

```java
firstValue(BOOK.ID).over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
first_value(BOOK.ID) OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-last-value"></a>
##### 3.11.27.20. LAST_VALUE

The `LAST_VALUE` window function allows for getting the value of an expression evaluated on the last row of the window.

```sql
SELECT
  ID,
  last_value(ID) OVER (ORDER BY ID
    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
  last_value(ID) OVER (ORDER BY ID
    ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING)
FROM
  BOOK;
```

```java
create.select(
         BOOK.ID,
         lastValue(BOOK.ID).over(orderBy(BOOK.ID)
           .rowsBetweenUnboundedPreceding().andUnboundedFollowing()),
         lastValue(BOOK.ID).over(orderBy(BOOK.ID)
           .rowsBetweenCurrentRow().andFollowing(1)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+------------+------------+
| id | last_value | last_value |
+----+------------+------------+
|  1 |          4 |          2 |
|  2 |          4 |          3 |
|  3 |          4 |          4 |
|  4 |          4 |          4 |
+----+------------+------------+
```

- The [window frame clause](#window-frame) is applied to `LAST_VALUE`. The default of `CURRENT ROW` being the upper bound is questionable, so an explicit upper bound is usually required.
- `LAST_VALUE` supports the optional [NULL treatment clause](#window-nulls).

###### Dialect support

This example using jOOQ:

```java
lastValue(BOOK.ID).over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
last_value(BOOK.ID) OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-nth-value"></a>
##### 3.11.27.21. NTH_VALUE

The `NTH_VALUE` window function allows for getting the value of an expression evaluated on the `N`th row of the window.

```sql
SELECT
  ID,
  nth_value(ID, 2) OVER (ORDER BY ID),
  nth_value(ID, 2) OVER (ORDER BY ID ROWS 2 PRECEDING)
FROM
  BOOK;
```

```java
create.select(
         BOOK.ID,
         nthValue(BOOK.ID, 2).over(orderBy(BOOK.ID)),
         nthValue(BOOK.ID, 2).over(orderBy(BOOK.ID).rowsPreceding(2)))
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+-----------+-----------+
| id | nth_value | nth_value |
+----+-----------+-----------+
|  1 |           |           |
|  2 |         2 |         2 |
|  3 |         2 |         2 |
|  4 |         2 |         3 |
+----+-----------+-----------+
```

- The [window frame clause](#window-frame) is applied to `NTH_VALUE`.
- `NTH_VALUE` supports the optional [NULL treatment clause](#window-nulls).
- `NTH_VALUE` supports the optional [FIRST / LAST clause](#window-first-last).

###### Dialect support

This example using jOOQ:

```java
nthValue(BOOK.ID, 2).over(orderBy(BOOK.ID))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, SQLite, Snowflake, Trino, Vertica, YugabyteDB

```sql
nth_value(BOOK.ID, 2) OVER (ORDER BY BOOK.ID)
```

###### ASE, Access, Aurora MySQL, Databricks, HSQLDB, Informix, Redshift, SQLDataWarehouse, SQLServer, Spanner, Sybase, Teradata

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="window-ratio-to-report"></a>
##### 3.11.27.22. RATIO_TO_REPORT

The `RATIO_TO_REPORT` window function allows for getting the ratio of the corrent value in the window to the `SUM` over the window.

```sql
SELECT
  ID,
  ratio_to_report(ID) OVER ()
FROM
  BOOK;
```

```java
create.select(
         BOOK.ID,
         ratioToReport(BOOK.ID).over())
     .from(BOOK)
     .fetch();
```

Producing:

```text
+----+-----------------+
| id | ratio_to_report |
+----+-----------------+
|  1 |             0.1 |
|  2 |             0.2 |
|  3 |             0.3 |
|  4 |             0.4 |
+----+-----------------+
```

###### Dialect support

This example using jOOQ:

```java
ratioToReport(BOOK.ID).over()
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Vertica, YugabyteDB

```sql
(cast(BOOK.ID AS decimal) / sum(BOOK.ID) OVER ())
```

###### BigQuery, Exasol, H2, Oracle, Snowflake, Teradata

```sql
ratio_to_report(BOOK.ID) OVER ()
```

###### Firebird, Trino

```sql
(cast(BOOK.ID AS decimal(38, 19)) / sum(BOOK.ID) OVER ())
```

###### SQLite

```sql
(cast(BOOK.ID AS double) / sum(BOOK.ID) OVER ())
```

###### ASE, Access, Aurora MySQL, HSQLDB, Spanner, Sybase

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="user-defined-functions"></a>
#### 3.11.28. User-defined functions

Some databases support user-defined functions, which can be embedded in any SQL statement, if you're using jOOQ's [code generator](#code-generation). Let's say you have the following simple function in Oracle SQL:

```sql
CREATE OR REPLACE FUNCTION echo (INPUT NUMBER)
RETURN NUMBER
IS
BEGIN
    RETURN INPUT;
END echo;
```

The above function will be made available from a generated [Routines](#codegen-procedures) class. You can use it like any other [column expression](#column-expressions):

```sql
SELECT echo(1) FROM DUAL WHERE echo(2) = 2
```

```java
create.select(echo(1)).where(echo(2).eq(2)).fetch();
```

Note that user-defined functions returning CURSOR or ARRAY data types can also be used wherever [table expressions](#table-expressions) can be used, if they are [unnested](#array-and-cursor-unnesting)

<a id="user-defined-aggregate-functions"></a>
#### 3.11.29. User-defined aggregate functions

Some databases support user-defined aggregate functions, which can then be used along with [GROUP BY clauses](#group-by-clause) or as [window functions](#window-functions). An example for such a database is Oracle. With Oracle, you can define the following `OBJECT` type (the example was taken from the [Oracle 11g documentation](https://docs.oracle.com/cd/B28359_01/appdev.111/b28425/ext_agg_ref.htm)):

```sql
CREATE TYPE U_SECOND_MAX AS OBJECT
(
  MAX NUMBER, -- highest value seen so far
  SECMAX NUMBER, -- second highest value seen so far
  STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT U_SECOND_MAX) RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateIterate(self IN OUT U_SECOND_MAX, value IN NUMBER) RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateTerminate(self IN U_SECOND_MAX, returnValue OUT NUMBER, flags IN NUMBER) RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateMerge(self IN OUT U_SECOND_MAX, ctx2 IN U_SECOND_MAX) RETURN NUMBER
);

CREATE OR REPLACE TYPE BODY U_SECOND_MAX IS
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT U_SECOND_MAX)
RETURN NUMBER IS
BEGIN
  SCTX := U_SECOND_MAX(0, 0);
  RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateIterate(self IN OUT U_SECOND_MAX, value IN NUMBER) RETURN NUMBER IS
BEGIN
  IF VALUE > SELF.MAX THEN
    SELF.SECMAX := SELF.MAX;
    SELF.MAX := VALUE;
  ELSIF VALUE > SELF.SECMAX THEN
    SELF.SECMAX := VALUE;
  END IF;
  RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateTerminate(self IN U_SECOND_MAX, returnValue OUT NUMBER, flags IN NUMBER) RETURN NUMBER IS
BEGIN
  RETURNVALUE := SELF.SECMAX;
  RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateMerge(self IN OUT U_SECOND_MAX, ctx2 IN U_SECOND_MAX) RETURN NUMBER IS
BEGIN
  IF CTX2.MAX > SELF.MAX THEN
    IF CTX2.SECMAX > SELF.SECMAX THEN
      SELF.SECMAX := CTX2.SECMAX;
    ELSE
      SELF.SECMAX := SELF.MAX;
    END IF;
    SELF.MAX := CTX2.MAX;
  ELSIF CTX2.MAX > SELF.SECMAX THEN
    SELF.SECMAX := CTX2.MAX;
  END IF;
  RETURN ODCIConst.Success;
END;
END;
```

The above `OBJECT` type is then available to function declarations as such:

```sql
CREATE FUNCTION SECOND_MAX (input NUMBER) RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING U_SECOND_MAX;
```

##### Using the generated aggregate function

jOOQ's [code generator](#code-generation) will detect such aggregate functions and generate them differently from regular [user-defined functions](#user-defined-functions). They implement the [`org.jooq.AggregateFunction`](https://www.jooq.org/javadoc/3.22.x/org/jooq/AggregateFunction.html) type, as mentioned in the manual's section about [aggregate functions](#aggregate-functions). Here's how you can use the `SECOND_MAX()` aggregate function with jOOQ:

```sql
-- Get the second-latest publishing date by author
SELECT SECOND_MAX(PUBLISHED_IN)
FROM BOOK
GROUP BY AUTHOR_ID
 
```

```java
// Routines.secondMax() can be static-imported
create.select(secondMax(BOOK.PUBLISHED_IN))
      .from(BOOK)
      .groupBy(BOOK.AUTHOR_ID)
      .fetch();
```

<a id="user-defined-type-constructor-expressions"></a>
#### 3.11.30. User-defined type constructor expressions

jOOQ's code generator supports [user-defined types (UDTs)](#codegen-udts) and generates meta data, records, POJOs and other artifacts for those types.

You can access the constructor expression from the generated [`org.jooq.UDT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDT.html) type as follows. Assuming this schema using PostgreSQL syntax:

```sql
CREATE TYPE country AS (
  iso_code TEXT,
  description TEXT
);

CREATE TYPE name AS (
  first_name TEXT,
  last_name TEXT
);

CREATE TYPE address AS (
  street TEXT,
  number TEXT,
  zip TEXT,
  city TEXT,
  country COUNTRY
);

CREATE TABLE customer (
  id INT PRIMARY KEY,
  first_name TEXT,
  last_name TEXT,
  street TEXT,
  number TEXT,
  zip TEXT,
  city TEXT,
  country_iso_code TEXT,
  country_description TEXT
);
```

This data can be fetched with jOOQ as follows:

```java
Record2<NameRecord, AddressRecord> result =
create.select(
         NAME(CUSTOMER.FIRST_NAME, CUSTOMER.LAST_NAME),
         ADDRESS(
             CUSTOMER.STREET,
             CUSTOMER.NUMBER,
             CUSTOMER.ZIP,
             CUSTOMER.CITY,
             COUNTRY(
                 CUSTOMER.COUNTRY_ISO_CODE,
                 CUSTOMER.COUNTRY_DESCRIPTION
             )
         ))
      .from(CUSTOMER)
      .where(CUSTOMER.ID.eq(1))
      .fetchOne();

System.out.println(result.value1().getFirstName());
System.out.println(result.value1().getLastName());
System.out.println(result.value2().getCountry().getIsoCode());
```

<a id="user-defined-type-attribute-paths"></a>
#### 3.11.31. User-defined type attribute paths

jOOQ's code generator supports [user-defined types (UDTs)](#codegen-udts) and generates meta data, records, POJOs and other artifacts for those types.

When dereferencing such types in SQL, you can access the [`org.jooq.UDTRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDTRecord.html) as follows. Assumnig this schema using PostgreSQL syntax:

```sql
CREATE TYPE country AS (
  iso_code TEXT,
  description TEXT
);

CREATE TYPE name AS (
  first_name TEXT,
  last_name TEXT
);

CREATE TYPE address AS (
  street TEXT,
  number TEXT,
  zip TEXT,
  city TEXT,
  country COUNTRY
);

CREATE TABLE customer (
  id INT PRIMARY KEY,
  name NAME,
  address ADDRESS
);
```

This data can be fetched with jOOQ as follows:

```java
Record2<NameRecord, AddressRecord> result =
create.select(CUSTOMER.NAME, CUSTOMER.ADDRESS)
      .from(CUSTOMER)
      .where(CUSTOMER.ID.eq(1))
      .fetchOne();

System.out.println(result.value1().getFirstName());
System.out.println(result.value1().getLastName());
System.out.println(result.value2().getCountry().getIsoCode());
```

If you don't need to fetch the entire UDT, you can also dereference individual attributes directly in SQL, in a type safe way!

```java
Record3<String, String, String> result =
create.select(
          CUSTOMER.NAME.FIRST_NAME,
          CUSTOMER.NAME.LAST_NAME,
          CUSTOMER.ADDRESS.COUNTRY.ISO_CODE)
      .from(CUSTOMER)
      .where(CUSTOMER.ID.eq(1))
      .fetchOne();

System.out.println(result.value1());
System.out.println(result.value2());
System.out.println(result.value3());
```

<a id="case-expressions"></a>
#### 3.11.32. The CASE expression

The `CASE` expression is part of the standard SQL syntax. While some RDBMS also offer an `IF` expression, or a `DECODE` function, you can always rely on the two types of `CASE` syntax:

```sql
SELECT

  -- Searched case
  CASE WHEN AUTHOR.FIRST_NAME = 'Paulo'  THEN 'brazilian'
       WHEN AUTHOR.FIRST_NAME = 'George' THEN 'english'
                                         ELSE 'unknown'
  END,

  -- Simple case
  CASE AUTHOR.FIRST_NAME WHEN 'Paulo'  THEN 'brazilian'
                         WHEN 'George' THEN 'english'
                                       ELSE 'unknown'
  END
FROM AUTHOR
```

```java
create.select(

  // Searched case
  when(AUTHOR.FIRST_NAME.eq("Paulo"), "brazilian")
  .when(AUTHOR.FIRST_NAME.eq("George"), "english")
  .otherwise("unknown");

  // Simple case
  choose(AUTHOR.FIRST_NAME)
  .when("Paulo", "brazilian")
  .when("George", "english")
  .otherwise("unknown"))
.from(AUTHOR)
.fetch();
```

In jOOQ, both syntaxes are supported (The second one is emulated in Derby, which only knows the first one). Unfortunately, both case and else are reserved words in Java. jOOQ chose to use decode() from the Oracle `DECODE` function, or `choose()` / `case_()`, and `otherwise()` / `else_()`.

A `CASE` expression can be used anywhere where you can place a [column expression (or Field)](#column-expressions). For instance, you can `SELECT` the above expression, if you're selecting from `AUTHOR`:

```sql
SELECT AUTHOR.FIRST_NAME, [... CASE EXPR ...] AS nationality
  FROM AUTHOR
```

##### Short forms of the CASE expression

The SQL standard and some vendors support a variety of short forms of the `CASE` expression, usually in the form of functions. These include:

- [COALESCE](#coalesce-function)
- [CHOOSE](#choose-function)
- [DECODE](#decode-function)
- [IIF or IF](#iif-function)
- [NULLIF](#nullif-function)
- [NVL](#nvl-function)
- [NVL2](#nvl2-function)

Sort indirection is often implemented with a `CASE` clause of a `SELECT`'s `ORDER BY` clause. See the manual's section about the [ORDER BY clause](#order-by-clause) for more details.

<a id="sequences-and-serials"></a>
#### 3.11.33. Sequences and serials

Sequences implement the [`org.jooq.Sequence`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Sequence.html) interface, providing essentially this functionality:

```java
// Get a field for the CURRVAL sequence property
Field<T> currval();

// Get a field for the NEXTVAL sequence property
Field<T> nextval();
```

So if you have a sequence like this in Oracle:

```sql
CREATE SEQUENCE s_author_id
```

You can then use your [generated sequence](#codegen-sequences) object directly in a SQL statement as such:

```java
// Reference the sequence in a SELECT statement:
Field<BigInteger> s = S_AUTHOR_ID.nextval();
BigInteger nextID = create.select(s).fetchOne(s);

// Reference the sequence in an INSERT statement:
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .values(S_AUTHOR_ID.nextval(), val("William"), val("Shakespeare"))
      .execute();
```

- For more information about generated sequences, refer to the manual's section about [generated sequences](#codegen-sequences)
- For more information about executing standalone calls to sequences, refer to the manual's section about [sequence execution](#sequence-execution)

<a id="scalar-subqueries"></a>
#### 3.11.34. Scalar subqueries

A scalar subquery is a subquery that produces a scalar value, i.e. one row and one column. Such values can be used as ordinary [column expressions](#column-expressions). Syntactically, any `Select<Record1<?>>` type qualifies as a scalar subquery, irrespective of content and whether it is "correlated".

There are mostly 3 ways of creating scalar subqueries in jOOQ

- Type safe wrapping using [`DSL.field(Select)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#field(org.jooq.Select))
- Type unsafe wrapping using [`Select.asField()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Select.html#asField())
- Through convenience methods, such as [`Field.eq(Select)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#eq(org.jooq.Select))

For example:

```sql
SELECT
  AUTHOR.ID, (
    SELECT count(*) FROM AUTHOR
  ) AS authors
FROM AUTHOR
```

```java
create.select(
          AUTHOR.ID,
          field(selectCount().from(AUTHOR)).as("authors"))
      .from(AUTHOR)
      .fetch();
```

##### Correlated subqueries

A "correlated" subquery is a subquery (scalar or not) whose execution depends on the query that it is embedded in. It acts as a function taking the current row as an input argument.

```sql
SELECT
  AUTHOR.ID, (
    SELECT count(*)
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  ) AS books
FROM AUTHOR
```

```java
create.select(
          AUTHOR.ID,
          field(selectCount()
            .from(BOOK)
            .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID)))
      .from(AUTHOR)
      .fetch();
```

In the above example, the subquery counts the number of books for each author from the outer query.

<a id="array-value-constructor"></a>
#### 3.11.35. ARRAY value constructor

The `ARRAY` value constructor allows for collecting the results of a single-column, non [scalar subquery](#scalar-subqueries) into a single nested collection value with `ARRAY` data type semantics (ordinals are defined on elements).

For example, let's find:

- All authors.
- The languages in which that author has their books published.
- The book stores at which that author's books are available.

This can be done in a single query:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  ARRAY(
    SELECT DISTINCT LANGUAGE.CD
    FROM BOOK
    JOIN LANGUAGE ON BOOK.LANGUAGE_ID = LANGUAGE.ID
  ) AS BOOKS,
  ARRAY(
    SELECT DISTINCT BOOK_TO_BOOK_STORE.BOOK_STORE_NAME
    FROM BOOK_TO_BOOK_STORE
    JOIN BOOK ON BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  ) AS BOOK_STORES
FROM AUTHOR
ORDER BY AUTHOR.ID
```

```java
var result = create.select(
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME,
          array(
              selectDistinct(BOOK.language().CD)
              .from(BOOK)
              .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
          ).as("books"),
          array(
              selectDistinct(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
              .from(BOOK_TO_BOOK_STORE)
              .where(BOOK_TO_BOOK_STORE.tBook().AUTHOR_ID.eq(AUTHOR.ID))
          ).as("book_stores"))
      .from(AUTHOR)
      .orderBy(AUTHOR.ID)
      .fetch();
```

The above `var result` is inferred to:

```java
Result<Record4<String, String, String[], String[]>> result =
```

The result of the above query may look like this:

```text
+----------+---------+--------+--------------------------------------------------+
|first_name|last_name|books   |book_stores                                       |
+----------+---------+--------+--------------------------------------------------+
|George    |Orwell   |[en]    |[Ex Libris, Orell Füssli]                         |
|Paulo     |Coelho   |[de, pt]|[Buchhandlung im Volkshaus, Ex Libris, Orell Fü...|
+----------+---------+--------+--------------------------------------------------+
```

<a id="multiset-value-constructor"></a>
#### 3.11.36. MULTISET value constructor

The `MULTISET` value constructor is one of jOOQ's and standard SQL's most powerful features. It allows for collecting the results of a non [scalar subquery](#scalar-subqueries) into a single nested collection value with `MULTISET` semantics (ordinals are not defined on elements, though jOOQ attempts to maintain `ORDER BY` produced ordering when projecting a `MULTISET`).

For example, let's find:

- All authors.
- The languages in which that author has their books published.
- The book stores at which that author's books are available.

This can be done in a single query:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  MULTISET(
    SELECT DISTINCT
      LANGUAGE.CD
      LANGUAGE.DESCRIPTION
    FROM BOOK
    JOIN LANGUAGE ON BOOK.LANGUAGE_ID = LANGUAGE.ID
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  ) AS BOOKS,
  MULTISET(
    SELECT DISTINCT BOOK_TO_BOOK_STORE.BOOK_STORE_NAME
    FROM BOOK_TO_BOOK_STORE
    JOIN BOOK ON BOOK_TO_BOOK_STORE.BOOK_ID = BOOK.ID
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  ) AS BOOK_STORES
FROM AUTHOR
ORDER BY AUTHOR.ID
```

```java
var result = create.select(
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME,
          multiset(
              selectDistinct(
                  BOOK.language().CD,
                  BOOK.language().DESCRIPTION)
              .from(BOOK)
              .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
          ).as("books"),
          multiset(
              selectDistinct(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
              .from(BOOK_TO_BOOK_STORE)
              .where(BOOK_TO_BOOK_STORE.tBook().AUTHOR_ID.eq(AUTHOR.ID))
          ).as("book_stores"))
      .from(AUTHOR)
      .orderBy(AUTHOR.ID)
      .fetch();
```

Notice how the Java 10 `var` keyword really shines here. It is usually not desirable to denote the types arising from nesting records or collections in jOOQ. The above `var result` is inferred to:

```java
Result<Record4<
    String,          // AUTHOR.FIRST_NAME
    String,          // AUTHOR.LAST_NAME
    Result<Record2<
        String,      // LANGUAGE.CD
        String       // LANGUAGE.DESCRIPTION
    >>,              // books
    Result<Record1<
        String       // BOOK_TO_BOOK_STORE.BOOK_STORE_NAME
    >>               // book_stores
>> result = ...
```

Notice also that in a lot of cases, using [RecordMappers](#recordmapper) can be very helpful when nesting collections to DTO trees, especially when combined with [ad hoc converters](#ad-hoc-converter).

The result of the above query may look like this:

```text
+----------+---------+-----------------------------+--------------------------------------------------+
|first_name|last_name|books                        |book_stores                                       |
+----------+---------+-----------------------------+--------------------------------------------------+
|George    |Orwell   |[(en, English)]              |[(Ex Libris), (Orell Füssli)]                     |
|Paulo     |Coelho   |[(de, Deutsch), (pt, {null})]|[(Buchhandlung im Volkshaus), (Ex Libris), (Ore...|
+----------+---------+-----------------------------+--------------------------------------------------+
```

Or, when [exported as JSON](#exporting-json) (alternatively, use [JSON_ARRAYAGG](#json-arrayagg-function) directly):

```text
[
  {
    "first_name": "George",
    "last_name": "Orwell",
    "books": [
      {
        "cd": "en",
        "description": "English"
      }
    ],
    "book_stores": [
      { "book_store_name": "Ex Libris" },
      { "book_store_name": "Orell Füssli" }
    ]
  },
  {
    "first_name": "Paulo",
    "last_name": "Coelho",
    "books": [
      {
        "cd": "de",
        "description": "Deutsch"
      },
      {
        "cd": "pt",
        "description": null
      }
    ],
    "book_stores": [
      { "book_store_name": "Buchhandlung im Volkshaus" },
      { "book_store_name": "Ex Libris" },
      { "book_store_name": "Orell Füssli" }
    ]
  }
]
```

Or, when [exported as XML](#exporting-xml) (alternatively, use [XMLAGG](#xml-agg-function) directly):

```text
<result>
  <record>
    <first_name>George</first_name>
    <last_name>Orwell</last_name>
    <books>
      <result>
        <record>
          <cd>en</cd>
          <description>English</description>
        </record>
      </result>
    </books>
    <book_stores>
      <result>
        <record>
          <book_store_name>Ex Libris</book_store_name>
        </record>
        <record>
          <book_store_name>Orell Füssli</book_store_name>
        </record>
      </result>
    </book_stores>
  </record>
  <record>
    <first_name>Paulo</first_name>
    <last_name>Coelho</last_name>
    <books>
      <result>
        <record>
          <cd>de</cd>
          <description>Deutsch</description>
        </record>
        <record>
          <cd>pt</cd>
          <description/>
        </record>
      </result>
    </books>
    <book_stores>
      <result>
        <record>
          <book_store_name>Buchhandlung im Volkshaus</book_store_name>
        </record>
        <record>
          <book_store_name>Ex Libris</book_store_name>
        </record>
        <record>
          <book_store_name>Orell Füssli</book_store_name>
        </record>
      </result>
    </book_stores>
  </record>
</result>
```

##### Implementation

The bad news is, hardly any dialect supports the `MULTISET` constructor natively (e.g. Informix or Oracle do). In all other dialects, it has to be emulated using SQL/JSON or SQL/XML. The above query may look like this, in PostgreSQL:

```sql
SELECT
  AUTHOR.FIRST_NAME,
  AUTHOR.LAST_NAME,
  (
    SELECT COALESCE(
      JSONB_AGG(JSONB_BUILD_ARRAY(V0, V1)),
      JSONB_BUILD_ARRAY()
    )
    FROM (
      SELECT DISTINCT
        ALIAS_86077489.CD AS V0,
        ALIAS_86077489.DESCRIPTION AS V1
      FROM BOOK
        JOIN LANGUAGE AS ALIAS_86077489
          ON BOOK.LANGUAGE_ID = ALIAS_86077489.ID
      WHERE BOOK.AUTHOR_ID = AUTHOR.ID
    ) AS T
  ) AS BOOKS,
  (
    SELECT COALESCE(
      JSONB_AGG(JSONB_BUILD_ARRAY(V0)),
      JSONB_BUILD_ARRAY()
    )
    FROM (
      SELECT DISTINCT BOOK_TO_BOOK_STORE.BOOK_STORE_NAME AS V0
      FROM BOOK_TO_BOOK_STORE
        JOIN BOOK AS ALIAS_129518614
          ON BOOK_TO_BOOK_STORE.BOOK_ID = ALIAS_129518614.ID
      WHERE ALIAS_129518614.AUTHOR_ID = AUTHOR.ID
    ) AS T
  ) AS BOOK_STORES
FROM AUTHOR
ORDER BY AUTHOR.ID
```

As you might notice, this produces a slightly different JSON structure than what one might have created manually. It generates arrays of arrays, which look something like this in a formatted result:

```text
+----------+---------+---------------------------------+----------------------------------------------------------------+
|first_name|last_name|books                            |book_stores                                                     |
+----------+---------+---------------------------------+----------------------------------------------------------------+
|George    |Orwell   |[["en", "English"]]              |[["Ex Libris"], ["Orell Füssli"]]                               |
|Paulo     |Coelho   |[["de", "Deutsch"], ["pt", null]]|[["Buchhandlung im Volkshaus"], ["Ex Libris"], ["Orell Füssli"]]|
+----------+---------+---------------------------------+----------------------------------------------------------------+
```

The benefits are:

1. Arrays take less space than objects in JSON, so the serialisation format is more optimal
2. Arrays don't care about duplicate column names, which can cause issues with various JSON parsers (even if JSON supports it)
3. Array elements have a well defined order, object keys do not, and index lookups are faster than name lookups

The resulting JSON or XML document will be parsed and mapped to a jOOQ [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) and [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) hierarchy.

By default, the "best" serialisation format is used (JSON, XML, or ARRAY in the future), but you can override it using [`Settings.emulateMultiset`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#emulateMultiset), which offers the following values:

- [`DEFAULT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/NestedCollectionEmulation.html#DEFAULT): Let jOOQ decide how to serialise nested collections
- [`XML`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/NestedCollectionEmulation.html#XML): Use XML to serialise nested collections
- [`JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/NestedCollectionEmulation.html#JSON): Use JSON to serialise nested collections
- [`JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/NestedCollectionEmulation.html#JSONB): Use JSONB to serialise nested collections
- [`NATIVE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/NestedCollectionEmulation.html#NATIVE): Generate a native syntax

##### Dialect support

This example using jOOQ:

```java
multiset(select(BOOK.ID, BOOK.TITLE).from(BOOK))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, Postgres, YugabyteDB

```sql
(
  SELECT coalesce(
    jsonb_agg(jsonb_build_array(t.v0, t.v1)),
    jsonb_build_array()
  )
  FROM (
    SELECT
      BOOK.ID v0,
      BOOK.TITLE v1
    FROM BOOK
  ) t
)
```

###### BigQuery

```sql
(
  SELECT coalesce(
    to_json(
      coalesce(
        array_agg(json_array(t.v0, t.v1)), cast(ARRAY[] AS array<json>)
      )
    ),
    json_array()
  )
  FROM (
    SELECT
      BOOK.ID v0,
      BOOK.TITLE v1
    FROM BOOK
  ) t
)
```

###### Databricks

```sql
(
  SELECT array_agg(t.c)
  FROM (
    SELECT STRUCT (
      coalesce(col1),
      coalesce(col2)
    )
    FROM (
      SELECT BOOK.ID, BOOK.TITLE
      FROM BOOK
    ) t (col1, col2)
  ) t (c)
)
```

###### DB2

```sql
(
  SELECT xmlelement(
    NAME result,
    xmlagg(xmlelement(
      NAME record,
      xmlelement(NAME v0, BOOK.ID),
      xmlelement(
        NAME v1,
        xmlattributes(
          CASE
            WHEN BOOK.TITLE IS NULL THEN 'true'
          END AS "xsi:nil"
        ),
        BOOK.TITLE
      )
    ))
  )
  FROM BOOK
)
```

###### DuckDB

```sql
ARRAY(
  SELECT t
  FROM (
    SELECT BOOK.ID, BOOK.TITLE
    FROM BOOK
  ) t
)
```

###### H2

```sql
(
  SELECT coalesce(
    json_arrayagg(json_array(
      BOOK.ID, BOOK.TITLE
      NULL ON NULL
    )),
    json_array(NULL ON NULL)
  )
  FROM BOOK
)
```

###### Informix

```sql
MULTISET(
  SELECT BOOK.ID, BOOK.TITLE
  FROM BOOK
)
```

###### MariaDB

```sql
(
  SELECT coalesce(
    json_merge_preserve(
      '[]',
      concat(
        '[',
        group_concat(json_array(BOOK.ID, BOOK.TITLE) SEPARATOR ','),
        ']'
      )
    ),
    json_array()
  )
  FROM BOOK
)
```

###### MySQL

```sql
(
  SELECT coalesce(
    json_merge_preserve(
      '[]',
      concat(
        '[',
        group_concat(json_array(t.v0, t.v1) SEPARATOR ','),
        ']'
      )
    ),
    json_array()
  )
  FROM (
    SELECT
      BOOK.ID v0,
      BOOK.TITLE v1
    FROM BOOK
  ) t
)
```

###### Oracle

```sql
(
  SELECT coalesce(
    json_arrayagg(json_array(
      t.v0, t.v1
      NULL ON NULL
      RETURNING clob
    ) FORMAT JSON RETURNING clob),
    json_array(RETURNING clob)
  )
  FROM (
    SELECT
      BOOK.ID v0,
      BOOK.TITLE v1
    FROM BOOK
  ) t
)
```

###### Snowflake

```sql
(
  SELECT coalesce(
    array_agg(array_construct(coalesce(
      to_variant(BOOK.ID),
      parse_json('null')
    ), coalesce(
      to_variant(BOOK.TITLE),
      parse_json('null')
    ))) WITHIN GROUP (ORDER BY NULL),
    array_construct()
  )
  FROM BOOK
)
```

###### Spanner

```sql
(
  SELECT coalesce(
    to_json(
      coalesce(
        array_agg(json_array(BOOK.ID, BOOK.TITLE)), cast(ARRAY[] AS array<json>)
      )
    ),
    json_array()
  )
  FROM BOOK
)
```

###### SQLite

```sql
(
  SELECT coalesce(
    json_group_array(json_array(t.v0, t.v1)),
    json_array()
  )
  FROM (
    SELECT
      BOOK.ID v0,
      BOOK.TITLE v1
    FROM BOOK
  ) t
)
```

###### SQLServer

```sql
coalesce(
  (
    SELECT
      v0 v0,
      v1 v1
    FROM (
      SELECT BOOK.ID, BOOK.TITLE
      FROM BOOK
    ) t (v0, v1)
    FOR XML RAW ('record'), ELEMENTS XSINIL, BINARY BASE64, TYPE, ROOT ('result')
  ),
  '<result/>'
)
```

###### Teradata

```sql
(
  SELECT xmlelement(
    NAME "result",
    xmlagg(xmlelement(
      NAME record,
      xmlelement(NAME v0, t.v0),
      xmlelement(
        NAME v1,
        xmlattributes(
          CASE
            WHEN t.v1 IS NULL THEN 'true'
          END AS nil
        ),
        t.v1
      )
    ))
  )
  FROM (
    SELECT
      BOOK.ID v0,
      BOOK.TITLE v1
    FROM BOOK
  ) t
)
```

###### Trino

```sql
(
  SELECT coalesce(
    cast(array_agg(cast(
      ARRAY[
        cast(t.v0 AS json),
        cast(t.v1 AS json)
      ]
      AS json
    )) AS json),
    cast(ARRAY[] AS json)
  )
  FROM (
    SELECT
      BOOK.ID v0,
      BOOK.TITLE v1
    FROM BOOK
  ) t
)
```

###### ASE, Access, Aurora MySQL, ClickHouse, Exasol, Firebird, HSQLDB, Hana, MemSQL, Redshift, SQLDataWarehouse, Sybase, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="row-value-expressions"></a>
#### 3.11.37. Tuples or row value expressions

According to the SQL standard, row value expressions can have a degree of more than one. This is commonly used in the [INSERT statement](#insert-statement), where the `VALUES` row value constructor allows for providing a row value expression as a source for `INSERT` data. Row value expressions can appear in various other places, though. They are supported by jOOQ as records / rows. jOOQ's [DSL](#dsl) allows for the construction of type-safe records up to the degree of 22. Higher-degree Rows are supported as well, but without any type-safety. Row types are modelled as follows:

```java
// The DSL provides overloaded row value expression constructor methods:
public static <T1>             Row1<T1>             row(T1 t1)                      { ... }
public static <T1, T2>         Row2<T1, T2>         row(T1 t1, T2 t2)               { ... }
public static <T1, T2, T3>     Row3<T1, T2, T3>     row(T1 t1, T2 t2, T3 t3)        { ... }
public static <T1, T2, T3, T4> Row4<T1, T2, T3, T4> row(T1 t1, T2 t2, T3 t3, T4 t4) { ... }

// [ ... idem for Row5, Row6, Row7, ..., Row22 ]

// Degrees of more than 22 are supported without type-safety
public static RowN row(Object... values) { ... }
```

##### Using row value expressions in predicates

Row value expressions are incompatible with most other [QueryParts](#queryparts), but they can be used as a basis for constructing various [conditional expressions](#conditional-expressions), such as:

- [comparison predicates](#comparison-predicate-degree-n)
- [NULL predicates](#null-predicate-degree-n)
- [BETWEEN predicates](#between-predicate-degree-n)
- [IN predicates](#in-predicate-degree-n)
- [OVERLAPS predicate](#overlaps-predicate) (for degree 2 row value expressions only)

See the relevant sections for more details about how to use row value expressions in predicates.

##### Projecting row value expressions

Row value expressions can be used to [project nested records](#nested-records), which allows for powerful mapping of structure data directly in SQL.

##### Using row value expressions in UPDATE statements

The [UPDATE statement](#update-statement) also supports a variant where row value expressions are updated, rather than single columns. See the relevant section for more details

##### Higher-degree row value expressions

jOOQ chose to explicitly support degrees up to 22 to match Scala 2's typesafe tuple, function and product support. Just like in Scala, 22 is an arbitrary choice of number as good as any other (though, in the case of jOOQ, reasonably high for most SQL queries). Unlike Scala 2, however, jOOQ also supports higher degrees without the additional typesafety.

##### Dialect support

This example using jOOQ:

```java
row(BOOK.ID, BOOK.TITLE)
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
(BOOK.ID, BOOK.TITLE)
```

###### Databricks

```sql
STRUCT (
  coalesce(BOOK.ID),
  coalesce(BOOK.TITLE)
)
```

###### Informix

```sql
ROW (BOOK.ID, BOOK.TITLE)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="nested-records"></a>
#### 3.11.38. Nested records

The [`DSL.row()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#row(org.jooq.Field...)) constructor isn't only useful for different types of [row value expression predicates](#row-value-expressions), but also to project nested record types, in most cases even [Record1 to Record22](#record-n) types, which maintain column level type safety.

All [`org.jooq.Row1`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Row1.html) to [`org.jooq.Row22`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Row22.html) types as well as the [`org.jooq.RowN`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RowN.html) type extend [`org.jooq.SelectField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SelectField.html), meaning they can be placed in the [SELECT clause](#select-clause) or the [RETURNING clause](#insert-returning). The `T` type variable in `SelectField<T>` is bound to the appropriate [Record1 to Record22](#record-n) type, which allows for easily projecting nested records:

```sql
SELECT
  ID,
  ROW(
    FIRST_NAME,
    LAST_NAME
  )
FROM AUTHOR
```

```java
// Type inference via lambdas or var really shines here!
Result<Record2<Integer, Record2<String, String>>> result =
create.select(
         AUTHOR.ID,
         row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME))
      .from(AUTHOR)
      .fetch();
```

##### Combining nested records with arrays

If your RDBMS supports `ARRAY` types and `ARRAY` constructors, and if nested records are natively supported, chances are that you can combine the two features. For example, to find all books for an author, as a nested collection rather than a flat [join](#join-clause):

```sql
SELECT
  ID,
  ROW(
    AUTHOR.FIRST_NAME,
    AUTHOR.LAST_NAME
  ),
  ARRAY(
    SELECT BOOK.ID, BOOK.TITLE
    FROM BOOK
    WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  )
FROM AUTHOR
```

```java
// Type inference via lambdas or var really shines here!
Result<Record3<
  Integer,
  Record2<String, String>,
  Record2<Integer, String>[]
>> result =
create.select(
         AUTHOR.ID,
         row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
         array(
           select(row(BOOK.ID, BOOK.TITLE))
           .from(BOOK)
           .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
         )
       )
      .from(AUTHOR)
      .fetch();
```

##### Attaching RecordMappers to nested records

Nested records help structure your result sets using structural typing, but they really shine when you attach a `RecordMapper` to them. A [RecordMapper](#recordmapper) is a [`java.lang.FunctionalInterface`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/FunctionalInterface.html) that can convert a `Record` subtype to any user type `E`. By calling e.g. [`Row2.mapping()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Row2.html#mapping(java.lang.Class,org.jooq.Function2)), you can attach an [ad-hoc converter](#ad-hoc-converter) to the nested record type to turn the nested object into something much more meaningful:

```java
// Especially useful using Java 16 record types!
record Name(String firstName, String lastName) {}
record Author(int id, Name name) {}

// The "scary" structural type has gone!
List<Author> authors =
create.select(
         AUTHOR.ID,
         row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).mapping(Name::new)
       )
      .from(AUTHOR)
      .fetch(Records.mapping(Author::new));
```

All of the above is type safe and uses no reflection! Try it out yourself - add or remove a column to the query or to the records, and observe the compilation errors that appear.

Now for the `ARRAY` example:

```java
record Name(String firstName, String lastName) {}
record Book(int id, String title) {}
record Author(int id, Name name, Book[] books) {}

// Again, no structural typing here has gone!
List<Author> authors =
create.select(
         AUTHOR.ID,
         row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).mapping(Name::new),
         array(
           select(row(BOOK.ID, BOOK.TITLE).mapping(Book.class, Book::new)
           .from(BOOK)
           .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
         )
       )
      .from(AUTHOR)
      .fetch(Records.mapping(Author::new));
```

Again, everything is type safe. Unfortunately, reflection is needed in this case to construct a `Book[]` array. You must pass the `Book.class` reference to help jOOQ with that. If you prefer lists, no problem. You can wrap the array again using the same technique, using an explicit [ad-hoc converter](#ad-hoc-converter):

```java
record Name(String firstName, String lastName) {}
record Book(int id, String title) {}
record Author(int id, Name name, List<Book> books) {} // Is now using a List<Book> instead of Book[]

// Again, no structural typing here has gone!
List<Author> authors =
create.select(
         AUTHOR.ID,
         row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).mapping(Name::new),
         array(
           select(row(BOOK.ID, BOOK.TITLE).mapping(Book.class, Book::new)
           .from(BOOK)
           .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
         ).convertFrom(Arrays::asList) // Additional converter here
       )
      .from(AUTHOR)
      .fetch(Records.mapping(Author::new));
```

##### Dialect support

This example using jOOQ:

```java
select(row(BOOK.ID, BOOK.TITLE))
```

Translates to the following dialect specific expressions:

###### Access

```sql
SELECT BOOK.ID [nested__ID],
BOOK.TITLE [nested__TITLE]
FROM (
  SELECT count(*) dual
  FROM MSysResources
) AS dual
```

###### ASE, SQLDataWarehouse, SQLServer

```sql
SELECT BOOK.ID [nested__ID],
BOOK.TITLE [nested__TITLE]
```

###### Aurora MySQL, MemSQL

```sql
SELECT BOOK.ID `nested__ID`,
BOOK.TITLE `nested__TITLE`
FROM DUAL
```

###### Aurora Postgres, CockroachDB, DuckDB, H2, Postgres, YugabyteDB

```sql
SELECT ROW (BOOK.ID, BOOK.TITLE) nested
```

###### BigQuery, MariaDB, MySQL, SQLite, Spanner

```sql
SELECT BOOK.ID `nested__ID`,
BOOK.TITLE `nested__TITLE`
```

###### ClickHouse

```sql
SELECT TUPLE (BOOK.ID, BOOK.TITLE) nested
```

###### Databricks

```sql
SELECT STRUCT (
  coalesce(BOOK.ID),
  coalesce(BOOK.TITLE)
) nested
```

###### DB2

```sql
SELECT BOOK.ID "nested__ID",
BOOK.TITLE "nested__TITLE"
FROM SYSIBM.DUAL
```

###### Exasol, Oracle, Redshift, Snowflake, Trino, Vertica

```sql
SELECT BOOK.ID "nested__ID",
BOOK.TITLE "nested__TITLE"
```

###### Firebird

```sql
SELECT BOOK.ID "nested__ID",
BOOK.TITLE "nested__TITLE"
FROM RDB$DATABASE
```

###### Hana

```sql
SELECT BOOK.ID "nested__ID",
BOOK.TITLE "nested__TITLE"
FROM SYS.DUMMY
```

###### HSQLDB

```sql
SELECT BOOK.ID "nested__ID",
BOOK.TITLE "nested__TITLE"
FROM (VALUES (1)) AS dual (dual)
```

###### Informix

```sql
SELECT ROW (BOOK.ID, BOOK.TITLE) nested
FROM (
  SELECT 1 AS dual
  FROM systables
  WHERE (tabid = 1)
) AS dual
```

###### Sybase

```sql
SELECT BOOK.ID [nested__ID],
BOOK.TITLE [nested__TITLE]
FROM SYS.DUMMY
```

###### Teradata

```sql
SELECT BOOK.ID "nested__ID",
BOOK.TITLE "nested__TITLE"
FROM (
  SELECT 1 AS "dual"
) AS "dual"
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="conditional-expressions"></a>
### 3.12. Conditional expressions

Conditions or conditional expressions are widely used in SQL and in the jOOQ API. They can be used in

- The [CASE expression](#case-expressions)
- The [JOIN clause](#join-clause) (or `JOIN .. ON` clause, to be precise) of a [SELECT statement](#select-statement), [UPDATE statement](#update-statement), [DELETE statement](#delete-statement)
- The [WHERE clause](#where-clause) of a [SELECT statement](#select-statement), [UPDATE statement](#update-statement), [DELETE statement](#delete-statement)
- The [CONNECT BY clause](#connect-by-clause) of a [SELECT statement](#select-statement)
- The [HAVING clause](#having-clause) of a [SELECT statement](#select-statement)
- The [MERGE statement](#merge-statement)'s ON clause

#### Boolean types in SQL

Before SQL:1999, boolean types did not really exist in SQL. They were modelled by 0 and 1 numeric/char values. With SQL:1999, true booleans were introduced and are now supported by most databases. In short, these are possible boolean values:

- `1` or `TRUE`
- `0` or `FALSE`
- `NULL` or `UNKNOWN`

It is important to know that SQL differs from many other languages in the way it interprets the `NULL` boolean value. Most importantly, the following facts are to be remembered:

- `[ANY] = NULL` yields `NULL` (not `FALSE`)
- `[ANY] != NULL` yields `NULL` (not `TRUE`)
- `NULL = NULL` yields `NULL` (not `TRUE`)
- `NULL != NULL` yields `NULL` (not `FALSE`)

For simplified `NULL` handling, please refer to the section about the [DISTINCT predicate](#distinct-predicate).

Note that jOOQ does not model these values as actual [column expression](#column-expressions) compatible.

<a id="condition-building"></a>
#### 3.12.1. Condition building

With jOOQ, most [conditional expressions](#conditional-expressions) are built from [column expressions](#column-expressions), calling various methods on them.

For instance, to build a [comparison predicate](#comparison-predicate), you can write the following expression:

```sql
TITLE  = 'Animal Farm'
```

```java
BOOK.TITLE.eq("Animal Farm")
```

##### Create conditions from the DSL

There are a few types of conditions, that can only be created statically from the [DSL](#dsl). These are:

- [Plain SQL conditions](#plain-sql), that allow you to phrase your own SQL string [conditional expression](#conditional-expressions)
- The [EXISTS predicate](#exists-predicate), a standalone predicate that creates a conditional expression
- The [UNIQUE predicate](#unique-predicate), another standalone predicate creating a conditional expression
- Constant [TRUE and FALSE](#true-false-no-condition) conditional expressions
- Converting a [BOOLEAN column](#boolean-column) to a condition

##### Connect conditions using boolean operators

Conditions can also be connected using [boolean operators](#boolean-operators) as will be discussed in a subsequent chapter.

<a id="true-false-no-condition"></a>
#### 3.12.2. TRUE and FALSE condition

When a [conditional expression](#conditional-expressions) is mandatory, or when using [dynamic SQL](#dynamic-sql), it may be required to provide a "dummy" condition that always evaluates to `TRUE` or `FALSE`. For this purpose, you can use [`DSL.trueCondition()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#trueCondition()), [`DSL.falseCondition()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#falseCondition()), or [`DSL.noCondition()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#noCondition()). For example:

##### TRUE

`TRUE` is the identity value of the `AND` [boolean operator](#boolean-operators), and can be used for procedural or functional reduction of a set of values to a condition:

```sql
TRUE
AND
  ID = 1
AND
  TITLE = 'Animal Farm'
```

```java
Condition condition = trueCondition();
if (id != null)
    condition = condition.and(BOOK.ID.eq(id));
if (title != null)
    condition = condition.and(BOOK.TITLE.eq(title));
```

If a dialect does not support [boolean column types](#boolean-column), jOOQ will simply generate `1 = 1`.

##### FALSE

`FALSE` is the identity value of the `OR` [boolean operator](#boolean-operators), and can be used for procedural or functional reduction of a set of values to a condition:

```sql
FALSE
OR
  ID = 1
OR
  ID = 7
```

```java
List<Integer> list = List.of(1, 7);
Condition condition = list
    .stream()
    .map(BOOK.ID::eq)
    .reduce(falseCondition(), Condition::or)
```

If a dialect does not support [boolean column types](#boolean-column), jOOQ will simply generate `1 = 0`.

##### NO condition

If you think that the "left-over" identity that is generated from the above reductions is ugly, you can just use the auxiliary [`DSL.noCondition()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#noCondition()), which acts as a pseudo-identity for both `AND` and `OR`, not generating any SQL, except if the reduction produces nothing (from an empty set), in case of which it will behave like `TRUE`, which is what you usually want when placing a dynamic condition in a `WHERE` clause.

If used with actual data:

```sql
ID = 1
OR
  ID = 7
```

```java
List<Integer> list = List.of(1, 7);
Condition condition = list.stream().map(BOOK.ID::eq)
    .reduce(noCondition(), Condition::or)
```

If used with empty sets:

```sql
TRUE
 
 
```

```java
List<Integer> list = List.of(1, 7);
Condition condition = list.stream().map(BOOK.ID::eq)
    .reduce(noCondition(), Condition::or)
```

Some additional information about the `noCondition()` and related topics can be found in the section about [dynamic SQL](#dynamic-sql).

<a id="boolean-column"></a>
#### 3.12.3. BOOLEAN columns

Some databases support the standard SQL BOOLEAN data type, which produces `Field<Boolean>` column types in jOOQ's [code generator](#code-generation). But even if your dialect doesn't support the `BOOLEAN` type out of the box, you may have applied a [data type rewrite](#codegen-database-forced-types-rewrite) to force a `TINYINT(1)` or `CHAR(1)` or `NUMBER(1)` column to act as a `BOOLEAN`.

When you have such a column, you will want to use it as a condition, and vice-versa. A [`org.jooq.Field<Boolean>`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) can be turned into a [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html) using [`DSL.condition(Field)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#condition(Field)). The inverse operation can be achieved using [`DSL.field(Condition)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#field(Condition)):

```java
Condition condition = BOOK.TITLE.eq("Animal Farm");
Field<Boolean> field = field(condition);

// Fetch boolean values from a table
create.select(field).from(BOOK).fetch();

// Use a boolean field as a condition
create.selectFrom(BOOK).where(field).fetch();
```

<a id="boolean-operators"></a>
#### 3.12.4. AND, OR, NOT boolean operators

In SQL, as in most other languages, [conditional expressions](#conditional-expressions) can be connected using the `AND` and `OR` binary operators, as well as the `NOT` unary operator, to form new conditional expressions. In jOOQ, this is modelled as such:

```sql
(TITLE = 'Animal Farm' OR TITLE = '1984')
  AND NOT (AUTHOR.LAST_NAME = 'Orwell')
```

```java
BOOK.TITLE.eq("Animal Farm").or(BOOK.TITLE.eq("1984"))
  .andNot(AUTHOR.LAST_NAME.eq("Orwell"))
```

The above example shows that the number of parentheses in Java can quickly explode. Proper indentation may become crucial in making such code readable. In order to understand how jOOQ composes combined conditional expressions, let's assign component expressions first:

```java
Condition a = BOOK.TITLE.eq("Animal Farm");
Condition b = BOOK.TITLE.eq("1984");
Condition c = AUTHOR.LAST_NAME.eq("Orwell");

Condition combined1 = a.or(b);             // These OR-connected conditions form a new condition, wrapped in parentheses
Condition combined2 = combined1.andNot(c); // The left-hand side of the AND NOT () operator is already wrapped in parentheses
```

##### The Condition API

Here are all boolean operators on the [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html) interface:

```java
and(Condition)            // Combine conditions with AND
and(String)               // Combine conditions with AND. Convenience for adding plain SQL to the right-hand side
and(String, Object...)    // Combine conditions with AND. Convenience for adding plain SQL to the right-hand side
and(String, QueryPart...) // Combine conditions with AND. Convenience for adding plain SQL to the right-hand side
andExists(Select<?>)      // Combine conditions with AND. Convenience for adding an exists predicate to the rhs
andNot(Condition)         // Combine conditions with AND. Convenience for adding an inverted condition to the rhs
andNotExists(Select<?>)   // Combine conditions with AND. Convenience for adding an inverted exists predicate to the rhs

or(Condition)             // Combine conditions with OR
or(String)                // Combine conditions with OR. Convenience for adding plain SQL to the right-hand side
or(String, Object...)     // Combine conditions with OR. Convenience for adding plain SQL to the right-hand side
or(String, QueryPart...)  // Combine conditions with OR. Convenience for adding plain SQL to the right-hand side
orExists(Select<?>)       // Combine conditions with OR. Convenience for adding an exists predicate to the rhs
orNot(Condition)          // Combine conditions with OR. Convenience for adding an inverted condition to the rhs
orNotExists(Select<?>)    // Combine conditions with OR. Convenience for adding an inverted exists predicate to the rhs

not()                     // Invert a condition (synonym for DSL.not(Condition)
```

<a id="boolean-operator-precedence"></a>
#### 3.12.5. Boolean operator precedence

As previously mentioned in the manual's section about [arithmetic expressions](#arithmetic-expressions), jOOQ does not implement operator precedence. All operators are evaluated from left to right, as expected in an object-oriented API. This is important to understand when combining [boolean operators](#boolean-operators), such as `AND`, `OR`, and `NOT`. The following expressions are equivalent:

```java
   A.and(B) .or(C) .and(D) .or(E)
(((A.and(B)).or(C)).and(D)).or(E)
```

In SQL, the two expressions wouldn't be the same, as SQL natively knows operator precedence.

```sql
   A AND B  OR C  AND D  OR E -- Precedence is applied
(((A AND B) OR C) AND D) OR E -- Precedence is overridden
```

<a id="xor-operator"></a>
#### 3.12.6. XOR boolean operator

The exclusive or (`XOR`) operator is true only if one of the operands is true, not both.

```sql
(TITLE = 'Animal Farm' XOR AUTHOR.LAST_NAME = 'Orwell')
```

```java
BOOK.TITLE.eq("Animal Farm").xor(AUTHOR.LAST_NAME.eq("Orwell"))
```

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.eq("Animal Farm").xor(AUTHOR.LAST_NAME.eq("Orwell"))
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, MariaDB, MySQL

```sql
(
  BOOK.TITLE = 'Animal Farm'
  XOR AUTHOR.LAST_NAME = 'Orwell'
)
```

###### ASE, DB2, SQLDataWarehouse, SQLServer, Sybase, Teradata

```sql
CASE
  WHEN BOOK.TITLE = 'Animal Farm' THEN 1
  WHEN NOT (BOOK.TITLE = 'Animal Farm') THEN 0
END <> CASE
  WHEN AUTHOR.LAST_NAME = 'Orwell' THEN 1
  WHEN NOT (AUTHOR.LAST_NAME = 'Orwell') THEN 0
END
```

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, MemSQL, Oracle, Postgres, Redshift, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
(BOOK.TITLE = 'Animal Farm') <> (AUTHOR.LAST_NAME = 'Orwell')
```

###### Hana

```sql
CASE
  WHEN BOOK.TITLE = 'Animal Farm' THEN TRUE
  WHEN NOT (BOOK.TITLE = 'Animal Farm') THEN FALSE
END <> CASE
  WHEN AUTHOR.LAST_NAME = 'Orwell' THEN TRUE
  WHEN NOT (AUTHOR.LAST_NAME = 'Orwell') THEN FALSE
END
```

###### Informix

```sql
CASE
  WHEN BOOK.TITLE = 'Animal Farm' THEN cast('t' AS boolean)
  WHEN NOT (BOOK.TITLE = 'Animal Farm') THEN cast('f' AS boolean)
END <> CASE
  WHEN AUTHOR.LAST_NAME = 'Orwell' THEN cast('t' AS boolean)
  WHEN NOT (AUTHOR.LAST_NAME = 'Orwell') THEN cast('f' AS boolean)
END
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="comparison-predicate"></a>
#### 3.12.7. Comparison predicate

In SQL, comparison predicates are formed using common comparison operators:

- **=** to test for equality
- **<>** or **!=** to test for non-equality
- **>** to test for being strictly greater
- **>=** to test for being greater or equal
- **<** to test for being strictly less
- **<=** to test for being less or equal

Unfortunately, Java does not support operator overloading, hence these operators are also implemented as methods in jOOQ, like any other SQL syntax elements. The relevant parts of the [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) interface are these:

```java
eq or equal(T);                                     // =  (some bind value)
eq or equal(Field<T>);                              // =  (some column expression)
eq or equal(Select<? extends Record1<T>>);          // =  (some scalar SELECT statement)
ne or notEqual(T);                                  // <> (some bind value)
ne or notEqual(Field<T>);                           // <> (some column expression)
ne or notEqual(Select<? extends Record1<T>>);       // <> (some scalar SELECT statement)
lt or lessThan(T);                                  // <  (some bind value)
lt or lessThan(Field<T>);                           // <  (some column expression)
lt or lessThan(Select<? extends Record1<T>>);       // <  (some scalar SELECT statement)
le or lessOrEqual(T);                               // <= (some bind value)
le or lessOrEqual(Field<T>);                        // <= (some column expression)
le or lessOrEqual(Select<? extends Record1<T>>);    // <= (some scalar SELECT statement)
gt or greaterThan(T);                               // >  (some bind value)
gt or greaterThan(Field<T>);                        // >  (some column expression)
gt or greaterThan(Select<? extends Record1<T>>);    // >  (some scalar SELECT statement)
ge or greaterOrEqual(T);                            // >= (some bind value)
ge or greaterOrEqual(Field<T>);                     // >= (some column expression)
ge or greaterOrEqual(Select<? extends Record1<T>>); // >= (some scalar SELECT statement)
```

Note that every operator is represented by two methods. A verbose one (such as `equal()`) and a two-character one (such as `eq()`). Both methods are the same. You may choose either one, depending on your taste. The manual will always use the more verbose one.

##### jOOQ's convenience methods using comparison operators

In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using comparison predicates:

```sql
LOWER(TITLE) = LOWER('animal farm')
```

```java
BOOK.TITLE.equalIgnoreCase("animal farm")
```

<a id="comparison-predicate-degree-n"></a>
#### 3.12.8. Comparison predicate (degree > 1)

All variants of the [comparison predicate](#comparison-predicate) that we've seen in the previous chapter also work for [row value expressions](#row-value-expressions). If your database does not support row value expression comparison predicates, jOOQ emulates them the way they are defined in the SQL standard:

```sql
-- Row value expressions (equal)
(A, B)    =  (X, Y)
(A, B, C) =  (X, Y, Z)
-- greater than
(A, B)    >  (X, Y)

(A, B, C) >  (X, Y, Z)


-- greater or equal
(A, B)    >= (X, Y)


(A, B, C) >= (X, Y, Z)



-- Inverse comparisons

(A, B)    <> (X, Y)
(A, B)    <  (X, Y)
(A, B)    <= (X, Y)
```

```sql
-- Equivalent factored-out predicates (equal)
(A = X) AND (B = Y)
(A = X) AND (B = Y) AND (C = Z)
-- greater than
(A > X)
  OR ((A = X) AND (B > Y))
(A > X)
  OR ((A = X) AND (B > Y))
  OR ((A = X) AND (B = Y) AND (C > Z))
-- greater or equal
(A > X)
  OR ((A = X) AND (B > Y))
  OR ((A = X) AND (B = Y))
(A > X)
  OR ((A = X) AND (B > Y))
  OR ((A = X) AND (B = Y) AND (C > Z))
  OR ((A = X) AND (B = Y) AND (C = Z))
-- For simplicity, these predicates are shown in terms
-- of their negated counter parts
NOT((A, B) =  (X, Y))
NOT((A, B) >= (X, Y))
NOT((A, B) >  (X, Y))
```

jOOQ supports all of the above row value expression comparison predicates, both with [column expression lists](#column-expressions) and [scalar subselects](#select-statement) at the right-hand side:

```sql
-- With regular column expressions
(BOOK.AUTHOR_ID, BOOK.TITLE) = (1, 'Animal Farm')

-- With scalar subselects
(BOOK.AUTHOR_ID, BOOK.TITLE) = (
  SELECT PERSON.ID, 'Animal Farm'
  FROM PERSON
  WHERE PERSON.ID = 1
)
```

```java
// Column expressions
row(BOOK.AUTHOR_ID, BOOK.TITLE).eq(1, "Animal Farm");

// Subselects
row(BOOK.AUTHOR_ID, BOOK.TITLE).eq(
  select(PERSON.ID, val("Animal Farm"))
  .from(PERSON)
  .where(PERSON.ID.eq(1))
);
```

##### Dialect support

This example using jOOQ:

```java
row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).eq("John", "Doe")
```

Translates to the following dialect specific expressions:

###### ASE, Access, DuckDB, Exasol, Firebird, Hana, MemSQL, SQLDataWarehouse, SQLServer, Sybase

```sql
(
  AUTHOR.FIRST_NAME = 'John'
  AND AUTHOR.LAST_NAME = 'Doe'
)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, H2, HSQLDB, MariaDB, MySQL, Postgres, Redshift, SQLite, Snowflake, Spanner, Trino, Vertica, YugabyteDB

```sql
(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) = ('John', 'Doe')
```

###### Databricks

```sql
STRUCT (
  coalesce(AUTHOR.FIRST_NAME),
  coalesce(AUTHOR.LAST_NAME)
) = STRUCT ('John', 'Doe')
```

###### Informix

```sql
ROW (AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) = ROW ('John', 'Doe')
```

###### Oracle

```sql
(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) = (('John', 'Doe'))
```

###### Teradata

```sql
(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) = (
  SELECT 'John', 'Doe'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="quantified-comparison-predicate"></a>
#### 3.12.9. Quantified comparison predicate

If the right-hand side of a [comparison predicate](#comparison-predicate) turns out to be a non-scalar table subquery, you can wrap that subquery in a quantifier, such as `ALL`, `ANY`, or `SOME`. Note that the SQL standard defines `ANY` and `SOME` to be equivalent. jOOQ settled for the more intuitive `ANY` and doesn't support `SOME`. Here are some examples, supported by jOOQ:

```sql
TITLE = ANY('Animal Farm', '1982')
PUBLISHED_IN > ALL(1920, 1940)
```

```java
BOOK.TITLE.eq(any("Animal Farm", "1982"));
BOOK.PUBLISHED_IN.gt(all(1920, 1940));
```

For the example, the right-hand side of the quantified comparison predicates were filled with argument lists. But it is easy to imagine that the source of values results from a [subselect](#scalar-subqueries).

##### ANY and the IN predicate

It is interesting to note that the SQL standard defines the [IN predicate](#in-predicate) in terms of the `ANY`-quantified predicate. The following two expressions are equivalent:

```text
[ROW VALUE EXPRESSION] IN [IN PREDICATE VALUE]
```

```text
[ROW VALUE EXPRESSION] = ANY [IN PREDICATE VALUE]
```

Typically, the [IN predicate](#in-predicate) is more readable than the quantified comparison predicate.

##### Dialect support

This example using jOOQ:

```java
BOOK.AUTHOR_ID.eq(any(select(AUTHOR.ID).from(AUTHOR)))
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, DB2, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MySQL, Oracle, Postgres, SQLServer, Sybase, Teradata, Vertica, YugabyteDB

```sql
BOOK.AUTHOR_ID = ANY (
  SELECT AUTHOR.ID
  FROM AUTHOR
)
```

###### Access, BigQuery, Databricks, Exasol, MemSQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="between-predicate"></a>
#### 3.12.10. BETWEEN predicate

The `BETWEEN` predicate can be seen as syntactic sugar for a pair of [comparison predicates](#comparison-predicate). According to the SQL standard, the following two predicates are equivalent:

```sql
A BETWEEN B AND C
```

```sql
A >= B AND A <= C
```

Note the inclusiveness of range boundaries in the definition of the `BETWEEN` predicate. Intuitively, this is supported in jOOQ as such:

```sql
PUBLISHED_IN     BETWEEN 1920 AND 1940
PUBLISHED_IN NOT BETWEEN 1920 AND 1940
```

```java
BOOK.PUBLISHED_IN.between(1920).and(1940)
BOOK.PUBLISHED_IN.notBetween(1920).and(1940)
```

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.between("E").and("K")
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
BOOK.TITLE BETWEEN 'E' AND 'K'
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

##### BETWEEN SYMMETRIC

The SQL standard defines the `SYMMETRIC` keyword to be used along with `BETWEEN` to indicate that you do not care which bound of the range is larger than the other. A database system should simply swap range bounds, in case the first bound is greater than the second one. jOOQ supports this keyword as well, emulating it if necessary.

```sql
PUBLISHED_IN     BETWEEN SYMMETRIC 1940 AND 1920
PUBLISHED_IN NOT BETWEEN SYMMETRIC 1940 AND 1920
```

```java
BOOK.PUBLISHED_IN.betweenSymmetric(1940).and(1920)
BOOK.PUBLISHED_IN.notBetweenSymmetric(1940).and(1920)
```

The emulation is done trivially:

```sql
A BETWEEN SYMMETRIC B AND C
```

```sql
(A BETWEEN B AND C) OR (A BETWEEN C AND B)
```

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.betweenSymmetric("K").and("E")
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, DuckDB, Firebird, H2, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
(
  BOOK.TITLE BETWEEN 'K' AND 'E'
  OR BOOK.TITLE BETWEEN 'E' AND 'K'
)
```

###### Aurora Postgres, CockroachDB, Exasol, HSQLDB, Postgres, YugabyteDB

```sql
BOOK.TITLE BETWEEN SYMMETRIC 'K' AND 'E'
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="between-predicate-degree-n"></a>
#### 3.12.11. BETWEEN predicate (degree > 1)

The SQL `BETWEEN` predicate also works well for [row value expressions](#row-value-expressions). Much like the [BETWEEN predicate for degree 1](#between-predicate), it is defined in terms of a pair of regular [comparison predicates](#comparison-predicate):

```sql
A BETWEEN           B AND C
A BETWEEN SYMMETRIC B AND C
```

```sql
 A >= B AND A <= C
(A >= B AND A <= C) OR (A >= C AND A <= B)
```

The above can be factored out according to the rules listed in the manual's section about [row value expression comparison predicates](#comparison-predicate-degree-n).

jOOQ supports the `BETWEEN [SYMMETRIC]` predicate and emulates it in all SQL dialects where necessary. An example is given here:

```java
row(BOOK.ID, BOOK.TITLE).between(1, "A").and(10, "Z");
```

##### Dialect support

This example using jOOQ:

```java
row(BOOK.ID, BOOK.TITLE).between(1, "A").and(10, "Z")
```

Translates to the following dialect specific expressions:

###### ASE, Access, DuckDB, Exasol, Firebird, Hana, Informix, MemSQL, Oracle, SQLDataWarehouse, SQLServer, Spanner, Sybase

```sql
(
  (
    BOOK.ID >= 1
    AND (
      BOOK.ID > 1
      OR (
        BOOK.ID = 1
        AND BOOK.TITLE >= 'A'
      )
    )
  )
  AND (
    BOOK.ID <= 10
    AND (
      BOOK.ID < 10
      OR (
        BOOK.ID = 10
        AND BOOK.TITLE <= 'Z'
      )
    )
  )
)
```

###### Aurora MySQL, MariaDB, MySQL

```sql
(
  (BOOK.ID, BOOK.TITLE) >= (1, 'A')
  AND (BOOK.ID, BOOK.TITLE) <= (10, 'Z')
)
```

###### Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, H2, HSQLDB, Postgres, Redshift, SQLite, Snowflake, Trino, Vertica, YugabyteDB

```sql
(BOOK.ID, BOOK.TITLE) BETWEEN (1, 'A') AND (10, 'Z')
```

###### Databricks

```sql
STRUCT (
  coalesce(BOOK.ID),
  coalesce(BOOK.TITLE)
) BETWEEN STRUCT (1, 'A') AND STRUCT (10, 'Z')
```

###### Teradata

```sql
(
  (BOOK.ID, BOOK.TITLE) >= (
    SELECT 1, 'A'
    FROM (
      SELECT 1 AS "dual"
    ) AS "dual"
  )
  AND (BOOK.ID, BOOK.TITLE) <= (
    SELECT 10, 'Z'
    FROM (
      SELECT 1 AS "dual"
    ) AS "dual"
  )
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="distinct-predicate"></a>
#### 3.12.12. DISTINCT predicate

Some databases support the `DISTINCT` predicate, which serves as a convenient, `NULL`-safe [comparison predicate](#comparison-predicate). With the `DISTINCT` predicate, the following truth table can be assumed:

- `[ANY] IS DISTINCT FROM NULL` yields `TRUE`
- `[ANY] IS NOT DISTINCT FROM NULL` yields `FALSE`
- `NULL IS DISTINCT FROM NULL` yields `FALSE`
- `NULL IS NOT DISTINCT FROM NULL` yields `TRUE`

For instance, you can compare two fields for distinctness, ignoring the fact that any of the two could be `NULL`, which would lead to funny results. This is supported by jOOQ as such:

```sql
TITLE IS DISTINCT FROM SUB_TITLE
TITLE IS NOT DISTINCT FROM SUB_TITLE
```

```java
BOOK.TITLE.isDistinctFrom(BOOK.SUB_TITLE)
BOOK.TITLE.isNotDistinctFrom(BOOK.SUB_TITLE)
```

##### Dialect support

This example using jOOQ:

```java
AUTHOR.FIRST_NAME.isDistinctFrom(AUTHOR.LAST_NAME)
```

Translates to the following dialect specific expressions:

###### ASE, Exasol, SQLDataWarehouse, Vertica

```sql
NOT EXISTS (
  SELECT AUTHOR.FIRST_NAME x
  INTERSECT
  SELECT AUTHOR.LAST_NAME x
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
(NOT(AUTHOR.FIRST_NAME <=> AUTHOR.LAST_NAME))
```

###### Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Firebird, H2, HSQLDB, Postgres, Redshift, SQLServer, Snowflake, Trino, YugabyteDB

```sql
AUTHOR.FIRST_NAME IS DISTINCT FROM AUTHOR.LAST_NAME
```

###### ClickHouse

```sql
arrayUniq(ARRAY(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)) = 2
```

###### Hana, Sybase

```sql
NOT EXISTS (
  SELECT AUTHOR.FIRST_NAME x
  FROM SYS.DUMMY
  INTERSECT
  SELECT AUTHOR.LAST_NAME x
  FROM SYS.DUMMY
)
```

###### Informix

```sql
NOT EXISTS (
  SELECT AUTHOR.FIRST_NAME x
  FROM (
    SELECT 1 AS dual
    FROM systables
    WHERE (tabid = 1)
  ) AS dual
  INTERSECT
  SELECT AUTHOR.LAST_NAME x
  FROM (
    SELECT 1 AS dual
    FROM systables
    WHERE (tabid = 1)
  ) AS dual
)
```

###### Oracle

```sql
decode(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, 1, 0) = 0
```

###### Spanner

```sql
NOT EXISTS (
  SELECT AUTHOR.FIRST_NAME x
  INTERSECT DISTINCT
  SELECT AUTHOR.LAST_NAME x
)
```

###### SQLite

```sql
(AUTHOR.FIRST_NAME IS NOT AUTHOR.LAST_NAME)
```

###### Teradata

```sql
NOT EXISTS (
  SELECT AUTHOR.FIRST_NAME x
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
  INTERSECT
  SELECT AUTHOR.LAST_NAME x
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
)
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="distinct-predicate-degree-n"></a>
#### 3.12.13. DISTINCT predicate (degree > 1)

The [DISTINCT predicate](#distinct-predicate) is also supported for [row value expressions](#row-value-expressions) of degree higher than 1. If your database does not support row value expression comparison predicates, jOOQ emulates them the way they are defined in the SQL standard:

```sql
(FIRST_NAME, LAST_NAME) IS DISTINCT FROM ('John', 'Doe')
(FIRST_NAME, LAST_NAME) IS NOT DISTINCT FROM ('John', 'Doe')
```

```java
row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).isNotDistinctFrom("John", "Doe")
row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).isNotDistinctFrom("John", "Doe")
```

##### Dialect support

This example using jOOQ:

```java
row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).isNotDistinctFrom("John", "Doe")
```

Translates to the following dialect specific expressions:

###### ASE, Exasol, Oracle, SQLDataWarehouse, SQLServer, Vertica

```sql
EXISTS (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  INTERSECT
  SELECT 'John', 'Doe'
)
```

###### Aurora MySQL, MariaDB, MySQL

```sql
(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) <=> ('John', 'Doe')
```

###### Aurora Postgres, BigQuery, CockroachDB, DuckDB, H2, HSQLDB, Postgres, Snowflake, Trino, YugabyteDB

```sql
(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) is not distinct from ('John', 'Doe')
```

###### ClickHouse

```sql
arrayUniq(ARRAY(
  TUPLE (AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME),
  TUPLE ('John', 'Doe')
)) = 1
```

###### Databricks

```sql
STRUCT (
  coalesce(AUTHOR.FIRST_NAME),
  coalesce(AUTHOR.LAST_NAME)
) is not distinct from STRUCT ('John', 'Doe')
```

###### DB2

```sql
EXISTS (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  FROM SYSIBM.DUAL
  INTERSECT
  SELECT 'John', 'Doe'
  FROM SYSIBM.DUAL
)
```

###### Firebird

```sql
NOT EXISTS (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  FROM RDB$DATABASE
  UNION
  SELECT 'John', 'Doe'
  FROM RDB$DATABASE
  OFFSET 1 ROWS
)
```

###### Hana, Sybase

```sql
EXISTS (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  FROM SYS.DUMMY
  INTERSECT
  SELECT 'John', 'Doe'
  FROM SYS.DUMMY
)
```

###### Informix

```sql
EXISTS (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  FROM (
    SELECT 1 AS dual
    FROM systables
    WHERE (tabid = 1)
  ) AS dual
  INTERSECT
  SELECT 'John', 'Doe'
  FROM (
    SELECT 1 AS dual
    FROM systables
    WHERE (tabid = 1)
  ) AS dual
)
```

###### MemSQL

```sql
EXISTS (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  FROM DUAL
  INTERSECT
  SELECT 'John', 'Doe'
  FROM DUAL
)
```

###### Redshift

```sql
NOT ((AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) is distinct from ('John', 'Doe'))
```

###### Spanner

```sql
EXISTS (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  INTERSECT DISTINCT
  SELECT 'John', 'Doe'
)
```

###### SQLite

```sql
(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) IS ('John', 'Doe')
```

###### Teradata

```sql
EXISTS (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
  INTERSECT
  SELECT 'John', 'Doe'
  FROM (
    SELECT 1 AS "dual"
  ) AS "dual"
)
```

###### Access

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="document-predicate"></a>
#### 3.12.14. DOCUMENT predicate

The `DOCUMENT` predicate can be used to check if a given expression is an XML document (as opposed to toher XML content).

```sql
SELECT 1
WHERE
  '<xml/>' IS DOCUMENT
  AND '<!-- comment -->' IS NOT DOCUMENT
```

```java
create.selectOne()
      .where(val("<xml/>").isDocument())
      .and(val("<!-- comment -->").isNotDocument())
      .fetch();
```

##### Dialect support

This example using jOOQ:

```java
AUTHOR.FIRST_NAME.isDocument()
```

Translates to the following dialect specific expressions:

###### Postgres

```sql
AUTHOR.FIRST_NAME IS DOCUMENT
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="exists-predicate"></a>
#### 3.12.15. EXISTS predicate

Slightly less intuitive, yet more powerful than the [IN predicate](#in-predicate) is the `EXISTS` predicate, that can be used to form semi-joins or anti-joins. With jOOQ, the `EXISTS` predicate can be formed in various ways:

- From the [DSL](#dsl), using static methods. This is probably the most used case
- From a [conditional expression](#conditional-expressions) using [convenience methods attached to boolean operators](#boolean-operators)
- From a [SELECT statement](#select-statement) using [convenience methods attached to the where clause](#where-clause), and from other clauses

An example of an `EXISTS` predicate can be seen here:

```sql
    EXISTS (SELECT 1 FROM BOOK
            WHERE AUTHOR_ID = 3)

NOT EXISTS (SELECT 1 FROM BOOK
            WHERE AUTHOR_ID = 3)
```

```java
   exists(create.selectOne().from(BOOK)
                .where(BOOK.AUTHOR_ID.eq(3)));

notExists(create.selectOne().from(BOOK)
                .where(BOOK.AUTHOR_ID.eq(3)));
```

Note that in SQL, the projection of a subselect in an `EXISTS` predicate is irrelevant. To help you write queries like the above, you can use jOOQ's selectZero() or selectOne() [DSL](#dsl) methods

##### Performance of IN vs. EXISTS

In theory, the two types of predicates can perform equally well. If your database system ships with a sophisticated cost-based optimiser, it will be able to transform one predicate into the other, if you have all necessary constraints set (e.g. referential constraints, not null constraints). However, in reality, performance between the two might differ substantially. An interesting blog post investigating this topic on the MySQL database can be seen here:  
[https://blog.jooq.org/not-in-vs-not-exists-vs-left-join-is-null-mysql/](https://blog.jooq.org/not-in-vs-not-exists-vs-left-join-is-null-mysql/)

##### Dialect support

This example using jOOQ:

```java
exists(select(asterisk()).from(BOOK))
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
EXISTS (
  SELECT *
  FROM BOOK
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="in-predicate"></a>
#### 3.12.16. IN predicate

In SQL, apart from comparing a value against several values, the `IN` predicate can be used to create semi-joins or anti-joins. jOOQ knows the following methods on the [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) interface, to construct such `IN` predicates:

```java
in(Collection<?>)                   // Construct an IN predicate from a collection of bind values
in(T...)                            // Construct an IN predicate from bind values
in(Field<?>...)                     // Construct an IN predicate from column expressions
in(Select<? extends Record1<T>>)    // Construct an IN predicate from a subselect
notIn(Collection<?>)                // Construct a NOT IN predicate from a collection of bind values
notIn(T...)                         // Construct a NOT IN predicate from bind values
notIn(Field<?>...)                  // Construct a NOT IN predicate from column expressions
notIn(Select<? extends Record1<T>>) // Construct a NOT IN predicate from a subselect
```

A sample `IN` predicate might look like this:

```sql
TITLE     IN ('Animal Farm', '1984')
TITLE NOT IN ('Animal Farm', '1984')
```

```java
BOOK.TITLE.in("Animal Farm", "1984")
BOOK.TITLE.notIn("Animal Farm", "1984")
```

##### NOT IN and NULL values

Beware that you should probably not have any `NULL` values in the right hand side of a `NOT IN` predicate, as the whole expression would evaluate to `NULL`, which is rarely desired. This can be shown informally using the following reasoning:

```sql
-- The following conditional expressions are formally or informally equivalent
A NOT IN (B, C)
A != ANY(B, C)
A != B AND A != C

-- Substitute C for NULL, you'll get
A NOT IN (B, NULL)   -- Substitute C for NULL
A != B AND A != NULL -- From the above rules
A != B AND NULL      -- [ANY] != NULL yields NULL
NULL                 -- [ANY] AND NULL yields NULL
```

A good way to prevent this from happening is to use the [EXISTS predicate](#exists-predicate) for anti-joins, which is `NULL`-value insensitive. See the manual's section about [conditional expressions](#conditional-expressions) to see a boolean truth table.

##### Dialect support

This example using jOOQ:

```java
val("TITLE").in(select(BOOK.TITLE).from(BOOK))
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
'TITLE' IN (
  SELECT BOOK.TITLE
  FROM BOOK
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="in-predicate-degree-n"></a>
#### 3.12.17. IN predicate (degree > 1)

The SQL `IN` predicate also works well for [row value expressions](#row-value-expressions). Much like the [IN predicate for degree 1](#in-predicate), it is defined in terms of a [quantified comparison predicate](#quantified-comparison-predicate). The two expressions are equivalent:

```sql
R IN [IN predicate value]
```

```sql
R = ANY [IN predicate value]
```

jOOQ supports the `IN` predicate with row value expressions. An example is given here:

```sql
-- Using an IN list
(BOOK.ID, BOOK.TITLE) IN ((1, 'A'), (2, 'B'))

-- Using a subselect
(BOOK.ID, BOOK.TITLE) IN (
  SELECT T.ID, T.TITLE
  FROM T
)
```

```java
// Using an IN list
row(BOOK.ID, BOOK.TITLE).in(row(1, "A"), row(2, "B"));

// Using a subselect
row(BOOK.ID, BOOK.TITLE).in(
  select(T.ID, T.TITLE)
  .from(T)
);
```

In both cases, i.e. when using an `IN` list or when using a subselect, the type of the predicate is checked. Both sides of the predicate must be of equal degree and row type.

Emulation of the `IN` predicate where row value expressions aren't well supported is currently only available for `IN` predicates that do not take a subselect as an `IN` predicate value.

##### Dialect support

This example using jOOQ:

```java
row("FIRST", "LAST").in(select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).from(AUTHOR))
```

Translates to the following dialect specific expressions:

###### ASE, Access, DuckDB, Exasol, Firebird, Hana, Informix, MemSQL, SQLDataWarehouse, SQLServer, Sybase

```sql
EXISTS (
  SELECT alias_1.v0, alias_1.v1
  FROM (
    SELECT
      AUTHOR.FIRST_NAME v0,
      AUTHOR.LAST_NAME v1
    FROM AUTHOR
  ) alias_1
  WHERE (
    'FIRST' = alias_1.v0
    AND 'LAST' = alias_1.v1
  )
)
```

###### Aurora MySQL, Aurora Postgres, ClickHouse, CockroachDB, H2, HSQLDB, MariaDB, MySQL, Postgres, Redshift, SQLite, Teradata, Trino, YugabyteDB

```sql
('FIRST', 'LAST') IN (
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  FROM AUTHOR
)
```

###### BigQuery, DB2, Snowflake, Spanner, Vertica

```sql
EXISTS (
  SELECT alias_1.v0, alias_1.v1
  FROM (
    SELECT
      AUTHOR.FIRST_NAME v0,
      AUTHOR.LAST_NAME v1
    FROM AUTHOR
  ) alias_1
  WHERE ('FIRST', 'LAST') = (alias_1.v0, alias_1.v1)
)
```

###### Databricks

```sql
EXISTS (
  SELECT alias_1.v0, alias_1.v1
  FROM (
    SELECT
      AUTHOR.FIRST_NAME v0,
      AUTHOR.LAST_NAME v1
    FROM AUTHOR
  ) alias_1
  WHERE STRUCT ('FIRST', 'LAST') = STRUCT (
    coalesce(alias_1.v0),
    coalesce(alias_1.v1)
  )
)
```

###### Oracle

```sql
('FIRST', 'LAST') IN ((
  SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
  FROM AUTHOR
))
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-predicate"></a>
#### 3.12.18. JSON predicate

The `JSON` predicate can be used to check if a given expression is valid JSON

```sql
SELECT 1
FROM dual
WHERE '{}' IS JSON
AND '{' IS NOT JSON
```

```java
create.selectOne()
      .where(val("{}").isJson())
      .and(val("{").isNotJson())
      .fetch();
```

##### Dialect support

This example using jOOQ:

```java
val("{}").isJson()
```

Translates to the following dialect specific expressions:

###### DuckDB, MariaDB, MySQL

```sql
json_valid('{}')
```

###### Oracle

```sql
'{}' IS JSON
```

###### Snowflake

```sql
(check_json('{}') IS NULL)
```

###### SQLDataWarehouse, SQLServer

```sql
(isjson(
  '{}',
  value
) = 1)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Postgres, Redshift, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="json-exists-predicate"></a>
#### 3.12.19. JSON_EXISTS predicate

The `JSON_EXISTS` predicate can be used to check whether a JSON path expression produces a value within a JSON document (see also the [JSON_VALUE function](#json-value-function))

```sql
SELECT 1
FROM dual
WHERE json_exists('{"a":1}', '$.a')
```

```java
create.selectOne()
      .where(jsonExists(val(json("{\"a\":1}")), "$.a"))
      .fetch();
```

##### Dialect support

This example using jOOQ:

```java
jsonExists(val(json("{\"a\":1}")), "$.a")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB

```sql
JSON_EXISTS(cast('{"a":1}' AS json), '$.a')
```

###### BigQuery

```sql
json_query('{"a":1}', '$.a') IS NOT NULL
```

###### ClickHouse, DB2, Oracle

```sql
JSON_EXISTS('{"a":1}', '$.a')
```

###### DuckDB

```sql
(JSON '{"a":1}'->'$.a') IS NOT NULL
```

###### MariaDB

```sql
JSON_EXISTS(json_extract('{"a":1}', '$'), '$.a')
```

###### MySQL

```sql
json_contains_path(cast('{"a":1}' AS json), 'one', '$.a')
```

###### Postgres, YugabyteDB

```sql
jsonb_path_exists(cast('{"a":1}' AS jsonb), cast('$.a' AS jsonpath))
```

###### Spanner

```sql
json_query(JSON '{"a":1}', '$.a') IS NOT NULL
```

###### SQLite

```sql
json_type(JSON('{"a":1}'), '$.a') IS NOT NULL
```

###### SQLServer

```sql
json_path_exists('{"a":1}', '$.a') = 1
```

###### ASE, Access, Aurora MySQL, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, Redshift, SQLDataWarehouse, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="like-predicate"></a>
#### 3.12.20. LIKE predicate

`LIKE` predicates are popular for simple wildcard-enabled pattern matching.

Supported wildcards in all SQL databases are:

- **_**: (single-character wildcard)
- **%**: (multi-character wildcard)

With jOOQ, the `LIKE` predicate can be created from any [column expression](#column-expressions) as such:

```sql
TITLE     LIKE '%abc%'
TITLE NOT LIKE '%abc%'
```

```java
BOOK.TITLE.like("%abc%")
BOOK.TITLE.notLike("%abc%")
```

##### Concatenating wildcards

A common practice is to conatenate wildcards to the actual expression. While concatenation is dangerous in [plain SQL](#plain-sql), it is safe when creating dynamic bind values using the DSL API:

```sql
-- Generated SQL is using a bind variable
TITLE     LIKE '%abc%'
TITLE NOT LIKE '%abc%'
```

```java
// abc might be user input
BOOK.TITLE.like("%" + abc "%")
BOOK.TITLE.notLike("%" + abc + "%")
```

##### Escaping operands with the LIKE predicate

Often, your pattern may contain any of the wildcard characters `"_"` and `"%"`, in case of which you may want to escape them. jOOQ does not automatically escape patterns in `like()` and `notLike()` methods. Instead, you can explicitly define an escape character as such:

```sql
TITLE     LIKE '%The !%-Sign Book%' ESCAPE '!'
TITLE NOT LIKE '%The !%-Sign Book%' ESCAPE '!'
```

```java
BOOK.TITLE.like("%The !%-Sign Book%", '!')
BOOK.TITLE.notLike("%The !%-Sign Book%", '!')
```

In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters `"!_"` and `"!%"`, as well as to escape the escape character itself: `"!!"`

Please refer to your database manual for more details about escaping patterns with the `LIKE` predicate.

> [!TIP]
> See [LIKE predicate (binary)](#binary-like-predicate) for a binary version of this predicate.

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.like("%abc%")
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
BOOK.TITLE LIKE '%abc%'
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="like-ignore-case-predicate"></a>
#### 3.12.21. LIKE IGNORE CASE predicate

The `LIKE IGNORE CASE` predicate is a special case of the [LIKE predicate](#like-predicate), where the operand case is ignored.

```sql
-- case insensitivity
TITLE ILIKE '%abc%'
TITLE NOT ILIKE '%abc%'
```

```java
// case insensitivity
BOOK.TITLE.likeIgnoreCase("%abc%")
BOOK.TITLE.notLikeIgnoreCase("%abc%")
```

While some dialects have native support for this operator via `ILIKE` or similar, most dialects can emulate the behaviour using the [LOWER function](#lower-function).

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.likeIgnoreCase("%abc%")
```

Translates to the following dialect specific expressions:

###### Access

```sql
lcase(BOOK.TITLE) LIKE lcase('%abc%')
```

###### ASE, Aurora MySQL, BigQuery, DB2, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
lower(BOOK.TITLE) LIKE lower('%abc%')
```

###### Aurora Postgres, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, H2, Postgres, Redshift, Snowflake, YugabyteDB

```sql
BOOK.TITLE ILIKE '%abc%'
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="binary-like-predicate"></a>
#### 3.12.22. LIKE predicate (binary)

Binary `LIKE` predicates are the binary version of the [LIKE predicate](#like-predicate).

With jOOQ, the binary `LIKE` predicate can be created from any [column expression](#column-expressions) as such:

```sql
TITLE     LIKE CAST('%abc%' AS VARBINARY)
TITLE NOT LIKE '%abc%'
```

```java
BOOK.TITLE.binaryLike("%abc%".getBytes())
BOOK.TITLE.notBinaryLike("%abc%".getBytes())
```

> [!TIP]
> See [LIKE predicate](#like-predicate) for a text version of this predicate.

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.binaryLike("%abc%".getBytes())
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
cast(BOOK.TITLE AS bytea) LIKE cast(E'\\045\\141\\142\\143\\045' AS bytea)
```

###### BigQuery, Spanner

```sql
cast(BOOK.TITLE AS bytes) LIKE b'\x25\x61\x62\x63\x25'
```

###### Databricks

```sql
cast(BOOK.TITLE AS binary) LIKE X'2561626325'
```

###### ASE, Access, Aurora MySQL, ClickHouse, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="like-regex-predicate"></a>
#### 3.12.23. LIKE REGEX predicate

Regular expression `LIKE` predicates work like the [LIKE predicate](#like-predicate), but they match against a regular expression, not just simple `LIKE` patterns.

```sql
     TITLE LIKE_REGEX '.*abc.*'
NOT (TITLE LIKE_REGEX '.*abc.*')
```

```java
BOOK.TITLE.likeRegex(".*abc.*")
BOOK.TITLE.notLikeRegex(".*abc.*")
```

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.likeRegex(".*abc.*")
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Databricks, H2, MariaDB, MemSQL, MySQL, Sybase

```sql
BOOK.TITLE REGEXP '.*abc.*'
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, YugabyteDB

```sql
(BOOK.TITLE ~ '.*abc.*')
```

###### HSQLDB

```sql
REGEXP_MATCHES(BOOK.TITLE, '.*abc.*')
```

###### Oracle, SQLServer, Snowflake, Vertica

```sql
REGEXP_LIKE(BOOK.TITLE, '.*abc.*')
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Exasol, Firebird, Hana, Informix, Redshift, SQLDataWarehouse, SQLite, Spanner, Teradata, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="quantified-like-predicate"></a>
#### 3.12.24. Quantified LIKE predicate

jOOQ also provides the synthetic `[NOT] LIKE ANY` and `[NOT] LIKE ALL` operators, which can be used to (positively resp. negatively) match a string against multiple patterns without having to manually string together multiple `[NOT] LIKE` predicates with `AND` or `OR` (learn about [other synthetic sql syntaxes](#synthetic-sql-clauses)). The following examples show how these synthetic predicates translate to SQL:

```sql
(TITLE     LIKE '%abc%'  OR TITLE     LIKE '%def%')
(TITLE NOT LIKE '%abc%'  OR TITLE NOT LIKE '%def%')
(TITLE     LIKE '%abc%' AND TITLE     LIKE '%def%')
(TITLE NOT LIKE '%abc%' AND TITLE NOT LIKE '%def%')
```

```java
BOOK.TITLE.like(any("%abc%", "%def%"))
BOOK.TITLE.notLike(any("%abc%", "%def%"))
BOOK.TITLE.like(all("%abc%", "%def%"))
BOOK.TITLE.notLike(all("%abc%", "%def%"))
```

All corresponding Java methods [`Field.like(QuantifiedSelect)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#like(org.jooq.QuantifiedSelect)) and [`Field.notLike(QuantifiedSelect)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#notLike(org.jooq.QuantifiedSelect)) return an instance of [`LikeEscapeStep`](https://www.jooq.org/javadoc/3.22.x/org/jooq/LikeEscapeStep.html), which can be used to specify an `ESCAPE` clause that will be applied to all patterns in the list. For brevity the examples above don't show this.

Note that both the `LIKE ANY` and `LIKE ALL` predicates allow matching a string against an empty list of patterns. For example, in the case of `LIKE ANY` this is equivalent to a `1 = 0` predicate and in the case of `NOT LIKE ALL` this behaves like `1 = 1`.

> [!TIP]
> See [quantified LIKE predicate (binary)](#quantified-binary-like-predicate) for a binary version of this predicate.

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.like(any(select(concat(val("%"), LANGUAGE.CD, val("%"))).from(LANGUAGE)))
```

Translates to the following dialect specific expressions:

###### ASE, DB2, Sybase, Teradata

```sql
1 = ANY (
  SELECT CASE
    WHEN BOOK.TITLE LIKE pattern THEN 1
    WHEN NOT (BOOK.TITLE LIKE pattern) THEN 0
  END
  FROM (
    SELECT ('%' || LANGUAGE.CD || '%') pattern
    FROM LANGUAGE
  ) t
)
```

###### Aurora MySQL, MariaDB, MySQL

```sql
TRUE = ANY (
  SELECT (BOOK.TITLE LIKE pattern)
  FROM (
    SELECT concat('%', LANGUAGE.CD, '%') pattern
    FROM LANGUAGE
  ) t
)
```

###### Aurora Postgres, ClickHouse, CockroachDB, Postgres, Snowflake, YugabyteDB

```sql
BOOK.TITLE LIKE ANY (
  SELECT ('%' || LANGUAGE.CD || '%')
  FROM LANGUAGE
)
```

###### DuckDB, Firebird, H2, HSQLDB, Oracle, Vertica

```sql
TRUE = ANY (
  SELECT (BOOK.TITLE LIKE pattern)
  FROM (
    SELECT ('%' || LANGUAGE.CD || '%') pattern
    FROM LANGUAGE
  ) t
)
```

###### Hana

```sql
TRUE = ANY (
  SELECT CASE
    WHEN BOOK.TITLE LIKE pattern THEN TRUE
    WHEN NOT (BOOK.TITLE LIKE pattern) THEN FALSE
  END
  FROM (
    SELECT ('%' || LANGUAGE.CD || '%') pattern
    FROM LANGUAGE
  ) t
)
```

###### Informix

```sql
cast('t' AS boolean) = ANY (
  SELECT CASE
    WHEN BOOK.TITLE LIKE pattern THEN cast('t' AS boolean)
    WHEN NOT (BOOK.TITLE LIKE pattern) THEN cast('f' AS boolean)
  END
  FROM (
    SELECT ('%' || LANGUAGE.CD || '%') pattern
    FROM LANGUAGE
  ) t
)
```

###### SQLServer

```sql
1 = ANY (
  SELECT CASE
    WHEN BOOK.TITLE LIKE pattern THEN 1
    WHEN NOT (BOOK.TITLE LIKE pattern) THEN 0
  END
  FROM (
    SELECT ('%' + LANGUAGE.CD + '%') pattern
    FROM LANGUAGE
  ) t
)
```

###### Access, BigQuery, Databricks, Exasol, MemSQL, Redshift, SQLDataWarehouse, SQLite, Spanner, Trino

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="quantified-binary-like-predicate"></a>
#### 3.12.25. Quantified LIKE predicate (binary)

The binary synthetic `[NOT] LIKE ANY` and `[NOT] LIKE ALL` operators can be used to (positively resp. negatively) match a binary string against multiple patterns without having to manually string together multiple `[NOT] LIKE` predicates with `AND` or `OR` (learn about [other synthetic sql syntaxes](#synthetic-sql-clauses)). The following examples show how these synthetic predicates translate to SQL:

```sql
(TITLE     LIKE CAST('%abc%' AS VARBINARY) OR
 TITLE     LIKE '%def%' AS VARBINARY))
(TITLE NOT LIKE CAST('%abc%' AS VARBINARY) OR
 TITLE NOT LIKE CAST('%def%' AS VARBINARY))
(TITLE     LIKE CAST('%abc%' AS VARBINARY) AND
 TITLE     LIKE CAST('%def%' AS VARBINARY))
(TITLE NOT LIKE CAST('%abc%' AS VARBINARY) AND
 TITLE NOT LIKE CAST('%def%' AS VARBINARY))
```

```java
BOOK.TITLE.binaryLike(
  any("%abc%".getBytes(), "%def%".getBytes()))
BOOK.TITLE.notBinaryLike(
  any("%abc%".getBytes(), "%def%".getBytes()))
BOOK.TITLE.binaryLike(
  all("%abc%".getBytes(), "%def%".getBytes()))
BOOK.TITLE.notBinaryLike(
  all("%abc%".getBytes(), "%def%".getBytes()))
```

Note that both the `LIKE ANY` and `LIKE ALL` predicates allow matching a binary string against an empty list of patterns. For example, in the case of `LIKE ANY` this is equivalent to a `1 = 0` predicate and in the case of `NOT LIKE ALL` this behaves like `1 = 1`.

> [!TIP]
> See [quantified LIKE predicate](#binary-like-predicate) for a text version of this predicate.

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.binaryLike(any(select(binaryConcat(binaryConcat(val("%".getBytes()), LANGUAGE.CD.cast(VARBINARY)), val("%".getBytes()))).from(LANGUAGE)))
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, Postgres, YugabyteDB

```sql
BOOK.TITLE LIKE ANY (
  SELECT ((cast(E'\\045' AS bytea) || cast(LANGUAGE.CD AS bytea)) || cast(E'\\045' AS bytea))
  FROM LANGUAGE
)
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="starts-with-predicate"></a>
#### 3.12.26. STARTS_WITH predicate

`STARTS_WITH` predicates allow for finding strings by a common, fixed prefix.

Unlike the [LIKE predicate](#like-predicate) (which can be used to emulate this), no wildcards are supported and the prefix must be matched exactly.

With jOOQ, the `STARTS_WITH` predicate can be created from any [column expression](#column-expressions) as such:

```sql
STARTS_WITH(TITLE, 'abc')
```

```java
BOOK.TITLE.startsWith("abc")
```

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.startsWith("abc")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
BOOK.TITLE LIKE (str_replace(
  str_replace(
    str_replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') ESCAPE '!'
```

###### Aurora MySQL, MariaDB, MySQL

```sql
BOOK.TITLE LIKE concat(
  replace(
    replace(
      replace('abc', '!', '!!'),
      '%',
      '!%'
    ),
    '_',
    '!_'
  ),
  '%'
) ESCAPE '!'
```

###### Aurora Postgres, CockroachDB, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, SQLite, Sybase, Vertica

```sql
BOOK.TITLE LIKE (replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') ESCAPE '!'
```

###### BigQuery

```sql
strpos(BOOK.TITLE, 'abc') = 1
```

###### ClickHouse

```sql
startsWith(BOOK.TITLE, 'abc')
```

###### Databricks

```sql
startswith(BOOK.TITLE, 'abc')
```

###### DB2

```sql
BOOK.TITLE LIKE cast((replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') AS VARCHAR(4000)) ESCAPE '!'
```

###### DuckDB, Spanner, Trino

```sql
starts_with(BOOK.TITLE, 'abc')
```

###### SQLDataWarehouse

```sql
charindex('abc', BOOK.TITLE) = 1
```

###### SQLServer

```sql
BOOK.TITLE LIKE (replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
) + '%') ESCAPE '!'
```

###### Access, Exasol, MemSQL, Redshift, Snowflake, Teradata, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="starts-with-ignore-case-predicate"></a>
#### 3.12.27. STARTS_WITH IGNORE CASE predicate

The `STARTS_WITH IGNORE CASE` predicate is a special case of the [STARTS_WITH predicate](#starts-with-predicate), where the operand case is ignored.

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.startsWithIgnoreCase("abc")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
lower(BOOK.TITLE) LIKE (str_replace(
  str_replace(
    str_replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') ESCAPE '!'
```

###### Aurora MySQL, MariaDB, MySQL

```sql
lower(BOOK.TITLE) LIKE concat(
  replace(
    replace(
      replace(
        lower('abc'),
        '!',
        '!!'
      ),
      '%',
      '!%'
    ),
    '_',
    '!_'
  ),
  '%'
) ESCAPE '!'
```

###### Aurora Postgres, CockroachDB, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, SQLite, Sybase, Vertica

```sql
lower(BOOK.TITLE) LIKE (replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') ESCAPE '!'
```

###### BigQuery

```sql
strpos(lower(BOOK.TITLE), lower('abc')) = 1
```

###### ClickHouse

```sql
startsWith(
  lower(BOOK.TITLE),
  lower('abc')
)
```

###### Databricks

```sql
startswith(
  lower(BOOK.TITLE),
  lower('abc')
)
```

###### DB2

```sql
lower(BOOK.TITLE) LIKE cast((replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') AS VARCHAR(4000)) ESCAPE '!'
```

###### DuckDB, Spanner, Trino

```sql
starts_with(
  lower(BOOK.TITLE),
  lower('abc')
)
```

###### SQLDataWarehouse

```sql
charindex(lower('abc'), lower(BOOK.TITLE)) = 1
```

###### SQLServer

```sql
lower(BOOK.TITLE) LIKE (replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
) + '%') ESCAPE '!'
```

###### Access, Exasol, MemSQL, Redshift, Snowflake, Teradata, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="ends-with-predicate"></a>
#### 3.12.28. ENDS_WITH predicate

`ENDS_WITH` predicates allow for finding strings by a common, fixed suffix.

Unlike the [LIKE predicate](#like-predicate) (which can be used to emulate this), no wildcards are supported and the suffix must be matched exactly.

With jOOQ, the `ENDS_WITH` predicate can be created from any [column expression](#column-expressions) as such:

```sql
ENDS_WITH(TITLE, 'abc')
```

```java
BOOK.TITLE.endsWith("abc")
```

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.endsWith("abc")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
BOOK.TITLE LIKE ('%' || str_replace(
  str_replace(
    str_replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
)) ESCAPE '!'
```

###### Aurora MySQL, MariaDB, MySQL

```sql
BOOK.TITLE LIKE concat(
  '%',
  replace(
    replace(
      replace('abc', '!', '!!'),
      '%',
      '!%'
    ),
    '_',
    '!_'
  )
) ESCAPE '!'
```

###### Aurora Postgres, CockroachDB, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, SQLite, Sybase, Vertica

```sql
BOOK.TITLE LIKE ('%' || replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
)) ESCAPE '!'
```

###### BigQuery

```sql
strpos(BOOK.TITLE, 'abc') = ((char_length(BOOK.TITLE) - char_length('abc')) + 1)
```

###### ClickHouse

```sql
endsWith(BOOK.TITLE, 'abc')
```

###### Databricks

```sql
endswith(BOOK.TITLE, 'abc')
```

###### DB2

```sql
BOOK.TITLE LIKE cast(('%' || replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
)) AS VARCHAR(4000)) ESCAPE '!'
```

###### DuckDB

```sql
suffix(BOOK.TITLE, 'abc')
```

###### Spanner

```sql
ends_with(BOOK.TITLE, 'abc')
```

###### SQLDataWarehouse

```sql
charindex('abc', BOOK.TITLE) = ((len(BOOK.TITLE) - len('abc')) + 1)
```

###### SQLServer

```sql
BOOK.TITLE LIKE ('%' + replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
)) ESCAPE '!'
```

###### Access, Exasol, MemSQL, Redshift, Snowflake, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="ends-with-ignore-case-predicate"></a>
#### 3.12.29. ENDS_WITH IGNORE CASE predicate

The `ENDS_WITH IGNORE CASE` predicate is a special case of the [ENDS_WITH predicate](#ends-with-predicate), where the operand case is ignored.

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.endsWithIgnoreCase("abc")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
lower(BOOK.TITLE) LIKE ('%' || str_replace(
  str_replace(
    str_replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
)) ESCAPE '!'
```

###### Aurora MySQL, MariaDB, MySQL

```sql
lower(BOOK.TITLE) LIKE concat(
  '%',
  replace(
    replace(
      replace(
        lower('abc'),
        '!',
        '!!'
      ),
      '%',
      '!%'
    ),
    '_',
    '!_'
  )
) ESCAPE '!'
```

###### Aurora Postgres, CockroachDB, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, SQLite, Sybase, Vertica

```sql
lower(BOOK.TITLE) LIKE ('%' || replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
)) ESCAPE '!'
```

###### BigQuery

```sql
strpos(lower(BOOK.TITLE), lower('abc')) = ((char_length(lower(BOOK.TITLE)) - char_length(lower('abc'))) + 1)
```

###### ClickHouse

```sql
endsWith(
  lower(BOOK.TITLE),
  lower('abc')
)
```

###### Databricks

```sql
endswith(
  lower(BOOK.TITLE),
  lower('abc')
)
```

###### DB2

```sql
lower(BOOK.TITLE) LIKE cast(('%' || replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
)) AS VARCHAR(4000)) ESCAPE '!'
```

###### DuckDB

```sql
suffix(
  lower(BOOK.TITLE),
  lower('abc')
)
```

###### Spanner

```sql
ends_with(
  lower(BOOK.TITLE),
  lower('abc')
)
```

###### SQLDataWarehouse

```sql
charindex(lower('abc'), lower(BOOK.TITLE)) = ((len(lower(BOOK.TITLE)) - len(lower('abc'))) + 1)
```

###### SQLServer

```sql
lower(BOOK.TITLE) LIKE ('%' + replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
)) ESCAPE '!'
```

###### Access, Exasol, MemSQL, Redshift, Snowflake, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="contains-predicate"></a>
#### 3.12.30. CONTAINS predicate

`CONTAINS` predicates allow for finding strings by a common, fixed infix.

Unlike the [LIKE predicate](#like-predicate) (which can be used to emulate this), no wildcards are supported and the infix must be matched exactly.

With jOOQ, the `CONTAINS` predicate can be created from any [column expression](#column-expressions) as such:

```sql
CONTAINS(TITLE, 'abc')
```

```java
BOOK.TITLE.contains("abc")
```

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.contains("abc")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
BOOK.TITLE LIKE ('%' || str_replace(
  str_replace(
    str_replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') ESCAPE '!'
```

###### Aurora MySQL, MariaDB, MySQL

```sql
BOOK.TITLE LIKE concat(
  '%',
  replace(
    replace(
      replace('abc', '!', '!!'),
      '%',
      '!%'
    ),
    '_',
    '!_'
  ),
  '%'
) ESCAPE '!'
```

###### Aurora Postgres, CockroachDB, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, SQLite, Sybase, Vertica

```sql
BOOK.TITLE LIKE ('%' || replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') ESCAPE '!'
```

###### BigQuery, Spanner

```sql
strpos(BOOK.TITLE, 'abc') > 0
```

###### Databricks, DuckDB

```sql
contains(BOOK.TITLE, 'abc')
```

###### DB2

```sql
BOOK.TITLE LIKE cast(('%' || replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') AS VARCHAR(4000)) ESCAPE '!'
```

###### SQLDataWarehouse

```sql
charindex('abc', BOOK.TITLE) > 0
```

###### SQLServer

```sql
BOOK.TITLE LIKE ('%' + replace(
  replace(
    replace('abc', '!', '!!'),
    '%',
    '!%'
  ),
  '_',
  '!_'
) + '%') ESCAPE '!'
```

###### Access, ClickHouse, Exasol, MemSQL, Redshift, Snowflake, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="contains-ignore-case-predicate"></a>
#### 3.12.31. CONTAINS IGNORE CASE predicate

The `CONTAINS IGNORE CASE` predicate is a special case of the [CONTAINS predicate](#contains-predicate), where the operand case is ignored.

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.containsIgnoreCase("abc")
```

Translates to the following dialect specific expressions:

###### ASE

```sql
lower(BOOK.TITLE) LIKE ('%' || str_replace(
  str_replace(
    str_replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') ESCAPE '!'
```

###### Aurora MySQL, MariaDB, MySQL

```sql
lower(BOOK.TITLE) LIKE concat(
  '%',
  replace(
    replace(
      replace(
        lower('abc'),
        '!',
        '!!'
      ),
      '%',
      '!%'
    ),
    '_',
    '!_'
  ),
  '%'
) ESCAPE '!'
```

###### Aurora Postgres, CockroachDB, Firebird, H2, HSQLDB, Hana, Informix, Oracle, Postgres, SQLite, Sybase, Vertica

```sql
lower(BOOK.TITLE) LIKE ('%' || replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') ESCAPE '!'
```

###### BigQuery, Spanner

```sql
strpos(lower(BOOK.TITLE), lower('abc')) > 0
```

###### Databricks, DuckDB

```sql
contains(
  lower(BOOK.TITLE),
  lower('abc')
)
```

###### DB2

```sql
lower(BOOK.TITLE) LIKE cast(('%' || replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
) || '%') AS VARCHAR(4000)) ESCAPE '!'
```

###### SQLDataWarehouse

```sql
charindex(lower('abc'), lower(BOOK.TITLE)) > 0
```

###### SQLServer

```sql
lower(BOOK.TITLE) LIKE ('%' + replace(
  replace(
    replace(
      lower('abc'),
      '!',
      '!!'
    ),
    '%',
    '!%'
  ),
  '_',
  '!_'
) + '%') ESCAPE '!'
```

###### Access, ClickHouse, Exasol, MemSQL, Redshift, Snowflake, Teradata, Trino, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="null-predicate"></a>
#### 3.12.32. NULL predicate

In SQL, you cannot compare `NULL` with any value using [comparison predicates](#comparison-predicate), as the result would yield `NULL` again, which is neither `TRUE` nor `FALSE` (see also the manual's section about [conditional expressions](#conditional-expressions)). In order to test a [column expression](#column-expressions) for `NULL`, use the `NULL` predicate as such:

```sql
TITLE IS NULL
TITLE IS NOT NULL
```

```java
BOOK.TITLE.isNull()
BOOK.TITLE.isNotNull()
```

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.isNull()
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
BOOK.TITLE IS NULL
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="null-predicate-degree-n"></a>
#### 3.12.33. NULL predicate (degree > 1)

The SQL `NULL` predicate also works well for [row value expressions](#row-value-expressions), although it has some subtle, counter-intuitive features when it comes to inversing predicates with the `NOT()` operator! Here are some examples:

```sql
-- Row value expressions
(A, B) IS     NULL
(A, B) IS NOT NULL

-- Inverse of the above
NOT((A, B) IS     NULL)
NOT((A, B) IS NOT NULL)
```

```sql
-- Equivalent factored-out predicates
(A IS     NULL) AND (B IS     NULL)
(A IS NOT NULL) AND (B IS NOT NULL)

-- Inverse
(A IS NOT NULL) OR  (B IS NOT NULL)
(A IS     NULL) OR  (B IS     NULL)
```

The SQL standard contains a nice truth table for the above rules:

```text
+-----------------------+-----------+---------------+---------------+-------------------+
| Expression            | R IS NULL | R IS NOT NULL | NOT R IS NULL | NOT R IS NOT NULL |
+-----------------------+-----------+---------------+---------------+-------------------+
| degree 1: null        | true      | false         | false         |  true             |
| degree 1: not null    | false     | true          | true          |  false            |
| degree > 1: all null  | true      | false         | false         |  true             |
| degree > 1: some null | false     | false         | true          |  true             |
| degree > 1: none null | false     | true          | true          |  false            |
+-----------------------+-----------+---------------+---------------+-------------------+
```

In jOOQ, you would simply use the `isNull()` and `isNotNull()` methods on row value expressions. Again, as with the [row value expression comparison predicate](#comparison-predicate-degree-n), the row value expression `NULL` predicate is emulated by jOOQ, if your database does not natively support it:

```java
row(BOOK.ID, BOOK.TITLE).isNull();
row(BOOK.ID, BOOK.TITLE).isNotNull();
```

##### Dialect support

This example using jOOQ:

```java
row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).isNull()
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
(
  AUTHOR.FIRST_NAME IS NULL
  AND AUTHOR.LAST_NAME IS NULL
)
```

###### Aurora Postgres, H2, Postgres, Redshift, YugabyteDB

```sql
(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) IS NULL
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="overlaps-predicate"></a>
#### 3.12.34. OVERLAPS predicate

When comparing dates, the SQL standard allows for using a special `OVERLAPS` predicate, which checks whether two date ranges overlap each other. The following can be said:

```sql
-- This yields true
(DATE '2010-01-01', DATE '2010-01-03') OVERLAPS (DATE '2010-01-02' DATE '2010-01-04')

-- INTERVAL data types are also supported. This is equivalent to the above
(DATE '2010-01-01', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND)) OVERLAPS
(DATE '2010-01-02', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND))
```

##### The OVERLAPS predicate in jOOQ

jOOQ supports the `OVERLAPS` predicate on [row value expressions of degree 2](#row-value-expressions). The following methods are contained in [`org.jooq.Row2`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Row2.html):

```java
Condition overlaps(T1 t1, T2 t2);
Condition overlaps(Field<T1> t1, Field<T2> t2);
Condition overlaps(Row2<T1, T2> row);
```

This allows for expressing the above predicates as such:

```java
// The date range tuples version
row(Date.valueOf('2010-01-01'), Date.valueOf('2010-01-03')).overlaps(Date.valueOf('2010-01-02'), Date.valueOf('2010-01-04'))

// The INTERVAL tuples version
row(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-01-02'), new DayToSecond(2))
```

##### jOOQ's extensions to the standard

Unlike the standard (or any database implementing the standard), jOOQ also supports the `OVERLAPS` predicate for comparing arbitrary [row vlaue expressions of degree 2](#row-value-expressions). For instance, `(1, 3) OVERLAPS (2, 4)` will yield true in jOOQ. This is emulated as such

```sql
-- This predicate
(A, B) OVERLAPS (C, D)

-- can be emulated as such
(C <= B) AND (A <= D)
```

##### Dialect support

This example using jOOQ:

```java
row(1, 3).overlaps(row(2, 4))
```

Translates to the following dialect specific expressions:

###### All dialects

```sql
(
  2 <= 3
  AND 1 <= 4
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="similar-predicate"></a>
#### 3.12.35. SIMILAR TO predicate

`SIMILAR TO` predicates are popular for more complex wildcard and regular expression enabled pattern matching.

Supported wildcards in all SQL databases are:

- **_**: (single-character wildcard)
- **%**: (multi-character wildcard)

With jOOQ, the `SIMILAR TO` predicate can be created from any [column expression](#column-expressions) as such:

```sql
TITLE     SIMILAR TO '%abc%'
TITLE NOT SIMILAR TO '%abc%'
```

```java
BOOK.TITLE.similarTo("%abc%")
BOOK.TITLE.notSimilarTo("%abc%")
```

##### Escaping operands with the SIMILAR TO predicate

Often, your pattern may contain any of the wildcard characters `"_"` and `"%"`, in case of which you may want to escape them. jOOQ does not automatically escape patterns in `similarTo()` and `notSimilarTo()` methods. Instead, you can explicitly define an escape character as such:

```sql
TITLE     SIMILAR TO '%The !%-Sign Book%' ESCAPE '!'
TITLE NOT SIMILAR TO '%The !%-Sign Book%' ESCAPE '!'
```

```java
BOOK.TITLE.similarTo("%The !%-Sign Book%", '!')
BOOK.TITLE.notSimilarTo("%The !%-Sign Book%", '!')
```

In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters `"!_"` and `"!%"`, as well as to escape the escape character itself: `"!!"`

Please refer to your database manual for more details about escaping patterns with the `SIMILAR TO` predicate as well as what regular expression syntax is supported.

##### Dialect support

This example using jOOQ:

```java
BOOK.TITLE.similarTo("%X%")
```

Translates to the following dialect specific expressions:

###### Aurora Postgres, CockroachDB, DuckDB, Exasol, Firebird, Postgres, Snowflake, YugabyteDB

```sql
BOOK.TITLE SIMILAR TO '%X%'
```

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, DB2, Databricks, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Redshift, SQLDataWarehouse, SQLServer, SQLite, Spanner, Sybase, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="spatial-predicates"></a>
#### 3.12.36. Spatial predicates

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A few databases have implemented the ISO/IEC 13249-3 SQL standard spatial extensions (or vendor specific adaptations thereof) to calculate geometric or geographic sets.

Most functionality comes in the form of [spatial functions](#spatial-functions), but some useful predicates can also be formed from geometries.

<a id="st-contains-predicate"></a>
##### 3.12.36.1. ST_Contains

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry contains another geometry.

```java
create.select(
  stContains(
    stGeomFromText("POLYGON ((-3 -1, -1 -1, -1 1, -3 1, -3 -1))"),
    stGeomFromText("POINT (-2 0)")
  ),
  stContains(
    stGeomFromText("POLYGON ((3 -1, 1 -1, 1 1, 3 1, 3 -1))"),
    stGeomFromText("POINT (4 0)")
  )
).fetch();
```

The result being, for example

```text
+-------------+-------------+
| ST_Contains | ST_Contains |
+-------------+-------------+
| true        | false       |
+-------------+-------------+
```

Or, visually:

```text
-- Geometry (WKT): geometrycollection(polygon ((-3 -1, -1 -1, -1 1, -3 1, -3 -1)), point (-2 0))
-- Background (WKT): geometrycollection(polygon ((3 -1, 1 -1, 1 1, 3 1, 3 -1)), point(4 0))
```

###### Dialect support

This example using jOOQ:

```java
stContains(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_contains(geometry1, geometry2)
```

###### Oracle

```sql
((st_contains(geometry1, geometry2) = 'TRUE'))
```

###### SQLServer

```sql
geometry1.STContains(geometry2) = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-crosses-predicate"></a>
##### 3.12.36.2. ST_Crosses

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry crosses another geometry.

```java
create.select(
  stCrosses(
    stGeomFromText("LINESTRING (-3 -1, -1 1)"),
    stGeomFromText("LINESTRING (-1 -1, -3 1)")
  ),
  stCrosses(
    stGeomFromText("LINESTRING (1 -1, 1 1)"),
    stGeomFromText("LINESTRING (3 -1, 3 1)")
  )
).fetch();
```

The result being, for example

```text
+------------+------------+
| ST_Crosses | ST_Crosses |
+------------+------------+
| true       | false      |
+------------+------------+
```

Or, visually:

```text
-- Geometry (WKT): geometrycollection(linestring (-3 -1, -1 1), linestring (-1 -1, -3 1))
-- Background (WKT): geometrycollection(linestring (1 -1, 1 1), linestring (3 -1, 3 1))
```

###### Dialect support

This example using jOOQ:

```java
stCrosses(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_crosses(geometry1, geometry2)
```

###### Oracle

```sql
((st_geometry(geometry1).st_crosses(st_geometry(geometry2)) = 1))
```

###### SQLServer

```sql
geometry1.STCrosses(geometry2) = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-disjoint-predicate"></a>
##### 3.12.36.3. ST_Disjoint

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry is disjoint from another geometry.

```java
create.select(stDisjoint(
  stGeomFromText("LINESTRING (-1 -1, -1 1)"),
  stGeomFromText("LINESTRING (1 -1, 1 1)")
)).fetch();
```

The result being, for example

```text
+-------------+
| ST_Disjoint |
+-------------+
| true        |
+-------------+
```

Or, visually:

```text
-- Geometry (WKT): geometrycollection(linestring (-1 -1, -1 1), linestring (1 -1, 1 1))
```

###### Dialect support

This example using jOOQ:

```java
stDisjoint(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Oracle, Postgres, Redshift, Snowflake

```sql
st_disjoint(geometry1, geometry2)
```

###### SQLServer

```sql
geometry1.STDisjoint(geometry2) = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-equals-predicate"></a>
##### 3.12.36.4. ST_Equals

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry is "spatially equal" to another geometry (i.e. the ordering of points is irrelevant for this equality).

```java
create.select(stEquals(
  stGeomFromText("LINESTRING (-1 -1, 1 1)"),
  stGeomFromText("LINESTRING (1 1, -1 -1)")
)).fetch();
```

The result being, for example

```text
+-----------+
| ST_Equals |
+-----------+
| true      |
+-----------+
```

Or, visually:

```text
-- Geometry (WKT): geometrycollection(linestring (-1 -1, 1 1), linestring (1 1, -1 -1))
```

###### Dialect support

This example using jOOQ:

```java
stEquals(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_equals(geometry1, geometry2)
```

###### Oracle

```sql
((st_equal(geometry1, geometry2) = 'TRUE'))
```

###### SQLServer

```sql
geometry1.STEquals(geometry2) = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-intersects-predicate"></a>
##### 3.12.36.5. ST_Intersects

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry intersects another geometry.

```java
create.select(
  stIntersects(
    stGeomFromText("LINESTRING (-3 -1, -1 1)"),
    stGeomFromText("LINESTRING (-1 -1, -3 1)")
  ),
  stIntersects(
    stGeomFromText("LINESTRING (1 -1, 1 1)"),
    stGeomFromText("LINESTRING (3 -1, 3 1)")
  )
).fetch();
```

The result being, for example

```text
+---------------+---------------+
| ST_Intersects | ST_Intersects |
+---------------+---------------+
| true          | false         |
+---------------+---------------+
```

Or, visually:

```text
-- Geometry (WKT): geometrycollection(linestring (-3 -1, -1 1), linestring (-1 -1, -3 1))
-- Background (WKT): geometrycollection(linestring (1 -1, 1 1), linestring (3 -1, 3 1))
```

###### Dialect support

This example using jOOQ:

```java
stIntersects(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_intersects(geometry1, geometry2)
```

###### Oracle

```sql
(sdo_geom.sdo_intersection(geometry1, geometry2, tol => null)).sdo_gtype IS NOT NULL
```

###### SQLServer

```sql
geometry1.STIntersects(geometry2) = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-isclosed-predicate"></a>
##### 3.12.36.6. ST_IsClosed

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a linestring has the same [start point](#st-startpoint-function) and [end point](#st-endpoint-function).

```java
create.select(
  stIsClosed(stGeomFromText("LINESTRING (-3 -1, -1 -1, -3 1, -3 -1)")),
  stIsClosed(stGeomFromText("LINESTRING (3 1, 1 1, 3 -1)"))
).fetch();
```

The result being, for example

```text
+-------------+-------------+
| ST_IsClosed | ST_IsClosed |
+-------------+-------------+
| true        | false       |
+-------------+-------------+
```

Or, visually:

```text
-- Geometry (WKT): linestring (-3 -1, -1 -1, -3 1, -3 -1)
-- Background (WKT): linestring (3 1, 1 1, 3 -1)
```

###### Dialect support

This example using jOOQ:

```java
stIsClosed(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_isclosed(geometry)
```

###### Oracle

```sql
(sdo_relate(sdo_lrs.geom_segment_start_pt(geometry), sdo_lrs.geom_segment_end_pt(geometry), 'mask=EQUAL'))
```

###### SQLServer

```sql
geometry.STIsClosed() = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-isempty-predicate"></a>
##### 3.12.36.7. ST_IsEmpty

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry is empty.

```java
create.select(stIsEmpty(stGeomFromText("POLYGON EMPTY"))).fetch();
```

The result being, for example

```text
+------------+
| ST_IsEmpty |
+------------+
| true       |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
stIsEmpty(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_isempty(geometry)
```

###### Oracle

```sql
((st_geometry(geometry).st_isempty() = 1))
```

###### SQLServer

```sql
geometry.STIsEmpty() = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-isring-predicate"></a>
##### 3.12.36.8. ST_IsRing

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry is both [closed](#st-isclosed-predicate) and [simple](#st-issimple-predicate).

```java
create.select(
  stIsRing(stGeomFromText("LINESTRING (0 0, 1 1, 2 0, 0 0)"))
  stIsRing(stGeomFromText("LINESTRING (0 0, 1 1, 2 0)")),
).fetch();
```

The result being, for example

```text
+-----------+-----------+
| ST_IsRing | ST_IsRing |
+-----------+-----------+
| true      | false     |
+-----------+-----------+
```

Or, visually:

```text
-- Geometry (WKT): linestring (-3 -1, -2 0, -1 -1, -3 -1)
-- Background (WKT): linestring (1 -1, 2 0, 3 -1)
```

###### Dialect support

This example using jOOQ:

```java
stIsRing(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, Postgres, Redshift

```sql
st_isring(geometry)
```

###### MySQL

```sql
(
  st_isclosed(geometry)
  AND st_issimple(geometry)
)
```

###### Oracle

```sql
(
  (sdo_relate(sdo_lrs.geom_segment_start_pt(geometry), sdo_lrs.geom_segment_end_pt(geometry), 'mask=EQUAL'))
  AND (st_geometry(geometry).st_issimple())
)
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-issimple-predicate"></a>
##### 3.12.36.9. ST_IsSimple

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry does not intersect or tangent itself.

```java
create.select(
  stIsSimple(stGeomFromText("POLYGON((0 0, 1 0, 2 2, 0 0))")),
  stIsSimple(stGeomFromText("POLYGON((0 0, 1 1, 2 2, 0 0))"))
).fetch();
```

The result being, for example

```text
+-------------+-------------+
| ST_IsSimple | ST_IsSimple |
+-------------+-------------+
| true        | false       |
+-------------+-------------+
```

Or, visually:

```text
-- Geometry (WKT): polygon ((-3 -1, -2 -1, -1 1, -3 -1))
-- Background (WKT): polygon ((1 -1, 2 0, 3 1, 1 -1))
```

###### Dialect support

This example using jOOQ:

```java
stIsSimple(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift

```sql
st_issimple(geometry)
```

###### Oracle

```sql
(st_geometry(geometry).st_issimple())
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-isvalid-predicate"></a>
##### 3.12.36.10. ST_IsValid

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if a geometry is well formed.

```java
create.select(stIsValid(stGeomFromText("POLYGON((0 0, 1 1, 1 1, 0 0))"))).fetch();
```

The result being, for example

```text
+------------+
| ST_IsValid |
+------------+
| false      |
+------------+
```

###### Dialect support

This example using jOOQ:

```java
stIsValid(geometry)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_isvalid(geometry)
```

###### Oracle

```sql
((geometry).st_isvalid())
```

###### SQLServer

```sql
geometry.STIsValid() = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-overlaps-predicate"></a>
##### 3.12.36.11. ST_Overlaps

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if two geometries overlap, i.e. they [intersect](#st-intersects-predicate), but no geometry completely [contains](#st-contains-predicate) the other.

```java
create.select(
  stOverlaps(
    stGeomFromText("POLYGON ((-3 -1, -1 -1, -1 1, -3 1, -3 -1))"),
    stGeomFromText("POLYGON ((-4 -2, -2 -2, -2 0, -4 0, -4 -2))")
  ),
  stOverlaps(
    stGeomFromText("POLYGON ((3 -1, 1 -1, 1 1, 3 1, 3 -1))"),
    stGeomFromText("POLYGON ((2 -1, 1 -1, 1 0, 2 0, 2 -1))")
  )
).fetch();
```

The result being, for example

```text
+-------------+-------------+
| ST_Overlaps | ST_Overlaps |
+-------------+-------------+
| true        | false       |
+-------------+-------------+
```

Or, visually:

```text
-- Geometry (WKT): geometrycollection(polygon ((-3 -1, -1 -1, -1 1, -3 1, -3 -1)), polygon((-4 -2, -2 -2, -2 0, -4 0, -4 -2)))
-- Background (WKT): geometrycollection(polygon ((3 -1, 1 -1, 1 1, 3 1, 3 -1)), polygon((2 -1, 1 -1, 1 0, 2 0, 2 -1)))
```

###### Dialect support

This example using jOOQ:

```java
stOverlaps(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_overlaps(geometry1, geometry2)
```

###### Oracle

```sql
((st_overlaps(geometry1, geometry2) = 'TRUE'))
```

###### SQLServer

```sql
geometry1.STOverlaps(geometry2) = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-touches-predicate"></a>
##### 3.12.36.12. ST_Touches

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if two geometries touch.

```java
create.select(
  stTouches(
    stGeomFromText("LINESTRING (-1 0, -1 1, -2 1, -2 2)"),
    stGeomFromText("LINESTRING (-1 1, -2 0)")
  ),
  stTouches(
    stGeomFromText("LINESTRING (1 0, 1 1, 2 1, 2 2)"),
    stGeomFromText("LINESTRING (1 2, 0 1)")
  )
).fetch();
```

The result being, for example

```text
+------------+------------+
| ST_Touches | ST_Touches |
+------------+------------+
| true       | false      |
+------------+------------+
```

Or, visually:

```text
-- Geometry (WKT): geometrycollection(linestring (-1 0, -1 1, -2 1, -2 2), linestring (-1 1, -2 0))
-- Background (WKT): geometrycollection(linestring (1 0, 1 1, 2 1, 2 2), linestring (1 2, 0 1))
```

###### Dialect support

This example using jOOQ:

```java
stTouches(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_touches(geometry1, geometry2)
```

###### Oracle

```sql
((st_touch(geometry1, geometry2) = 'TRUE'))
```

###### SQLServer

```sql
geometry1.STTouches(geometry2) = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="st-within-predicate"></a>
##### 3.12.36.13. ST_Within

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

This predicate checks if one geometry is within another. This is the inverse of [ST_Contains](#st-contains-predicate).

```java
create.select(
  stWithin(
    stGeomFromText("POINT (-2 0)"),
    stGeomFromText("POLYGON ((-3 -1, -1 -1, -1 1, -3 1, -3 -1))")
  ),
  stWithin(
    stGeomFromText("POINT (4 0)"),
    stGeomFromText("POLYGON ((3 -1, 1 -1, 1 1, 3 1, 3 -1))")
  )
).fetch();
```

The result being, for example

```text
+-----------+-----------+
| ST_Within | ST_Within |
+-----------+-----------+
| true      | false     |
+-----------+-----------+
```

Or, visually:

```text
-- Geometry (WKT): geometrycollection(polygon ((-3 -1, -1 -1, -1 1, -3 1, -3 -1)), point (-2 0))
-- Background (WKT): geometrycollection(polygon ((3 -1, 1 -1, 1 1, 3 1, 3 -1)), point(4 0))
```

###### Dialect support

This example using jOOQ:

```java
stWithin(geometry1, geometry2)
```

Translates to the following dialect specific expressions:

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, MariaDB, MySQL, Postgres, Redshift, Snowflake

```sql
st_within(geometry1, geometry2)
```

###### Oracle

```sql
((sdo_inside(geometry1, geometry2) = 'TRUE'))
```

###### SQLServer

```sql
geometry1.STWithin(geometry2) = 1
```

###### ASE, Access, BigQuery, ClickHouse, DB2, Databricks, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MemSQL, SQLDataWarehouse, SQLite, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="unique-predicate"></a>
#### 3.12.37. UNIQUE predicate

The `UNIQUE` predicate is defined by the SQL standard, yet hardly any database implements this feature. It is a standalone predicate (much like the [EXISTS predicate](#exists-predicate)) which is used to check for uniqueness of rows returned by a given subquery. An example of an `UNIQUE` predicate can be seen here:

```sql
    UNIQUE (SELECT PUBLISHED_IN FROM BOOK
            WHERE AUTHOR_ID = 3)

NOT UNIQUE (SELECT PUBLISHED_IN FROM BOOK
            WHERE AUTHOR_ID = 3)
```

```java
   unique(create.select(BOOK.PUBLISHED_IN).from(BOOK)
                .where(BOOK.AUTHOR_ID.eq(3)));

notUnique(create.select(BOOK.PUBLISHED_IN).from(BOOK)
                .where(BOOK.AUTHOR_ID.eq(3)));
```

The first example above evaluates to `TRUE` only if all books written by the given author were published in distinct years, whereas the second example will be `TRUE` if the author published at least two books within the same year.

Currently jOOQ emulates the `UNIQUE` predicate for all databases using an `EXISTS` predicate with a `GROUP BY` subquery wrapping the original subquery:

```sql
NOT EXISTS (
  SELECT 1 FROM (
    SELECT PUBLISHED_IN
    FROM BOOK
    WHERE AUTHOR_ID = 3
  ) T
  WHERE (T.PUBLISHED_IN) IS NOT NULL
  GROUP BY T.PUBLISHED_IN
  HAVING COUNT(*) > 1
)
```

##### NULL values

Be aware that (as mandated by the SQL standard) any rows returned by the subquery having `NULL` values for any of the projected columns will be ignored by the `UNIQUE` predicate. Also, for a subquery which doesn't return any rows (or all rows have at least one `NULL` value) the `UNIQUE` predicate evaluates to `TRUE`.

##### Dialect support

This example using jOOQ:

```java
unique(select(BOOK.PUBLISHED_IN).from(BOOK))
```

Translates to the following dialect specific expressions:

###### ASE, Access, Aurora MySQL, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica

```sql
NOT EXISTS (
  SELECT 1
  FROM (
    SELECT BOOK.PUBLISHED_IN
    FROM BOOK
  ) t
  WHERE t.PUBLISHED_IN IS NOT NULL
  GROUP BY t.PUBLISHED_IN
  HAVING count(*) > 1
)
```

###### Aurora Postgres, Postgres, Redshift, YugabyteDB

```sql
NOT EXISTS (
  SELECT 1
  FROM (
    SELECT BOOK.PUBLISHED_IN
    FROM BOOK
  ) t
  WHERE (t.PUBLISHED_IN) IS NOT NULL
  GROUP BY t.PUBLISHED_IN
  HAVING count(*) > 1
)
```

###### H2

```sql
UNIQUE (
  SELECT BOOK.PUBLISHED_IN
  FROM BOOK
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="xml-exists-predicate"></a>
#### 3.12.38. XMLEXISTS predicate

The `XMLEXISTS` predicate can be used to check whether an XQuery or XPath expression produces a value within an XML document (see also the [XMLQUERY function](#xml-query-function))

```sql
SELECT 1
WHERE xmlexists('/a/b' PASSING '<a><b/></a>')
```

```java
create.selectOne()
      .where(xmlexists("/a/b").passing(XML.valueOf("<a><b/></a>")))
      .fetch();
```

##### Dialect support

This example using jOOQ:

```java
xmlexists("/a/b").passing(xml("<a><b/></a>"))
```

Translates to the following dialect specific expressions:

###### DB2

```sql
XMLEXISTS(
  '/a/b'
  PASSING xmlparse(DOCUMENT '<a><b/></a>')
)
```

###### Oracle

```sql
XMLEXISTS(
  '/a/b'
  PASSING xmltype.createxml('<a><b/></a>')
)
```

###### Postgres

```sql
XMLEXISTS(
  '/a/b'
  PASSING cast('<a><b/></a>' AS xml)
)
```

###### SQLServer

```sql
(cast('<a><b/></a>' AS xml).EXIST('/a/b') = 1)
```

###### Teradata

```sql
XMLEXISTS(
  '/a/b'
  PASSING '<a><b/></a>'
)
```

###### ASE, Access, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Sybase, Trino, Vertica, YugabyteDB

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="query-by-example"></a>
#### 3.12.39. Query By Example (QBE)

A popular approach to querying database tables is called [Query by Example](https://en.wikipedia.org/wiki/Query_by_Example), meaning that an "example" of a result record is provided instead of a formal query

```text
-- example book record:
ID          :
AUTHOR_ID   : 1
TITLE       :
PUBLISHED_IN: 1970
LANGUAGE_ID : 1
```

```sql
-- Corresponding query
SELECT *
FROM book
WHERE author_id = 1
AND published_in = 1970
AND language_id = 1
```

The translation from an example record to a query is fairly straight-forward:

- If a record attribute is set to a value, then that value is used for an equality predicate
- If a record attribute is not set, then that attribute is not used for any predicates

jOOQ knows a simple API called [`DSL.condition(Record)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#condition(org.jooq.Record)), which translates a [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) to a [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html):

```java
BookRecord book = new BookRecord();
book.setAuthorId(1);
book.setPublishedIn(1970);
book.setLanguageId(1);

// Using the explicit condition() API
Result<BookRecord> books1 =
DSL.using(configuration)
   .selectFrom(BOOK)
   .where(condition(book))
   .fetch();

// Using the convenience API on DSLContext
Result<BookRecord> books2 = DSL.using(configuration).fetchByExample(book);
```

The latter API call makes use of the convenience API [`DSLContext.fetchByExample(TableRecord)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchByExample(org.jooq.TableRecord)).

<a id="operator-precedence"></a>
### 3.13. Operator precedence

jOOQ supports various operators, such as:

- [Set operators](#set-operations)
- [JOIN operators](#join-clause)
- [AND, OR, NOT](#boolean-operators)
- [XOR](#xor-operator)
- [=, <, >, etc.](#comparison-predicate)
- [+, -, *, /, etc.](#arithmetic-expressions)
- Many more

While in actual SQL, operator precedence is important (and quite vendor specific, unfortunately!), in jOOQ this topic is irrelevant, as there are always explicit parentheses imposed by the host language (Java, Kotlin, Scala), which remove all ambiguity. For example:

```sql
A AND B OR C -- same as (A AND B) OR C
A OR B AND C -- same as A OR (B AND C)
```

```java
A.and(B).or(C)
A.or(B.and(C))
```

In other words, if you're chaining methods like this:

```java
A.op1(B).op2(C).op3(D)
```

... then, you're nesting operands from left to right like this:

```sql
(((A op1 B) op2 C) op3 D)
```

<a id="data-types"></a>
### 3.14. Data types

In jOOQ, the [column expression](#column-expressions) is represented by a [`Field<T>`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) type, where the `T` type variable is derived from its [`Field.getDataType()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Typed.html#getDataType()) property. The [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html) API models the rich world of SQL data types. A `DataType` models:

- A database type reference, such as [VARCHAR](#data-type-varchar) or [INTEGER](#data-type-integer)
- A variety of flags modifying the type, such as [precision](#data-type-length), [precision](#data-type-precision), [scale](#data-type-scale), and many more.
- A Java representation of the database type reference, usually denoted as the `T` type variable (for "type"), e.g. [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) or [`java.lang.Integer`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Integer.html)
- A Java representation of the user type reference, usually denoted as the `U` type variable (for "user type"), e.g. `Email` if it's a [custom data type](#converted-data-types). By default, this is the same as `T`.

Data types include:

- [Built-in data types](#built-in-data-types): These are types that are supported by the underlying RDBMS directly, such as [VARCHAR](#data-type-varchar) or [INTEGER](#data-type-integer). jOOQ's core library offers support for these out of the box, and can emulate some of them where not supported, e.g. [UUID](#data-type-uuid) is just a `VARCHAR(36)`
- [Extended data types](#extended-data-types): These are also built-in data types, but very dialect specific, such that jOOQ's core library doesn't offer them out of the box.
- [Enum data types](#enum-data-types): Some dialects support a special kind of constraint on [VARCHAR](#data-type-varchar) style types, which allows only for certain enumerated values in the type.
- [Domain data types](#domain-data-types): The SQL standard specifies `DOMAIN` types to be a set of re-usable constraints on an existing data type, which is supported in numerous dialects.
- [User-defined data types](#user-defined-data-types): The SQL standard specifies user-defined types to be a number of refinements on existing types, or the creation of a object type. The latter is what a few ORDBMS, JBDC, and jOOQ support.
- [Converted data types](#converted-data-types): Any data type `T` of the above list can be converted to a user type `U` using a [Converter](#data-type-converter) and/or [Binding](#data-type-binding), in order to change the user representation in Java code.

<a id="data-type-flags"></a>
#### 3.14.1. Flags modifying data types

Many [built-in data types](#built-in-data-types) offer a set of flags to modify things like their [length](#data-type-length), [precision](#data-type-precision), or [scale](#data-type-scale). Other flags are purely client side.

<a id="data-type-length"></a>
##### 3.14.1.1. Data type length

The data type length allows for specifying the length of character or binary data types, such as:

- `VARCHAR(20)` is a [VARCHAR](#data-type-varchar) typed string of 20 characters or bytes, depending on the RDBMS, collation, and character set
- `VARBINARY(20)` is a [VARBINARY](#data-type-varbinary) typed binary value of 20 bytes

Starting with jOOQ 3.22, the standard SQL length unit specification is available with string data types supporting a length, specifically:

- `VARCHAR(20, LengthUnit.CHARACTERS)` is a [VARCHAR](#data-type-varchar) typed string of 20 characters
- `VARCHAR(20, LengthUnit.OCTETS)` is a [VARCHAR](#data-type-varchar) typed string of 20 octets (8 bit bytes)

<a id="data-type-precision"></a>
##### 3.14.1.2. Data type precision

The data type precision allows for spceifying the precision of certain numeric or temporal data types, such as:

- `NUMERIC(20)` is a [NUMERIC](#data-type-numeric) typed decimal number of a total of 20 digits before the decimal point. (see [scale](#data-type-scale) for an example with precision and scale)
- `TIMESTAMP(3)` is a [TIMESTAMP](#data-type-timestamp) typed temporal value of 3 digits millisecond precision after the decimal point.

<a id="data-type-scale"></a>
##### 3.14.1.3. Data type scale

The data type scale allows for spceifying the scale of certain numeric data types, such as:

- `NUMERIC(20, 5)` is a [NUMERIC](#data-type-numeric) typed decimal number of 20 digits in total, out of which 5 after the decimal point. For example: `123456789012345.67890`.

<a id="built-in-data-types"></a>
#### 3.14.2. Built-in data types

The SQL standard and most RBDMS agree on a set of well-known primitive data types with a different set of names and variations. These include the following groups of types:

- Numeric integers: [TINYINT](#data-type-tinyint), [SMALLINT](#data-type-smallint), [INTEGER](#data-type-integer), [BIGINT](#data-type-bigint)
- Numeric floats: [REAL](#data-type-real), [DOUBLE](#data-type-double), [FLOAT](#data-type-float)
- Numeric decimals: [NUMERIC](#data-type-numeric), [DECIMAL](#data-type-decimal)
- Strings of fixed length: [CHAR](#data-type-char)
- Strings of variable length: [VARCHAR](#data-type-varchar), [CLOB](#data-type-clob)
- Binary strings of fixed length: [BINARY](#data-type-binary)
- Binary strings of variable length: [VARBINARY](#data-type-varbinary), [BLOB](#data-type-blob)
- Temporal data types: [DATE](#data-type-date), [TIME](#data-type-time), [TIMESTAMP](#data-type-timestamp)

In addition to the above primitives, there are also a few more specialised data types that are frequently seen in RDBMS, including:

- Document data types: [JSON](#data-type-json), [JSONB](#data-type-jsonb), [XML](#data-type-xml)
- Spatial data types: [GEOMETRY](#data-type-geometry), [GEOGRAPHY](#data-type-geography)
- Other types: [UUID](#data-type-uuid), [UUID](#data-type-uuid)
- And more...

<a id="data-type-bigint"></a>
##### 3.14.2.1. BIGINT (Long)

The [`BIGINT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#BIGINT) data type represents a signed, 64 bit integer, or [`java.lang.Long`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Long.html) in Java, or [`Types.BIGINT`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#BIGINT) in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", BIGINT)
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c numeric
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c bigint NULL
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c bigint
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c int64
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(bigint)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c bigint
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(19)
)
```

###### SQLite

```sql
CREATE TABLE t (
  c int8
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), BIGINT)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, SQLDataWarehouse, SQLServer, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS bigint
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS signed
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS int64
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(bigint)
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(19)
)
```

###### SQLite

```sql
cast(
  c
  AS int8
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-bigint-unsigned"></a>
##### 3.14.2.2. BIGINT UNSIGNED (ULong)

The [`BIGINT UNSIGNED`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#BIGINTUNSIGNED) data type represents an unsigned, 64 bit integer, or [`org.jooq.types.ULong`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/ULong.html) in Java. It has no representation in JDBC.

> [!TIP]
> If unsigned support is unavailable in a dialect, jOOQ will just map the type to the next higher integer type [DECIMAL INTEGER (BigInteger)](#data-type-decimal-integer).

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", BIGINTUNSIGNED)
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse, SQLServer, SQLite, Spanner, Teradata

```sql
CREATE TABLE t (
  c numeric
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c unsigned bigint NULL
)
```

###### Aurora MySQL, BigQuery, DB2, Informix, MariaDB, MemSQL, MySQL, Trino

```sql
CREATE TABLE t (
  c bigint unsigned
)
```

###### Aurora Postgres, CockroachDB, Firebird, HSQLDB, Hana, Postgres, Redshift, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c decimal
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(UInt64)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c bigint unsigned
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DuckDB

```sql
CREATE TABLE t (
  c ubigint
)
```

###### Exasol, H2

```sql
CREATE TABLE t (
  c number
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(20)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), BIGINTUNSIGNED)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Sybase

```sql
cast(
  c
  AS unsigned bigint
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS unsigned
)
```

###### Aurora Postgres, CockroachDB, HSQLDB, Hana, Postgres, Redshift, Vertica, YugabyteDB

```sql
cast(
  c
  AS decimal
)
```

###### BigQuery, DB2, Databricks, Informix, Trino

```sql
cast(
  c
  AS bigint unsigned
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(UInt64)
)
```

###### DuckDB

```sql
cast(
  c
  AS ubigint
)
```

###### Exasol, H2

```sql
cast(
  c
  AS number
)
```

###### Firebird

```sql
cast(
  c
  AS varchar(20)
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(20)
)
```

###### SQLDataWarehouse, SQLServer, SQLite, Spanner, Teradata

```sql
cast(
  c
  AS numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-binary"></a>
##### 3.14.2.3. BINARY (byte[])

The [`BINARY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#BINARY) data type represents a fixed length binary type, or `byte[]` in Java, or [`Types.BINARY`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#BINARY) in JDBC.

Given the fixed size characteristic, the `BINARY` type should be accompanied by an explicit [length](#data-type-length) flag.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", BINARY(16))
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, Snowflake, Vertica

```sql
CREATE TABLE t (
  c binary(16)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c binary(16) NULL
)
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
CREATE TABLE t (
  c bytea
)
```

###### BigQuery, CockroachDB

```sql
CREATE TABLE t (
  c bytes
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(varbinary(16))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c binary
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, Firebird, SQLite

```sql
CREATE TABLE t (
  c blob(16)
)
```

###### DuckDB

```sql
CREATE TABLE t (
  c binary
)
```

###### Informix

```sql
CREATE TABLE t (
  c blob
)
```

###### Oracle

```sql
CREATE TABLE t (
  c raw(16)
)
```

###### Redshift

```sql
CREATE TABLE t (
  c varbyte
)
```

###### Spanner

```sql
CREATE TABLE t (
  c bytes(16)
)
```

###### Teradata

```sql
CREATE TABLE t (
  c byte(16)
)
```

###### Trino

```sql
CREATE TABLE t (
  c varbinary
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), BINARY(16))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Vertica

```sql
cast(
  c
  AS binary(16)
)
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
cast(
  c
  AS bytea
)
```

###### BigQuery, CockroachDB, Spanner

```sql
cast(
  c
  AS bytes
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(varbinary(16))
)
```

###### Databricks, DuckDB

```sql
cast(
  c
  AS binary
)
```

###### DB2, Firebird, SQLite

```sql
cast(
  c
  AS blob(16)
)
```

###### Informix

```sql
cast(
  c
  AS blob
)
```

###### Oracle

```sql
to_blob(c)
```

###### Redshift

```sql
cast(
  c
  AS varbyte
)
```

###### Teradata

```sql
cast(
  c
  AS byte(16)
)
```

###### Trino

```sql
cast(
  c
  AS varbinary
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-bit"></a>
##### 3.14.2.4. BIT (Boolean)

The [`BIT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#BIT) data type represents a boolean type, or [`java.lang.Boolean`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Boolean.html) in Java, or [`Types.BIT`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#BIT) in JDBC.

> [!TIP]
> Some RDBMS use `BIT` to represent a bit string, instead, i.e. a set of boolean values instead of a single one. This usage is currently not supported by jOOQ.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", BIT)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, BigQuery, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, Trino

```sql
CREATE TABLE t (
  c bit
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c bit NULL
)
```

###### Aurora Postgres, CockroachDB, Informix, Postgres, Redshift, SQLite, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c boolean
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(bit)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c bit
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2

```sql
CREATE TABLE t (
  c smallint
)
```

###### Oracle, Snowflake, Teradata

```sql
CREATE TABLE t (
  c number
)
```

###### Spanner

```sql
CREATE TABLE t (
  c bool
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), BIT)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cbool(c)
```

###### ASE, BigQuery, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, SQLDataWarehouse, SQLServer, Sybase, Trino

```sql
cast(
  c
  AS bit
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS unsigned
)
```

###### Aurora Postgres, CockroachDB, Informix, Postgres, Redshift, SQLite, Vertica, YugabyteDB

```sql
cast(
  c
  AS boolean
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(bit)
)
```

###### DB2

```sql
cast(
  c
  AS smallint
)
```

###### Oracle, Snowflake, Teradata

```sql
cast(
  c
  AS number(1)
)
```

###### Spanner

```sql
cast(
  c
  AS bool
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-blob"></a>
##### 3.14.2.5. BLOB (byte[])

The [`BLOB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#BLOB) (Binary Large OBject) data type represents a variable length binary type, or `byte[]` in Java, or [`Types.BLOB`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#BLOB) in JDBC.

Some RDBMS support different variable size binary types, where the `BLOB` type allows for very big objects to be stored in separate storage. In those RDBMS, `BLOB` may behave subtly differently from [VARBINARY (byte[])](#data-type-varbinary).

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", BLOB)
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse

```sql
CREATE TABLE t (
  c binary
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c binary NULL
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
CREATE TABLE t (
  c longblob
)
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
CREATE TABLE t (
  c bytea
)
```

###### BigQuery, CockroachDB

```sql
CREATE TABLE t (
  c bytes
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(varbinary)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c binary
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Oracle, SQLite, Teradata

```sql
CREATE TABLE t (
  c blob
)
```

###### Redshift

```sql
CREATE TABLE t (
  c varbyte
)
```

###### Snowflake, Trino

```sql
CREATE TABLE t (
  c varbinary
)
```

###### Spanner

```sql
CREATE TABLE t (
  c bytes(10485760)
)
```

###### SQLServer

```sql
CREATE TABLE t (
  c varbinary(max)
)
```

###### Vertica

```sql
CREATE TABLE t (
  c long varbinary
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), BLOB)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Databricks, MariaDB, MemSQL, MySQL, SQLDataWarehouse, Sybase

```sql
cast(
  c
  AS binary
)
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
cast(
  c
  AS bytea
)
```

###### BigQuery, CockroachDB, Spanner

```sql
cast(
  c
  AS bytes
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(varbinary)
)
```

###### DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, SQLite, Teradata

```sql
cast(
  c
  AS blob
)
```

###### Oracle

```sql
to_blob(c)
```

###### Redshift

```sql
cast(
  c
  AS varbyte
)
```

###### Snowflake, Trino

```sql
cast(
  c
  AS varbinary
)
```

###### SQLServer

```sql
cast(
  c
  AS varbinary(max)
)
```

###### Vertica

```sql
cast(
  c
  AS long varbinary
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-boolean"></a>
##### 3.14.2.6. BOOLEAN (Boolean)

The [`BOOLEAN`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#BOOLEAN) data type represents a boolean type, or [`java.lang.Boolean`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Boolean.html) in Java, or [`Types.BOOLEAN`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#BOOLEAN) in JDBC.

> [!TIP]
> While all RDBMS support `BOOLEAN` expressions in the form of a [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html), not all RDBMS support [Column expressions](#column-expressions) of type `BOOLEAN`. If such boolean type support is unavailable in a dialect, jOOQ will just map the type to [INTEGER (Integer)](#data-type-integer) with possible values being `0` and `1`.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", BOOLEAN)
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse, SQLServer

```sql
CREATE TABLE t (
  c bit
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c bit NULL
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLite, Snowflake, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c boolean
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c bool
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(boolean)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c boolean
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2

```sql
CREATE TABLE t (
  c smallint
)
```

###### Oracle, Teradata

```sql
CREATE TABLE t (
  c number
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), BOOLEAN)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cbool(c)
```

###### ASE, SQLDataWarehouse, SQLServer, Sybase

```sql
cast(
  c
  AS bit
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS unsigned
)
```

###### Aurora Postgres, CockroachDB, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, SQLite, Snowflake, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS boolean
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS bool
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(boolean)
)
```

###### DB2

```sql
cast(
  c
  AS smallint
)
```

###### Oracle, Teradata

```sql
cast(
  c
  AS number(1)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-char"></a>
##### 3.14.2.7. CHAR (String)

The [`CHAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#CHAR) data type represents a fixed length string type, or [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) in Java, or [`Types.CHAR`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#CHAR) in JDBC.

Given the fixed size characteristic, the `CHAR` type should be accompanied by an explicit [length](#data-type-length) flag.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", CHAR(3))
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c character(3)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c char(3) NULL
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c char(3)
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(char(3))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c char(3)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Spanner

```sql
CREATE TABLE t (
  c string(3)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), CHAR(3))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS char(3)
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(char(3))
)
```

###### Oracle

```sql
cast(
  c
  AS varchar2(3)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-clob"></a>
##### 3.14.2.8. CLOB (String)

The [`CLOB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#CLOB) (Character Large OBject) data type represents a variable length string type, or [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) in Java, or [`Types.CLOB`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#CLOB) in JDBC.

Some RDBMS support different variable size string types, where the `CLOB` type allows for very big objects to be stored in separate storage. In those RDBMS, `CLOB` may behave subtly differently from [VARCHAR (String)](#data-type-varchar).

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", CLOB)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
CREATE TABLE t (
  c longtext
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c text NULL
)
```

###### Aurora Postgres, CockroachDB, Informix, Postgres, Redshift, Snowflake, YugabyteDB

```sql
CREATE TABLE t (
  c text
)
```

###### BigQuery, DuckDB

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(varchar)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c string
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, Exasol, H2, HSQLDB, Hana, Oracle, SQLite, Teradata

```sql
CREATE TABLE t (
  c clob
)
```

###### Firebird

```sql
CREATE TABLE t (
  c blob sub_type text
)
```

###### Spanner

```sql
CREATE TABLE t (
  c string(2621440)
)
```

###### SQLDataWarehouse, Trino

```sql
CREATE TABLE t (
  c varchar
)
```

###### SQLServer

```sql
CREATE TABLE t (
  c varchar(max)
)
```

###### Vertica

```sql
CREATE TABLE t (
  c long varchar
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), CLOB)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora Postgres, CockroachDB, Informix, Postgres, Redshift, Snowflake, Sybase, YugabyteDB

```sql
cast(
  c
  AS text
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS char
)
```

###### BigQuery, Databricks, DuckDB, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(varchar)
)
```

###### DB2, Exasol, H2, HSQLDB, Hana, SQLite

```sql
cast(
  c
  AS clob
)
```

###### Firebird

```sql
cast(
  c
  AS blob sub_type text
)
```

###### Oracle

```sql
to_clob(c)
```

###### SQLDataWarehouse, Trino

```sql
cast(
  c
  AS varchar
)
```

###### SQLServer

```sql
cast(
  c
  AS varchar(max)
)
```

###### Teradata

```sql
cast(
  cast(
    c
    AS varchar(32000)
  )
  AS clob
)
```

###### Vertica

```sql
cast(
  c
  AS long varchar
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-date"></a>
##### 3.14.2.9. DATE (Date)

The [`DATE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#DATE) data type represents a local date type, or [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html) in Java, or [`Types.DATE`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#DATE) in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", DATE)
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c datetime
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c date NULL
)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c date
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(date)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c date
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), DATE)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdate(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS date
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(date)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-decfloat"></a>
##### 3.14.2.10. DECFLOAT (Decfloat)

The [`DECFLOAT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#DECFLOAT) data type represents a variable bit floating point number, optimised for decimal values as opposed to binary ones, or [`org.jooq.Decfloat`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Decfloat.html) in Java. It has no representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", DECFLOAT(20))
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c decfloat(20)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c decfloat(20) NULL
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c decfloat
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(decfloat(20))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c decfloat(20)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Hana

```sql
CREATE TABLE t (
  c smalldecimal(20)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), DECFLOAT(20))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS decfloat(20)
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS decfloat
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(decfloat(20))
)
```

###### Hana

```sql
cast(
  c
  AS smalldecimal(20)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-decimal"></a>
##### 3.14.2.11. DECIMAL (BigDecimal)

The [`DECIMAL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#DECIMAL) data type represents a decimal number, or [`java.math.BigDecimal`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/math/BigDecimal.html) in Java, or [`Types.DECIMAL`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#DECIMAL) in JDBC.

Given the variable precision characteristic, the `DECIMAL` type should usually be accompanied by explicit [precision](#data-type-precision) and [scale](#data-type-scale) flags. If absent, the default behaviour is dialect specific.

> [!TIP]
> For most practical purposes, the `DECIMAL` type is the same as the [NUMERIC](#data-type-numeric) type.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", DECIMAL(10, 5))
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c numeric(10, 5)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c decimal(10, 5) NULL
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c decimal(10, 5)
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c bigdecimal
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(decimal(10, 5))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c decimal(10, 5)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Snowflake

```sql
CREATE TABLE t (
  c number(10, 5)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), DECIMAL(10, 5))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS decimal(10, 5)
)
```

###### BigQuery

```sql
cast(
  c
  AS bigdecimal
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(decimal(10, 5))
)
```

###### Snowflake

```sql
cast(
  c
  AS number(10, 5)
)
```

###### Spanner

```sql
cast(
  c
  AS numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-decimal-integer"></a>
##### 3.14.2.12. DECIMAL INTEGER (BigInteger)

The [`DECIMAL_INTEGER`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#DECIMAL_INTEGER) data type represents a zero-scale decimal number, or [`java.math.BigInteger`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/math/BigInteger.html) in Java. It has no representation in JDBC.

Given the variable precision characteristic, the `DECIMAL_INTEGER` type should usually be accompanied by an explicit [precision](#data-type-precision) flag. If absent, the default behaviour is dialect specific.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", DECIMAL_INTEGER(10))
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse, SQLServer, Teradata

```sql
CREATE TABLE t (
  c numeric(10)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c decimal(10) NULL
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c decimal(10)
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c bigdecimal
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(decimal(10))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c decimal(10)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle

```sql
CREATE TABLE t (
  c number(10)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c numeric
)
```

###### SQLite

```sql
CREATE TABLE t (
  c unsigned big int(10)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), DECIMAL_INTEGER(10))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Sybase, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS decimal(10)
)
```

###### BigQuery

```sql
cast(
  c
  AS bigdecimal
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(decimal(10))
)
```

###### Oracle

```sql
cast(
  c
  AS number(10)
)
```

###### Spanner

```sql
cast(
  c
  AS numeric
)
```

###### SQLDataWarehouse, SQLServer, Teradata

```sql
cast(
  c
  AS numeric(10)
)
```

###### SQLite

```sql
cast(
  c
  AS unsigned big int(10)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-double"></a>
##### 3.14.2.13. DOUBLE (Double)

The [`DOUBLE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#DOUBLE) data type represents a 64 bit floating point number, or [`java.lang.Double`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Double.html) in Java, or [`Types.DOUBLE`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#DOUBLE) in JDBC

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", DOUBLE)
```

Translates to the following dialect specific expressions:

###### Access, Informix, Oracle, SQLDataWarehouse, SQLServer, Snowflake

```sql
CREATE TABLE t (
  c float
)
```

###### ASE

```sql
CREATE TABLE t (
  c double precision NULL
)
```

###### Aurora MySQL, DB2, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, SQLite, Trino

```sql
CREATE TABLE t (
  c double
)
```

###### Aurora Postgres, CockroachDB, Firebird, Postgres, Redshift, Teradata, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c double precision
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c float64
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(double)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c double
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Sybase

```sql
CREATE TABLE t (
  c double NULL
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), DOUBLE)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdbl(c)
```

###### ASE, Aurora Postgres, CockroachDB, Firebird, Postgres, Redshift, Teradata, Vertica, YugabyteDB

```sql
cast(
  c
  AS double precision
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS decimal
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS float64
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(double)
)
```

###### DB2, Databricks, DuckDB, Exasol, H2, HSQLDB, Hana, SQLite, Sybase, Trino

```sql
cast(
  c
  AS double
)
```

###### Informix, Oracle, SQLDataWarehouse, SQLServer, Snowflake

```sql
cast(
  c
  AS float
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-float"></a>
##### 3.14.2.14. FLOAT (Double)

The [`FLOAT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#FLOAT) data type represents a variable bit floating point number, or [`java.lang.Double`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Double.html) in Java, or [`Types.FLOAT`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#FLOAT) in JDBC

> [!TIP]
> jOOQ currently doesn't support a precision on a `FLOAT` type.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", FLOAT)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, DB2, DuckDB, Exasol, H2, HSQLDB, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLDataWarehouse, SQLServer, Snowflake, Teradata, Trino, Vertica

```sql
CREATE TABLE t (
  c float
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c float NULL
)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
CREATE TABLE t (
  c float8
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c float64
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(float)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c double
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Firebird

```sql
CREATE TABLE t (
  c double precision
)
```

###### Hana, SQLite

```sql
CREATE TABLE t (
  c double
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), FLOAT)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdbl(c)
```

###### ASE, DB2, DuckDB, Exasol, H2, HSQLDB, Informix, Oracle, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Teradata, Trino, Vertica

```sql
cast(
  c
  AS float
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS decimal
)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
cast(
  c
  AS float8
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS float64
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(float)
)
```

###### Databricks, Hana, SQLite

```sql
cast(
  c
  AS double
)
```

###### Firebird

```sql
cast(
  c
  AS double precision
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-geography"></a>
##### 3.14.2.15. GEOGRAPHY (Geography)

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The [`GEOGRAPHY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#GEOGRAPHY) data type represents spatial `GEOGRAPHY` value, or [`org.jooq.Geography`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Geography.html) in Java. It has no representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", GEOGRAPHY)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c geography
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c geography NULL
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c geography
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c geography
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), GEOGRAPHY)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, ClickHouse, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS geography
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-geometry"></a>
##### 3.14.2.16. GEOMETRY (Geometry)

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The [`GEOMETRY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#GEOMETRY) data type represents spatial `GEOMETRY` value, or [`org.jooq.Geometry`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Geometry.html) in Java. It has no representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", GEOMETRY)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c geometry
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c geometry NULL
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Geometry
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c geometry
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle

```sql
CREATE TABLE t (
  c sdo_geometry
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), GEOMETRY)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS geometry
)
```

###### ClickHouse

```sql
cast(
  c
  AS Geometry
)
```

###### Oracle

```sql
cast(
  c
  AS sdo_geometry
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-instant"></a>
##### 3.14.2.17. INSTANT (Instant)

The [`INSTANT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#INSTANT) data type represents an offset date time type with time zone fixed to UTC, or [`java.time.Instant`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/Instant.html) in Java, or [`Types.TIMESTAMP_WITH_TIMEZONE`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#TIMESTAMP_WITH_TIMEZONE) in JDBC.

Some dialects support an explicit [precision](#data-type-precision) flag on this data type. If absent, the default is dialect specific.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", INSTANT)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, DB2, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLite, Vertica

```sql
CREATE TABLE t (
  c instant
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c instant NULL
)
```

###### Aurora Postgres, DuckDB, Exasol, Firebird, H2, HSQLDB, Oracle, Postgres, Teradata, Trino, YugabyteDB

```sql
CREATE TABLE t (
  c timestamp with time zone
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c timestamp
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(instant)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE t (
  c timestamptz
)
```

###### Databricks

```sql
CREATE TABLE t (
  c timestamp
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Snowflake

```sql
CREATE TABLE t (
  c timestamp_tz
)
```

###### SQLDataWarehouse, SQLServer

```sql
CREATE TABLE t (
  c datetimeoffset
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), INSTANT)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, DB2, Hana, Informix, MariaDB, MemSQL, MySQL, Redshift, SQLite, Sybase, Vertica

```sql
cast(
  c
  AS instant
)
```

###### Aurora Postgres, DuckDB, Exasol, Firebird, H2, HSQLDB, Oracle, Postgres, Teradata, Trino, YugabyteDB

```sql
cast(
  c
  AS timestamp with time zone
)
```

###### BigQuery, Databricks, Spanner

```sql
cast(
  c
  AS timestamp
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(instant)
)
```

###### CockroachDB

```sql
cast(
  c
  AS timestamptz
)
```

###### Snowflake

```sql
cast(
  c
  AS timestamp_tz
)
```

###### SQLDataWarehouse, SQLServer

```sql
cast(
  c
  AS datetimeoffset
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-integer"></a>
##### 3.14.2.18. INTEGER (Integer)

The [`INTEGER`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#INTEGER) data type represents a signed, 32 bit integer, or [`java.lang.Integer`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Integer.html) in Java, or [`Types.INTEGER`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#INTEGER) in JDBC

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", INTEGER)
```

Translates to the following dialect specific expressions:

###### Access, DB2, Firebird, Hana, Informix, Teradata

```sql
CREATE TABLE t (
  c integer
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c int NULL
)
```

###### Aurora MySQL, Aurora Postgres, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c int
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c int64
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(integer)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE t (
  c int4
)
```

###### Databricks

```sql
CREATE TABLE t (
  c int
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(10)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), INTEGER)
```

Translates to the following dialect specific expressions:

###### Access

```sql
clng(c)
```

###### ASE, Aurora Postgres, Databricks, DuckDB, Exasol, H2, HSQLDB, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Sybase, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS int
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS signed
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS int64
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(integer)
)
```

###### CockroachDB

```sql
cast(
  c
  AS int4
)
```

###### DB2, Firebird, Hana, Informix, Teradata

```sql
cast(
  c
  AS integer
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(10)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-integer-unsigned"></a>
##### 3.14.2.19. INTEGER UNSIGNED (UInteger)

The [`INTEGER UNSIGNED`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#INTEGERUNSIGNED) data type represents an unsigned, 32 bit integer, or [`org.jooq.types.UInteger`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/UInteger.html) in Java. It has no representation in JDBC.

> [!TIP]
> If unsigned support is unavailable in a dialect, jOOQ will just map the type to the next higher integer type [BIGINT UNSIGNED (ULong)](#data-type-bigint-unsigned).

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", INTEGERUNSIGNED)
```

Translates to the following dialect specific expressions:

###### Access, Spanner

```sql
CREATE TABLE t (
  c numeric
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c unsigned int NULL
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
CREATE TABLE t (
  c int unsigned
)
```

###### Aurora Postgres, CockroachDB, Exasol, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Teradata, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c bigint
)
```

###### BigQuery, DB2, Informix, Trino

```sql
CREATE TABLE t (
  c integer unsigned
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(UInt32)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c integer unsigned
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DuckDB

```sql
CREATE TABLE t (
  c uinteger
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(10)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), INTEGERUNSIGNED)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Sybase

```sql
cast(
  c
  AS unsigned int
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS unsigned
)
```

###### Aurora Postgres, CockroachDB, Exasol, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Teradata, Vertica, YugabyteDB

```sql
cast(
  c
  AS bigint
)
```

###### BigQuery, DB2, Databricks, Informix, Trino

```sql
cast(
  c
  AS integer unsigned
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(UInt32)
)
```

###### DuckDB

```sql
cast(
  c
  AS uinteger
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(10)
)
```

###### Spanner

```sql
cast(
  c
  AS numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-interval"></a>
##### 3.14.2.20. INTERVAL (YearToSecond)

The [`INTERVAL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#INTERVAL) data type represents a combined [YEAR TO MONTH](#data-type-interval-year-to-month) and [DAY TO SECOND](#data-type-interval-day-to-second) interval, or [`org.jooq.types.YearToSecond`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/YearToSecond.html) in Java. It has no representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", INTERVAL)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c interval
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c interval NULL
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(interval)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c interval
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), INTERVAL)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS interval
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(interval)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-interval-day-to-second"></a>
##### 3.14.2.21. INTERVAL DAY TO SECOND (DayToSecond)

The [`INTERVALDAYTOSECOND`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#INTERVALDAYTOSECOND) data type represents a `DAY TO SECOND` interval, or [`org.jooq.types.DayToSecond`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/DayToSecond.html) in Java. It has no representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", INTERVALDAYTOSECOND)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c interval day to second
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c interval day to second NULL
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(interval day to second)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c interval day to second
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Spanner

```sql
CREATE TABLE t (
  c interval
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), INTERVALDAYTOSECOND)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS interval day to second
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(interval day to second)
)
```

###### Exasol, H2, HSQLDB, Oracle

```sql
cast(
  c
  AS interval day(9) to second
)
```

###### Spanner

```sql
cast(
  c
  AS interval
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-interval-year-to-month"></a>
##### 3.14.2.22. INTERVAL YEAR TO MONTH (YearToMonth)

The [`INTERVALYEARTOMONTH`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#INTERVALYEARTOMONTH) data type represents a `YEAR TO MONTH` interval, or [`org.jooq.types.YearToMonth`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/YearToMonth.html) in Java. It has no representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", INTERVALYEARTOMONTH)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c interval year to month
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c interval year to month NULL
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(interval year to month)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c interval year to month
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Spanner

```sql
CREATE TABLE t (
  c interval
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), INTERVALYEARTOMONTH)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS interval year to month
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(interval year to month)
)
```

###### Spanner

```sql
cast(
  c
  AS interval
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-json"></a>
##### 3.14.2.23. JSON (JSON)

The [`JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#JSON) data type represents a possibly formatted JSON document, or [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) in Java. It has no direct representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", JSON)
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c longtext
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c text NULL
)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DuckDB, Exasol, H2, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Spanner, Trino, YugabyteDB

```sql
CREATE TABLE t (
  c json
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c JSON
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c json
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, HSQLDB, Hana, SQLite, Teradata

```sql
CREATE TABLE t (
  c clob
)
```

###### Firebird

```sql
CREATE TABLE t (
  c blob sub_type text
)
```

###### Informix, MemSQL

```sql
CREATE TABLE t (
  c text
)
```

###### Snowflake

```sql
CREATE TABLE t (
  c variant
)
```

###### Vertica

```sql
CREATE TABLE t (
  c long varchar
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), JSON)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Informix, Sybase

```sql
cast(
  c
  AS text
)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, Databricks, DuckDB, Exasol, H2, MariaDB, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, Spanner, Trino, YugabyteDB

```sql
cast(
  c
  AS json
)
```

###### ClickHouse

```sql
cast(
  c
  AS JSON
)
```

###### DB2, HSQLDB, Hana, SQLite, Teradata

```sql
cast(
  c
  AS clob
)
```

###### Firebird

```sql
cast(
  c
  AS blob sub_type text
)
```

###### MemSQL

```sql
cast(
  c
  AS char
)
```

###### Snowflake

```sql
cast(
  c
  AS variant
)
```

###### Vertica

```sql
cast(
  c
  AS long varchar
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-jsonb"></a>
##### 3.14.2.24. JSONB (JSONB)

The [`JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#JSONB) data type represents a pre-processed, binary-stored JSON document, or [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html) in Java. It has no direct representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", JSONB)
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c binary
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c binary NULL
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Postgres, Redshift, SQLDataWarehouse, SQLServer, YugabyteDB

```sql
CREATE TABLE t (
  c jsonb
)
```

###### BigQuery, DuckDB, Exasol, H2, MariaDB, MySQL, Oracle, Spanner, Trino

```sql
CREATE TABLE t (
  c json
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c JSON
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c jsonb
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, Firebird, HSQLDB, Hana, Informix, MemSQL, SQLite, Teradata

```sql
CREATE TABLE t (
  c blob
)
```

###### Snowflake

```sql
CREATE TABLE t (
  c variant
)
```

###### Vertica

```sql
CREATE TABLE t (
  c long varbinary
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), JSONB)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, MemSQL, Sybase

```sql
cast(
  c
  AS binary
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, Postgres, Redshift, SQLDataWarehouse, SQLServer, YugabyteDB

```sql
cast(
  c
  AS jsonb
)
```

###### BigQuery, DuckDB, Exasol, H2, MariaDB, MySQL, Oracle, Spanner, Trino

```sql
cast(
  c
  AS json
)
```

###### ClickHouse

```sql
cast(
  c
  AS JSON
)
```

###### DB2, Firebird, HSQLDB, Hana, Informix, SQLite, Teradata

```sql
cast(
  c
  AS blob
)
```

###### Snowflake

```sql
cast(
  c
  AS variant
)
```

###### Vertica

```sql
cast(
  c
  AS long varbinary
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-localdate"></a>
##### 3.14.2.25. LOCALDATE (LocalDate)

The [`LOCALDATE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#LOCALDATE) is a `java.time` bound variant of the [DATE](#data-type-date) type, when the old JDBC binding should be avoided, i.e. [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html) in Java, or [`Types.DATE`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#DATE) in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", LOCALDATE)
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c datetime
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c date NULL
)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c date
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(date)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c date
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), LOCALDATE)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS date
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(date)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-localdatetime"></a>
##### 3.14.2.26. LOCALDATETIME (LocalDateTime)

The [`LOCALDATETIME`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#LOCALDATETIME) is a `java.time` bound variant of the [TIMESTAMP](#data-type-timestamp) type, when the old JDBC binding should be avoided, i.e. [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html) in Java, or [`Types.TIMESTAMP`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#TIMESTAMP) in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", LOCALDATETIME)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, BigQuery, MemSQL, MySQL, SQLDataWarehouse, SQLite

```sql
CREATE TABLE t (
  c datetime
)
```

###### ASE, MariaDB, Sybase

```sql
CREATE TABLE t (
  c datetime NULL
)
```

###### Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c timestamp
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(timestamp)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c timestamp_ntz
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DuckDB

```sql
CREATE TABLE t (
  c timestamp without time zone
)
```

###### Informix

```sql
CREATE TABLE t (
  c datetime year to fraction(5)
)
```

###### Snowflake

```sql
CREATE TABLE t (
  c timestamp_ntz
)
```

###### SQLServer

```sql
CREATE TABLE t (
  c datetime2
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), LOCALDATETIME)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, BigQuery, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Sybase

```sql
cast(
  c
  AS datetime
)
```

###### Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS timestamp
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(timestamp)
)
```

###### Databricks, Snowflake

```sql
cast(
  c
  AS timestamp_ntz
)
```

###### DuckDB

```sql
cast(
  c
  AS timestamp without time zone
)
```

###### Informix

```sql
cast(
  cast(
    c
    AS datetime year to fraction(5)
  )
  AS datetime year to fraction(5)
)
```

###### SQLServer

```sql
cast(
  c
  AS datetime2
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-localtime"></a>
##### 3.14.2.27. LOCALTIME (LocalTime)

The [`LOCALTIME`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#LOCALTIME) is a `java.time` bound variant of the [TIME](#data-type-time) type, when the old JDBC binding should be avoided, i.e. [`java.time.LocalTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalTime.html) in Java, or [`Types.TIME`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#TIME) in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", LOCALTIME)
```

Translates to the following dialect specific expressions:

###### Access, Informix, SQLite

```sql
CREATE TABLE t (
  c datetime
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c time NULL
)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c time
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(time)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c time
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle

```sql
CREATE TABLE t (
  c timestamp
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), LOCALTIME)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS time
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(time)
)
```

###### Informix

```sql
cast(
  c
  AS datetime hour to second
)
```

###### Oracle

```sql
cast(
  c
  AS timestamp
)
```

###### SQLite

```sql
cast(
  c
  AS datetime
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-longnvarchar"></a>
##### 3.14.2.28. LONGNVARCHAR (String)

The [`LONGNVARCHAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#LONGNVARCHAR) data type represents a variable length "national" (unicode) string type, or [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) in Java, or [`Types.LONGNVARCHAR`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#LONGNVARCHAR) in JDBC.

This data type is mostly offered as a compatibility type as the difference between this type and other variable length binary types like [NVARCHAR (String)](#data-type-nvarchar) and [NCLOB (String)](#data-type-nclob) is not very well defined.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", LONGNVARCHAR)
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c longtext
)
```

###### ASE

```sql
CREATE TABLE t (
  c unitext NULL
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
CREATE TABLE t (
  c text
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake, Trino, YugabyteDB

```sql
CREATE TABLE t (
  c varchar
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(String)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c string
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, Informix

```sql
CREATE TABLE t (
  c clob
)
```

###### Exasol, HSQLDB

```sql
CREATE TABLE t (
  c longvarchar
)
```

###### Firebird

```sql
CREATE TABLE t (
  c blob sub_type text
)
```

###### H2

```sql
CREATE TABLE t (
  c longnvarchar
)
```

###### Hana

```sql
CREATE TABLE t (
  c nclob
)
```

###### Oracle

```sql
CREATE TABLE t (
  c nvarchar2(4000)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c string(2621440)
)
```

###### SQLDataWarehouse

```sql
CREATE TABLE t (
  c nvarchar(4000)
)
```

###### SQLite

```sql
CREATE TABLE t (
  c nvarchar
)
```

###### SQLServer

```sql
CREATE TABLE t (
  c nvarchar(max)
)
```

###### Sybase

```sql
CREATE TABLE t (
  c long nvarchar NULL
)
```

###### Teradata

```sql
CREATE TABLE t (
  c varchar(32000)
)
```

###### Vertica

```sql
CREATE TABLE t (
  c long varchar
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), LONGNVARCHAR)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE

```sql
cast(
  c
  AS unitext
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS char
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake, Trino, YugabyteDB

```sql
cast(
  c
  AS varchar
)
```

###### BigQuery, Databricks, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(String)
)
```

###### DB2, Informix

```sql
cast(
  c
  AS clob
)
```

###### Exasol, HSQLDB

```sql
cast(
  c
  AS longvarchar
)
```

###### Firebird

```sql
cast(
  c
  AS blob sub_type text
)
```

###### H2

```sql
cast(
  c
  AS longnvarchar
)
```

###### Hana

```sql
cast(
  c
  AS nclob
)
```

###### Oracle

```sql
cast(
  c
  AS nvarchar2(4000)
)
```

###### SQLDataWarehouse

```sql
cast(
  c
  AS nvarchar(4000)
)
```

###### SQLite

```sql
cast(
  c
  AS nvarchar
)
```

###### SQLServer

```sql
cast(
  c
  AS nvarchar(max)
)
```

###### Sybase

```sql
cast(
  c
  AS long nvarchar
)
```

###### Teradata

```sql
cast(
  c
  AS varchar(32000)
)
```

###### Vertica

```sql
cast(
  c
  AS long varchar
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-longvarbinary"></a>
##### 3.14.2.29. LONGVARBINARY (byte[])

The [`LONGVARBINARY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#LONGVARBINARY) data type represents a variable length binary type, or `byte[]` in Java, or [`Types.LONGVARBINARY`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#LONGVARBINARY) in JDBC.

This data type is mostly offered as a compatibility type as the difference between this type and other variable length binary types like [VARBINARY (byte[])](#data-type-varbinary) and [BLOB (byte[])](#data-type-blob) is not very well defined.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", LONGVARBINARY)
```

Translates to the following dialect specific expressions:

###### Access, Snowflake

```sql
CREATE TABLE t (
  c binary
)
```

###### ASE

```sql
CREATE TABLE t (
  c varbinary NULL
)
```

###### Aurora MySQL, DB2, Firebird, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, SQLite

```sql
CREATE TABLE t (
  c blob
)
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
CREATE TABLE t (
  c bytea
)
```

###### BigQuery, CockroachDB

```sql
CREATE TABLE t (
  c bytes
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(longvarbinary)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c binary
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DuckDB, Trino

```sql
CREATE TABLE t (
  c varbinary
)
```

###### Exasol, H2, HSQLDB

```sql
CREATE TABLE t (
  c longvarbinary
)
```

###### Redshift

```sql
CREATE TABLE t (
  c varbyte
)
```

###### Spanner

```sql
CREATE TABLE t (
  c bytes(10485760)
)
```

###### SQLDataWarehouse

```sql
CREATE TABLE t (
  c varbinary(8000)
)
```

###### SQLServer

```sql
CREATE TABLE t (
  c varbinary(max)
)
```

###### Sybase

```sql
CREATE TABLE t (
  c long binary NULL
)
```

###### Teradata

```sql
CREATE TABLE t (
  c varbyte(32000)
)
```

###### Vertica

```sql
CREATE TABLE t (
  c long varbinary
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), LONGVARBINARY)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, DuckDB, Trino

```sql
cast(
  c
  AS varbinary
)
```

###### Aurora MySQL, Databricks, MariaDB, MemSQL, MySQL, Snowflake

```sql
cast(
  c
  AS binary
)
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
cast(
  c
  AS bytea
)
```

###### BigQuery, CockroachDB, Spanner

```sql
cast(
  c
  AS bytes
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(longvarbinary)
)
```

###### DB2, Firebird, Hana, Informix, SQLite

```sql
cast(
  c
  AS blob
)
```

###### Exasol, H2, HSQLDB

```sql
cast(
  c
  AS longvarbinary
)
```

###### Oracle

```sql
to_blob(c)
```

###### Redshift

```sql
cast(
  c
  AS varbyte
)
```

###### SQLDataWarehouse

```sql
cast(
  c
  AS varbinary(8000)
)
```

###### SQLServer

```sql
cast(
  c
  AS varbinary(max)
)
```

###### Sybase

```sql
cast(
  c
  AS long binary
)
```

###### Teradata

```sql
cast(
  c
  AS varbyte(32000)
)
```

###### Vertica

```sql
cast(
  c
  AS long varbinary
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-longvarchar"></a>
##### 3.14.2.30. LONGVARCHAR (String)

The [`LONGVARCHAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#LONGVARCHAR) data type represents a variable length string type, or [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) in Java, or [`Types.LONGVARCHAR`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#LONGVARCHAR) in JDBC.

This data type is mostly offered as a compatibility type as the difference between this type and other variable length binary types like [VARCHAR (String)](#data-type-varchar) and [CLOB (String)](#data-type-clob) is not very well defined.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", LONGVARCHAR)
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c longtext
)
```

###### ASE

```sql
CREATE TABLE t (
  c text NULL
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
CREATE TABLE t (
  c text
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake, Trino, YugabyteDB

```sql
CREATE TABLE t (
  c varchar
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(String)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c string
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, Hana, Informix

```sql
CREATE TABLE t (
  c clob
)
```

###### Exasol, H2, HSQLDB, SQLite

```sql
CREATE TABLE t (
  c longvarchar
)
```

###### Firebird

```sql
CREATE TABLE t (
  c varchar(4000)
)
```

###### Oracle

```sql
CREATE TABLE t (
  c varchar2(4000)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c string(2621440)
)
```

###### SQLDataWarehouse

```sql
CREATE TABLE t (
  c varchar(8000)
)
```

###### SQLServer

```sql
CREATE TABLE t (
  c varchar(max)
)
```

###### Sybase

```sql
CREATE TABLE t (
  c long varchar NULL
)
```

###### Teradata

```sql
CREATE TABLE t (
  c varchar(32000)
)
```

###### Vertica

```sql
CREATE TABLE t (
  c long varchar
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), LONGVARCHAR)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE

```sql
cast(
  c
  AS text
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS char
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Postgres, Redshift, Snowflake, Trino, YugabyteDB

```sql
cast(
  c
  AS varchar
)
```

###### BigQuery, Databricks, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(String)
)
```

###### DB2, Hana, Informix

```sql
cast(
  c
  AS clob
)
```

###### Exasol, H2, HSQLDB, SQLite

```sql
cast(
  c
  AS longvarchar
)
```

###### Firebird

```sql
cast(
  c
  AS varchar(4000)
)
```

###### Oracle

```sql
cast(
  c
  AS varchar2(4000)
)
```

###### SQLDataWarehouse

```sql
cast(
  c
  AS varchar(8000)
)
```

###### SQLServer

```sql
cast(
  c
  AS varchar(max)
)
```

###### Sybase, Vertica

```sql
cast(
  c
  AS long varchar
)
```

###### Teradata

```sql
cast(
  c
  AS varchar(32000)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-nchar"></a>
##### 3.14.2.31. NCHAR (String)

The [`NCHAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#NCHAR) data type represents a fixed length "national" (unicode) string type, or [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) in Java, or [`Types.NCHAR`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#NCHAR) in JDBC.

Given the fixed size characteristic, the `NCHAR` type should be accompanied by an explicit [length](#data-type-length) flag.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", NCHAR(3))
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c text(3)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c nchar(3) NULL
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c char(3)
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(char(3))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c char(3)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Exasol, H2, Hana, Informix, Oracle, SQLDataWarehouse, SQLServer, SQLite

```sql
CREATE TABLE t (
  c nchar(3)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c string(3)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), NCHAR(3))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Exasol, H2, Hana, Informix, SQLDataWarehouse, SQLServer, SQLite, Sybase

```sql
cast(
  c
  AS nchar(3)
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, Databricks, DuckDB, Firebird, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS char(3)
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(char(3))
)
```

###### DB2

```sql
cast(
  c
  AS varchar(3)
)
```

###### Oracle

```sql
cast(
  c
  AS nvarchar2(3)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-nclob"></a>
##### 3.14.2.32. NCLOB (String)

The [`NCLOB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#NCLOB) (National Character Large OBject) data type represents a variable length "national" (unicode) string type, or [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) in Java, or [`Types.NCLOB`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#NCLOB) in JDBC.

Some RDBMS support different variable size string types, where the `NCLOB` type allows for very big objects to be stored in separate storage. In those RDBMS, `NCLOB` may behave subtly differently from [NVARCHAR (String)](#data-type-nvarchar).

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", NCLOB)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
CREATE TABLE t (
  c longtext
)
```

###### ASE

```sql
CREATE TABLE t (
  c unitext NULL
)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
CREATE TABLE t (
  c text
)
```

###### BigQuery, DuckDB

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(varchar)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c string
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, Exasol, HSQLDB, Informix, Teradata, Vertica

```sql
CREATE TABLE t (
  c clob
)
```

###### Firebird

```sql
CREATE TABLE t (
  c blob sub_type text
)
```

###### H2, Hana, Oracle, SQLite

```sql
CREATE TABLE t (
  c nclob
)
```

###### Snowflake, Trino

```sql
CREATE TABLE t (
  c varchar
)
```

###### Spanner

```sql
CREATE TABLE t (
  c string(2621440)
)
```

###### SQLDataWarehouse

```sql
CREATE TABLE t (
  c nvarchar
)
```

###### SQLServer

```sql
CREATE TABLE t (
  c nvarchar(max)
)
```

###### Sybase

```sql
CREATE TABLE t (
  c ntext NULL
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), NCLOB)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE

```sql
cast(
  c
  AS unitext
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS char
)
```

###### Aurora Postgres, CockroachDB, Postgres, Redshift, YugabyteDB

```sql
cast(
  c
  AS text
)
```

###### BigQuery, Databricks, DuckDB, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(varchar)
)
```

###### DB2, Exasol, HSQLDB, Informix, Vertica

```sql
cast(
  c
  AS clob
)
```

###### Firebird

```sql
cast(
  c
  AS blob sub_type text
)
```

###### H2, Hana, SQLite

```sql
cast(
  c
  AS nclob
)
```

###### Oracle

```sql
to_clob(c)
```

###### Snowflake, Trino

```sql
cast(
  c
  AS varchar
)
```

###### SQLDataWarehouse

```sql
cast(
  c
  AS nvarchar
)
```

###### SQLServer

```sql
cast(
  c
  AS nvarchar(max)
)
```

###### Sybase

```sql
cast(
  c
  AS ntext
)
```

###### Teradata

```sql
cast(
  cast(
    c
    AS varchar(32000)
  )
  AS clob
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-numeric"></a>
##### 3.14.2.33. NUMERIC (BigDecimal)

The [`NUMERIC`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#NUMERIC) data type represents a decimal number, or [`java.math.BigDecimal`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/math/BigDecimal.html) in Java, or [`Types.NUMERIC`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#NUMERIC) in JDBC.

Given the variable precision characteristic, the `NUMERIC` type should usually be accompanied by explicit [precision](#data-type-precision) and [scale](#data-type-scale) flags. If absent, the default behaviour is dialect specific.

> [!TIP]
> For most practical purposes, the `NUMERIC` type is the same as the [DECIMAL](#data-type-decimal) type.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", NUMERIC(10, 5))
```

Translates to the following dialect specific expressions:

###### Access, Aurora Postgres, CockroachDB, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Teradata, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c numeric(10, 5)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c numeric(10, 5) NULL
)
```

###### Aurora MySQL, DB2, MariaDB, MemSQL, MySQL, Trino

```sql
CREATE TABLE t (
  c decimal(10, 5)
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c bignumeric
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(decimal(10, 5))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c numeric(10, 5)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Exasol, Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(10, 5)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), NUMERIC(10, 5))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Aurora Postgres, CockroachDB, Databricks, DuckDB, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Sybase, Teradata, Vertica, YugabyteDB

```sql
cast(
  c
  AS numeric(10, 5)
)
```

###### Aurora MySQL, DB2, MariaDB, MemSQL, MySQL, Trino

```sql
cast(
  c
  AS decimal(10, 5)
)
```

###### BigQuery

```sql
cast(
  c
  AS bignumeric
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(decimal(10, 5))
)
```

###### Exasol, Oracle, Snowflake

```sql
cast(
  c
  AS number(10, 5)
)
```

###### Spanner

```sql
cast(
  c
  AS numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-nvarchar"></a>
##### 3.14.2.34. NVARCHAR (String)

The [`NVARCHAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#NVARCHAR) data type represents a variable length "national" (unicode) string type, or [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) in Java, or [`Types.NVARCHAR`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#NVARCHAR) in JDBC.

Given the variable size characteristic, the `NVARCHAR` type may or may not be accompanied by an explicit [length](#data-type-length) flag. If absent, the default in most dialects is to set the maximum length available.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", NVARCHAR(16))
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c text(16)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c nvarchar(16) NULL
)
```

###### Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Firebird, HSQLDB, MariaDB, MemSQL, MySQL, Postgres, Redshift, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c varchar(16)
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(varchar(16))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c varchar(16)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Exasol, H2, Hana, Informix, SQLDataWarehouse, SQLServer, SQLite

```sql
CREATE TABLE t (
  c nvarchar(16)
)
```

###### Oracle

```sql
CREATE TABLE t (
  c nvarchar2(16)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c string(16)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), NVARCHAR(16))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Exasol, H2, Hana, Informix, SQLDataWarehouse, SQLServer, SQLite, Sybase

```sql
cast(
  c
  AS nvarchar(16)
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS char(16)
)
```

###### Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Firebird, HSQLDB, Postgres, Redshift, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS varchar(16)
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(varchar(16))
)
```

###### Oracle

```sql
cast(
  c
  AS nvarchar2(16)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-offsetdatetime"></a>
##### 3.14.2.35. OFFSETDATETIME (OffsetDateTime)

This type is just a synonym for [TIMESTAMP WITH TIME ZONE](#data-type-timestampwithtimezone).

<a id="data-type-offsettime"></a>
##### 3.14.2.36. OFFSETTIME (OffsetTime)

This type is just a synonym for [TIME WITH TIME ZONE](#data-type-timewithtimezone).

<a id="data-type-other"></a>
##### 3.14.2.37. OTHER (Object)

The [`OTHER`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#OTHER) data type represents any unsupported data type, which jOOQ cannot represent and/or bind natively, or [`java.lang.Object`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Object.html) in Java, or [`Types.OTHER`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#OTHER) in JDBC

> [!TIP]
> While certain JDBC types can occasionally be passed through jOOQ transparently without jOOQ knowing about them (e.g. PostgreSQL's `PGobject`), it is never a good idea to rely on this implicit behaviour. It is always better to design a [custom data type binding](#data-type-binding) in order to make the binding and data type conversion explicit.

Unlike other data types, this type acts as a placeholder. It cannot be used in [DDL statements](#ddl-statements) or [CAST expressions](#cast-expressions) directly.

<a id="data-type-real"></a>
##### 3.14.2.38. REAL (Float)

The [`REAL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#REAL) data type represents a 32 bit floating point number, or [`java.lang.Float`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Float.html) in Java, or [`Types.REAL`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#REAL) in JDBC

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", REAL)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c real
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c real NULL
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c float64
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(real)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c float
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Firebird

```sql
CREATE TABLE t (
  c float
)
```

###### Informix

```sql
CREATE TABLE t (
  c smallfloat
)
```

###### Spanner

```sql
CREATE TABLE t (
  c float32
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), REAL)
```

Translates to the following dialect specific expressions:

###### Access

```sql
csng(c)
```

###### ASE, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS real
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS decimal
)
```

###### BigQuery

```sql
cast(
  c
  AS float64
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(real)
)
```

###### Databricks, Firebird

```sql
cast(
  c
  AS float
)
```

###### Informix

```sql
cast(
  c
  AS smallfloat
)
```

###### Spanner

```sql
cast(
  c
  AS float32
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-record"></a>
##### 3.14.2.39. RECORD (Record)

The [`RECORD`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#RECORD) data type represents any nested record data type. It has no direct representation in JDBC.

Unlike other data types, this type acts as a placeholder for ad-hoc [nested record types](#nested-records). It cannot be used in [DDL statements](#ddl-statements) or [CAST expressions](#cast-expressions) directly.

<a id="data-type-result"></a>
##### 3.14.2.40. RESULT (Result)

The [`RECORD`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#RECORD) data type represents any nested record data type. It has no direct representation in JDBC.

Unlike other data types, this type acts as a placeholder for ad-hoc nested collection types such as e.g. [MULTISET nested collections](#multiset-value-constructor). It cannot be used in [DDL statements](#ddl-statements) or [CAST expressions](#cast-expressions) directly.

<a id="data-type-rowid"></a>
##### 3.14.2.41. ROWID (RowId)

The [`ROWID`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#ROWID) data type represents an unspecified length and typed rowid value, or [`org.jooq.RowId`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RowId.html) in Java, or [`Types.ROWID`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#ROWID) in JDBC

Unlike other data types, this type acts as a placeholder for rowid types. It cannot be used in [DDL statements](#ddl-statements) or [CAST expressions](#cast-expressions) directly.

<a id="data-type-smallint"></a>
##### 3.14.2.42. SMALLINT (Short)

The [`SMALLINT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#SMALLINT) data type represents a signed, 16 bit integer, or [`java.lang.Short`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Short.html) in Java, or [`Types.SMALLINT`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#SMALLINT) in JDBC

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", SMALLINT)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c smallint
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c smallint NULL
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c int64
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(smallint)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c smallint
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(5)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), SMALLINT)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cint(c)
```

###### ASE, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS smallint
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS signed
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS int64
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(smallint)
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(5)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-smallint-unsigned"></a>
##### 3.14.2.43. SMALLINT UNSIGNED (UShort)

The [`SMALLINT UNSIGNED`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#SMALLINTUNSIGNED) data type represents an unsigned, 16 bit integer, or [`org.jooq.types.UShort`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/UShort.html) in Java. It has no representation in JDBC.

> [!TIP]
> If unsigned support is unavailable in a dialect, jOOQ will just map the type to the next higher integer type [INTEGER UNSIGNED (UInteger)](#data-type-integer-unsigned).

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", SMALLINTUNSIGNED)
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c integer
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c unsigned smallint NULL
)
```

###### Aurora MySQL, BigQuery, DB2, Informix, MariaDB, MemSQL, MySQL, Trino

```sql
CREATE TABLE t (
  c smallint unsigned
)
```

###### Aurora Postgres, Exasol, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Teradata, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c int
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(UInt16)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE t (
  c int4
)
```

###### Databricks

```sql
CREATE TABLE t (
  c smallint unsigned
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DuckDB

```sql
CREATE TABLE t (
  c usmallint
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(5)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), SMALLINTUNSIGNED)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Sybase

```sql
cast(
  c
  AS unsigned smallint
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS unsigned
)
```

###### Aurora Postgres, Exasol, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Teradata, Vertica, YugabyteDB

```sql
cast(
  c
  AS int
)
```

###### BigQuery, DB2, Databricks, Informix, Trino

```sql
cast(
  c
  AS smallint unsigned
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(UInt16)
)
```

###### CockroachDB

```sql
cast(
  c
  AS int4
)
```

###### DuckDB

```sql
cast(
  c
  AS usmallint
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(5)
)
```

###### Spanner

```sql
cast(
  c
  AS numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-time"></a>
##### 3.14.2.44. TIME (Time)

The [`TIME`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#TIME) data type represents a local time type, or [`java.sql.Time`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Time.html) in Java, or [`Types.TIME`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#TIME) in JDBC.

Some dialects support an explicit [precision](#data-type-precision) flag on this data type. If absent, the default is dialect specific.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", TIME)
```

Translates to the following dialect specific expressions:

###### Access, Informix, SQLite

```sql
CREATE TABLE t (
  c datetime
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c time NULL
)
```

###### Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c time
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(time)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c time
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle

```sql
CREATE TABLE t (
  c timestamp
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), TIME)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdate(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS time
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(time)
)
```

###### Informix

```sql
cast(
  c
  AS datetime hour to second
)
```

###### Oracle

```sql
cast(
  c
  AS timestamp
)
```

###### SQLite

```sql
cast(
  c
  AS datetime
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-timestamp"></a>
##### 3.14.2.45. TIMESTAMP (Timestamp)

The [`TIMESTAMP`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#TIMESTAMP) data type represents a local date time type, or [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html) in Java, or [`Types.TIMESTAMP`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#TIMESTAMP) in JDBC.

Some dialects support an explicit [precision](#data-type-precision) flag on this data type. If absent, the default is dialect specific.

> [!TIP]
> For historic reasons, this data type was also capable of representing a [TIMESTAMP WITH TIME ZONE](#data-type-timestampwithtimezone) data type in JDBC, by making complicated use of [`java.util.Calendar`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Calendar.html) when binding the type to a [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html), or reading it from a [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html). jOOQ, however, treats it as a [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html) as suggested by various methods on the type, such as [`Timestamp.valueOf(LocalDateTime)`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html#valueOf(java.time.LocalDateTime)) or, more importantly, [`Timestamp.valueOf(String)`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html#valueOf(java.lang.String)), which is not capable of parsing time zone information.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", TIMESTAMP)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, BigQuery, MemSQL, MySQL, SQLDataWarehouse, SQLite

```sql
CREATE TABLE t (
  c datetime
)
```

###### ASE, MariaDB, Sybase

```sql
CREATE TABLE t (
  c datetime NULL
)
```

###### Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c timestamp
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(timestamp)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c timestamp_ntz
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DuckDB

```sql
CREATE TABLE t (
  c timestamp without time zone
)
```

###### Informix

```sql
CREATE TABLE t (
  c datetime year to fraction(5)
)
```

###### Snowflake

```sql
CREATE TABLE t (
  c timestamp_ntz
)
```

###### SQLServer

```sql
CREATE TABLE t (
  c datetime2
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), TIMESTAMP)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdate(c)
```

###### ASE, Aurora MySQL, BigQuery, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLite, Sybase

```sql
cast(
  c
  AS datetime
)
```

###### Aurora Postgres, CockroachDB, DB2, Exasol, Firebird, H2, HSQLDB, Hana, Oracle, Postgres, Redshift, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS timestamp
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(timestamp)
)
```

###### Databricks, Snowflake

```sql
cast(
  c
  AS timestamp_ntz
)
```

###### DuckDB

```sql
cast(
  c
  AS timestamp without time zone
)
```

###### Informix

```sql
cast(
  cast(
    c
    AS datetime year to fraction(5)
  )
  AS datetime year to fraction(5)
)
```

###### SQLServer

```sql
cast(
  c
  AS datetime2
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-timestampwithtimezone"></a>
##### 3.14.2.46. TIMESTAMP WITH TIME ZONE (OffsetDateTime)

The [`TIMESTAMP WITH TIME ZONE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#TIMESTAMPWITHTIMEZONE) data type represents an offset date time type, or [`java.time.OffsetDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetDateTime.html) in Java, or [`Types.TIMESTAMP_WITH_TIMEZONE`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#TIMESTAMP_WITH_TIMEZONE) in JDBC.

Some dialects support an explicit [precision](#data-type-precision) flag on this data type. If absent, the default is dialect specific.

> [!TIP]
> JDBC's standardisation of this type to [`java.time.OffsetDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetDateTime.html) is controversial as it is arguably the least useful representation of a "timestamp with time zone", compared to [`java.time.Instant`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/Instant.html) (supported by jOOQ via [INSTANT (Instant)](#data-type-instant)) or [`java.time.ZonedDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/ZonedDateTime.html) (not currently supported by jOOQ, out of the box.) Users can override jOOQ's default by applying a [Forced type](#codegen-database-forced-types) configuration to their code generation setup, if they wish to change the default behaviour.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", TIMESTAMPWITHTIMEZONE)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c timestamp with time zone
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c timestamp with time zone NULL
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c timestamp
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(timestamp with time zone)
)
ENGINE Log()
```

###### CockroachDB

```sql
CREATE TABLE t (
  c timestamptz
)
```

###### Databricks

```sql
CREATE TABLE t (
  c timestamp
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Snowflake

```sql
CREATE TABLE t (
  c timestamp_tz
)
```

###### SQLDataWarehouse, SQLServer

```sql
CREATE TABLE t (
  c datetimeoffset
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), TIMESTAMPWITHTIMEZONE)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Oracle, Postgres, Redshift, SQLite, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS timestamp with time zone
)
```

###### BigQuery, Databricks, Spanner

```sql
cast(
  c
  AS timestamp
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(timestamp with time zone)
)
```

###### CockroachDB

```sql
cast(
  c
  AS timestamptz
)
```

###### Snowflake

```sql
cast(
  c
  AS timestamp_tz
)
```

###### SQLDataWarehouse, SQLServer

```sql
cast(
  c
  AS datetimeoffset
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-timewithtimezone"></a>
##### 3.14.2.47. TIME WITH TIME ZONE (OffsetTime)

The [`TIME WITH TIME ZONE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#TIMEWITHTIMEZONE) data type represents an offset date time type, or [`java.time.OffsetTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetTime.html) in Java, or [`Types.TIME_WITH_TIMEZONE`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#TIME_WITH_TIMEZONE) in JDBC.

Some dialects support an explicit [precision](#data-type-precision) flag on this data type. If absent, the default is dialect specific.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", TIMEWITHTIMEZONE)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c time with time zone
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c time with time zone NULL
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(time with time zone)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c time with time zone
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle

```sql
CREATE TABLE t (
  c timestamp with time zone
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), TIMEWITHTIMEZONE)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS time with time zone
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(time with time zone)
)
```

###### Oracle

```sql
cast(
  c
  AS timestamp with time zone
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-tinyint"></a>
##### 3.14.2.48. TINYINT (Byte)

The [`TINYINT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#TINYINT) data type represents a signed, 8 bit integer, or [`java.lang.Byte`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Byte.html) in Java, or [`Types.TINYINT`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#TINYINT) in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", TINYINT)
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse

```sql
CREATE TABLE t (
  c signed tinyint
)
```

###### ASE

```sql
CREATE TABLE t (
  c signed tinyint NULL
)
```

###### Aurora MySQL, DuckDB, Exasol, H2, HSQLDB, MariaDB, MemSQL, MySQL, SQLServer, SQLite, Trino, Vertica

```sql
CREATE TABLE t (
  c tinyint
)
```

###### Aurora Postgres, CockroachDB, DB2, Firebird, Hana, Informix, Postgres, Redshift, YugabyteDB

```sql
CREATE TABLE t (
  c smallint
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c int64
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(tinyint)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c tinyint
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(3)
)
```

###### Sybase

```sql
CREATE TABLE t (
  c tinyint NULL
)
```

###### Teradata

```sql
CREATE TABLE t (
  c byteint
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), TINYINT)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cbyte(c)
```

###### ASE, Databricks, DuckDB, Exasol, H2, HSQLDB, SQLDataWarehouse, SQLServer, SQLite, Sybase, Trino, Vertica

```sql
cast(
  c
  AS tinyint
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS signed
)
```

###### Aurora Postgres, CockroachDB, DB2, Firebird, Hana, Informix, Postgres, Redshift, YugabyteDB

```sql
cast(
  c
  AS smallint
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS int64
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(tinyint)
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(3)
)
```

###### Teradata

```sql
cast(
  c
  AS byteint
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-tinyint-unsigned"></a>
##### 3.14.2.49. TINYINT UNSIGNED (UByte)

The [`TINYINT UNSIGNED`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#TINYINTUNSIGNED) data type represents an unsigned, 8 bit integer, or [`org.jooq.types.UByte`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/UByte.html) in Java. It has no representation in JDBC.

> [!TIP]
> If unsigned support is unavailable in a dialect, jOOQ will just map the type to the next higher integer type [SMALLINT UNSIGNED (UShort)](#data-type-smallint-unsigned).

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", TINYINTUNSIGNED)
```

Translates to the following dialect specific expressions:

###### Access, Hana, SQLDataWarehouse, SQLServer

```sql
CREATE TABLE t (
  c tinyint
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c tinyint NULL
)
```

###### Aurora MySQL, BigQuery, DB2, Informix, MariaDB, MemSQL, MySQL, Trino

```sql
CREATE TABLE t (
  c tinyint unsigned
)
```

###### Aurora Postgres, CockroachDB, Exasol, Firebird, H2, HSQLDB, Postgres, Redshift, SQLite, Teradata, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c smallint
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(UInt8)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c tinyint unsigned
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DuckDB

```sql
CREATE TABLE t (
  c utinyint
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number(3)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), TINYINTUNSIGNED)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cdec(c)
```

###### ASE, Hana, SQLDataWarehouse, SQLServer, Sybase

```sql
cast(
  c
  AS tinyint
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS unsigned
)
```

###### Aurora Postgres, CockroachDB, Exasol, Firebird, H2, HSQLDB, Postgres, Redshift, SQLite, Teradata, Vertica, YugabyteDB

```sql
cast(
  c
  AS smallint
)
```

###### BigQuery, DB2, Databricks, Informix, Trino

```sql
cast(
  c
  AS tinyint unsigned
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(UInt8)
)
```

###### DuckDB

```sql
cast(
  c
  AS utinyint
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(3)
)
```

###### Spanner

```sql
cast(
  c
  AS numeric
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-uuid"></a>
##### 3.14.2.50. UUID (UUID)

The [`UUID`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#UUID) data type represents a `UUID` value, or [`java.util.UUID`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/UUID.html) in Java. It has no representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", UUID)
```

Translates to the following dialect specific expressions:

###### Access, SQLDataWarehouse, SQLServer

```sql
CREATE TABLE t (
  c uniqueidentifier
)
```

###### ASE

```sql
CREATE TABLE t (
  c varchar(36) NULL
)
```

###### Aurora MySQL, DB2, Firebird, Hana, MariaDB, MemSQL, MySQL, SQLite, Snowflake, Teradata, Vertica

```sql
CREATE TABLE t (
  c varchar(36)
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Exasol, H2, HSQLDB, Postgres, Redshift, Trino, YugabyteDB

```sql
CREATE TABLE t (
  c uuid
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(UUID)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c varchar(36)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Informix

```sql
CREATE TABLE t (
  c lvarchar(36)
)
```

###### Oracle

```sql
CREATE TABLE t (
  c varchar2(36)
)
```

###### Spanner

```sql
CREATE TABLE t (
  c string(36)
)
```

###### Sybase

```sql
CREATE TABLE t (
  c uniqueidentifier NULL
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), UUID)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, SQLite, Teradata

```sql
cast(
  c
  AS varchar
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS char
)
```

###### Aurora Postgres, CockroachDB, DuckDB, Exasol, H2, HSQLDB, Postgres, Redshift, Trino, YugabyteDB

```sql
cast(
  c
  AS uuid
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(UUID)
)
```

###### DB2, Databricks, Firebird, Hana, Informix, Vertica

```sql
cast(
  c
  AS varchar(36)
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS varchar2(36)
)
```

###### SQLDataWarehouse, SQLServer, Sybase

```sql
cast(
  c
  AS uniqueidentifier
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-varbinary"></a>
##### 3.14.2.51. VARBINARY (byte[])

The [`VARBINARY`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#VARBINARY) data type represents a variable length binary type, or `byte[]` in Java, or [`Types.VARBINARY`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#VARBINARY) in JDBC.

Given the variable size characteristic, the `VARBINARY` type may or may not be accompanied by an explicit [length](#data-type-length) flag. If absent, the default in most dialects is to set the maximum length available.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", VARBINARY(16))
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c binary(16)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c varbinary(16) NULL
)
```

###### Aurora MySQL, Exasol, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, SQLDataWarehouse, SQLServer, Snowflake, Vertica

```sql
CREATE TABLE t (
  c varbinary(16)
)
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
CREATE TABLE t (
  c bytea
)
```

###### BigQuery, CockroachDB

```sql
CREATE TABLE t (
  c bytes
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(varbinary(16))
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c binary
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### DB2, Firebird, SQLite

```sql
CREATE TABLE t (
  c blob(16)
)
```

###### DuckDB, Trino

```sql
CREATE TABLE t (
  c varbinary
)
```

###### Informix

```sql
CREATE TABLE t (
  c byte
)
```

###### Oracle

```sql
CREATE TABLE t (
  c raw(16)
)
```

###### Redshift

```sql
CREATE TABLE t (
  c varbyte
)
```

###### Spanner

```sql
CREATE TABLE t (
  c bytes(16)
)
```

###### Teradata

```sql
CREATE TABLE t (
  c varbyte(16)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), VARBINARY(16))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Exasol, H2, HSQLDB, Hana, SQLDataWarehouse, SQLServer, Snowflake, Sybase, Vertica

```sql
cast(
  c
  AS varbinary(16)
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS binary(16)
)
```

###### Aurora Postgres, Postgres, YugabyteDB

```sql
cast(
  c
  AS bytea
)
```

###### BigQuery, CockroachDB, Spanner

```sql
cast(
  c
  AS bytes
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(varbinary(16))
)
```

###### Databricks

```sql
cast(
  c
  AS binary
)
```

###### DB2, Firebird, SQLite

```sql
cast(
  c
  AS blob(16)
)
```

###### DuckDB, Trino

```sql
cast(
  c
  AS varbinary
)
```

###### Informix

```sql
cast(
  c
  AS byte
)
```

###### Oracle

```sql
to_blob(c)
```

###### Redshift

```sql
cast(
  c
  AS varbyte
)
```

###### Teradata

```sql
cast(
  c
  AS varbyte(16)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-varchar"></a>
##### 3.14.2.52. VARCHAR (String)

The [`VARCHAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#VARCHAR) data type represents a variable length string type, or [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html) in Java, or [`Types.VARCHAR`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#VARCHAR) in JDBC.

Given the variable size characteristic, the `VARCHAR` type may or may not be accompanied by an explicit [length](#data-type-length) flag. If absent, the default in most dialects is to set the maximum length available.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", VARCHAR(16))
```

Translates to the following dialect specific expressions:

###### Access

```sql
CREATE TABLE t (
  c text(16)
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c varchar(16) NULL
)
```

###### Aurora MySQL, Aurora Postgres, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c varchar(16)
)
```

###### BigQuery

```sql
CREATE TABLE t (
  c string
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(String(16))
)
ENGINE Log()
```

###### CockroachDB, Spanner

```sql
CREATE TABLE t (
  c string(16)
)
```

###### Databricks

```sql
CREATE TABLE t (
  c varchar(16)
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Informix

```sql
CREATE TABLE t (
  c lvarchar(16)
)
```

###### Oracle

```sql
CREATE TABLE t (
  c varchar2(16)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), VARCHAR(16))
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora Postgres, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS varchar(16)
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS char(16)
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS string
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(String(16))
)
```

###### CockroachDB

```sql
cast(
  c
  AS string(16)
)
```

###### Informix

```sql
cast(
  c
  AS lvarchar(16)
)
```

###### Oracle

```sql
cast(
  c
  AS varchar2(16)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-xml"></a>
##### 3.14.2.53. XML (XML)

The [`XML`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#XML) data type represents an XML document, or [`org.jooq.XML`](https://www.jooq.org/javadoc/3.22.x/org/jooq/XML.html) in Java, or [`Types.SQLXML`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Types.html#SQLXML) in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", XML)
```

Translates to the following dialect specific expressions:

###### Access, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c xml
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c xml NULL
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(xml)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c xml
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle

```sql
CREATE TABLE t (
  c xmltype
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), XML)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora MySQL, Aurora Postgres, BigQuery, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, MariaDB, MemSQL, MySQL, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Snowflake, Spanner, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS xml
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(xml)
)
```

###### Oracle

```sql
xmltype(c)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="data-type-year"></a>
##### 3.14.2.54. YEAR (Year)

The [`YEAR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html#YEAR) data type represents a `YEAR` value, or [`java.time.Year`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/Year.html) in Java. It has no representation in JDBC.

###### DDL support

###### Dialect support

This example using jOOQ:

```java
createTable("t").column("c", YEAR)
```

Translates to the following dialect specific expressions:

###### Access, Aurora Postgres, CockroachDB, DB2, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Teradata, Trino, Vertica, YugabyteDB

```sql
CREATE TABLE t (
  c smallint
)
```

###### ASE, Sybase

```sql
CREATE TABLE t (
  c smallint NULL
)
```

###### Aurora MySQL, MariaDB, MemSQL, MySQL

```sql
CREATE TABLE t (
  c year
)
```

###### BigQuery, Spanner

```sql
CREATE TABLE t (
  c int64
)
```

###### ClickHouse

```sql
CREATE TABLE t (
  c Nullable(smallint)
)
ENGINE Log()
```

###### Databricks

```sql
CREATE TABLE t (
  c smallint
)
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.feature.allowColumnDefaults' = 'supported'
)
```

###### Oracle, Snowflake

```sql
CREATE TABLE t (
  c number
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

###### Cast support

###### Dialect support

This example using jOOQ:

```java
cast(field("c"), YEAR)
```

Translates to the following dialect specific expressions:

###### Access

```sql
cstr(c)
```

###### ASE, Aurora Postgres, CockroachDB, DB2, Databricks, DuckDB, Exasol, Firebird, H2, HSQLDB, Hana, Informix, Postgres, Redshift, SQLDataWarehouse, SQLServer, SQLite, Sybase, Teradata, Trino, Vertica, YugabyteDB

```sql
cast(
  c
  AS smallint
)
```

###### Aurora MySQL

```sql
cast(
  c
  AS year
)
```

###### BigQuery, Spanner

```sql
cast(
  c
  AS int64
)
```

###### ClickHouse

```sql
cast(
  c
  AS Nullable(smallint)
)
```

###### MariaDB, MemSQL, MySQL

```sql
cast(
  c
  AS signed
)
```

###### Oracle, Snowflake

```sql
cast(
  c
  AS number(4)
)
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="extended-data-types"></a>
#### 3.14.3. Extended data types

Some RDBMS support additional data types that are very specific to that RDBMS, such that jOOQ does not offer support for them from the core library. Additional extension modules can be used to import:

- [Data type converters](#data-type-converter) for simple cases
- [Data type bindings](#data-type-binding) to ensure optimal JDBC interaction
- [Data type formatters](#data-type-formatter) to help embed extended types in certain built-in types, such as [JSON (JSON)](#data-type-json) or [XML (XML)](#data-type-xml).

<a id="extended-type-pg-cidr"></a>
##### 3.14.3.1. PostgreSQL CIDR type

The `CIDR` type stores an IPv4 or IPv6 network specification, such as `192.168.1.0/24`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.Cidr` type that exposes the data structure in form of a [`java.net.InetAddress`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/InetAddress.html) and [`java.lang.Integer`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Integer.html) prefix.

```java
Cidr cidr = create.fetchValue(T.CIDR, T.ID.eq(id));
InetAddress value = cidr.address();
Integer prefix = cidr.prefix();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-citext"></a>
##### 3.14.3.2. PostgreSQL CITEXT type

The `CITEXT` type stands for "case insensitive text," which simplifies handling scenarios where case insensitive comparisons are made frequently while still storing and projecting the original case. There is no special data type to represent a `CITEXT` column in Java, it's just a [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html).

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-daterange"></a>
##### 3.14.3.3. PostgreSQL DATERANGE type

The `DATERANGE` type stores an open or closed interval of [DATE](#data-type-date) values, such as `[2010-01-01, 2011-01-01)`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.DateRange` or `org.jooq.postgres.extensions.types.LocalDateRange` type (depending on the [javaTimeTypes code generation flag](#codegen-generate-java-time-types)) that exposes the data structure in form of a set of bounds and flags.

```java
LocalDateRange range = create.fetchValue(T.DATERANGE, T.ID.eq(id));
LocalDate lower = range.lower();
LocalDate upper = range.upper();
boolean lowerIncluding = range.lowerIncluding();
boolean upperIncluding = range.upperIncluding();
boolean empty = range.isEmpty();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-hstore"></a>
##### 3.14.3.4. PostgreSQL HSTORE type

The `HSTORE` type stores a key value store of the form `key1 => value1, key2 => value2`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.Hstore` type that exposes the data structure in form of a `Map<String, String>`

```java
Hstore store = create.fetchValue(T.HSTORE, T.ID.eq(id));
Map<String, String> value = store.data();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-inet"></a>
##### 3.14.3.5. PostgreSQL INET type

The `INET` type stores an IPv4 or IPv6 address, such as `192.168.1.1`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.Inet` type that exposes the data structure in form of a [`java.net.InetAddress`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/InetAddress.html)

```java
Inet inet = create.fetchValue(T.INET, T.ID.eq(id));
InetAddress value = inet.address();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-int4range"></a>
##### 3.14.3.6. PostgreSQL INT4RANGE type

The `INT4RANGE` type stores an open or closed interval of [INTEGER](#data-type-integer) values, such as `[0, 10)`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.IntegerRange` type that exposes the data structure in form of a set of bounds and flags.

```java
IntegerRange range = create.fetchValue(T.INT4RANGE, T.ID.eq(id));
Integer lower = range.lower();
Integer upper = range.upper();
boolean lowerIncluding = range.lowerIncluding();
boolean upperIncluding = range.upperIncluding();
boolean empty = range.isEmpty();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-int8range"></a>
##### 3.14.3.7. PostgreSQL INT8RANGE type

The `INT8RANGE` type stores an open or closed interval of [BIGINT](#data-type-bigint) values, such as `[0, 10)`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.LongRange` type that exposes the data structure in form of a set of bounds and flags.

```java
LongRange range = create.fetchValue(T.INT8RANGE, T.ID.eq(id));
Long lower = range.lower();
Long upper = range.upper();
boolean lowerIncluding = range.lowerIncluding();
boolean upperIncluding = range.upperIncluding();
boolean empty = range.isEmpty();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-ltree"></a>
##### 3.14.3.8. PostgreSQL LTREE type

The `LTREE` type stores a set of labels in a hierarchical, tree like data structure, such as `Label1.Label2.Label3`, or with a more specific example, `Countries.Europe.Switzerland`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.Ltree` type that exposes the data structure in form of a [`java.lang.String`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/String.html).

```java
Ltree ltree = create.fetchValue(T.LTREE, T.ID.eq(id));
String value = ltree.data();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-numrange"></a>
##### 3.14.3.9. PostgreSQL NUMRANGE type

The `NUMRANGE` type stores an open or closed interval of [NUMERIC](#data-type-numeric) values, such as `[0.0, 10.0)`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.BigDecimalRange` type that exposes the data structure in form of a set of bounds and flags.

```java
BigDecimalRange range = create.fetchValue(T.NUMRANGE, T.ID.eq(id));
BigDecimal lower = range.lower();
BigDecimal upper = range.upper();
boolean lowerIncluding = range.lowerIncluding();
boolean upperIncluding = range.upperIncluding();
boolean empty = range.isEmpty();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-tsrange"></a>
##### 3.14.3.10. PostgreSQL TSRANGE type

The `TSRANGE` type stores an open or closed interval of [TIMESTAMP](#data-type-timestamp) values, such as `[2010-01-01 00:00:00, 2011-01-01 00:00:00)`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.TimestampRange` or `org.jooq.postgres.extensions.types.LocalDateTimeRange` type (depending on the [javaTimeTypes code generation flag](#codegen-generate-java-time-types)) that exposes the data structure in form of a set of bounds and flags.

```java
LocalDateTimeRange range = create.fetchValue(T.TSRANGE, T.ID.eq(id));
LocalDateTime lower = range.lower();
LocalDateTime upper = range.upper();
boolean lowerIncluding = range.lowerIncluding();
boolean upperIncluding = range.upperIncluding();
boolean empty = range.isEmpty();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="extended-type-pg-tstzrange"></a>
##### 3.14.3.11. PostgreSQL TSTZRANGE type

The `TSTZRANGE` type stores an open or closed interval of [TIMESTAMP WITH TIME ZONE](#data-type-timestampwithtimezone) values, such as `[2010-01-01 00:00:00+02:00, 2011-01-01 00:00:00+02:00)`. jOOQ offers support for this type via a `org.jooq.postgres.extensions.types.OffsetDateTimeRange` type that exposes the data structure in form of a set of bounds and flags.

```java
OffsetDateTimeRange range = create.fetchValue(T.TSTZRANGE, T.ID.eq(id));
OffsetDateTime lower = range.lower();
OffsetDateTime upper = range.upper();
boolean lowerIncluding = range.lowerIncluding();
boolean upperIncluding = range.upperIncluding();
boolean empty = range.isEmpty();
```

> [!TIP]
> Support for this data type is included in the [jooq-postgres-extensions](#codegen-extension-postgres) module.

<a id="enum-data-types"></a>
#### 3.14.4. Enum data types

Enumerated data types are a vendor specific SQL feature by some RDBMS that allow for adding a constraint like restriction to a [VARCHAR](#data-type-varchar) column. PostgreSQL style enum types can be created using the [CREATE TYPE .. AS ENUM statement](#create-type-statement).

There are mainly two flavours:

```sql
// PostgreSQL: Explicit, reusable types
CREATE TYPE day_of_week AS ENUM ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');
CREATE TABLE t (day_of_week day_of_week);

// MySQL: Implicit, ad-hoc types
CREATE TABLE t (day_of_week ENUM ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'));
```

In both cases, a [`org.jooq.EnumType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EnumType.html) class is generated by the code generator, containing type information as well as the enum literals.

```java
public enum DayOfWeek implements EnumType {
    Mon("Mon"),
    Tue("Tue"),
    Wed("Wed"),
    Thu("Thu"),
    Fri("Fri"),
    Sat("Sat"),
    Sun("Sun");
    
    // ...
}
```

Even without code generation, any `enum` type that also implements jOOQ's [`org.jooq.EnumType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EnumType.html) can be used to construct a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html):

```java
DataType<DayOfWeek> dayOfWeekType = VARCHAR.asEnumDataType(DayOfWeek.class);
```

And then, the type can be attached to any expression, e.g. if generated code is not available:

```java
// Plain SQL template based
Field<DayOfWeek> f1 = DSL.field("my_table.day_of_week", emailType);

// Name based
Field<DayOfWeek> f2 = DSL.field(name("my_table", "day_of_week"), emailType);
```

<a id="domain-data-types"></a>
#### 3.14.5. Domain data types

A `DOMAIN` type is a standard SQL way of declaring a type name to be associated with a set of restrictions on existing types, typically on [Built-in data types](#built-in-data-types). Domain types can be created using the [CREATE DOMAIN statement](#create-domain-statement). The simplest type just declares the base type it enhances, without any additional clauses or constraints:

```sql
CREATE DOMAIN email AS VARCHAR(256)
```

To get a hold of the backing `DataType<String>` for this domain type, the generated code can be used as follows:

```java
DataType<String> emailType = Domains.EMAIL.getDataType();
```

Additional type safety can be achieved using [embedded domains](#codegen-embedded-domains), in case of which:

```java
DataType<EmailRecord> emailType = Domains.EMAIL.getDataType();
```

<a id="user-defined-data-types"></a>
#### 3.14.6. User-defined data types (UDTs)

jOOQ has rich support for User-defined data types (UDTs) via [CREATE TYPE](#create-composite-type-statement) statement as well via [code generation](#codegen-udts). When generating code for a UDT as follows:

```sql
CREATE TYPE point (x double precision, y double precision)
```

... then, not only will there be a `Point` ([`org.jooq.UDT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDT.html)) and `PointRecord` ([`org.jooq.UDTRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDTRecord.html)) generated, but also a `DataType<PointRecord>` is available for use in expressions of type `PointRecord`, wherever this UDT is referenced.

<a id="converted-data-types"></a>
#### 3.14.7. Converted data types

A converted data type is a type that is being converted to some user data structure, which can be independent of any data structures from the database. There are tons of use-cases for converted data types:

- To attach more semantic types to certain primitives, e.g. `Email` instead of just `String` (see also [DOMAIN types](#domain-data-types) to do this directly within the database)
- To increase type safety, and to avoid comparing two seemingly related types (`VARCHAR` and `VARCHAR`), which aren't really comparable (e.g. `Email` and `Username`)
- To work with libraries instead of raw data, e.g. JAXB or Jackson bindings instead of [raw XML types](#data-type-xml) or [raw JSON types](#data-type-json) or GeoTools or JTS instead of jOOQ's simple [GEOMETRY type](#data-type-geometry)

<a id="data-type-converter"></a>
##### 3.14.7.1. Custom data type Converter

A converted data type is a simple `DataType<U<` where a `Converter<T, U>` converts from some [Built-in data types](#built-in-data-types) to a custom data type. The simplest way to get a `DataType<U<` reference is by calling:

```java
dataType.asConvertedDataType(converter)
```

Where a [`org.jooq.Converter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html) must implement at least these four methods:

```java
public interface Converter<T, U> {

    // Your conversion logic goes into these two methods, that can convert
    // between the database type T and the user type U in both directions:
    U from(T databaseObject);
    T to(U userObject);

    // You need to provide Class instances for each type, too:
    Class<T> fromType();
    Class<U> toType();
}
```

Or, using a specific example:

```java
record Email(String email) {}

// Using a simpler, functional API:
Converter<String, Email> emailConverter = Converter.of(
    String.class, 
    Email.class,
    
    // Converting String -> Email 
    Email::new, 
    
    // Converting Email -> String
    Email::email
);

DataType<Email> emailType = VARCHAR.asConvertedDataType(emailConverter);
```

In most practical cases, the `DataType<U<` does not need to be denoted like this. Instead, a re-usable `Converter` class is attached to the generated `EMAIL` columns throughout the schema using [forced types](#codegen-database-forced-types) configuration. However, when using [plain SQL](#plain-sql), this API usage can be useful:

```java
// Plain SQL template based
Field<Email> f1 = DSL.field("my_table.my_email_column", emailType);

// Name based
Field<Email> f2 = DSL.field(name("my_table", "my_email_column"), emailType);
```

> [!TIP]
> In many cases, converters are single use and single direction only (e.g. fetching only). In those cases, there exists convenience API that is much less verbose to use, see [ad-hoc converters](#ad-hoc-converter) for details.

<a id="data-type-binding"></a>
##### 3.14.7.2. Custom data type Binding

While converters are very useful for simple use-cases, [`org.jooq.Binding`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Binding.html) is useful when you need to customise data type interactions at a JDBC level, e.g. when you want to bind a PostgreSQL JSON data type. Custom bindings implement the following SPI:

```java
public interface Binding<T, U> extends Serializable {

    // A converter that does the conversion between the database type T
    // and the user type U (see previous examples)
    Converter<T, U> converter();

    // A callback that generates the SQL string for bind values of this
    // binding type. Typically, just ?, but also ?::json, etc.
    void sql(BindingSQLContext<U> ctx) throws SQLException;

    // Callbacks that implement all interaction with JDBC types, such as
    // PreparedStatement, CallableStatement, SQLOutput, SQLinput, ResultSet
    void register(BindingRegisterContext<U> ctx) throws SQLException;
    void set(BindingSetStatementContext<U> ctx) throws SQLException;
    void set(BindingSetSQLOutputContext<U> ctx) throws SQLException;
    void get(BindingGetResultSetContext<U> ctx) throws SQLException;
    void get(BindingGetStatementContext<U> ctx) throws SQLException;
    void get(BindingGetSQLInputContext<U> ctx) throws SQLException;
}
```

Below is full fledged example implementation that uses Google Gson to model JSON documents in Java

```java
// We're binding <T> = JSON (or JSONB), and <U> = JsonElement (user type)
// Alternatively, extend org.jooq.impl.AbstractBinding to implement fewer methods.
public class PostgresJSONGsonBinding implements Binding<JSON, JsonElement> {

    private final Gson gson = new Gson();

    // The converter does all the work
    @Override
    public Converter<JSON, JsonElement> converter() {
        return new Converter<JSON, JsonElement>() {
            @Override
            public JsonElement from(JSON t) {
                return t == null ? JsonNull.INSTANCE : gson.fromJson(t.data(), JsonElement.class);
            }

            @Override
            public JSON to(JsonElement u) {
                return u == null || u == JsonNull.INSTANCE ? null : JSON.json(gson.toJson(u));
            }

            @Override
            public Class<JSON> fromType() {
                return JSON.class;
            }

            @Override
            public Class<JsonElement> toType() {
                return JsonElement.class;
            }
        };
    }

    // Rending a bind variable for the binding context's value and casting it to the json type
    @Override
    public void sql(BindingSQLContext<JsonElement> ctx) throws SQLException {
        // Depending on how you generate your SQL, you may need to explicitly distinguish
        // between jOOQ generating bind variables or inlined literals.
        if (ctx.render().paramType() == ParamType.INLINED)
            ctx.render().visit(DSL.inline(ctx.convert(converter()).value())).sql("::json");
        else
            ctx.render().sql(ctx.variable()).sql("::json");
    }

    // Registering VARCHAR types for JDBC CallableStatement OUT parameters
    @Override
    public void register(BindingRegisterContext<JsonElement> ctx) throws SQLException {
        ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR);
    }

    // Converting the JsonElement to a String value and setting that on a JDBC PreparedStatement
    @Override
    public void set(BindingSetStatementContext<JsonElement> ctx) throws SQLException {
        JSON json = ctx.convert(converter()).value();
        ctx.statement().setString(ctx.index(), json == null ? null : json.data());
    }

    // Getting a String value from a JDBC ResultSet and converting that to a JsonElement
    @Override
    public void get(BindingGetResultSetContext<JsonElement> ctx) throws SQLException {
        ctx.convert(converter()).value(JSON.json(ctx.resultSet().getString(ctx.index())));
    }

    // Getting a String value from a JDBC CallableStatement and converting that to a JsonElement
    @Override
    public void get(BindingGetStatementContext<JsonElement> ctx) throws SQLException {
        ctx.convert(converter()).value(JSON.json(ctx.statement().getString(ctx.index())));
    }

    // Setting a value on a JDBC SQLOutput (useful for Oracle OBJECT types)
    @Override
    public void set(BindingSetSQLOutputContext<JsonElement> ctx) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    // Getting a value from a JDBC SQLInput (useful for Oracle OBJECT types)
    @Override
    public void get(BindingGetSQLInputContext<JsonElement> ctx) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }
}
```

Just like with simple [Converters](#data-type-converter), a [`org.jooq.Binding`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Binding.html) can be attached to a [column expression](#column-expressions) either directly in the code generator using [forced types](#codegen-database-forced-types) configuration, or explictly, e.g. when constructing [plain SQL](#plain-sql) expressions:

```java
// Construct the DataType:
DataType<JsonElement> jsonElementType = JSON.asConvertedDataType(new PostgresJSONGsonBinding());
                                            
// Plain SQL template based
Field<JsonElement> f1 = DSL.field("my_table.my_json_column", jsonElementType);

// Name based
Field<JsonElement> f2 = DSL.field(name("my_table", "my_json_column"), jsonElementType);
```

<a id="data-type-formatter"></a>
##### 3.14.7.3. Custom data type Formatter

When working with [bindings](#data-type-binding) for advanced, vendor-specific types, it is not unlikely that the default embeddings in [JSON types](#data-type-json) or [XML types](#data-type-xml) is inadequate, or not implemented. For example, in PostgreSQL, when embedding a spatial type in a JSON or XML document, it simply doesn't behave:

```sql
SELECT 
  JSON_ARRAY(CAST('point (1 1)' AS geometry)),
  XMLELEMENT(NAME e, CAST('point (1 1)' AS geometry))
```

This produces:

```text
+------------------------------------------------+---------------------------------------------------+
| json_array                                     | xmlelement                                        |
+------------------------------------------------+---------------------------------------------------+
| "[{\"type\":\"Point\",\"coordinates\":[1,1]}]" | <e>0101000000000000000000F03F000000000000F03F</e> |
+------------------------------------------------+---------------------------------------------------+
```

This produces GeoJSON and WKB representations, respectively, because, why not. What if we wanted a WKT/WKB representation in both cases, though? A [`org.jooq.Formatter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Formatter.html) implementation can help:

```java
public class SpatialFormatter implements Formatter {

        @Override
        public final void formatJSON(FormatterContext ctx) {
            ctx.field(ctx.field().cast(CLOB));
        }

        @Override
        public final void formatJSONB(FormatterContext ctx) {
            formatJSON(ctx);
        }

        @Override
        public final void formatXML(FormatterContext ctx) {
        }
    }
```

This simple `Formatter`, if attached to a [`org.jooq.Binding`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Binding.html) for [GEOMETRY types](#data-type-geometry), ensures that any reference to a [`org.jooq.Geometry`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Geometry.html) typed `Field` will be wrapped in a `CAST(.. AS TEXT)` expression. So, the SQL generated instead would be:

```sql
SELECT 
  JSON_ARRAY(CAST(CAST('point (1 1)' AS geometry) AS text)),
  XMLELEMENT(NAME e, CAST('point (1 1)' AS geometry))
```

Resulting in:

```text
+----------------------------------------------------+---------------------------------------------------+
| json_array                                         | xmlelement                                        |
+----------------------------------------------------+---------------------------------------------------+
| "[\"0101000000000000000000F03F000000000000F03F\"]" | <e>0101000000000000000000F03F000000000000F03F</e> |
+----------------------------------------------------+---------------------------------------------------+
```

For this to work, just return the formatter from your `Binding`:

```java
public class MyGeometryBinding implements Binding<Geometry, MyGeometryType> {
    // ...
    
    static final SpatialFormatter FORMATTER = new SpatialFormatter();
    
    public Formatter formatter() { 
        return FORMATTER;
    }
}
```

> [!TIP]
> jOOQ offers such `Formatter` implementations out of the box for all [Built-in data types](#built-in-data-types) (including [GEOMETRY](#data-type-geometry)) and [Extended data types](#extended-data-types).

<a id="synthetic-sql-clauses"></a>
### 3.15. Synthetic SQL clauses

Most of the previously mentioned SQL clauses have a native representation in at least one of jOOQ's supported [SQL dialects](#sql-dialects). For example, when a function like `LPAD()` is unavailable, jOOQ produces an equivalent expression for it:

```sql
-- MySQL (native support)
lpad('a', 10, ' ')

-- SQL Server (emulation)
(replicate(' ', (10 - len('a'))) + 'a')
```

```java
// In Java



lpad("a", 10, " ")
```

However, since a lot of SQL is emulated for dialect compatibility, nothing prevents jOOQ from supporting synthetic SQL clauses that do not have any native representation anywhere.

An example for this is the [quantified like predicate](#like-predicate), introduced in jOOQ 3.12, which would be really useful in any database:

```sql
(TITLE     LIKE '%abc%'  OR TITLE     LIKE '%def%')
(TITLE NOT LIKE '%abc%'  OR TITLE NOT LIKE '%def%')
(TITLE     LIKE '%abc%' AND TITLE     LIKE '%def%')
(TITLE NOT LIKE '%abc%' AND TITLE NOT LIKE '%def%')
```

```java
BOOK.TITLE.like(any("%abc%", "%def%"))
BOOK.TITLE.notLike(any("%abc%", "%def%"))
BOOK.TITLE.like(all("%abc%", "%def%"))
BOOK.TITLE.notLike(all("%abc%", "%def%"))
```

In this section, we briefly list most such synthetic SQL clauses, which are available both through the jOOQ API, and through the [jOOQ parser](#sql-parser), yet they do not have a native representation in any dialect.

- [Implicit JOIN](#implicit-join): Implicit JOINs are implicit [LEFT JOINs](#join-clause) that are derived from to-one relationship path expressions. In order to e.g. access the `COUNTRY` columns from a `CUSTOMER` record, it is possible to write `CUSTOMER.address().city().country().NAME`. jOOQ will produce the necessary `LEFT JOIN` graph, which is much more tedious to write.
- [MULTISET_AGG function](#multiset-agg-function): The `MULTISET` aggregate function is not natively supported anywhere, even if a native implementation for the [MULTISET value constructor](#multiset-value-constructor) exists.
- [Relational Division](#relational-division): Relational algebra supports a divison operator, which is the inverse operator of the cross product.
- [SEEK clause](#seek-clause): The SEEK clause is a synthetic clause of the [SELECT statement](#select-statement), which provides an alternative way of paginating other than the [OFFSET clause](#limit-clause). From a performance perspective, it is generally the preferred way to paginate.
- [SEMI JOIN and ANTI JOIN](#join-clause): Relational algebra defines SEMI JOIN and ANTI JOIN operators, which do not have a representation in any SQL dialect supported by jOOQ (Apache Impala has it, though). In SQL, the [EXISTS predicate](#exists-predicate) or [IN predicate](#in-predicate) is used instead.
- [Sort indirection](https://blog.jooq.org/how-to-implement-sort-indirection-in-sql/): When sorting, sometimes, we want to sort by a derived value, not the actual value of a column. Sort indirection makes this very easy with jOOQ.
- [UNIQUE predicate](#unique-predicate): This SQL standard predicate has not yet been implemented in any SQL dialect (it is being considered for H2). An esoteric, yet occasionally useful predicate that is difficult to emulate manually using the [EXISTS predicate](#exists-predicate).
- [inline derived tables](#inline-derived-tables): A quick and type safe way to add a [WHERE clause](#where-clause) to a [table expression](#table-expressions) for simplified dynamic SQL.
- [ON CONFLICT .. SET ALL TO EXCLUDED](#insert-on-conflict-all-excluded) and [ON DUPLICATE KEY .. SET ALL TO EXCLUDED](#insert-on-duplicate-key-all-excluded): Convenience methods for the most common type of `UPSERT` statement.

<a id="dynamic-sql"></a>
### 3.16. Dynamic SQL

In most cases, [table expressions](#table-expressions), [column expressions](#column-expressions), and [conditional expressions](#conditional-expressions) as introduced in the previous chapters will be embedded into different SQL statement clauses as if the statement were a static SQL statement (e.g. in a view or stored procedure):

```java
create.select(
          AUTHOR.FIRST_NAME.concat(AUTHOR.LAST_NAME),
          count()
      .from(AUTHOR)
      .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
      .groupBy(AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .orderBy(count().desc())
      .fetch();
```

It is, however, interesting to think of all of the above expressions as what they are: expressions. And as such, nothing keeps users from extracting expressions and referencing them from outside the statement. The following statement is exactly equivalent:

```java
SelectField<?>[] select = {
    AUTHOR.FIRST_NAME.concat(AUTHOR.LAST_NAME),
    count()
};
Table<?> from = AUTHOR.join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID));
GroupField[] groupBy = { AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME };
SortField<?>[] orderBy = { count().desc() };

create.select(select)
      .from(from)
      .groupBy(groupBy)
      .orderBy(orderBy)
      .fetch();
```

Each individual expression, and collection of expressions can be seen as an independent entity that can be

1. Constructed dynamically
2. Reused across queries

Dynamic construction is particularly useful in the case of the [WHERE clause](#where-clause), for dynamic predicate building. For instance:

```java
public Condition condition(HttpServletRequest request) {
    Condition result = noCondition();

    if (request.getParameter("title") != null)
        result = result.and(BOOK.TITLE.like("%" + request.getParameter("title") + "%"));

    if (request.getParameter("author") != null)
        result = result.and(BOOK.AUTHOR_ID.in(
            select(AUTHOR.ID).from(AUTHOR).where(
                    AUTHOR.FIRST_NAME.like("%" + request.getParameter("author") + "%")
                .or(AUTHOR.LAST_NAME .like("%" + request.getParameter("author") + "%"))
            )
        ));

    return result;
}

// And then:
create.select()
      .from(BOOK)
      .where(condition(httpRequest))
      .fetch();
```

The dynamic SQL building power may be one of the biggest advantages of using a runtime query model like the one offered by jOOQ. Queries can be created dynamically, of arbitrary complexity. In the above example, we've just constructed a dynamic [WHERE clause](#where-clause). The same can be done for any other clauses, including dynamic [FROM clauses (dynamic JOINs)](#from-clause), or adding additional [WITH clauses](#with-clause) as needed.

The above example made use of an [optional condition](#no-condition), a mechanism that is explained in the following sections.

<a id="no-field"></a>
#### 3.16.1. Optional column expressions

A key capability when creating [dynamic SQL queries](#dynamic-sql) is to be able to provide optional [column expressions](#column-expressions). For example, imagine you have a condition based on which you want to add an [ORDER BY clause](#order-by-clause) and a [LIMIT clause](#limit-clause). You can do this using [`DSL.noField()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#noField()):

```java
boolean condition = ...

create.select(BOOK.ID)
      .from(BOOK)
      .orderBy(condition ? BOOK.ID : noField())
      .limit(condition ? val(10) : noField(INTEGER))
      .fetch();
```

The above query produces:

```sql
-- If condition is true
SELECT book.id FROM book ORDER BY book.id LIMIT 10

-- If condition is false
SELECT book.id FROM book
```

In clauses that do not project columns, the `noField()` expression will be ignored. If that means the clause is empty, then the entire clause will be omitted. This does not apply to clauses that project a `Record` type, including the [SELECT clause](#select-clause), [row value expressions](#row-value-expressions), or [nested records](#nested-records), as well as function calls, in case of which a `NULL` value will be projected.

Using a `noField()` as a [conditional expression](#conditional-expressions), e.g. by wrapping it with [`DSL.condition(noField())`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#condition(Field)) will produce a [DSL.noCondition()](#no-condition).

> [!TIP]
> The `noField()` expression is supported only in the [DSL API](#dsl-api), not in the [model API](#model-api), where the behaviour of `noField()` is undefined.

<a id="no-condition"></a>
#### 3.16.2. Optional conditional expressions

A key capability when creating [dynamic SQL queries](#dynamic-sql) is to be able to provide optional [conditional expressions](#conditional-expressions).

```java
boolean condition = ...

create.select(BOOK.ID)
      .from(BOOK)
      .where(condition ? BOOK.ID.eq(10) : noCondition())
      .fetch();
```

The above query produces:

```sql
-- If condition is true
SELECT book.id FROM book WHERE book.id = 10

-- If condition is false
SELECT book.id FROM book
```

The `noCondition()` expression will be ignored. If that means the clause is empty, then the entire clause will be omitted. This does not apply to clauses that project a `Record` type, including the [SELECT clause](#select-clause), [row value expressions](#row-value-expressions), or [nested records](#nested-records), as well as function calls, in case of which a `NULL` value will be projected.

Some additional interactions of the `noCondition()` can be seen in the section about [TRUE and FALSE conditions](#true-false-no-condition).

Using a `noCondition()` as a [column expression](#column-expressions), e.g. by wrapping it with [`DSL.field(noCondition())`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#field(Condition)) will produce a [DSL.noField(BOOLEAN)](#no-field).

> [!TIP]
> The `noCondition()` expression is supported only in the [DSL API](#dsl-api), not in the [model API](#model-api), where the behaviour of `noCondition()` is undefined.

<a id="no-table"></a>
#### 3.16.3. Optional tables

A key capability when creating [dynamic SQL queries](#dynamic-sql) is to be able to provide optional [table expressions](#table-expressions).

```java
boolean condition = ...

create.select(BOOK.ID)
      .from(BOOK)
      .join(condition ? AUTHOR : noTable()).on(BOOK.AUTHOR_ID.eq(AUTHOR_ID))
      .fetch();
```

The above query produces:

```sql
-- If condition is true
SELECT book.id FROM book JOIN author ON book.author_id = author.id

-- If condition is false
SELECT book.id FROM book
```

The `noTable()` expression will be ignored. If that means the `FROM` clause is empty, then the entire clause will be omitted. Depending on the [JOIN type](#join-clause), an `ON` clause may still be required, syntactically. If `noTable()` is supplied, however, the `ON` clause has no effect and will be ignored.

> [!TIP]
> The `noTable()` expression is supported only in the [DSL API](#dsl-api), not in the [model API](#model-api), where the behaviour of `noTable()` is undefined.

<a id="no-path"></a>
#### 3.16.4. Optional join paths

A key capability when creating [dynamic SQL queries](#dynamic-sql) is to be able to provide optional [table expressions](#table-expressions), also by means of [explicit path joins](#explicit-path-join).

```java
boolean condition = ...

create.select(BOOK.ID)
      .from(BOOK)
      .join(condition ? BOOK.author() : noPath())
      .fetch();
```

The above query produces:

```sql
-- If condition is true
SELECT book.id FROM book JOIN author ON book.author_id = author.id

-- If condition is false
SELECT book.id FROM book
```

The `noPath()` expression will be ignored. If that means the `FROM` clause is empty, then the entire clause will be omitted. If `noPath()` is supplied, the optional `ON` clause has no effect and will be ignored.

> [!TIP]
> The `noPath()` expression is supported only in the [DSL API](#dsl-api), not in the [model API](#model-api), where the behaviour of `noPath()` is undefined.

<a id="no-json-entry"></a>
#### 3.16.5. Optional JSON entry expressions

An occasionally useful capability when creating [dynamic SQL queries](#dynamic-sql) is to be able to provide optional [JSON_OBJECT function arguments](#json-object-function). You can do this using [`DSL.noJsonEntry()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#noJsonEntry()):

```java
boolean condition = ...

create.select(jsonObject(
            key("id").value(BOOK.ID),
            
            // The following two are equivalent
            key("title1").value(condition ? BOOK.TITLE : noField()),
            condition ? key("title2").value(BOOK.TITLE) : noJsonEntry()
       ))
      .from(BOOK)
      .fetch();
```

The above query produces:

```sql
-- If condition is true
SELECT json_object(KEY id VALUE book.id, KEY title1 VALUE book.title, KEY title2 VALUE book.title)
FROM book

-- If condition is false
SELECT json_object(KEY id VALUE book.id)
FROM book
```

> [!TIP]
> The `noJsonEntry()` expression is supported only in the [DSL API](#dsl-api), not in the [model API](#model-api), where the behaviour of `noJsonEntry()` is undefined.

<a id="plain-sql"></a>
### 3.17. Plain SQL

A DSL is a nice thing to have, it feels "fluent" and "natural", especially if it models a well-known language, such as SQL.

But an internal DSL comes with two main limitations:

- It is limited by what is defined explicitly as formal API, unlike external DSLs, which can be supported completely as unchecked `String` types.
- It has to follow the rules of the host language (Java in this case), and thus cannot mimic the equivalent external DSL to 100%.

We have seen a few functionalities where the DSL becomes a bit verbose. This can be especially true for:

- [aliasing](#aliased-columns)
- [derived tables](#derived-tables)

The use-cases for jOOQ where verbosity or missing functionality is a problem are rather rare, and when they come up, you do have an option. Just write SQL the way you're used to using "plain SQL."

<a id="plain-sql-api"></a>
#### 3.17.1. Plain SQL API

jOOQ allows you to embed SQL as a String into any supported [statement](#sql-statements) in these contexts:

- Plain SQL as a [conditional expression](#conditional-expressions)
- Plain SQL as a [column expression](#column-expressions)
- Plain SQL as a [function](#column-expressions)
- Plain SQL as a [table expression](#table-expressions)
- Plain SQL as a [query](#query-vs-resultquery)

Plain SQL API methods are usually overloaded in three ways. Let's look at the `condition` query part constructor:

```java
// Construct a condition without bind values
// Example: condition("a = b")
@PlainSQL
Condition condition(String sql);

// Construct a condition with bind values
// Example: condition("a = ?", 1);
@PlainSQL
Condition condition(String sql, Object... bindings);

// Construct a condition taking other jOOQ object arguments
// Example: condition("a = {0}", val(1));
@PlainSQL
Condition condition(String sql, QueryPart... parts);
```

> [!TIP]
> Note the `@PlainSQL` annotation that can be used with the [jOOQ checker](#checker-framework) to forbid using plain SQL API entirely, or locally, for improved SQL injection protection.

Both the bind value and the query part argument overloads support jOOQ's [plain SQL templating language](#plain-sql-templating-language). Please refer to the [`org.jooq.impl.DSL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html) Javadoc for more details.

The following is a more complete listing of plain SQL construction methods from the DSL:

```java
// A condition
Condition condition(String sql);
Condition condition(String sql, Object... bindings);
Condition condition(String sql, QueryPart... parts);

// A field with an unknown data type
Field<Object> field(String sql);
Field<Object> field(String sql, Object... bindings);
Field<Object> field(String sql, QueryPart... parts);

// A field with a known data type
<T> Field<T> field(String sql, Class<T> type);
<T> Field<T> field(String sql, Class<T> type, Object... bindings);
<T> Field<T> field(String sql, Class<T> type, QueryPart... parts);
<T> Field<T> field(String sql, DataType<T> type);
<T> Field<T> field(String sql, DataType<T> type, Object... bindings);
<T> Field<T> field(String sql, DataType<T> type, QueryPart... parts);

// A field with a known name (properly escaped)
Field<Object> field(Name name);
<T> Field<T>  field(Name name, Class<T> type);
<T> Field<T>  field(Name name, DataType<T> type);

// A function
<T> Field<T> function(String name, Class<T> type, Field<?>... arguments);
<T> Field<T> function(String name, DataType<T> type, Field<?>... arguments);

// A table
Table<?> table(String sql);
Table<?> table(String sql, Object... bindings);
Table<?> table(String sql, QueryPart... parts);

// A table with a known name (properly escaped)
Table<Record> table(Name name);

// A query without results (update, insert, etc)
Query query(String sql);
Query query(String sql, Object... bindings);
Query query(String sql, QueryPart... parts);

// A query with results
ResultQuery<Record> resultQuery(String sql);
ResultQuery<Record> resultQuery(String sql, Object... bindings);
ResultQuery<Record> resultQuery(String sql, QueryPart... parts);

// A query with results. This is the same as resultQuery(...).fetch();
Result<Record> fetch(String sql);
Result<Record> fetch(String sql, Object... bindings);
Result<Record> fetch(String sql, QueryPart... parts);
```

Apart from the general factory methods, plain SQL is also available in various other contexts for convenience. For instance, when adding a `.where("a = b")` clause to a query. Hence, there exist several convenience methods where plain SQL can be inserted usefully. This is an example displaying all various use-cases in one single query:

```java
// You can use your table aliases in plain SQL fields
// As long as that will produce syntactically correct SQL
Field<?> LAST_NAME    = field("a.LAST_NAME");

// You can alias your plain SQL fields
Field<?> COUNT1       = field("count(*) x");

// If you know a reasonable Java type for your field, you
// can also provide jOOQ with that type
Field<Integer> COUNT2 = field("count(*) y", Integer.class);

       // Use plain SQL as select fields
create.select(LAST_NAME, COUNT1, COUNT2)

       // Use plain SQL as aliased tables (be aware of syntax!)
      .from("author a")
      .join("book b")

       // Use plain SQL for conditions both in JOIN and WHERE clauses
      .on("a.id = b.author_id")

       // Bind a variable in plain SQL
      .where("b.title != ?", "Brida")

       // Use plain SQL again as fields in GROUP BY and ORDER BY clauses
      .groupBy(LAST_NAME)
      .orderBy(LAST_NAME)
      .fetch();
```

##### Important things to note about plain SQL!

There are some important things to keep in mind when using plain SQL:

- You have to provide something that will be syntactically correct. If it's not, then jOOQ won't know. Only your JDBC driver or your RDBMS will detect the syntax error.
- You have to provide consistency when you use variable binding. The number of ? must match the number of variables
- Your SQL is inserted into jOOQ queries without further checks. Hence, jOOQ can't prevent SQL injection or transform your SQL string in any way.

<a id="plain-sql-templating-language"></a>
#### 3.17.2. Plain SQL templating language

The [plain SQL API](#plain-sql-api), as documented in the previous chapter, supports a string templating mini-language that allows for constructing complex SQL string content from smaller parts. A simple example can be seen below, e.g. when looking for support for one of PostgreSQL's various vendor-specific operator types:

```sql
ARRAY[1,4,3] && ARRAY[2,1]
```

```java
condition("{0} && {1}", array1, array2);
```

Such a plain SQL template always consists of two things:

- The SQL string fragment containing `{number}` style placeholders.
- A set of [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) arguments, which are expected to be embedded in the SQL string

The SQL string may reference the arguments by 0-based indexing. Each argument may be referenced several times. For instance, SQLite's emulation of the `REPEAT(string, count)` function may look like this:

```java
Field<Integer> count = val(3);
Field<String> string = val("abc");
field("replace(substr(quote(zeroblob(({0} + 1) / 2)), 3, {0}), '0', {1})", String.class, count, string);
//                                     ^                  ^          ^                   ^^^^^  ^^^^^^
//                                     |                  |          |                     |       |
// argument "count" is repeated twice: \------------------+----------|---------------------/       |
// argument "string" is used only once:                              \-----------------------------/
```

For convenience, there is also a [`DSL.list(QueryPart...)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#list(org.jooq.QueryPart...)) API that allows for wrapping a comma-separated list of query parts in a single template argument:

```java
Field<String> a = val("a");
Field<String> b = val("b");
Field<String> c = val("c");

// These two produce the same result:
condition("my_column IN ({0}, {1}, {2})", a, b, c); // Using distinct template arguments
condition("my_column IN ({0})", list(a, b, c));    // Using a single template argument
```

##### Parsing rules

When processing these plain SQL templates, a mini parser is run that handles things like

- String literals like `'abc'` or `$$abc$$`
- Quoted names like `"name"`, `` `name` ``, or `[name]`
- Comments like `/* block */` or `-- line`
- JDBC escape sequences like `{d '2000-01-01'}`
- Indexed (`?`) or named (`:identifier`) bind variable placeholders

The above are recognised by the templating engine and contents inside of them are ignored when replacing numbered placeholders and/or bind variables. For instance:

```java
query(
  """
  SELECT /* In a comment, this is not a placeholder: {0}. And this is not a bind variable: ? */ title AS `title {1} ?`
  -- Another comment without placeholders: {2} nor bind variables: ?
  FROM book
  WHERE title = 'In a string literal, this is not a placeholder: {3}. And this is not a bind variable: ?'
  """
);
```

The above query does not contain any numbered placeholders nor bind variables, because the tokens that would otherwise be searched for are contained inside of comments, string literals, or quoted names.

<a id="plain-sql-raw-templates"></a>
#### 3.17.3. Plain SQL raw templates

The [previous section about plain SQL templating](#plain-sql-templating-language) showed examples of the useful plain SQL templating language. Sometimes, you want plain SQL to just be "raw," omitting any processing by jOOQ. In particular, this can be the case when your SQL contains jOOQ's placeholder tokens, such as `{` and `}`. In that case, you can use the [`DSL.raw(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#raw(java.lang.String)) method to create a [`org.jooq.SQL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SQL.html) type that isn't getting processed.

For example, when using Informix's native [MULTISET value constructor](#multiset-value-constructor) support:

```java
resultQuery(raw(
  "SELECT * FROM TABLE (MULTISET {1})"
));
```

In this case, you certainly don't want that `{1}` token to be processed as a placeholder.

You can also turn off the templating feature globally, using [`Settings.renderPlainSQLTemplatesAsRaw`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#renderPlainSQLTemplatesAsRaw).

<a id="hints"></a>
### 3.18. Hints

A variety of RDBMS support hints, which are vendor specific instructions to the optimiser, telling it what algorithms or meta data usage should be enforced / prevented. Typically, hints are used to enforce hash joins, nested loop joins, etc. or to enforce / prevent index access.

In most cases, you should not need to hint the optimiser, as it can be reasonably expected to make the right decisions on your behalf. But every now and then, it does not, and in those cases, hints can be useful (still, do check if your statistics are up to date, if you have all the meta data you should have, etc.)

jOOQ supports the most common hints for the following database products:

<a id="hints-mysql"></a>
#### 3.18.1. MySQL hints

MySQL implements multiple hint syntaxes, including its own classic hints, as well as [Oracle style hints](#hints-oracle), since more recent versions.

The following sections show what different types of MySQL hints are supported by jOOQ.

<a id="hints-mysql-index"></a>
##### 3.18.1.1. Index hints

Numerous syntaxes exist to make or prevent MySQL from using an index to access a table or for certain operations. Unlike the more generic [Oracle-style hint comment syntax](#hints-mysql-oracle), these hints are embedded in the SQL statement directly:

```sql
SELECT *
FROM BOOK USE INDEX i_book_a
```

```java
create.selectFrom(BOOK.useIndex("i_book_a"))
      .fetch()
```

The following methods on [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) can be used for that purpose:

- [`Table.useIndex()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#useIndex(java.lang.String...))
- [`Table.useIndexForJoin()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#useIndexForJoin(java.lang.String...))
- [`Table.useIndexForOrderBy()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#useIndexForOrderBy(java.lang.String...))
- [`Table.useIndexForGroupBy()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#useIndexForGroupBy(java.lang.String...))
- [`Table.forceIndex()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#forceIndex(java.lang.String...))
- [`Table.forceIndexForJoin()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#forceIndexForJoin(java.lang.String...))
- [`Table.forceIndexForOrderBy()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#forceIndexForOrderBy(java.lang.String...))
- [`Table.forceIndexForGroupBy()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#forceIndexForGroupBy(java.lang.String...))
- [`Table.ignoreIndex()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#ignoreIndex(java.lang.String...))
- [`Table.ignoreIndexForJoin()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#ignoreIndexForJoin(java.lang.String...))
- [`Table.ignoreIndexForOrderBy()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#ignoreIndexForOrderBy(java.lang.String...))
- [`Table.ignoreIndexForGroupBy()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#ignoreIndexForGroupBy(java.lang.String...))

<a id="hints-mysql-join"></a>
##### 3.18.1.2. STRAIGHT_JOIN

MySQL supports a special type of [JOIN operator](#join-clause) to hint at the optimiser that the `JOIN` order must be from left to right: The `STRAIGHT_JOIN`

```sql
SELECT *
FROM BOOK
STRAIGHT_JOIN AUTHOR
  ON BOOK.AUTHOR_ID = AUTHOR.ID
```

```java
create.select()
      .from(BOOK)
      .straightJoin(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .fetch()
```

<a id="hints-mysql-oracle"></a>
##### 3.18.1.3. Oracle style hints in MySQL

Since more recent versions of MySQL, [Oracle-style hints](#hints-oracle) are now also supported.

For example, this has always been possible in MySQL:

```sql
SELECT SQL_CALC_FOUND_ROWS field1, field2
FROM table1

 
```

```java
create.select(field1, field2)
      .hint("SQL_CALC_FOUND_ROWS")
      .from(table1)
      .fetch()
```

But now, you can also use the Oracle syntax for hints:

```sql
SELECT /*+ MAX_EXECUTION_TIME(1000) */ field1, field2
FROM table1

 
```

```java
create.select(field1, field2)
      .hint("/*+ MAX_EXECUTION_TIME(1000) */")
      .from(table1)
      .fetch()
```

<a id="hints-oracle"></a>
#### 3.18.2. Oracle hints

Oracle implements hints using a comment style syntax, where the multi line comment contains a special `+` token to distinguish it from an ordinary comment, e.g. `/*+HINT*/`.

For example, the following hint tells the optimiser that the client is going to consume all the rows from the result set, as opposed to aborting the fetch after a few rows:

```sql
SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME
  FROM AUTHOR
```

This can be done in jOOQ using the `.hint()` clause in your SELECT statement:

```java
create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .hint("/*+ALL_ROWS*/")
      .from(AUTHOR)
      .fetch();
```

Note that you can pass any string in the `.hint()` clause, including any non-hint comment if you wish to use this syntax to mark your queries. If you use that clause, the passed string will always be put in between the `SELECT [DISTINCT]` keywords and the actual projection list. This can be useful in other databases too, such as MySQL, for instance:

```sql
SELECT SQL_CALC_FOUND_ROWS field1, field2
FROM table1

 
```

```java
create.select(field1, field2)
      .hint("SQL_CALC_FOUND_ROWS")
      .from(table1)
      .fetch()
```

See also [Oracle-style hints in MySQL](#hints-mysql-oracle) for more details.

<a id="hints-sql-server"></a>
#### 3.18.3. SQL Server hints

SQL Server supports hints both on a table level as well as on a query level. Unlike [Oracle-style hints](#hints-oracle), which use a special comment syntax, SQL Server hints are syntactic tokens that are part of your queries.

The following sections show what different types of SQL Server hints are supported by jOOQ.

<a id="hints-sql-server-table"></a>
##### 3.18.3.1. WITH

The `WITH` hint in SQL Server is used for table level hints.

For example:

```sql
SELECT *
FROM BOOK WITH (READUNCOMMITTED)
```

```java
create.selectFrom(BOOK.with("READUNCOMMITTED"))
      .fetch()
```

###### Dialect support

This example using jOOQ:

```java
selectFrom(BOOK.with("ROWLOCK, UPDLOCK"))
```

Translates to the following dialect specific expressions:

###### ASE, Aurora MySQL, MariaDB, MemSQL

```sql
SELECT
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM BOOK
FOR UPDATE
```

###### Aurora Postgres, CockroachDB, H2, HSQLDB, MySQL, Postgres, YugabyteDB

```sql
SELECT
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM BOOK
FOR UPDATE OF BOOK
```

###### DB2, Hana

```sql
SELECT
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM BOOK
FOR UPDATE OF ID, AUTHOR_ID, TITLE, PUBLISHED_IN, LANGUAGE_ID
```

###### Firebird

```sql
SELECT
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM BOOK
FOR UPDATE OF BOOK WITH LOCK
```

###### Informix, Oracle

```sql
SELECT
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM BOOK
FOR UPDATE OF BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE, BOOK.PUBLISHED_IN, BOOK.LANGUAGE_ID
```

###### SQLServer, Sybase

```sql
SELECT
  BOOK.ID,
  BOOK.AUTHOR_ID,
  BOOK.TITLE,
  BOOK.PUBLISHED_IN,
  BOOK.LANGUAGE_ID
FROM BOOK WITH (ROWLOCK, UPDLOCK)
```

###### Access, BigQuery, ClickHouse, Databricks, DuckDB, Exasol, Redshift, SQLDataWarehouse, SQLite, Snowflake, Spanner, Teradata, Trino, Vertica

```sql
/* UNSUPPORTED */
```

> [!TIP]
> Generated with jOOQ 3.22. Support in older jOOQ versions may differ. [Translate your own SQL on our website](https://www.jooq.org/translate)

<a id="hints-sql-server-option"></a>
##### 3.18.3.2. OPTION

The `OPTION` hint in SQL Server is used for query level hints.

For example:

```sql
SELECT field1, field2
FROM table1
OPTION (OPTIMIZE FOR UNKNOWN)
 
```

```java
create.select(field1, field2)
      .from(table1)
      .option("OPTION (OPTIMIZE FOR UNKNOWN)")
      .fetch()
```

Not all of these query level hints include the `OPTION` keyword, which is why it must be added manually to the `OPTION` string in jOOQ.

<a id="sql-parser"></a>
### 3.19. SQL Parser

A full-fledged SQL parser is available from [`DSLContext.parser()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#parser()) and from [`DSLContext.parsingConnection()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#parsingConnection()) (see [the manual's section about parsing connections for the latter](#parsing-connection)).

<a id="sql-parser-api"></a>
#### 3.19.1. SQL Parser API

##### Goal

Historically, jOOQ implements an [internal domain-specific language](https://en.wikipedia.org/wiki/Domain-specific_language) in Java, which generates SQL (an external domain-specific language) for use with JDBC. The jOOQ API is built from two parts: The [DSL API](#dsl-api) and the [model API](#model-api), where the DSL API adds lexical convenience for programmers on top of the model API, which is really just a SQL expression tree, similar to what a SQL parser does inside of any database.

With this parser, the whole set of jOOQ functionality will now also be made available to anyone who is not using jOOQ directly, including JDBC and/or JPA users, e.g. through the [parsing connection](#parsing-connection), which proxies all JDBC Connection calls to the jOOQ parser before forwarding them to the database, or through the [`DSLContext.parser()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#parser()) API, which allows for a more low-level access to the parser directly, e.g. for tool building on top of jOOQ.

The possibilities are endless, including standardised, SQL string based database migrations that work on any `SQLDialect` that is supported by jOOQ.

##### Example

This parser API allows for parsing an arbitrary SQL string fragment into a variety of jOOQ API elements:

- [`Parser.parse(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parse(java.lang.String)): This produces the [`org.jooq.Queries`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Queries.html) type, containing a batch of queries.
- [`Parser.parseQuery(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseQuery(java.lang.String)): This produces the [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html) type, containing a single query (any type of query).
- [`Parser.parseResultQuery(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseResultQuery(java.lang.String)): This produces the [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) type, containing a single result query (`SELECT` or other).
- [`Parser.parseSelect(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseSelect(java.lang.String)): This produces the [`org.jooq.Select`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Select.html) type, containing a single [SELECT query](#select-statement).
- [`Parser.parseStatement(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseStatement(java.lang.String)): This produces the [`org.jooq.Statement`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Statement.html) type, containing a single [procedural statement](#procedural-statements).
- [`Parser.parseTable(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseTable(java.lang.String)): This produces the [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) type, containing a table expression.
- [`Parser.parseField(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseField(java.lang.String)): This produces the [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) type, containing a field expression.
- [`Parser.parseRow(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseRow(java.lang.String)): This produces the [`org.jooq.Row`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Row.html) type, containing a row expression.
- [`Parser.parseCondition(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseCondition(java.lang.String)): This produces the [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html) type, containing a condition expression.
- [`Parser.parseName(String)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parser.html#parseName(java.lang.String)): This produces the [`org.jooq.Name`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Name.html) type, containing a name expression.

See this blog post [for more information about the various jOOQ types](https://blog.jooq.org/a-brief-overview-over-the-most-common-jooq-types/).

The parser is able to parse any unspecified dialect to produce a jOOQ representation of the SQL expression, for instance:

```java
ResultQuery<?> query =
DSL.using(configuration)
   .parser()
   .parseResultQuery("SELECT * FROM (VALUES (1, 'a'), (2, 'b')) t(a, b)")
```

The above SQL query is valid standard SQL and runs out of the box on PostgreSQL and SQL Server, among others. The jOOQ `ResultQuery` that is generated from this SQL string, however, will also work on any other database, as jOOQ can emulate the two interesting SQL features being used here:

- The [VALUES() constructor](#values)
- The [derived column list syntax](#aliased-tables) (aliasing table *and* columns in one go)

The query might be rendered as follows on the H2 database, which supports `VALUES()`, but not derived column lists:

```sql
select
  t.a,
  t.b
from (
  (
    select
      null a,
      null b
    where 1 = 0
  )
  union all (
    select *
    from (values
      (1, 'a'),
      (2, 'b')
    ) t
  )
) t;
```

Or like this on Oracle, which supports neither feature:

```sql
select
  t.a,
  t.b
from (
  (
    select
      null a,
      null b
    from dual
    where 1 = 0
  )
  union all (
    select *
    from (
      (
        select
          1,
          'a'
        from dual
      )
      union all (
        select
          2,
          'b'
        from dual
      )
    ) t
  )
) t;
```

<a id="sql-parser-cli"></a>
#### 3.19.2. SQL Parser CLI

The Parser API can be used as a translator between source and target dialects programmatically, as we've seen in the [previous section about the parser API](#sql-parser-api). This functionality can also usefully be accessed on the command line as shown below:

```text
$ java -cp jooq-3.22.0-SNAPSHOT.jar:reactive-streams-1.0.3.jar:r2dbc-spi-1.0.0.RELEASE.jar org.jooq.ParserCLI -h
Usage:
  -f / --formatted                                                    Format output SQL
  -h / --help                                                         Display this help
  -k / --keyword                                  <RenderKeywordCase> Specify the output keyword case (org.jooq.conf.RenderKeywordCase)
  -i / --identifier                               <RenderNameCase>    Specify the output identifier case (org.jooq.conf.RenderNameCase)
  -Q / --quoted                                   <RenderQuotedNames> Specify the output identifier quoting (org.jooq.conf.RenderQuotedNames)
  -F / --from-dialect                             <SQLDialect>        Specify the input dialect (org.jooq.SQLDialect)
  -T / --to-dialect                               <SQLDialect>        Specify the output dialect (org.jooq.SQLDialect)
  -s / --sql                                      <String>            Specify the input SQL string
  -S / --schema                                   <String>            Specify the input schema

Commercial distribution only features:
  --render-coalesce-to-empty-string-in-concat     <boolean>
  --render-optional-inner-keyword                 <RenderOptionalKeyword>
  --render-optional-outer-keyword                 <RenderOptionalKeyword>
  --render-optional-as-keyword-for-field-aliases  <RenderOptionalKeyword>
  --render-optional-as-keyword-for-table-aliases  <RenderOptionalKeyword>
  --transform-ansi-join-to-table-lists            <boolean>
  --transform-qualify                             <Transformation>
  --transform-rownum                              <Transformation>
  --transform-group-by-column-index               <Transformation>
  --transform-inline-cte                          <Transformation>
  --transform-table-lists-to-ansi-join            <boolean>
  --transform-unneeded-arithmetic                 <TransformUnneededArithmeticExpressions>

  -I / --interactive                                                  Start interactive mode"

$ java -cp jooq-3.22.0-SNAPSHOT.jar:reactive-streams-1.0.3.jar:r2dbc-spi-1.0.0.RELEASE.jar org.jooq.ParserCLI -T ORACLE -s "SELECT substring('abcde', 2, 3)"
select substr('abcde', 2, 3) from dual;
```

**Windows users:** Please replace `:` by `;` in the above examples.

Another way to use this API is the [https://www.jooq.org/translate](https://www.jooq.org/translate) website.

<a id="sql-parser-listener"></a>
#### 3.19.3. SQL Parser Listener

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

In order to implement custom parser behaviour, it is possible to provide your [Configuration](#dsl-context) with a set of custom [`org.jooq.ParseListener`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ParseListener.html) implementations.

The current SPI offers hooking into the parsing of 3 types of syntactic elements (see also [the parser grammar](#sql-parser-grammar)):

- `term` to parse [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) expressions
- `predicate` to parse [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html) expressions
- `tableFactor` to parse [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) expressions

And also these two lifecycle events:

- Before the start of a parse call
- After the end of a parse call

The idea is that any listener implementation you provide the parser with may be able to parse functions, top-level-precedence operators, etc. without having to deal with all the lower level precedence operators, such as `AND`, `OR`, `NOT`, `+`, `-`, etc. etc.

For example, assuming you want to add support for a logical `LOGICAL_XOR` operator as a function:

```java
Query query = configuration
    .derive(ParseListener.onParseCondition(ctx -> {
        if (ctx.parseFunctionNameIf("LOGICAL_XOR")) {
            ctx.parse('(');
            Condition c1 = ctx.parseCondition();
            ctx.parse(',');
            Condition c2 = ctx.parseCondition();
            ctx.parse(')');

            return c1.andNot(c2).or(c2.andNot(c1));
        }

        // Let the parser take over if we don't know the token
        return null;
    })
    .dsl()
    .parser()
    .parseQuery("select * from t where logical_xor(t.a = 1, t.b = 2)");
```

The above will just translate the convenience function `LOGICAL_XOR(c1, c2)` into its formal definition `c1 AND NOT c2 OR c2 AND NOT c1`. But we can do even better than this. If a dialect has native `XOR` support, why not support that?

```java
Query query = configuration
    .derive(ParseListener.onParseCondition(ctx -> {
        if (ctx.parseFunctionNameIf("LOGICAL_XOR")) {
            ctx.parse('(');
            Condition c1 = ctx.parseCondition();
            ctx.parse(',');
            Condition c2 = ctx.parseCondition();
            ctx.parse(')');

            return CustomCondition.of(c -> {
                switch (c.family()) {
                    case MARIADB:
                    case MYSQL:
                        c.visit(condition("{0} xor {1}", c1, c2));
                        break;
                    default:
                        c.visit(c1.andNot(c2).or(c2.andNot(c1)));
                        break;
                }
            });
        }

        // Let the parser take over if we don't know the token
        return null;
    }))
    .dsl()
    .parser()
    .parseQuery("select * from t where logical_xor(t.a = 1, t.b = 2)");

System.out.println(DSL.using(SQLDialect.MYSQL).render(query));
System.out.println(DSL.using(SQLDialect.ORACLE).render(query));
```

The output of the above is now:

```sql
-- MYSQL:
select * from t where (t.a = 1 xor t.b = 2);

-- ORACLE:
select * from t where (t.a = 1 and not (t.b = 2)) or (t.b = 2 and not (t.a = 1));
```

This way, with a modest effort, you can parse and/or translate arbitrary [column expressions](#column-expressions), [table expressions](#table-expressions), or [conditional expressions](#conditional-expressions) that jOOQ does not support natively, or override the default behaviour of the parser in this area.

<a id="sql-parser-translator"></a>
#### 3.19.4. SQL translator

The [SQL parser](#sql-parser) can be used as a SQL translator, as shown in action on our website: [https://www.jooq.org/translate](https://www.jooq.org/translate), or via the [SQL parser CLI](#sql-parser-cli). The fact that translation happens is just an emerging feature of combining:

- The parser API to parse a SQL string into the jOOQ [query object model API](#model-api)
- Using jOOQ to render the query object model again into a SQL string.

The simplest example is this one:

```java
System.out.println(create.parser().parse("SELECT 1").toString());
```

This will parse the generic SQL string `SELECT 1`, and render it according to the configured [Configuration](#dsl-context), [SQLDialect](#sql-dialects), [Settings](#custom-settings), etc.

<a id="sql-parser-grammar"></a>
#### 3.19.5. SQL Parser Grammar

The existing implementation of the SQL parser is a hand-written, recursive descent parser. There are great advantages of this approach over formal grammar-based, generated parsers (e.g. by using ANTLR). These advantages are, among others:

- They can be tuned easily for performance
- They are very simple and easy to maintain
- It's easy to implement corner cases of the grammar, which might require context (that's a big plus with SQL)
- It's the easiest way to bind a grammar to an existing backing expression tree implementation (which is what jOOQ really is)

Nevertheless, there is a grammar available for documentation purposes and it is included in the manual here:

```text
batch = query { ';' query };

query =
  ddlStatement
| dmlStatement
| transactionStatement
| blockStatement
;

ddlStatement =
  alterDatabaseStatement
| alterDomainStatement
| alterFunctionStatement
| alterIndexStatement
| alterProcedureStatement
| alterSchemaStatement
| alterSequenceStatement
| alterSessionStatement
| alterTableStatement
| alterTypeStatement
| alterViewStatement
| commentStatement
| createDatabaseStatement
| createDomainStatement
| createFunctionStatement
| createIndexStatement
| createProcedureStatement
| createSchemaStatement
| createSequenceStatement
| createSynonymStatement
| createTableStatement
| createTriggerStatement
| createTypeStatement
| createViewStatement
| dropDatabaseStatement
| dropDomainStatement
| dropFunctionStatement
| dropIndexStatement
| dropProcedureStatement
| dropTableStatement
| dropTypeStatement
| dropSchemaStatement
| dropSequenceStatement
| dropSynonymStatement
| dropTriggerStatement
| dropViewStatement
| grantStatement
| renameStatement
| revokeStatement
| setCatalogStatement
| setSchemaStatement
| setConstraintStatement
| truncateStatement
| useStatement
;

dmlStatement =
  deleteStatement
| insertStatement
| mergeStatement
| resultStatement
| updateStatement
;

transactionStatement =
  startTransactionStatement
| savepointStatement
| releaseSavepointStatement
| commitStatement
| rollbackStatement
;

proceduralStatements = ( proceduralStatement ';' )+
;

proceduralStatement = [ label ]
(
  query
| assignmentStatement
| callStatement
| caseStatement [ labelName ]
| continueStatement
| declareStatement
| executeStatement
| exitStatement
| forStatement [ labelName ]
| gotoStatement
| ifStatement [ labelName ]
| loopStatement [ labelName ]
| nullStatement
| repeatStatement [ labelName ]
| returnStatement
| signalStatement
| whileStatement [ labelName ]
)
;

label = '<<' labelName '>>' | labelName ':'
;

blockStatement =
  [ 'EXECUTE BLOCK AS' | 'DECLARE' ( declarationStatement ';' )+ ]
  'BEGIN' [ [ 'NOT' ] 'ATOMIC' ] proceduralStatements 'END'
| 'DO' stringLiteral
;

declarationStatement =
  variableName [ 'CONSTANT' ] dataType [ [ 'NOT' ] 'NULL' ] [ ( '=' | ':=' | 'DEFAULT' ) field ]
;

declareStatement =
  ( 'DECLARE' | 'DEFINE' )
        ( variableNames [ 'AS' ] dataType [ ( '=' | 'DEFAULT' ) field ] )
  { ',' ( variableNames [ 'AS' ] dataType [ ( '=' | 'DEFAULT' ) field ] ) }
;

assignmentStatement =
  ( 'SET' | 'LET' ) variableName '=' field
| 'SET' '(' variableNames ')' '=' ( fields | select )
| variableName ':=' field
;

ifStatement = 'IF' condition ( ifSimpleBody | ifBlockBody )
;

ifSimpleBody = proceduralStatement [ 'ELSE' proceduralStatement ]
;

ifBlockBody = 'THEN' proceduralStatements break
  { ( 'ELSIF' | 'ELSEIF' ) condition 'THEN' proceduralStatement } break
  [ 'ELSE' proceduralStatements ] break
  'END IF'
;

caseStatement =
  'CASE'
(
  field ( 'WHEN' field 'THEN' proceduralStatements )+
| ( 'WHEN' condition 'THEN' proceduralStatements )+
)
  [ 'ELSE' proceduralStatements ]
  'END CASE'
;

loopStatement =
  'LOOP' proceduralStatements 'END LOOP'
;

forStatement =
  'FOR' variableName 'IN' [ 'REVERSE' ] int '..' int [ 'BY' int ]
  loopStatement
;

whileStatement =
  'WHILE' condition ( loopStatement | 'DO' proceduralStatements 'END WHILE' )
;

repeatStatement =
  'REPEAT' proceduralStatements 'UNTIL' condition 'END REPEAT'
;

executeStatement = 'EXECUTE' [ 'IMMEDIATE' | 'STATEMENT' ] ( field | '(' field ')' )
;

callStatement = (
  'CALL' procedureName '(' arguments ')'
| 'EXECUTE PROCEDURE' procedureName ( '(' arguments ')' | arguments )
| procedureName '(' arguments ')'
| 'EXEC'  procedureName arguments
)
;

arguments = argument { ',' argument }
;

argument = parameterName
;

gotoStatement =
  'GOTO' labelName
;

continueStatement =
  ( 'CONTINUE' | 'ITERATE' ) [ labelName ] [ 'WHEN' condition ]
;

exitStatement =
  ( 'EXIT' | 'LEAVE' ) [ label ] [ 'WHEN' condition ]
;

returnStatement =
  'RETURN' [ field ]
;

signalStatement = (
  'SIGNAL' 'SQLSTATE' [ 'VALUE' ] stringLiteral [ 'SET' 'MESSAGE_TEXT' '=' stringLiteral | '(' stringLiteral ')' ]
| 'RAISE' [ 'EXCEPTION' ] 'SQLSTATE' stringLiteral [ 'USING' 'MESSAGE' '=' stringLiteral ]
)
;

nullStatement = 'NULL'
;

alterDatabaseStatement = 'ALTER DATABASE' [ 'IF EXISTS' ] catalogName (
  'RENAME' ( 'TO' | 'AS' ) catalogName
| 'OWNER' 'TO' userName
)
;

alterDomainStatement = 'ALTER DOMAIN' [ 'IF EXISTS' ] domainName (
  'ADD' ( constraint | 'CONSTRAINT' [ constraintName ] constraint )
| 'DROP' 'CONSTRAINT' [ 'IF EXISTS' ] constraintName [ 'CASCADE' | 'RESTRICT' ]
| 'RENAME' ( 'TO' | 'AS' ) domainName
| 'RENAME' 'CONSTRAINT' [ 'IF EXISTS' ] constraintName ( 'TO' | 'AS' ) constraintName
| ( 'SET DEFAULT' concat | 'DROP DEFAULT' )
| ( 'SET' | 'DROP' ) 'NOT NULL'
| 'OWNER' 'TO' userName
)
;

alterFunctionStatement = 'ALTER FUNCTION' functionName 'COMMENT' stringLiteral
;

alterIndexStatement = 'ALTER INDEX' [ 'IF EXISTS' ] indexName
  'RENAME' ( 'TO' | 'AS' ) indexName
;

alterProcedureStatement = 'ALTER PROCEDURE' functionName 'COMMENT' stringLiteral
;

alterSchemaStatement = 'ALTER SCHEMA' [ 'IF EXISTS' ] schemaName (
  'RENAME' ( 'TO' | 'AS' ) schemaName
| 'OWNER' 'TO' userName
)
;

alterSequenceStatement =
(
  'ALTER SEQUENCE' [ 'IF EXISTS' ] sequenceName
  (
    'RENAME' ( 'TO' | 'AS' ) sequenceName
  | 'OWNER' 'TO' userName
  |
  {
        'RESTART' [ 'WITH' uint ]
      | 'START' [ 'WITH' | '=' ] int
      | 'INCREMENT' [ 'BY' | '=' ] int
      | 'MINVALUE' [ '=' ] int | 'NO MINVALUE' | 'NOMINVALUE'
      | 'MAXVALUE' [ '=' ] int | 'NO MAXVALUE' | 'NOMAXVALUE'
      | 'CYCLE' | 'NO CYCLE' | 'NOCYCLE'
      | 'CACHE' [ '=' ] uint | 'NO CACHE' | 'NOCACHE'
  }
  )
| 'SET GENERATOR' sequenceName 'TO' uint
)
;

alterSessionStatement = 'ALTER SESSION' 'SET CURRENT_SCHEMA' '=' schemaName
;

alterTableStatement = 'ALTER TABLE' [ 'IF EXISTS' ] [ 'ONLY' ] tableName break
(
  'ADD' (
    [ 'WITH CHECK' ] constraint
  | [ 'WITH CHECK' ] 'CONSTRAINT' [ constraintName ] constraint
  | [ 'COLUMN' ] [ 'IF NOT EXISTS' ] column [ 'FIRST' | 'BEFORE' columnName | 'AFTER' columnName | 'LAST' ]
  |   '(' ( [ 'WITH CHECK' ] 'CONSTRAINT' [ constraintName ] constraint | constraint | column )
    { ',' ( [ 'WITH CHECK' ] 'CONSTRAINT' [ constraintName ] constraint | constraint | column ) } ')'
  | 'INDEX' [ 'IF NOT EXISTS' ] indexName '(' sortFields ')' [ 'TYPE' name ]
  )
| ( 'ALTER' | 'MODIFY' ) (
    [ 'COLUMN' ] [ 'IF EXISTS' ] identifier
    (
      [ [ 'SET DATA' ] 'TYPE' ] dataType [ [ 'NOT' ] 'NULL' ]
    | dataType [ [ 'CONSTRAINT' constraintName ] [ 'NOT' ] 'NULL' ]
    | 'DROP NOT NULL'
    | [ 'SET' ] [ 'NOT' ] 'NULL'
    | [ 'SET' ] 'DEFAULT' concat
    | ( 'SET' | 'ADD' ) 'GENERATED' ( 'BY DEFAULT' | 'ALWAYS' ) [ 'AS IDENTITY' ]
    | ( 'AS' | 'SET EXPRESSION AS' | [ 'SET' ] 'GENERATED ALWAYS AS' | 'COMPUTED' [ 'BY' ] ) '(' field ')'
    | 'SET OPTIONS' '(' 'DESCRIPTION' '=' stringLiteral ')'
    | 'DROP DEFAULT'
    | 'DROP IDENTITY'
    | 'DROP' ( 'EXPRESSION' | 'GENERATED' )
    | [ 'RENAME' ] ( 'TO' | 'AS' ) identifier
    )
  | column
  | '(' column ')'
  | 'CONSTRAINT' constraintName [ constraintState ]
  )
| 'CHANGE' [ 'COLUMN' ] [ 'IF EXISTS' ] identifier identifier dataType
| 'COMMENT' (
    [ '=' | 'IS' ] stringLiteral
  | 'COLUMN' stringLiteral
  )
| 'SET OPTIONS' '(' 'DESCRIPTION' '=' stringLiteral ')'
| 'DROP'
  (
    [ 'COLUMN' ] [ 'IF EXISTS' ] identifier [ 'CASCADE' | 'RESTRICT' ]
  | 'CONSTRAINT' [ 'IF EXISTS' ] constraintName [ 'CASCADE' | 'RESTRICT' ]
  | 'UNIQUE' ( constraintName | '(' sortFields ')' ) [ 'CASCADE' | 'RESTRICT' ]
  | 'FOREIGN KEY' constraintName
  | 'PRIMARY KEY' [ constraintName ] [ 'CASCADE' | 'RESTRICT' ]
  | 'INDEX' [ 'IF EXISTS' ] indexName
  )
| 'RENAME' [ [ 'COLUMN' [ 'IF EXISTS' ] | 'INDEX' | 'CONSTRAINT' ] identifier ] ( 'TO' | 'AS' ) identifier
| 'OWNER' 'TO' userName
)
;

alterTypeStatement = 'ALTER TYPE' [ 'IF EXISTS' ] typeName (
  'RENAME TO' typeName
| 'SET SCHEMA' schemaName
| 'ADD VALUE' stringLiteral
| 'RENAME VALUE' stringLiteral 'TO' stringLiteral
| 'OWNER' 'TO' userName
)
;

alterViewStatement = 'ALTER VIEW' [ 'IF EXISTS' ] tableName (
  'RENAME' ( 'TO' | 'AS' ) tableName
| 'OWNER' 'TO' userName
| [ '(' fieldNames ')' ] 'AS' select
)
;

commentStatement = 'COMMENT ON' (
  'TABLE' tableName [ 'IS' stringLiteral ] [ ( columnName 'IS' stringLiteral ) { ',' ( columnName 'IS' stringLiteral ) } ]
| (
    'COLUMN' fieldName
  | [ 'MATERIALIZED' ] 'VIEW' tableName
  | 'FUNCTION' functionName [ '(' [ parameterDeclarations ] ')' ]
  | 'PROCEDURE' procedureName [ '(' [ parameterDeclarations ] ')' ]
  ) 'IS' stringLiteral
)
;

createDatabaseStatement = 'CREATE DATABASE' [ 'IF NOT EXISTS' ] catalogName
;

createDomainStatement = 'CREATE DOMAIN' [ 'IF NOT EXISTS' ] domainName [ 'AS' ] dataType break
  [ 'DEFAULT' concat ]
  { constraint | 'CONSTRAINT' [ constraintName ] constraint }
;

createFunctionStatement = 'CREATE' [ 'OR ALTER' | 'OR REPLACE' ] 'FUNCTION' functionName [ '(' [ parameterDeclarations ] ')' ] break
  ( 'RETURNS' | 'RETURN' | 'RETURNING' ) dataType
{
  ( 'NO SQL' | 'CONTAINS SQL' | 'READS SQL DATA' | 'MODIFIES SQL DATA' )
| ( [ 'NOT' ] 'DETERMINISTIC' )
| ( 'RETURNS NULL ON NULL INPUT' | 'CALLED ON NULL INPUT' )
| 'COMMENT' [ '=' | 'IS' ] stringLiteral 
}
[ 'AS' | 'IS' ] break
(
  ( declarationStatement ';' )+ 'BEGIN' proceduralStatements 'END'
| proceduralStatement
)
;

createIndexStatement = 'CREATE' [ 'UNIQUE' ] 'INDEX' [ 'IF NOT EXISTS' ] [ indexName ] break
  [ indexType ] [ '(' sortFields ')' ] 'ON' tableName [ indexType ] [ '(' sortFields ')' ] [ indexType ] break
  [ ( 'INCLUDE' | 'COVERING' | 'STORING' ) '(' identifiers ')' ]
  [ 'VISIBLE' ]
  [ 'WHERE' condition | 'EXCLUDE NULL KEYS' ]
;

createProcedureStatement = 'CREATE' [ 'OR ALTER' | 'OR REPLACE' ] ( 'PROC' | 'PROCEDURE' ) procedureName [ '(' [ parameterDeclarations ] ')' ] break
{ 
  ( 'NO SQL' | 'CONTAINS SQL' | 'READS SQL DATA' | 'MODIFIES SQL DATA' )
| 'COMMENT' [ '=' | 'IS' ] stringLiteral
} 
[ 'AS' | 'IS' ]
(
  ( declarationStatement ';' )+ 'BEGIN' proceduralStatements 'END'
| proceduralStatement
)
;

createSchemaStatement = 'CREATE SCHEMA' [ 'IF NOT EXISTS' ] (
  schemaName
| [ 'AUTHORIZATION' userName ]
| schemaName [ 'AUTHORIZATION' userName ]
)
;

createSequenceStatement = 'CREATE' ( 'SEQUENCE' | 'GENERATOR' ) [ 'IF NOT EXISTS' ] sequenceName break
  [ 'AS' dataType ] break
  [ 'START' [ 'WITH' | '=' ] int ] break
  [ 'INCREMENT' [ 'BY' | '=' ] int ] break
  [ 'MINVALUE' [ '=' ] int | 'NO MINVALUE' | 'NOMINVALUE' ] break
  [ 'MAXVALUE' [ '=' ] int | 'NO MAXVALUE' | 'NOMAXVALUE' ] break
  [ 'CYCLE' | 'NO CYCLE' | 'NOCYCLE' ] break
  [ 'CACHE' [ '=' ] uint | 'NO CACHE' | 'NOCACHE' ]
  [ 'BIT_REVERSED_POSITIVE' ]
;

createSynonymStatement = 'CREATE' [ 'OR REPLACE' ] [ 'PUBLIC' | 'PRIVATE' ] ( 'ALIAS' | 'SYNONYM' ) synonymName 'FOR' name
;

createTableStatement = ( ( 'CREATE' | 'DECLARE' ) [ [ 'GLOBAL' | 'LOCAL' | 'PRIVATE' ] ( 'TEMP' | 'TEMPORARY' ) | 'VIRTUAL' ] 'TABLE' | 'CT' ) [ 'IF NOT EXISTS' ] tableName [ 'USING' identifier ]
( break )
(
  [ '(' identifiers ')' ] [ 'AS' ] select
| '('   ( 'CONSTRAINT' [ constraintName ] constraint | constraint | index | column )
  { ',' ( 'CONSTRAINT' [ constraintName ] constraint | constraint | index | column ) } ')'
)
break
[ 'ON COMMIT' ( 'DELETE ROWS' | 'DROP' | 'PRESERVE ROWS' ) ]
[ 'COMMENT' [ '=' | 'IS' ] stringLiteral ] break
[ 'OPTIONS' '(' 'DESCRIPTION' '=' stringLiteral ')' ]
;

createTriggerStatement = 'CREATE' [ 'OR ALTER' | 'OR REPLACE' ] 'TRIGGER'
[ 'ON' table ] break
( ( 'BEFORE' | 'FOR' ) | 'AFTER' | 'INSTEAD OF' )
  ( 'INSERT' | 'UPDATE' [ 'OF' fields ] | 'DELETE' ) { [ 'OR' | ',' ] ( 'INSERT' | 'UPDATE' [ 'OF' fields ] | 'DELETE' ) } break
[ 'ON' table ]
[ 'REFERENCING' ( ( 'OLD' | 'NEW' ) [ 'ROW' | 'TABLE' ] [ 'AS' ] identifier )+ ] break
[ 'FOR' [ 'EACH' ] ( 'ROW' | 'STATEMENT' ) ]
[ 'WHEN' '(' condition ')' ]
[ 'AS' ]
  proceduralStatement
;

createTypeStatement = 'CREATE TYPE' [ 'IF NOT EXISTS' ] typeName (
  'AS' (
    'ENUM' '(' [ stringLiteral { ',' stringLiteral } ] ')'
  | [ 'OBJECT' | 'STRUCT' ] '(' attribute { ',' attribute } ')'
  )
| 'FROM' dataType
)
;

createViewStatement = ( 'CREATE' [ 'OR ALTER' | 'OR REPLACE' ] [ 'FORCE' ] [ 'MATERIALIZED' ] 'VIEW' | 'CV' ) [ 'IF NOT EXISTS' ] tableName
  [ '(' fieldNames ')' ] 'AS' select
;

dropDatabaseStatement = 'DROP DATABASE' [ 'IF EXISTS' ] catalogName [ 'IF EXISTS' ]
;

dropDomainStatement = 'DROP DOMAIN' [ 'IF EXISTS' ] domainName [ 'IF EXISTS' ] [ 'CASCADE' | 'RESTRICT' ]
;

dropFunctionStatement = 'DROP FUNCTION' [ 'IF EXISTS' ] functionName [ '(' [ parameterDeclarations | parameterTypeDeclarations ] ')' ] [ 'IF EXISTS' ]
;

dropIndexStatement = 'DROP INDEX' [ 'IF EXISTS' ] indexName [ 'IF EXISTS' ] [ 'ON' tableName ] [ 'CASCADE' | 'RESTRICT' ]
;

dropProcedureStatement = 'DROP' ( 'PROC' | 'PROCEDURE' ) [ 'IF EXISTS' ] procedureName [ '(' [ parameterDeclarations | parameterTypeDeclarations ] ')' ] [ 'IF EXISTS' ]
;

dropSequenceStatement = 'DROP' ( 'SEQUENCE' | 'GENERATOR' ) [ 'IF EXISTS' ] sequenceName [ 'IF EXISTS' ] [ 'RESTRICT' ]
;

dropSequenceStatement = 'DROP' [ 'PUBLIC' ]  ( 'ALIAS' | 'SYNONYM' ) [ 'IF EXISTS' ] synonymName [ 'IF EXISTS' ] [ 'FOR' name ]
;

dropSchemaStatement = 'DROP SCHEMA' [ 'IF EXISTS' ] schemaName [ 'IF EXISTS' ] [ 'CASCADE' | 'RESTRICT' ]
;

dropTableStatement = 'DROP' [ [ 'GLOBAL' | 'LOCAL' ] 'TEMPORARY' ] 'TABLE' [ 'IF EXISTS' ] tableName [ 'IF EXISTS' ] [ 'CASCADE' [ 'CONSTRAINTS' ] | 'RESTRICT' ]
;

dropTriggerStatement = 'DROP TRIGGER' [ 'IF EXISTS' ] triggerName [ 'IF EXISTS' ] [ 'ON' tableName ]
;

dropTypeStatement = 'DROP TYPE' [ 'IF EXISTS' ] typeName { ',' typeName } [ 'IF EXISTS' ] [ 'CASCADE' | 'RESTRICT' ]
;

dropViewStatement = 'DROP' [ 'MATERIALIZED' ] 'VIEW' [ 'IF EXISTS' ] tableName [ 'IF EXISTS' ] [ 'CASCADE' [ 'CONSTRAINTS' ] | 'RESTRICT' ]
;

renameStatement = 'RENAME'
(
  'COLUMN' [ 'IF EXISTS' ] fieldName ( 'TO' | 'AS' ) fieldName
| 'DATABASE' [ 'IF EXISTS' ] catalogName ( 'TO' | 'AS' ) catalogName
| 'INDEX' [ 'IF EXISTS' ] indexName ( 'TO' | 'AS' ) indexName
| 'SCHEMA' [ 'IF EXISTS' ] schemaName ( 'TO' | 'AS' ) schemaName
| 'SEQUENCE' [ 'IF EXISTS' ] sequenceName ( 'TO' | 'AS' ) sequenceName
| 'VIEW' [ 'IF EXISTS' ] tableName ( 'TO' | 'AS' ) tableName
| [ 'TABLE' ] [ 'IF EXISTS' ] tableName ( 'TO' | 'AS' ) tableName
)
;

setCatalogStatement = 'SET CATALOG' catalogName
;

setSchemaStatement = ( 'SET' | 'OPEN' ) (
  [ 'CURRENT' ] 'SCHEMA'
| 'CURRENT SQLID'
) [ '=' ] ( schemaName | stringLiteral )
;

setConstraintStatement = 'SET' 'CONSTRAINT' ( 'ALL' | constraintNames ) ( 'DEFERRED' | 'IMMEDIATE' )
;

useStatement = 'USE' ( [ 'DATABASE' ] catalogName | [ 'SCHEMA' ] schemaName )
;

truncateStatement = 'TRUNCATE' [ 'TABLE' ] tableName { ',' tableName } [ 'CONTINUE IDENTITY' | 'RESTART IDENTITY' ] [ 'CASCADE' | 'RESTRICT' ]
;

grantStatement = 'GRANT' ( 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE' ) 'ON' tableName 'TO' ( userName | roleName | 'PUBLIC') [ 'WITH GRANT OPTION' ]
;

revokeStatement = 'REVOKE'
  [ 'GRANT OPTION FOR' ]
  (
    'SELECT'
  | 'INSERT'
  | 'UPDATE'
  | 'DELETE'
  )
  'ON' tableName
  'FROM' ( userName | roleName | 'PUBLIC')
;

resultStatement =
  selectStatement
| (
    insertStatement
  | updateStatement
  | deleteStatement
  )
  'RETURNING' ( '*' | fields )
;

selectStatement = select
;

insertStatement =
  [ with ]
  ( 'INSERT' | 'INS' ) [ 'INTO' ]  ( tableName | '(' select ')' ) [ [ 'AS' ] identifier ]
  [ '(' identifiers ')' ] break
  (
    values
  | 'DEFAULT VALUES'
  | 'SET' setClauses
  | select
  )
  break
  [
    'ON DUPLICATE KEY UPDATE' [ 'SET' ] ( setClauses | ( 'ALL' | 'NON KEY' | 'NON PRIMARY KEY' | 'NON CONFLICTING KEY' ) 'TO EXCLUDED' ) [ 'WHERE' condition ]
  | 'ON DUPLICATE KEY IGNORE'
  | 'ON CONFLICT' ( 'ON CONSTRAINT' constraintName | '(' fieldNames ')' ) [ 'WHERE' condition ] 'DO'
    (
      'NOTHING'
    | 'UPDATE' 'SET' ( setClauses | ( 'ALL' | 'NON KEY' | 'NON PRIMARY KEY' | 'NON CONFLICTING KEY' ) 'TO EXCLUDED' ) [ 'WHERE' condition ]
    )
  ]
;

values = [ 'VALUES' ] (
  rowValueExpression { ',' rowValueExpression }
| field { ',' field }
)
;

updateStatement =
  [ with ]
  ( 'UPDATE' | 'UPD' ) [ topSimple ]  ( tableName [ periodPortion ] | '(' select ')' ) [ [ 'AS' ] identifier ] break
( [ 'FROM' tables ] 'SET' setClauses
| 'SET' setClauses [ 'FROM' tables ] ) break
  [ 'WHERE' condition | 'ALL' ] break
  [ 'ORDER BY' sortFields ]
  [ 'LIMIT' field ]
;

setClauses = setClause { ',' setClause }
;

setClause = (
  fieldName '=' field
| rowValueExpression '=' ( rowValueExpression | select )
)
;

deleteStatement =
  [ with ]
  ( 'DELETE' | 'DEL' ) [ topSimple ] [ 'FROM' ] ( tableName [ periodPortion ] | '(' select ')' ) [ [ 'AS' ] identifier ] break
  [ ( 'USING' | 'FROM' ) tables ]
  [ 'WHERE' condition | 'ALL' ]
  [ 'ORDER BY' sortFields ]
  [ 'LIMIT' field ]
;

mergeStatement = [ with ] 'MERGE' [ 'INTO' ] tableName [ [ 'AS' ] identifier ]
  'USING' '(' select ')' [ correlationName ]
  'ON' condition break
  {
    'WHEN MATCHED' [ 'AND' condition ] 'THEN' mergeMatched
  | 'WHEN NOT MATCHED' [ 'BY SOURCE' ] [ 'AND' condition ] 'THEN' mergeMatched
  | 'WHEN NOT MATCHED' [ 'BY TARGET' ] [ 'AND' condition ] 'THEN' mergeNotMatched
  }
;

mergeMatched = ( 'DELETE' | 'UPDATE SET' setClauses [ 'WHERE' condition ] [ 'DELETE WHERE' condition ] )
;

mergeNotMatched = 'INSERT' '(' identifiers ')' 'VALUES' '(' fields ')' [ 'WHERE' condition ]
;

column =
(
  identifier [ dataType ]
  {
    (
      'DEFAULT' [ 'ON NULL' ] concat [ 'WITH VALUES' ]
    | 'ON UPDATE' field
    | ( 'COMPUTE' | 'COMPUTED' [ 'BY' ] | [ 'GENERATED' 'ALWAYS' ] 'AS' | 'ALIAS' | 'MATERIALIZED' ) field [ [ 'NOT' ] 'MATERIALIZED' | 'PERSISTED' | 'STORED' | 'VIRTUAL' ]
    | 'GENERATED' ( 'ALWAYS' | 'BY DEFAULT' [ 'ON NULL' ] ) 'AS IDENTITY' '('
        [ identity ]
      ')'
    | ( [ 'CONSTRAINT' [ constraintName ] ] (
        [ 'NOT' ] 'NULL'
      | 'PRIMARY KEY'
      | 'UNIQUE' [ 'KEY' | 'INDEX' ]
      | 'CHECK' '(' condition ')'
      | [ 'FOREIGN KEY' ] 'REFERENCES' reference
      ) )
    | 'AUTO_INCREMENT'
    | 'AUTOINCREMENT'
    | 'IDENTITY' [ '(' int ',' int ')' ]
    | 'READONLY'
    | ( 'VISIBLE' | 'NOT HIDDEN' | 'INVISIBLE' | 'NOT VISIBLE' | [ 'IMPLICITLY' ] 'HIDDEN' )
    | 'COMMENT' [ '=' | 'IS' ] stringLiteral
    | 'OPTIONS' '(' 'DESCRIPTION' '=' stringLiteral ')'
    )
  }
)
;

attribute = identifier dataType
;

startTransactionStatement = ( 'START' | 'BEGIN' ) ( 'WORK' | 'TRAN' | 'TRANSACTION' ) [ 'READ' 'WRITE' ] | 'BT'
;

savepointStatement =
  ( 'SAVE' ( 'TRAN' | 'TRANSACTION' )  | 'SAVEPOINT' ) identifier
  [ 'UNIQUE' ]
  [ 'ON ROLLBACK RETAIN CURSORS' ]
;

releaseSavepointStatement = 'RELEASE' [ [ 'TO' ] 'SAVEPOINT' ] identifier
;

commitStatement = 'COMMIT' [ 'WORK' | 'TRAN' | 'TRANSACTION' ] | 'END' 'TRANSACTION' | 'ET'
;

rollbackStatement = 'ROLLBACK' [ 'WORK' | 'TRAN' | 'TRANSACTION' ] [ [ 'TO' [ 'SAVEPOINT' ] ] identifier ] | 'ROLLBACK'
;

index = ( 'KEY' | 'INDEX' ) [ identifier ] [ indexType ] '(' sortFields ')' [ indexType ]
;

indexType = 'USING' identifier
;

constraint =
(
  [ 'NOT' ] 'NULL'
| 'PRIMARY KEY' [ indexType ] [ 'CLUSTERED' | 'NONCLUSTERED' ] '(' ( fieldNames | fieldName [ 'AUTOINCREMENT' ] ) ')' [ indexType ]
| 'UNIQUE' [ 'KEY' | 'INDEX' ] [ identifier ] [ indexType ] '(' sortFields ')' [ indexType ]
| 'FOREIGN KEY' '(' fieldNames ')' 'REFERENCES' reference
| 'CHECK' '(' condition ')'
) constraintState
;

constraintState = [ constraintDeferrability ] [ constraintEnforcement ]
;

constraintDeferrability =
  [ 'NOT' ] 'DEFERRABLE' [ 'INITIALLY' ( 'DEFERRED' | 'IMMEDIATE' ) ]
| 'INITIALLY' ( 'DEFERRED' | 'IMMEDIATE' ) [ [ 'NOT' ] 'DEFERRABLE' ]
;

constraintEnforcement =
  'ENABLE' [ 'VALIDATE' ]
| 'DISABLE' [ 'NOVALIDATE' ]
| [ 'NOT' ] 'ENFORCED'
;

reference = tableName '(' fieldNames ')'
  {
    'ON' ( 'DELETE' | 'UPDATE' )
    (
      'CASCADE'
    | 'NO ACTION'
    | 'RESTRICT'
    | 'SET DEFAULT'
    | 'SET NULL'
    )
  }
;

identity = identityProperty { [ ',' ] identityProperty }
;

identityProperty =
(
  'START WITH' ( 'LIMIT VALUE' | uint )
| 'INCREMENT BY' uint
| ( 'MAXVALUE' uint | 'NOMAXVALUE' )
| ( 'MINVALUE' uint | 'NOMINVALUE' )
| ( 'CACHE' uint | 'NOCACHE' )
| ( 'CYCLE' | 'NOCYCLE' )
| ( 'ORDER' | 'NOORDER' )
)
;

parameterDeclarations = parameterDeclaration { ',' parameterDeclaration }
;

parameterDeclaration = (
  [ parameterMode ] [ parameterName ] [ 'AS' | parameterMode ] dataType [ ( '=' | ':=' | 'DEFAULT' ) field ] [ 'OUT' | 'OUTPUT' ] [ 'READONLY' ]
)
;

parameterMode = 'IN' | 'OUT' | ( 'IN OUT' | 'INOUT' )
; 

parameterTypeDeclarations = dataType { ',' dataType }
;

with = 'WITH' [ 'RECURSIVE' ] commonTableExpression { ',' commonTableExpression }
;

commonTableExpression = identifier [ '(' identifiers ')' ] 'AS' [ [ 'NOT' ] 'MATERIALIZED' ] '(' resultStatement ')'
;

select =
  [ with ]
  queryExpressionBody
  [ orderBy ]
  [ seekFetch | offsetFetch ]
  [ forXML | forJSON ]
  [ forUpdate ]
  [ 'WITH' ( 'READ ONLY' | 'CHECK OPTION' ) ]
;

queryExpressionBody =
  queryTerm { ( 'UNION' | 'EXCEPT' | 'MINUS' ) [ 'ALL' | 'DISTINCT' ] queryTerm }
;

queryTerm =
  queryPrimary { 'INTERSECT' [ 'ALL' | 'DISTINCT' ] queryTerm }
;

queryPrimary =
  '(' select ')'
| ( 'SELECT' | 'SEL' )
    [ distinct ]
    [ top ]
    selectList
    [ 'INTO' ( tableName | variableNames ) ]
    [ tableExpression ]
| values
| 'TABLE' tableName
;

distinct = ( 'DISTINCT' | 'UNIQUE' ) [ 'ON' '(' fields ')' ] | 'ALL'
;

topSimple =
  'TOP' uint [ 'PERCENT' ]
;

top =
  'TOP' uint [ 'PERCENT' ] [ 'START AT' uint | 'WITH TIES' ]
| 'SKIP' uint [ 'FIRST' uint ]
;

selectList = selectField { ',' selectField }
;

selectField =
  '*' [ ( 'EXCEPT' | 'EXCLUDE' ) '(' fields ')' ]
| tableName '.' '*' [ ( 'EXCEPT' | 'EXCLUDE' ) '(' fields ')' ]
| field [ [ 'AS' ] identifier ]
;

tableExpression =
  [ 'FROM' tables ]
  [ 'WHERE' condition ]
  [ connectBy ]
  [ groupBy ] break
  [ 'HAVING' condition ]
  [ 'WINDOW' windows ]
  [ 'QUALIFY' condition ]
;

connectBy =
  'START WITH' condition 'CONNECT BY' [ 'NOCYCLE' ] condition
| 'CONNECT BY' [ 'NOCYCLE' ] condition [ 'START WITH' condition ]
;

groupBy = 'GROUP BY' [ 'ALL' | 'DISTINCT' ]
(
  'ROLLUP' '(' fields ')'
| 'CUBE' '(' fields ')'
| 'GROUPING SETS' '(' groupingSet { ',' groupingSet } ')'
| groupingSets [ 'WITH ROLLUP' ]
)
;

groupingSets = ( fields | groupingSet ) { ',' ( fields | groupingSet ) }
;

groupingSet = '(' [ fields ] ')'
;

windows = window { ',' window }
;

window = identifier 'AS' '(' windowSpecification ')'
;

windowSpecification =
  [ 'PARTITION BY' fields ]
  [ 'ORDER BY' sortFields ] break
  [ ( 'ROWS' | 'RANGE' | 'GROUPS' )
    ( 'BETWEEN' rangeBound 'AND' rangeBound | rangeBound)
    [ 'EXCLUDE' ( 'CURRENT ROW' | 'TIES' | 'GROUPS' | 'NO OTHERS' ) ]
  ]
;

orderBy =
  'ORDER' [ 'SIBLINGS' ] 'BY' sortFields
;

seekFetch =
  'SEEK' fields
  [
    'FETCH' ( 'FIRST' | 'NEXT' ) [ field ] [ 'PERCENT' ] ( 'ROW' | 'ROWS' ) ( 'ONLY' | 'WITH TIES' )
  | [ 'LIMIT' field [ 'PERCENT' ] [ 'WITH TIES' ] ]
  ]
;

offsetFetch =
  'OFFSET' field
  [
    [ 'ROW' | 'ROWS' ] 'FETCH' ( 'FIRST' | 'NEXT' ) [ field ] [ 'PERCENT' ] ( 'ROW' | 'ROWS' ) ( 'ONLY' | 'WITH TIES' )
  | 'LIMIT' field [ 'PERCENT' ] [ 'WITH TIES' ]
  ]
| 'LIMIT' field [ 'PERCENT' ]
  (
    [ 'WITH TIES' ] [ 'OFFSET' field ]
  | [ ',' field ]
  )
| 'ROWS' field [ 'TO' field ]
;

forUpdate =
  'FOR SHARE'
| 'FOR KEY SHARE'
| 'FOR NO KEY UPDATE'
| 'FOR UPDATE' [ 'OF' fields ] [ 'NOWAIT' | 'WAIT' uint | 'SKIP LOCKED' ]
;

forXML = 'FOR XML'
(
  'RAW' [ '(' stringLiteral ')' ]
| 'AUTO'
| 'PATH' [ '(' stringLiteral ')' ]
| 'EXPLICIT'
) { ',' ( 'ELEMENTS' [ 'XSINIL' | 'ABSENT' ]  | 'BINARY BASE64' | 'TYPE' | 'ROOT' [ '(' stringLiteral ')' ] ) }
;

forJSON = 'FOR' ( 'JSON' | 'JSONB') ( 'AUTO' | 'PATH' ) { ',' ( 'INCLUDE_NULL_VALUES' | 'WITHOUT_ARRAY_WRAPPER' | 'ROOT' [ '(' stringLiteral ')' ] ) }
;

sortFields = sortField { ',' sortField }
;

sortField = field [ 'ASC' | 'DESC' ] [ 'NULLS FIRST' | 'NULLS LAST' ]
;

tables = table { ',' table }
;

table = lateral { unqualifiedJoin | innerJoin | outerJoin | semiAntiJoin }
;

optionallyQualifiedJoin = 'CROSS JOIN'
( table joinQualification | lateral )
;

unqualifiedJoin =
( 'CROSS APPLY' | 'OUTER APPLY' | 'NATURAL' [ ( 'LEFT' | 'RIGHT' | 'FULL' ) [ 'OUTER' ] ] 'JOIN' )
lateral
;

innerJoin =
( [ 'INNER' ] [ joinHint ] 'JOIN' | 'STRAIGHT_JOIN' )
  table joinQualification
;

outerJoin =
  [ 'PARTITION BY' '(' fields ')' ]
( 'LEFT' | 'RIGHT' | 'FULL' ) [ 'OUTER' ] [ joinHint ] 'JOIN'
  table
  [ 'PARTITION BY' '(' fields ')' ]
  joinQualification
;

semiAntiJoin = [ 'LEFT' ] ( 'SEMI' | 'ANTI' ) 'JOIN' table joinQualification
;

joinHint = ( 'HASH' | 'LOOP' | 'LOOKUP' | 'MERGE' | 'STRAIGHT' )
;

lateral =
  'LATERAL' tableFactor
| tableFactor
;

tableFactor =
  tableName [ versions [ versions ] ] [ 'WITH ORDINALITY' ] [ correlationName ] [ tableHints ]
| '(' table ')' [ 'WITH ORDINALITY' ] [ correlationName ]
| '(' select ')' [ 'WITH ORDINALITY' ] [ correlationName ]
| tableFunction [ 'WITH ORDINALITY' ] [ correlationName ]
| 'UNNEST' '(' field ')' [ 'WITH ORDINALITY' ] [ correlationName ]
| values [ 'WITH ORDINALITY' ] [ correlationName ]
| 'OLD' 'TABLE' '(' ( updateStatement | deleteStatement | mergeStatement ) ')' [ 'WITH ORDINALITY' ] [ correlationName ]
| ( 'NEW' | 'FINAL' ) 'TABLE' '(' ( insertStatement |updateStatement | mergeStatement ) ')' [ 'WITH ORDINALITY' ] [ correlationName ]
| 'JSON_TABLE' '(' field ',' field 'COLUMNS' '(' jsonTableColumn { ',' jsonTableColumn } ')' ')'
| 'OPENJSON' '(' field [ ',' field ] ')' 'WITH' '(' openjsonColumn { ',' openjsonColumn } ')'
| 'XMLTABLE' '(' field [ 'PASSING' [ 'BY' ( 'REF' | 'VALUE' ) ] field ] 'COLUMNS' xmlTableColumn { ',' xmlTableColumn } ')'
;

jsonTableColumn =
  identifier ( dataType [ 'PATH' stringLiteral ] | 'FOR ORDINALITY' )
;

openjsonColumn =
  identifier dataType [ stringLiteral ]
;

xmlTableColumn =
  identifier ( dataType [ 'PATH' stringLiteral ] | 'FOR ORDINALITY' )
;

tableFunction =
  ( 'GENERATE_SERIES' | 'SYSTEM_RANGE' ) '(' field ',' field [ ',' field ] ')'
| ( 'SERIES_GENERATE_TINYINT' | 'SERIES_GENERATE_SMALLINT' | 'SERIES_GENERATE_INTEGER' | 'SERIES_GENERATE_BIGINT' ) '(' field ',' field ',' field ')'
| 'TABLE' '(' 'GENERATOR' '(' 'ROWCOUNT' '=>' unsignedInteger ')' ')'
| 'NUMBERS' '(' field [ ',' field ] ')'
;

tableHints =
  'WITH' '(' tableHint { ',' tableHint } ')'
| { ( 'USE' | 'FORCE' | 'IGNORE' ) ( 'INDEX' | 'KEY' ) [ 'FOR' ( 'JOIN' | 'ORDER BY' | 'GROUP BY' ) ] '(' [ identifiers ] ')' }
| '@{' 'FORCE_INDEX' '=' indexName '}'
;

pivot = todo
;

versions =
  'VERSIONS BETWEEN'
  ( 'SCN' | 'TIMESTAMP' ) ( 'MINVALUE' | field ) 'AND' ( 'MAXVALUE' | field )
| 'AS OF' ( 'SCN' | 'TIMESTAMP' )
| 'FOR' periodSpecification
;

periodSpecification = periodName (
  'AS OF' field
| 'BETWEEN' field 'AND' field
| periodSpecificationFromTo
| 'CONTAINED IN' '(' field ',' field ')'
| 'ALL'
)
;

periodPortion = 'FOR PORTION OF' periodSpecificationFromTo
;

periodSpecificationFromTo = 'FROM' field 'TO' field
;

periodName = name
;

joinQualification = 'ON' condition | 'USING' '(' [ identifiers ] ')'
;

correlationName = [ 'AS' ] identifier [ '(' identifiers ')' ]
;

rowValueExpression = [ 'ROW' | 'TUPLE' ] '(' [ fields ] ')'
;

arrayElements = arrayElement { ',' arrayElement }
;

arrayElement = field | '[' arrayElements ']'
;

fields = field { ',' field }
;

field = or
;

condition = or
;

or = xor { 'OR' xor }
;

xor = and { 'OR' and }
;

and = not { 'AND' not }
;

not = [ 'NOT' ] predicate
;

predicate =
  'EQUAL_NULL' '(' field ',' field ')'
| 'EXISTS' '(' select ')'
| 'JSON_EXISTS' '(' field ',' field [ ( 'TRUE' | 'FALSE' | 'UNKNOWN' | 'ERROR' ) 'ON ERROR' ]  ')'
| 'REGEXP_LIKE' '(' concat ',' concat ')'
| ( 'ST_COVEREDBY' '(' field ',' field ')' | 'SDO_COVEREDBY' '(' field ',' field ')' '=' "'TRUE'" )
| ( 'ST_COVERS' '(' field ',' field ')' | 'SDO_COVERS' '(' field ',' field ')' '=' "'TRUE'" )
| ( 'ST_CONTAINS' '(' field ',' field ')' | 'SDO_CONTAINS' '(' field ',' field ')' '=' "'TRUE'" | field '.' 'STContains' '(' field ')' )
| ( 'ST_CROSSES' '(' field ',' field ')' | field '.' 'STCrosses' '(' field ')' )
| ( 'ST_DISJOINT' '(' field ',' field ')' | field '.' 'STDisjoint' '(' field ')' )
| ( 'ST_EQUALS' '(' field ',' field ')' | 'SDO_EQUAL' '(' field ',' field ')' '=' "'TRUE'" | field '.' 'STEquals' '(' field ')' )
| ( 'ST_INTERSECTS' '(' field ',' field ')' | field '.' 'STIntersects' '(' field ')' )
| ( 'ST_ISCLOSED' '(' field ')' | field '.' 'STIsClosed' '(' ')' )
| ( 'ST_ISEMPTY' '(' field ')' | field '.' 'STIsEmpty' '(' ')' )
| ( 'ST_ISRING' '(' field ')' | field '.' 'STIsRing' '(' ')' )
| ( 'ST_ISSIMPLE' '(' field ')' | field '.' 'STIsSimple' '(' ')' )
| ( 'ST_ISVALID' '(' field ')' | field '.' 'STIsValid' '(' ')' | field '.' 'ST_ISVALID' '(' ')' )
| ( 'ST_OVERLAPS' '(' field ',' field ')' | 'SDO_OVERLAPS' '(' field ',' field ')' '=' "'TRUE'" | field '.' 'STOverlaps' '(' field ')' )
| ( 'ST_TOUCHES' '(' field ',' field ')' | 'SDO_TOUCH' '(' field ',' field ')' '=' "'TRUE'" | field '.' 'STTouches' '(' field ')' )
| ( 'ST_WITHIN' '(' field ',' field ')' | 'SDO_INSIDE' '(' field ',' field ')' '=' "'TRUE'" | field '.' 'STWithin' '(' field ')' )
| 'UNIQUE' '(' select ')'
| ( 'XMLEXISTS' '(' field 'PASSING' [ 'BY' ( 'REF' | 'VALUE' ) ] field ')' | field '.' 'exist' '(' field ')' )
| concat
  [
    comparator
    (
      ( 'ALL' | 'ANY' | 'SOME' ) '(' [ select | fields ] ')'
    | concat
    )
  | 'IS' [ 'NOT' ]
    (
      'NULL'
    | 'DOCUMENT'
    | 'JSON'
    | 'DISTINCT FROM' concat
    | concat
    )
  | [ 'NOT' ]
    (
      'IN' ( '(' [ select | fields ] ')' | field )
    | 'BETWEEN' [ 'SYMMETRIC' ] concat 'AND' concat
    | ( 'REGEXP' | 'RLIKE' | 'LIKE_REGEX' ) concat
    | 'LIKE' ( 'ANY' | 'ALL' ) '(' concat { ',' concat } ')' [ 'ESCAPE' characterLiteral ]
    | ( 'LIKE' | 'ILIKE' ) concat [ 'ESCAPE' characterLiteral ]
    | 'SIMILAR' 'TO' concat [ 'ESCAPE' characterLiteral ]
    )
  | '@>' concat
  | ( '~~' | '~~*' | '!~~' | '!~~*' | '~' | '!~' ) concat
  ]
| concat '*=' concat
| concat '=*' concat
| row2 'OVERLAPS' row2
;

row = [ 'ROW' | 'TUPLE' ] '(' fields ')'
;

row2 = [ 'ROW' | 'TUPLE' ] '(' field ',' field ')'
;

concat = collated { '||' collated }
;

collated = op [ 'COLLATE' collation ]
;

op = sum { ( '<<' | '>>' | '->' | '->>' | '?' ) sum }
;

sum = factor { ( '+' | '-' ) factor }
;

factor = exp { ( '*' | '/' | '%' | 'MOD' ) exp }
;

exp = unaryOps { ( '^' | '**' ) unaryOps }
;

unaryOps = { '+' | '-' | '~' | 'CONNECT_BY_ROOT' } term [ '(+)' ] { '::' dataType } [ '[' field ']' ]
;

term =
  ':' identifier
| '?'
| binaryLiteral
| bitLiteral
| stringLiteral
| ( 'ADD' | 'PLUS' ) '(' field ',' field ')'
| ( 'ADD_YEARS' | 'ADD_MONTHS' | 'ADD_DAYS' | 'ADD_HOURS' | 'ADD_MINUTES' | 'ADD_SECONDS' ) '(' field ',' field ')'
| 'ANY' '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ filter ] [ over ]
| ( 'ANY_VALUE' | 'ARBITRARY' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field [ 'HAVING' ( 'MIN' | 'MAX' ) field ] ')' [ filter ] [ over ]
| 'ACOS' '(' field ')'
| 'ACOSH' '(' field ')'
| 'ACOT' '(' field ')'
| 'ACOTH' '(' field ')'
| 'AND' '(' field ',' field ')'
| ( 'APPROX_COUNT_DISTINCT' | 'APPROXIMATE_COUNT_DISTINCT' | 'APPROX_DISTINCT' | 'uniq' ) '(' field ')' [ keep | filter ] [ over ]
| ( 'APPROX_PERCENTILE' | 'APPROX_PERCENTILE_CONT' | 'APPROX_PERCENTILE_DISC' ) '(' [ 'ALL' ] field ')' withinGroup [ over ]
| ( 'APPROXIMATE' 'PERCENTILE_DISC' ) '(' [ 'ALL' ] field ')' withinGroup [ over ]
| ( 'APPROX_QUANTILE' | 'APPROX_PERCENTILE' ) '(' field ',' field ')' [ filter ] [ over ]
| 'APPROXIMATE' 'COUNT' '(' 'DISTINCT' field ')' [ keep | filter ] [ over ]
| 'ARRAY' ( '[' [ arrayElements ] ']' | '(' select ')' )
| ( 'ARRAY_AGG' | 'groupArray' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field [ 'ORDER BY' sortFields ] ')' [ filter ] [ over ]
| ( 'ARRAY_APPEND' | 'arrayPushBack' ) '(' field ',' field ')'
| ( 'ARRAY_CAT' | 'ARRAY_CONCAT' | 'arrayConcat' ) '(' field ',' field ')'
| 'ARRAY_CONSTRUCT' '(' [ fields ] ')'
| 'ARRAY_CONSTRUCT_COMPACT' '(' [ fields ] ')'
| ( 'ARRAY_CONTAINS' | 'ARRAY_INCLUDES' | 'LIST_CONTAINS' | 'CONTAINS' | 'has' ) '(' field ',' field ')' 
| ( 'ARRAY_ALL_MATCH' | 'ALL_MATCH' | 'arrayAll' ) '(' ( field ',' lambda1 | lambda1 ',' field ) ')'
| ( 'ARRAY_ANY_MATCH' | 'ANY_MATCH' | 'arrayExists' ) '(' ( field ',' lambda1 | lambda1 ',' field ) ')'
| ( 'ARRAY_FILTER' | 'arrayFilter' ) '(' ( field ',' lambda1 | lambda1 ',' field ) ')'
| ( 'ARRAY_GET' | 'arrayElement' ) '(' field ',' field ')'
| ( 'ARRAY_MAP' | 'arrayMap' | 'ARRAY_TRANSFORM' | 'TRANSFORM' ) '(' ( field ',' lambda1 | lambda1 ',' field ) ')'
| ( 'ARRAY_NONE_MATCH' | 'NONE_MATCH' ) '(' ( field ',' lambda1 | lambda1 ',' field ) ')'
| ( 'ARRAY_OVERLAP' | 'ARRAYS_OVERLAP' ) '(' field ',' field ')'
| ( 'ARRAY_PREPEND' | 'arrayPushFront' ) '(' field ',' field ')'
| 'ARRAY_REMOVE' '(' field ',' field ')'
| 'ARRAY_REPLACE' '(' field ',' field ',' field ')'
| 'ARRAY_REVERSE' '(' field ')'
| 'ARRAY_TO_STRING' '(' field ',' field [ ',' field ] ')'
| ( 'ASC' | 'ASCII' | 'ASCII_VAL' ) '(' field ')'
| 'ASCII_CHAR' '(' field ')'
| 'ASIN' '(' field ')'
| 'ASINH' '(' field ')'
| 'ATAN' '(' field ')'
| 'ATANH' '(' field ')'
| ( 'ATN2' | 'ATAN2' ) '(' field ',' field ')'
| 'AVG' '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ keep | filter ] [ over ]
| 'BIN_SHL' '(' field ',' field ')'
| 'BIN_SHR' '(' field ',' field ')'
| ( 'BIT_GET' | 'BITGET' | 'GET_BIT' | 'GETBIT' | 'bitTest' ) '(' field ',' field ')'
| ( 'BIT_SET' | 'BITSET' | 'SET_BIT' | 'SETBIT' ) '(' field ',' field [ ',' field ] ')'
| 'BIT_LENGTH' '(' field ')'
| ( 'BITCOUNT' | 'BIT_COUNT' | 'bitCount' ) '(' field ')'
| ( 'BIN_AND' | 'BIN_AND_AGG' | 'BITAND' | 'BITAND_AGG' | 'BIT_AND' | 'BIT_AND_AGG' | 'BITWISE_AND_AGG' | 'groupBitAnd' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ filter ] [ over ]
| ( 'BIN_NAND' | 'BITNAND' | 'BIT_NAND' | 'BITWISE_AND' | 'bitAnd' ) '(' field ',' field ')'
| ( 'BIN_NAND' | 'BIN_NAND_AGG' | 'BITNAND' | 'BITNAND_AGG' | 'BIT_NAND' | 'BIT_NAND_AGG' | 'groupBitNand' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ filter ] [ over ]
| ( 'BIN_NOR' | 'BITNOR' | 'BIT_NOR' | 'bitNor' ) '(' field ',' field ')'
| ( 'BIN_NOR' | 'BIN_NOR_AGG' | 'BITNOR' | 'BITNOR_AGG' | 'BIT_NOR' | 'BIT_NOR_AGG' | 'groupBitNor' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ filter ] [ over ]
| ( 'BIN_NOT' | 'BITNOT' | 'BIT_NOT' | 'BITWISE_NOT' | 'bitNot' ) '(' field ')'
| ( 'BIN_OR' | 'BITOR' | 'BIT_OR' | 'BITWISE_OR' | 'bitOr' ) '(' field ',' field ')'
| ( 'BIN_OR' | 'BIN_OR_AGG' | 'BITOR' | 'BITOR_AGG' | 'BIT_OR' | 'BIT_OR_AGG' | 'BITWISE_OR_AGG' | 'groupBitOr' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ filter ] [ over ]
| ( 'BIN_TO_UUID' | 'UUIDNumToString' ) '(' field ')'
| ( 'BIN_XNOR' | 'BITXNOR' | 'BIT_XNOR' | 'bitXnor' ) '(' field ',' field ')'
| ( 'BIN_XNOR' | 'BIN_XNOR_AGG' | 'BITXNOR' | 'BITXNOR_AGG' | 'BIT_XNOR' | 'BIT_XNOR_AGG' | 'groupBitXnor' ) '(' [ 'ALL' ] field ')' [ filter ] [ over ]
| ( 'BIN_XOR' | 'BITXOR' | 'BIT_XOR' | 'BITWISE_XOR' | 'bitXor' ) '(' field ',' field ')'
| ( 'BIN_XOR' | 'BIN_XOR_AGG' | 'BITXOR' | 'BITXOR_AGG' | 'BIT_XOR' | 'BIT_XOR_AGG' | 'groupBitXor' ) '(' [ 'ALL' ] field ')' [ filter ] [ over ]
| ( 'BOOL_AND' | 'BOOLAND_AGG' | 'EVERY' | 'LOGICAL_AND' ) '(' field ')' [ filter ] [ over ]
| ( 'BOOL_OR' | 'BOOLOR_AGG' | 'LOGICAL_OR' ) '(' field ')' [ filter ] [ over ]
| 'CARDINALITY' '(' field ')'
| case
| 'CAST' '(' ( field | row ) 'AS' castDataType [ 'DEFAULT' 'NULL' 'ON' 'CONVERSION' 'ERROR' ]  ')'
| 'CBRT' '(' field ')'
| ( 'CEIL' | 'CEILING' ) '(' field ')'
| 'CENTURY' '(' field ')'
| 'CHARINDEX' '(' field ',' field [ ',' field ] ')'
| 'CHAR_LENGTH' '(' field ')'
| ( 'CHOOSE' | 'ELT' ) '(' fields ')'
| ( 'CHR' | 'CHAR' | 'ASCII_CHAR' ) '(' field ')'
| 'COALESCE' '(' fields ')'
| 'COERCE' '(' field 'AS' castDataType ')'
| 'CONCAT' '(' fields ')'
| 'CONCAT_WS' '(' field ',' fields ')'
| 'CONNECT_BY_ISCYCLE'
| 'CONNECT_BY_ISLEAF'
| 'CONTAINS' '(' field ',' field ')'
| 'CONVERT' '(' dataType ',' field [ ',' uint ] ')'
| 'COS' '(' field ')'
| 'COSH' '(' field ')'
| 'COT' '(' field ')'
| 'COTH' '(' field ')'
| 'COUNT' '(' [ [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] ( [ tableName '.' ] '*' | field | rowValueExpression ) ] ')' [ keep | filter ] [ over ]
| ( 'COUNTIF' | 'COUNT_IF' ) '(' condition ')' [ over ]
| 'CORR' '(' [ 'ALL' ] field ',' field ')' [ filter ] [ over ]
| ( 'COVAR_POP' | 'covarPop' ) '(' [ 'ALL' ] field ',' field ')' [ filter ] [ over ]
| ( 'COVAR_SAMP' | 'covarSamp' ) '(' [ 'ALL' ] field ',' field ')' [ filter ] [ over ]
| 'CUME_DIST' ( '(' ')' over | '(' [ 'ALL' ] fields ')' withinGroup )
| 'CURRVAL' '(' ( name | stringLiteral ) ')'
| 'CURRENT_CATALOG' '(' ')'
| 'CURRENT_DATABASE' '(' ')'
| ( 'CURRENT' 'DATE' | 'CURRENT_DATE' ) [ '(' ')' ]
| ( 'CURRENT' 'SCHEMA' | 'CURRENT_SCHEMA' ) [ '(' ')' ]
| ( 'CURRENT' 'TIME' | 'CURRENT_TIME' ) [ '(' ')' ]
| ( 'CURRENT' 'TIMESTAMP' | 'CURRENT_TIMESTAMP' ) [ '(' [ uint ] ')' ]
| ( 'CURRENT' 'USER' | 'CURRENT_USER' ) [ '(' ')' ]
| 'CURDATE' '(' ')'
| 'CURTIME' '(' ')'
| 'DATABASE' '(' ')'
| dateLiteral
| 'DATE' '(' ')'
| 'DATEADD' '(' datePart ',' field ',' field ')'
| 'DATEDIFF' '(' [ datePart ',' ] field ',' field ')'
| 'DATE_DIFF' '(' field ',' field ',' datePart ')'
| ( 'DATEPART' | 'DATE_PART' ) '(' datePart ',' field ')'
| 'DATE_PART_YEAR' '(' field ')'
| 'DATE_ADD' '(' field ',' field ')'
| 'DATE_SUB' '(' field ',' field ')'
| ( 'DATE_TRUNC' | 'DATETIME_TRUNC' ) '(' ( stringLiteral ',' field | field ',' datePart ) ')'
| 'DAY' '(' field ')'
| 'DAYOFMONTH' '(' field ')'
| 'DAYOFWEEK' '(' field ')'
| 'DB_NAME' '(' ')'
| 'DBINFO' '(' field ')'
| 'DECADE' '(' field ')'
| ( 'DECODE' | 'MAP' ) '(' field { ',' field ',' field } [ ',' field ] ')'
| ( 'DENSE_RANK' | 'DENSERANK' ) ( '(' ')' over | '(' [ 'ALL' ] fields ')' withinGroup )
| ( 'DEG' | 'DEGREE' | 'DEGREES' ) '(' field ')'
| 'DIGITS' '(' field ')'
| ( 'DIV' | 'DIVIDE' ) '(' field ',' field ')'
| 'ELEMENT_AT' '(' field ',' field ')'
| ( 'ENDS_WITH' | 'endsWith' ) '(' field ',' field ')'
| 'EPOCH' '(' field ')'
| 'EXTRACT' '(' datePart 'FROM' field ')'
| 'EXP' '(' field ')'
| 'FLOOR' '(' field ')'
| 'FIELD' '(' field ',' fields ')'
| 'FIRST_VALUE' '(' field [ 'RESPECT NULLS' | 'IGNORE NULLS' ] ')' [ 'RESPECT NULLS' | 'IGNORE NULLS' ] over
| 'GETDATE' '(' ')'
| 'GET_NEXT_SEQUENCE_VALUE' '(' [ 'SEQUENCE' ] name ')'
| ( 'GREATEST' | 'MAX' | 'MAXVALUE' ) '(' fields ')'
| 'GROUP_CONCAT' '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field [ 'ORDER BY' sortFields ] [ 'SEPARATOR' stringLiteral ] ')'
| 'GROUP_ID' '(' ')'
| 'GROUPING_ID' '(' fields ')'
| 'GROUPING' '(' fields ')'
| ( 'HEX' | 'TO_HEX') '(' field ')'
| 'HOUR' '(' field ')'
| 'IFNULL' '(' field ',' field ')'
| 'INSERT' '(' field ',' field ',' field ',' field ')'
| 'INSTR' '(' field ',' field [ ',' field ] ')'
| intervalLiteral
| ( 'IF' | 'IIF' ) '(' condition ',' field ',' field ')'
| 'ISJSON' '(' field ')'
| 'ISNULL' '(' field [ ',' field ] ')'
| 'IS_FIRST' '(' uint ')' over
| ( 'JSON' | 'JSONB' ) ( '[' [ fields ] ']' | '{' [ field ':' field { ',' field ':' field } ] '}' | stringLiteral )
| ( 'JSON_AGG' | 'JSONB_AGG' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field [ 'ORDER BY' sortFields ] ')' [ filter ] [ over ]
| 'JSON_ARRAY' '(' [ fields ] [ jsonNull ] [ jsonReturning ] ')'
| 'JSON_ARRAYAGG' '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field [ 'ORDER BY' sortFields ] [ jsonNull ] [ jsonReturning ] ')'
| ( 'JSON_ARRAY_LENGTH' | 'JSON_LENGTH' | 'JSONArrayLength' ) '(' field ')'
| ( 'JSON_BUILD_ARRAY' | 'JSONB_BUILD_ARRAY' ) '(' [ fields ] ')'
| ( 'JSON_BUILD_OBJECT' | 'JSONB_BUILD_OBJECT' ) '(' [ fields ] ')'
| ( 'JSON_KEY_EXISTS' | 'JSONB_KEY_EXISTS' ) '(' field ',' field ')'
| ( 'JSON_KEYS' | 'JSONB_KEYS' | 'JSONExtractKeys' ) '(' field ')'
| ( 'JSON_INSERT' | 'JSONB_INSERT' | 'JSON_ARRAY_INSERT' ) '(' field ',' field ',' field ')'
| 'JSON_OBJECT' '(' [ jsonEntries ] [ jsonNull ] [ jsonReturning ] ')'
| ( 'JSON_OBJECT_AGG' | 'JSONB_OBJECT_AGG' ) '(' [ 'ALL' ] field ',' field ')'
| 'JSON_OBJECTAGG' '(' [ 'ALL' ] jsonEntry [ jsonNull ] [ jsonReturning ] ')'
| ( 'JSON_REMOVE' | 'JSONB_REMOVE' ) '(' field ',' field ')'
| ( 'JSON_REPLACE' | 'JSONB_REPLACE' ) '(' field ',' field ',' field ')'
| ( 'JSON_SET' | 'JSONB_SET' ) '(' field ',' field ',' field ')'
| 'JSON_QUERY' '(' field ',' field { ( 'ERROR' | 'NULL' ) ( 'ON EMPTY' | 'ON ERROR' ) } [ jsonReturning ] ')'
| 'JSON_VALID' '(' field ')'
| 'JSON_VALUE' '(' field ',' field { ( 'ERROR' | 'NULL' | 'DEFAULT' field ) ( 'ON EMPTY' | 'ON ERROR' ) } [ jsonReturning ] ')'
| ( 'LOWER' | 'LCASE' ) '(' field ')'
| ( 'LPAD' | 'leftPad' ) '(' field ',' field [ ',' field ] ')'
| ( 'LTRIM' | 'trimLeft' ) '(' field [ ',' field ] ')'
| 'LEFT' '(' field ',' field ')'
| 'LEN' '(' field ')'
| 'LENGTH' '(' field ')'
| ( 'LN' | 'LOGN' ) '(' field ')'
| 'LOCATE' '(' field ',' field [ ',' field ] ')'
| 'LOCATE_IN_STRING' '(' field ',' field [ ',' field ] ')'
| 'LOG' '(' field [ ',' field ] ')'
| 'LOG10' '(' field ')'
| 'LEVEL'
| ( 'LEAST' | 'MIN' | 'MINVALUE' ) '(' fields ')'
| ( 'LEAD' | 'leadInFrame' ) '(' field [ ',' uint [ ',' field ] ] [ 'RESPECT NULLS' | 'IGNORE NULLS' ] ')' [ 'RESPECT NULLS' | 'IGNORE NULLS' ] over
| ( 'LAG' | 'lagInFrame' ) '(' field [ ',' uint [ ',' field ] ] [ 'RESPECT NULLS' | 'IGNORE NULLS' ] ')' [ 'RESPECT NULLS' | 'IGNORE NULLS' ] over
| 'LAST_DAY' '(' field ')'
| 'LAST_VALUE' '(' field [ 'RESPECT NULLS' | 'IGNORE NULLS' ] ')' [ 'RESPECT NULLS' | 'IGNORE NULLS' ] over
| 'LISTAGG' '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field [ ',' stringLiteral ] ')' [ withinGroup ] [ over ]
| ( 'MAX' | 'MAXIMUM' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ keep | filter ] [ over ]
| ( 'MAX_BY' | 'ARG_MAX' | 'argMax' ) '(' field ',' field ')' [ filter ] [ over ]
| ( 'MD5' | 'HASH_MD5' ) '(' field ')'
| 'MEDIAN' '(' field ')' [ filter ] [ over ]
| 'MICROSECOND' '(' field ')'
| 'MID' '(' field ',' field ',' field ')'
| 'MILLISECOND' '(' field ')'
| ( 'MIN' | 'MINIMUM' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ keep | filter ] [ over ]
| ( 'MIN_BY' | 'ARG_MIN' | 'argMin' ) '(' field ',' field ')' [ filter ] [ over ]
| 'MINUTE' '(' field ')'
| ( 'MOD' | 'MODULO' ) '(' field ',' field ')'
| 'MODE' '(' ')' withinGroup [ over ]
| 'MONTH' '(' field ')'
| ( 'MUL' | 'PRODUCT' ) '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ keep | filter ] [ over ]
| ( 'MUL' | 'MULTIPLY' ) '(' field ',' field ')'
| 'MULTISET' '(' select ')'
| 'MULTISET_AGG' '(' [ 'ALL' ] field [ 'ORDER BY' sortFields ] ')' [ filter ] [ over ]
| ( 'NEG' | 'NEGATE' ) '(' field ')'
| 'NEXT VALUE FOR' sequenceName
| 'NEXTVAL' '(' ( name | stringLiteral ) ')'
| 'NEWID' '(' [ field ] ')'
| 'NOW' '(' [ uint ] ')'
| 'NTH_VALUE' '(' field ',' uint [ 'FROM FIRST' | 'FROM LAST' ] [ 'RESPECT NULLS' | 'IGNORE NULLS' ] ')' [ 'FROM FIRST' | 'FROM LAST' ] [ 'RESPECT NULLS' | 'IGNORE NULLS' ] over
| 'NTILE' '(' uint ')' over
| 'NULLIF' '(' field ',' field ')'
| 'NVL' '(' field ',' field ')'
| 'NVL2' '(' field ',' field ',' field ')'
| 'OBJECT_AGG' '(' field ',' field ')'
| 'OBJECT_CONSTRUCT' '(' [ fields ] ')'
| 'OBJECT_CONSTRUCT_KEEP_NULL' '(' [ fields ] ')'
| ( 'OCTET_LENGTH' | 'BYTE_LENGTH' | 'DATALENGTH' | 'LENGTHB' ) '(' field ')'
| 'OR' '(' field ',' field ')'
| 'OVERLAY' '(' field 'PLACING' field 'FROM' field [ 'FOR' field ] ')'
| 'PI' '(' ')'
| 'POSITION' '(' ( field 'IN' field | field ',' field [ ',' field ] ) ')'
| 'PERCENT_RANK' ( '(' ')' over | '(' [ 'ALL' ] fields ')' withinGroup )
| ( 'PERCENTILE_CONT' | 'PERCENTILE_DISC' ) '(' [ 'ALL' ] field ')' withinGroup [ over ]
| ( 'PERCENTILE_CONT' | 'PERCENTILE_DISC' ) '(' field ',' field [ 'IGNORE NULLS' ] ')' over
| ( 'POW' | 'POWER' ) '(' field ',' field ')'
| 'PRIOR' concat
| 'QUARTER' '(' field ')'
| (
    'REGR_SLOPE'
  | 'REGR_INTERCEPT'
  | 'REGR_COUNT'
  | 'REGR_R2'
  | 'REGR_AVGX'
  | 'REGR_AVGY'
  | 'REGR_SXX'
  | 'REGR_SYY'
  | 'REGR_SXY'
  ) '(' [ 'ALL' ] field ',' field ')' [ filter ] [ over ]
| ( 'RAD' | 'RADIAN' | 'RADIANS' ) '(' field ')'
| 'RANK' ( '(' ')' over | '(' [ 'ALL' ] fields ')' withinGroup )
| 'RATIO_TO_REPORT' '(' field ')' over
| 'REGEXP_REPLACE' '(' field ',' field [ ',' field ] ')'
| 'REGEXP_REPLACE_ALL' '(' field ',' field [ ',' field ] ')'
| 'REGEXP_REPLACE_FIRST' '(' field ',' field [ ',' field ] ')'
| ( 'REPEAT' | 'REPLICATE' ) '(' field ',' field ')'
| ( 'REPLACE' | 'OREPLACE' | 'STR_REPLACE' | 'replaceAll' ) '(' field ',' field [ ',' field ] ')'
| 'REPLACE_REGEXPR' '(' field 'IN' field [ 'WITH' field ] [ 'OCCURRENCE' ( 'ALL' | unsignedInteger ) ] ')'
| ( 'REVERSE' | 'STRREVERSE' ) '(' field ')'
| 'RIGHT' '(' field ',' field ')'
| 'ROOT' '(' field ',' field ')'
| 'ROUND' '(' field [ ',' uint ] ')'
| ( 'ROW_NUMBER' | 'ROWNUMBER' ) '(' ')' over
| 'ROWNUM'
| ( 'RPAD' | 'rightPad' ) '(' field ',' field [ ',' field ] ')'
| ( 'RTRIM' | 'trimRight' ) '(' field [ ',' field ] ')'
| 'SCHEMA' '(' ')'
| 'SECOND' '(' field ')'
| ( 'SEQ4' | 'SEQ8' ) '(' ')'
| ( 'SHL' | 'SHIFTLEFT' | 'LSHIFT' | 'LEFT_SHIFT' | 'BIT_LSHIFT' | 'BITWISE_LEFT_SHIFT' | 'bitShiftLeft' ) '(' field ',' field ')'
| ( 'SHR' | 'SHIFTRIGHT' | 'RSHIFT' | 'RIGHT_SHIFT' | 'BIT_RSHIFT'| 'BITWISE_RIGHT_SHIFT' | 'bitShiftRight' ) '(' field ',' field ')'
| ( 'SIGN' | 'SGN' ) '(' field ')'
| ( 'SQR' | 'SQRT' ) '(' field ')'
| 'SQUARE' '(' field ')'
| 'SIN' '(' field ')'
| 'SINH' '(' field ')'
| 'SPLIT' '(' field ',' field ')'
| 'SPLIT_PART' '(' field ',' field ',' field ')'
| 'SPACE' '(' field ')'
| ( 'STARTS_WITH' | 'startsWith' ) '(' field ',' field ')'
| ( 'STDDEV' | 'STDDEV_POP' | 'STDEVP' | 'stddevPop' ) '(' [ 'ALL' ] field ')' [ over ]
| ( 'STDDEV_SAMP' | 'STDEV' | 'STDEV_SAMP' | 'stddevSamp' ) '(' [ 'ALL' ] field ')' [ over ]
| 'STRPOS' '(' field ',' field ')'
| 'STR_REPLACE' '(' field ',' field ',' field ')'
| 'STRING_AGG' '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ',' stringLiteral [ 'ORDER BY' sortFields ] ')' [ withinGroup ] [ over ]
| 'STRING_TO_ARRAY' '(' field ',' field [ ',' field ] ')'
| ( 'ST_AREA' '(' field ')' | 'SDO_GEOM' '.' 'SDO_AREA' '(' field ',' field ')' | field '.' 'STArea' '(' ')' )
| ( ( 'ST_ASBINARY' | 'ST_ASWKB' ) '(' field ')' | field '.' ( 'Get_WKB' '(' ')' | 'STAsBinary' '(' ')' ) )
| ( 'ST_ASTEXT' '(' field ')' | field '.' ( 'Get_WKT' '(' ')' | 'STAsText' '(' ')' ) )
| ( 'ST_BOUNDARY' '(' field ')' )
| ( 'ST_CENTROID' '(' field ')' | 'SDO_GEOM' '.' 'SDO_CENTROID' '(' field ',' field ')' | field '.' 'STCentroid' '(' ')' )
| ( 'ST_DIFFERENCE' '(' field ',' field ')' | 'SDO_GEOM' '.' 'SDO_DIFFERENCE' '(' field ',' field ',' field ')' | field '.' 'STDifference' '(' field ')' )
| ( 'ST_DIMENSION' '(' field ')' | field '.' 'STDimension' '(' ')' )
| ( 'ST_DISTANCE' '(' field ',' field ')' | 'SDO_GEOM' '.' 'SDO_DISTANCE' '(' field ',' field ',' field ')' | field '.' 'STDistance' '(' field ')' )
| ( 'ST_ENDPOINT' '(' field ')' | 'SDO_LRS' '.' 'GEOM_SEGMENT_END_PT' '(' field ')' | field '.' 'STEndPoint' '(' ')' )
| ( 'ST_EXTERIORRING' '(' field ')' | field '.' 'STExteriorRing' '(' ')' )
| ( 'ST_GEOMETRYN' '(' field ',' field ')' | 'SDO_UTIL' '.' 'EXTRACT' '(' field ',' field ')' | field '.' 'STGeometryN' '(' field ')' )
| ( 'ST_GEOMETRYTYPE' '(' field ')' | field '.' 'STGeometryType' '(' ')' )
| ( 'ST_GEOMFROMWKB' | 'SDO_GEOMETRY' | ( 'GEOMETRY' | 'GEOGRAPHY' ) '::' 'STGeomFromWKB' ) '(' field [ ',' field ] ')'
| ( 'ST_GEOMFROMTEXT' | 'SDO_GEOMETRY' | ( 'GEOMETRY' | 'GEOGRAPHY' ) '::' 'STGeomFromText' ) '(' field [ ',' field ] ')'
| ( 'ST_INTERIORRINGN' '(' field ')' | field '.' 'STInteriorRingN' '(' ')' )
| ( 'ST_INTERSECTION' '(' field ',' field ')' | 'SDO_GEOM' '.' 'SDO_INTERSECTION' '(' field ',' field ',' field ')' | field '.' 'STIntersection' '(' field ')' )
| ( 'ST_LENGTH' '(' field ')' | 'SDO_GEOM' '.' 'SDO_LENGTH' '(' field ',' field ')' | field '.' 'STLength' '(' ')' )
| ( 'ST_NUMGEOMETRIES' '(' field ')' | 'SDO_UTIL' '.' 'GETNUMELEM' '(' field ')' | field '.' 'STNumGeometries' '(' ')' )
| ( ( 'ST_NUMINTERIORRING' | 'ST_NUMINTERIORRINGS' | 'ST_NINTERIORRINGS' ) '(' field ')' | field '.' 'STNumInteriorRing' '(' ')' )
| ( ( 'ST_NPOINTS' | 'ST_NUMPOINTS' ) '(' field ')' | field '.' 'STNumPoints' '(' ')' )
| ( 'ST_PERIMETER' '(' field ')' )
| ( 'ST_POINTN' '(' field ',' field ')' | field '.' 'STPointN' '(' field ')' )
| ( 'ST_SRID' '(' field ')' | field '.' 'SDO_SRID' | field '.' 'STSrid' '(' ')' )
| ( 'ST_STARTPOINT' '(' field ')' | 'SDO_LRS' '.' 'GEOM_SEGMENT_START_PT' '(' field ')' | field '.' 'STStartPoint' '(' ')' )
| ( 'ST_TRANSFORM' '(' field ',' field ')' | 'SDO_CS' '.' 'TRANSFORM' '(' field ',' field ')' )
| ( 'ST_UNION' '(' field ',' field ')' | 'SDO_GEOM' '.' 'SDO_UNION' '(' field ',' field ',' field ')' | field '.' 'STUnion' '(' field ')' )
| ( 'ST_X' '(' field ')' | field '.' ( 'SDO_POINT' '.' 'X' | 'STX' ) )
| ( 'ST_XMIN' '(' field ')' | 'SDO_GEOM' '.' 'SDO_MIN_MBR_ORDINATE' '(' field ',' '1' ')' )
| ( 'ST_XMAX' '(' field ')' | 'SDO_GEOM' '.' 'SDO_MAX_MBR_ORDINATE' '(' field ',' '1' ')' )
| ( 'ST_Y' '(' field ')' | field '.' ( 'SDO_POINT' '.' 'Y' | 'STY' ) )
| ( 'ST_YMIN' '(' field ')' | 'SDO_GEOM' '.' 'SDO_MIN_MBR_ORDINATE' '(' field ',' '2' ')' )
| ( 'ST_YMAX' '(' field ')' | 'SDO_GEOM' '.' 'SDO_MAX_MBR_ORDINATE' '(' field ',' '2' ')' )
| ( 'ST_Z' '(' field ')' | field '.' ( 'SDO_POINT' '.' 'Z' | 'STZ' ) )
| ( 'ST_ZMIN' '(' field ')' | 'SDO_GEOM' '.' 'SDO_MIN_MBR_ORDINATE' '(' field ',' '3' ')' )
| ( 'ST_ZMAX' '(' field ')' | 'SDO_GEOM' '.' 'SDO_MAX_MBR_ORDINATE' '(' field ',' '3' ')' )
| ( 'SUB' | 'SUBTRACT' | 'MINUS' ) '(' field ',' field ')'
| ( 'SUBSTR' | 'SUBSTRING' ) '(' field ',' field [ ',' field ] ')'
| 'SUBSTRING' '(' field 'FROM' field [ 'FOR' field ] ')'
| ( 'SUBSTRING_INDEX' | 'substringIndex' ) '(' field ',' field ',' field ')'
| 'SUM' '(' [ 'DISTINCT' | 'UNIQUE' | 'ALL' ] field ')' [ keep | filter ] [ over ]
| 'SYS_CONNECT_BY_PATH' '(' field ',' stringLiteral ')'
| 'TAN' '(' field ')'
| 'TANH' '(' field ')'
| timeLiteral
| timestampLiteral
| 'TIMESTAMP_DIFF' '(' field ',' field ',' datePart ')'
| 'TIMEZONE' '(' field ')'
| 'TIMEZONE_HOUR' '(' field ')'
| 'TIMEZONE_MINUTE' '(' field ')'
| 'TO_CHAR' '(' field [ ',' field ] ')'
| 'TO_DATE' '(' field ',' field ')'
| 'TO_NUMBER' '(' field ')'
| 'TO_TIMESTAMP' '(' field ',' field ')'
| ( 'TRANSLATE' | 'OTRANSLATE' ) '(' field ',' field ',' field ')'
| ( 'TRIM' | 'trimBoth' ) '(' field [ ',' field ] ')'
| 'TRIM' '(' [ ( 'LEADING' | 'L' | 'TRAILING' | 'T' | 'BOTH' | 'B' ) [ field ] ] 'FROM' field ')'
| 'TRUNC' '(' field [ ',' stringLiteral ] ')'
| ( 'TRUNC' | 'TRUNCATE' | 'TRUNCNUM' ) '(' field ',' field ')'
| truthValue
| 'UNIX_TIMESTAMP' '(' field ')'
| ( 'UUID' | 'UUID_GENERATE' | 'UUID_STRING' | 'GENGUID' | 'GENERATE_UUID' | 'GEN_RANDOM_UUID' | 'RANDOM_UUID' | 'SYS_GUID' | 'SYSUUID' ) '(' ')'
| ( 'UUID_TO_BIN' | 'UUIDStringToNum' ) '(' field ')'
| ( 'UPPER' | 'UCASE' ) '(' field ')'
| ( 'VAR_POP' | 'VARIANCE' | 'VARP' | 'varPop' ) '(' [ 'ALL' ] field ')' [ filter ] [ over ]
| ( 'VAR_SAMP' | 'VARIANCE_SAMP' | 'VAR' | 'varSamp' ) '(' [ 'ALL' ] field ')' [ filter ] [ over ]
| ( 'WIDTH_BUCKET' | 'widthBucket' ) '(' field ',' field ',' field ',' field ')'
| 'XMLAGG' '(' [ 'ALL' ] field [ 'ORDER BY' sortFields ] ')' [ filter ] [ over ]
| 'XMLCOMMENT' '(' field ')'
| 'XMLCONCAT' '(' fields ')'
| 'XMLDOCUMENT' '(' field ')'
| 'XMLELEMENT' '(' [ 'NAME' ] identifier [ ',' 'XMLATTRIBUTES' '(' ( field [ 'AS' identifier ] ) { ',' ( field [ 'AS' identifier ] ) } ')' ]
| 'XMLFOREST' '(' ( field [ 'AS' identifier ] ) { ',' ( field [ 'AS' identifier ] ) } ')'
| 'XMLPARSE' '(' ( 'DOCUMENT' | 'CONTENT' ) field ')'
| 'XMLPI' '(' 'NAME' identifier [ ',' field ] ')'
| ( 'XMLQUERY' '(' field 'PASSING' [ 'BY' ( 'REF' | 'VALUE' ) ] field [ 'RETURNING CONTENT' ] ')' | field '.' 'query' '(' field ')' )
| 'XMLSERIALIZE' '(' [ 'DOCUMENT' | 'CONTENT' ] field ')'
| 'XMLTYPE' '(' field ')'
| 'XMLPI' '(' 'NAME' identifier [ ',' field ] ')'
| 'XOR' '(' field ',' field ')'
| 'YEAR' '(' field ')'
| 'ZEROIFNULL' '(' field ')'
| unsignedNumericLiteral
| '(' select ')'
| rowValueExpression
| typedLiteral
| '{' 'd' stringLiteral '}'
| '{' 't' stringLiteral '}'
| '{' 'fn' term '}'
| '{' 'ts' stringLiteral '}'
| identifier '(' [ fields ] ')'
;

lambda1 = 
  fieldName '->' field
| 'LAMBDA' fieldName ':' field
;

lambda2 = 
  '(' fieldName ',' fieldName ')' '->' field
| 'LAMBDA' fieldName ',' fieldName ':' field
;

jsonNull = 'NULL ON NULL' | 'ABSENT ON NULL'
;

jsonReturning = 'RETURNING' dataType
;

jsonEntries = jsonEntry { ',' jsonEntry }
;

jsonEntry =
  [ 'KEY' ] field 'VALUE' field
| field ',' field
;

truthValue = 'TRUE' | 'FALSE' | 'NULL'
;

datePart =
  ( 'YEAR' | 'YYYY' | 'YY' )
| ( 'MONTH' | 'MM' | 'M' )
| ( 'DAY' | 'DD' | 'D' )
| ( 'HOUR' | 'HH' )
| ( 'MINUTE' | 'MI' | 'N' )
| ( 'SECOND' | 'SS' | 'S' )
| ( 'MILLISECOND' | 'MS' )
| ( 'MICROSECOND' | 'MCS' )
| ( 'NANOSECOND' | 'NS' )
| 'EPOCH'
| ( 'QUARTER' | 'QQ' | 'Q' )
| ( 'WEEK ' | 'WW' | 'WK' )
| ( 'ISO_DAY_OF_WEEK' | 'ISODOW' )
| ( 'DAY_OF_WEEK' | 'DAYOFWEEK' | 'WEEKDAY' | 'W' )
| ( 'DAY_OF_YEAR' | 'DAYOFYEAR' | 'DOY' | 'DY' | 'Y')
;

keep = 'KEEP' '(' 'DENSE_RANK' ( 'FIRST' | 'LAST' ) 'ORDER BY' sortFields ')'
;

filter = 'FILTER' '(' 'WHERE' condition ')'
;

over = 'OVER' ( identifier | '(' windowSpecification ')' )
;

withinGroup = 'WITHIN GROUP' '(' 'ORDER BY' sortFields ')'
;

rangeBound =
  ( 'UNBOUNDED' | uint) ( 'PRECEDING' | 'FOLLOWING' )
| 'CURRENT ROW'
;

case = 'CASE'
(
  (
    'WHEN' condition 'THEN' field
  )+
| field
  (
    'WHEN' field 'THEN' field
  )+
)
[ 'ELSE' field ] 'END'
;

comparator = '=' | '==' | '!=' | '<>' | '^=' | '>=' | '>' | '<=>' | '<=' | '<' | 'EQ' | 'NE' | 'GT' | 'GE' | 'LT' | 'LE'
;

castDataType =
  dataType
| 'SIGNED' [ 'INTEGER' ]
| 'UNSIGNED' [ 'INTEGER' ]
;

dataType =
(
  'AUTO_INCREMENT' [ '(' fields ')' ]
| 'BIGINT' [ 'UNSIGNED' ]
| 'BINARY' [ 'VARYING' ] [ '(' uint ')' ]
| 'BIT' [ '(' uint ')' ]
| 'BLOB' [ '(' uint ')' | 'SUB_TYPE' ( '0' | 'BINARY' | '1' | 'TEXT' ) ]
| ( 'BOOL' | 'BOOLEAN' )
| ( 'CHAR' | 'CHARACTER' ) [ 'VARYING' ] [ '(' uint [ 'BYTE' | 'CHAR' ] ')' ] [ 'FOR BIT DATA' ] [ 'COLLATE' collationName ]
| ( ( 'CHAR' | 'CHARACTER' ) 'LARGE OBJECT' | 'CLOB' ) [ '(' uint ')' ] [ 'COLLATE' collationName ]
| 'DATE'
| ( 'DEC' | 'DECIMAL' | 'BIGDECIMAL' ) [ '(' ( '*' | uint ) [ ',' int ] ')' ]
| 'DOUBLE' [ 'PRECISION' ] [ '(' uint [ ',' uint ] ')' ]
| 'ENUM' '(' stringLiteral [ ',' stringLiteral ] ')' [ 'COLLATE' collationName ]
| 'FLOAT' [ '(' uint [ ',' uint ] ')' ]
| 'GEOGRAPHY'
| 'GEOMETRY'
| 'IDENTITY' [ '(' fields ')' ]
| ( 'INT' | 'INTEGER' ) [ '(' uint ')' ] [ 'UNSIGNED' ]
| 'INTERVAL' ( 'YEAR' [ '(' uint ')' ] 'TO' 'MONTH' | 'DAY' [ '(' uint ')' ] 'TO' 'SECOND' [ '(' uint ')' ] )
| 'JSON'
| 'JSONB'
| 'LONGBLOB'
| 'LONGTEXT' [ 'COLLATE' collationName ]
| 'LONG NVARCHAR' [ '(' characterLength ')' ] [ 'COLLATE' collationName ]
| 'LONG VARBINARY' [ '(' uint ')' ]
| 'LONG VARCHAR' [ '(' uint ')' ] [ 'FOR BIT DATA' ] [ 'COLLATE' collationName ]
| 'MEDIUMBLOB'
| 'MEDIUMINT' [ '(' uint ')' ] [ 'UNSIGNED' ]
| 'MEDIUMTEXT' [ 'COLLATE' collationName ]
| 'NATIONAL' ( 'CHAR' | 'CHARACTER' ) [ 'VARYING' ] [ '(' uint ')' ] [ 'COLLATE' collationName ]
| 'NCHAR' [ '(' uint ')' ] [ 'COLLATE' collationName ]
| 'NCLOB' [ 'COLLATE' collationName ]
| ( 'NUMBER' | 'NUMERIC' | 'BIGNUMERIC' ) [ '(' ( '*' | uint ) [ ',' int ] ')' ]
| 'NVARCHAR' [ '(' uint ')' ] [ 'COLLATE' collationName ]
| 'OTHER'
| 'REAL' [ '(' uint [ ',' uint ] ')' ]
| 'SERIAL'
| 'SERIAL4'
| 'SERIAL8'
| 'SET' '(' stringLiteral [ ',' stringLiteral ] ')' [ 'COLLATE' collationName ]
| 'SMALLINT' [ '(' uint ')' ] [ 'UNSIGNED' ]
| 'TEXT' [ '(' uint ')' ] [ 'COLLATE' collationName ]
| 'TIMESTAMP' [ '(' uint ')' ] [ ( 'WITH' | 'WITHOUT' ) 'TIME ZONE' ]
| 'TIMESTAMPTZ' [ '(' uint ')' ]
| 'TIME' [ '(' uint ')' ] [ ( 'WITH' | 'WITHOUT' ) 'TIME ZONE' ]
| 'TIMETZ' [ '(' uint ')' ]
| 'TINYBLOB'
| 'TINYINT' [ '(' uint ')' ] [ 'UNSIGNED' ]
| 'TINYTEXT' [ 'COLLATE' collationName ]
| 'UBIGINT'
| 'UINTEGER'
| 'USMALLINT'
| 'UTINYINT'
| 'UUID'
| ( 'VARCHAR' | 'CHARACTER VARYING' ) [ '(' uint [ 'BYTE' | 'CHAR' ] ')' ] [ 'FOR BIT DATA' ] [ 'COLLATE' collationName ]
| 'VARCHAR_IGNORECASE' [ '(' uint ')' ]
| 'VARCHAR2' [ '(' uint [ 'BYTE' | 'CHAR' ] ')' ] [ 'COLLATE' collationName ]
| 'VARBINARY' [ '(' uint ')' ]
| 'XML'
| 'YEAR' '(' uint ')'
| arrayDataType
)
;

characterLength = uint [ 'BYTE' | 'CHAR' | 'OCTETS' | 'CHARACTERS' ]
;

arrayType = (
  'ARRAY'
| dataType [ 'ARRAY' ] '[' [ uint ] ']'
| dataType '[' ']'
| 'ARRAY' '(' dataType ')'
| 'ARRAY' '<' dataType '>'
)
;

constraintNames = constraintName { ',' constraintName }
;

constraintName = identifier
;

catalogName = name
;

domainName = name
;

schemaName = name
;

tableName = name
;

triggerName = name
;

typeName = name
;

functionName = name
;

indexName = name
;

parameterName = name
;

procedureName = name
;

sequenceName = name
;

synonymName = name
;

userName = name
;

roleName = name
;

fieldNames = fieldName { ',' fieldName }
;

fieldName = name
;

collation = name
;

variableNames = variableName { ',' variableName }
;

variableName = name
;

labelName = name
;

name = identifier { ( '.' | '!' ) identifier }
;

binaryLiteral = 'X' "'" characters* "'"
;

bitLiteral = 'B' "'" { 0 | 1 } "'"
;

stringLiteral =
(
  [ 'N' ] "'" character* "'"
| '$' nonSpaceCharacter* '$' character* '$' nonSpaceCharacter* '$'
| "q'[" characters* "]'"
| "q'{" characters* "}'"
| "q'(" characters* ")'"
| "q'<" characters* ">'"
| "q'" nonSpaceCharacter characters* nonSpaceCharacter "'"
)
;

characterLiteral = "'" character "'"
;

typedLiteral = (
  'BIGINT'
| 'BOOLEAN'
| 'CHAR'
| 'DECFLOAT'
| 'DECIMAL'
| 'DOUBLE' [ 'PRECISION' ]
| 'FLOAT'
| 'INT'
| 'INTEGER'
| 'JSON'
| 'JSONB'
| 'NUMBER'
| 'NUMERIC'
| 'REAL'
| 'SMALLINT'
| 'TINYINT'
| 'UUID'
| 'VARCHAR'
) stringLiteral
;

dateLiteral = 'DATE' stringLiteral
;

timeLiteral = 'TIME' stringLiteral
;

timestampLiteral = 'TIMESTAMP' stringLiteral
;

intervalLiteral =
  'INTERVAL' (
  stringLiteral
| field
  (
    ( 'YEAR' [ 'TO' 'MONTH' ] | 'YEAR_MONTH' | 'YEARS' )
  | ( 'QUARTER' | 'QUARTERS' )
  | ( 'MONTH' | 'MONTHS' )
  | ( 'WEEK' | 'WEEKS' )
  | ( 'DAY' [ '(' uint ')' ] [ 'TO' ( 'HOUR' | 'MINUTE' | 'SECOND' ) [ '(' uint ')' ] ] | 'DAY_HOUR' | 'DAY_MINUTE' | 'DAY_SECOND' | 'DAYS' )
  | ( 'HOUR' [ '(' uint ')' ] [ 'TO' ( 'MINUTE' | 'SECOND' ) [ '(' uint ')' ] ] | 'HOUR_MINUTE' | 'HOUR_SECOND' | 'HOURS' )
  | ( 'MINUTE' [ '(' uint ')' ] [ 'TO' 'SECOND' [ '(' uint ')' ] ] | 'MINUTE_SECOND' | 'MINUTES' )
  | ( 'SECOND' [ '(' uint ')' ] | 'SECONDS' )
  | ( 'MILLISECOND' [ '(' uint ')' ] | 'MILLISECONDS' )
  | ( 'MICROSECOND' [ '(' uint ')' ] | 'MICROSECONDS' )
  | ( 'NANOSECOND' [ '(' uint ')' ] | 'NANOSECONDS' )
  )
)
;

int = signedInteger
;

signedInteger = todo
;

uint = unsignedInteger
;

unsignedInteger = todo
;

unsignedNumericLiteral = todo
;

signedFloatLiteral = todo
;

unsignedFloatLiteral = todo
;

identifiers = identifier { ',' identifier }
;

identifier =
  identifierStart { identifierPart }
| '"' doubleQuotedIdentifierPart { doubleQuotedIdentifierPart } '"'
| '`' backtickQuotedIdentifierPart { backtickQuotedIdentifierPart } '`'
| '[' brackedQuotedIdentifierPart { brackedQuotedIdentifierPart } ']'
;

identifierStart = todo
;

identifierPart = todo
;

doubleQuotedIdentifierPart =
  nonDoubleQuoteCharacter
| doubleQuote
;

backtickQuotedIdentifierPart =
  nonBacktickCharacter
| doubleBacktick
;

brackedQuotedIdentifierPart =
  nonClosingBracketCharacter
| doubleClosingBracket
;

nonDoubleQuoteCharacter = todo
;

nonBacktickCharacter = todo
;

nonClosingBracketCharacter = todo
;

doubleQuote = '""'
;

doubleBacktick = '``'
;

doubleClosingBracket = ']]'
;
```

The diagrams have been created with the neat [RRDiagram library by Christopher Deckers](https://github.com/Chrriis/RRDiagram).

<a id="sql-interpreter"></a>
### 3.20. SQL interpreter

Starting with jOOQ 3.13, a SQL interpreter has been implemented, which can interpret a subset of the SQL language (mostly [DDL statements](#ddl-statements)) and maintain an up-to-date in-memory representation of your database meta model.

The interpreter is made available through a variety of [`DSLContext.meta()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#meta(java.lang.String...)) methods, which can be used for example as follows:

```java
// Using the parser
Meta meta1 = create.meta(
  "create table t (i int)",
  "alter table t add primary key (i)",
  "create table u (i int references t)"
);

Meta meta2 = create.meta(
  createTable("t").column("i", INTEGER),
  alterTable("t").add(primaryKey("i")),
  createTable("u").column("i", INTEGER).constraint(foreignKey("i").references("t"))
);
```

Interpretation is incremental. On any pre-existing [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) model, `apply()` can be called to derive a new version of the model. This includes being able to combine different source of models, including JDBC [`java.sql.DatabaseMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/DatabaseMetaData.html) based ones.

```java
// Get live access to your current Connection's DatabaseMetaData
Meta meta1 = create.meta();

// Create a new model representation with an interpreted, additional table
// The query is not executed! The DDL is only interpreted in jOOQ, and a derived meta model is created from it
Meta meta2 = meta1.apply("create table t (i int)");

// Create another new model representation, with a table removed
// Again, none of these queries are executed.
Meta meta3 = meta2.apply("drop table u cascade");
```

Finally, if you want to export the meta model to one of the different supported formats, you can use:

```java
// The JAXB annotated XML version of your "information schema":
InformationSchema is = meta.informationSchema();

// A set of DDL queries that can be used to reproduce your schema on any database and dialect:
Queries queries = meta.ddl();
```

Different sources for the meta model can be used, including jOOQ API built [DDL statements](#ddl-statements), or a set of SQL strings that will be parsed using the [SQL parser](#sql-parser), dynamically. These sources could be database change management scripts, such as those managed by Flyway, or by jOOQ.

The resulting type is the runtime [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) model, which gives access to the ordinary jOOQ API, including [catalogs and schemas](#catalog-and-schema-expressions) or [tables](#table-expressions). These objects can then, in turn, be used with any other jOOQ API, for instance to count all the rows in all tables in a database:

```java
for (Table<?> table : meta.getTables())
  System.out.println(table + " has " + create.fetchCount(table) + " rows");
```

For a set of interpreter configuration flags, please refer to the [section about the interpreter settings](#settings-interpreter).

<a id="schema-diff"></a>
### 3.21. Schema diff

Starting with jOOQ 3.13, and the capability of [interpreting DDL](#sql-interpreter), jOOQ is now able to create a "diff" between two versions of your schema. An example:

```java
// We're using interpreted Meta objects. But any other type of Meta can be used, too
Meta m1 = create.meta("create table t (i int)");
Meta m2 = create.meta("create table t (i int, j int)");

// The diff is now printed in both directions:
System.out.println("-- Schema upgrade");
System.out.println(m1.migrateTo(m2));
System.out.println();
System.out.println("-- Schema downgrade");
System.out.println(m2.migrateTo(m1));
```

The output of the above program is:

```sql
-- Schema upgrade
alter table T add J int;

-- Schema downgrade
alter table T drop J;
```

The diff algorithm can non-ambiguously determine the following set of changes

- Catalog additions and removals
- Schema additions and removals
- Table additions and removals
- Column additions and removals
- Column type changes
- Constraint additions, removals, and renamings (including primary keys, unique keys, foreign keys, and check constraints)
- Index additions, removals, and renamings
- View additions, removals, and replacements
- Sequence additions, removals, and sequence flag changes
- Domain additions, removals, and property changes
- Synonym additions and removals
- Comment additions and removals

The following set of changes are difficult to detect. Some heuristics could be implemented, but are not yet supported in jOOQ:

- Catalog renamings
- Schema renamings, and moving between catalogs
- Table renamings, and moving between schemas
- Column renamings, and moving between tables
- View renamings

Another way to use this API is the [https://www.jooq.org/diff](https://www.jooq.org/diff) website.

<a id="schema-diff-cli"></a>
### 3.22. Schema diff CLI

The schema diff API can be used to generate a diff between schema versions programmatically, as we've seen in the [previous section about the schema diff API](#schema-diff). This functionality can also usefully be accessed on the command line as shown below:

```text
$ java -cp jooq-3.22.0-SNAPSHOT.jar:reactive-streams-1.0.3.jar:r2dbc-spi-1.0.0.RELEASE.jar org.jooq.DiffCLI -h
Usage:
  -f / --formatted                          Format output SQL
  -h / --help                               Display this help
  -k / --keyword      <RenderKeywordStyle>  Specify the output keyword style (org.jooq.conf.RenderKeywordStyle)
  -i / --identifier   <RenderNameStyle>     Specify the output identifier style (org.jooq.conf.RenderNameStyle)
  -F / --from-dialect <SQLDialect>          Specify the input dialect (org.jooq.SQLDialect)
  -T / --to-dialect   <SQLDialect>          Specify the output dialect (org.jooq.SQLDialect)
  -1 / --sql1         <String>              Specify the input SQL string 1 (from SQL)
  -2 / --sql2         <String>              Specify the input SQL string 2 (to SQL)

$ java -cp jooq-3.22.0-SNAPSHOT.jar:reactive-streams-1.0.3.jar:r2dbc-spi-1.0.0.RELEASE.jar org.jooq.DiffCLI -T POSTGRES -1 "create table t (i int);" -2 "create table t (i int, j int)"
alter table t add j int null;
```

**Windows users:** Please replace `:` by `;` in the above examples.

Another way to use this API is the [https://www.jooq.org/diff](https://www.jooq.org/diff) website.

<a id="names"></a>
### 3.23. Names and identifiers

Various SQL objects [columns](#column-expressions) or [tables](#table-expressions) can be referenced using names (often also called identifiers). SQL dialects differ in the way they understand names, syntactically. The differences include:

- The permitted characters to be used in "unquoted" names
- The permitted characters to be used in "quoted" names
- The name quoting characters (e.g. `"double quotes"`, `` `backticks` ``, or `[brackets]`) (e.g. `"double quotes"`, `` `backticks` ``, or `[brackets]`)
- The standard case for case-insensitive ("unquoted") names

For the above reasons, and also to prevent an additional SQL injection risk where names might contain SQL code, jOOQ by default quotes all names in generated SQL to be sure they match what is really contained in your database. This means that the following names will be rendered

```sql
-- Unquoted name
AUTHOR.TITLE

-- MariaDB, MySQL
`AUTHOR`.`TITLE`

-- MS Access, SQL Server, Sybase ASE, Sybase SQL Anywhere
[AUTHOR].[TITLE]

-- All the others, including the SQL standard
"AUTHOR"."TITLE"
```

Note that you can influence jOOQ's name rendering behaviour through [custom settings](#custom-settings), if you prefer another name style to be applied.

#### Creating custom names

Custom, qualified or unqualified names can be created very easily using the [`DSL.name()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#name(java.lang.String...)) constructor:

```java
// Unqualified name
Name name = name("TITLE");

// Qualified name
Name name = name("AUTHOR", "TITLE");
```

Such names can be used as standalone [QueryParts](#queryparts), or as DSL entry point for SQL expressions, like

- [Common table expressions](#common-table-expressions) to be used with [the WITH clause](#with-clause)
- Window specifications to be used with [the WINDOW clause](#window-clause)

More details about how to use names / identifiers to construct such expressions can be found in the relevant sections of the manual.

<a id="bind-values"></a>
### 3.24. Bind values and parameters

Bind values are used in SQL / JDBC for various reasons. Among the most obvious ones are:

- Protection against SQL injection. Instead of inlining values possibly originating from user input, you bind those values to your prepared statement and let the JDBC driver / database take care of handling security aspects.
- Increased speed. Advanced databases such as Oracle can keep execution plans of similar queries in a dedicated cache to prevent hard-parsing your query again and again. In many cases, the actual value of a bind variable does not influence the execution plan, hence it can be reused. Preparing a statement will thus be faster
- On a JDBC level, you can also reuse the SQL string and prepared statement object instead of constructing it again, as you can bind new values to the prepared statement. jOOQ currently does not cache prepared statements, internally.

The following sections explain how you can introduce bind values in jOOQ, and how you can control the way they are rendered and bound to SQL.

<a id="indexed-parameters"></a>
#### 3.24.1. Indexed parameters

JDBC only knows indexed bind values. A typical example for using bind values with JDBC is this:

```java
try (PreparedStatement stmt = connection.prepareStatement("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?")) {

    // bind values to the above statement for appropriate indexes
    stmt.setInt(1, 5);
    stmt.setString(2, "Animal Farm");
    stmt.executeQuery();
}
```

With dynamic SQL, keeping track of the number of question marks and their corresponding index may turn out to be hard. jOOQ abstracts this and lets you provide the bind value right where it is needed. A trivial example is this:

```java
create.select().from(BOOK).where(BOOK.ID.eq(5)).and(BOOK.TITLE.eq("Animal Farm")).fetch();

// This notation is in fact a short form for the equivalent:
create.select().from(BOOK).where(BOOK.ID.eq(val(5))).and(BOOK.TITLE.eq(val("Animal Farm"))).fetch();
```

Note the using of [`DSL.val()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#val(java.lang.Object)) to explicitly create an indexed bind value. You don't have to worry about that index. When the query is [rendered](#sql-rendering), each bind value will render a question mark. When the query [binds its variables](#variable-binding), each bind value will generate the appropriate bind value index.

##### Extract bind values from a query

Should you decide to run the above query outside of jOOQ, using your own [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html), you can do so as follows:

```java
Select<?> select = create.select().from(BOOK).where(BOOK.ID.eq(5)).and(BOOK.TITLE.eq("Animal Farm"));

// Render the SQL statement:
String sql = select.getSQL();
assertEquals("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", sql);

// Get the bind values:
List<Object> values = select.getBindValues();
assertEquals(2, values.size());
assertEquals(5, values.get(0));
assertEquals("Animal Farm", values.get(1));
```

For more details about jOOQ's internals, see the manual's section about [QueryParts](#queryparts).

<a id="named-parameters"></a>
#### 3.24.2. Named parameters

Some SQL access abstractions that are built on top of JDBC, or some that bypass JDBC may support named parameters. jOOQ allows you to give names to your parameters as well, although those names are not rendered to SQL strings by default. Here is an example of how to create named parameters using the [`org.jooq.Param`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Param.html) type:

```java
// Create a query with a named parameter. You can then use that name for accessing the parameter again
Query query1 = create.select().from(AUTHOR).where(LAST_NAME.eq(param("lastName", "Poe")));
Param<?> param1 = query.getParam("lastName");

// Or, keep a reference to the typed parameter in order not to lose the <T> type information:
Param<String> param2 = param("lastName", "Poe");
Query query2 = create.select().from(AUTHOR).where(LAST_NAME.eq(param2));
```

The [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html) interface also allows for setting new bind values directly, without accessing the Param type:

```java
Query query1 = create.select().from(AUTHOR).where(LAST_NAME.eq("Poe"));
query1.bind(1, "Orwell");

// Or, with named parameters
Query query2 = create.select().from(AUTHOR).where(LAST_NAME.eq(param("lastName", "Poe")));
query2.bind("lastName", "Orwell");
```

In order to actually render named parameter names in generated SQL, use the [`DSLContext.renderNamedParams()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#renderNamedParams(org.jooq.QueryPart)) method:

```sql
-- The named bind variable can be rendered

SELECT *
FROM AUTHOR
WHERE LAST_NAME = :lastName
```

```java
create.renderNamedParams(
    create.select()
          .from(AUTHOR)
          .where(LAST_NAME.eq(
                 param("lastName", "Poe"))));
```

<a id="inlined-parameters"></a>
#### 3.24.3. Inlined parameters

Sometimes, you may wish to avoid rendering bind variables while still using custom values in SQL. [Some example reasons can be seen in this blog post](https://blog.jooq.org/when-to-use-bind-values-and-when-to-use-inline-values-in-sql/). jOOQ refers to that as "inlined" bind values. When bind values are inlined, they render the actual value in SQL rather than a JDBC question mark. Bind value inlining can be achieved in several ways:

- Globally, by using the [Settings](#custom-settings) and setting the [`org.jooq.conf.StatementType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/StatementType.html) to STATIC_STATEMENT. This will inline all bind values for SQL statements rendered from such a Configuration.
- Per query locally, by using the [`Query.getSQL(ParamType)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html#getSQL(org.jooq.conf.ParamType)) method.
- Per [`QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) locally, by using any of the [`DSL.inlined(Condition)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#inlined(org.jooq.Condition)), [`DSL.inlined(Field)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#inlined(org.jooq.Field)), [`DSL.inlined(QueryPart)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#inlined(org.jooq.QueryPart)), or [`DSL.inlined(Statement)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#inlined(org.jooq.Statement)) wrapper methods.
- Per value locally, by using [`DSL.inline()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#inline(java.lang.Object)) methods.

In all cases, your inlined bind values will be properly escaped to avoid SQL syntax errors and SQL injection. Some examples:

```java
// Use dedicated calls to inline() in order to specify
// single bind values to be rendered as inline values
// --------------------------------------------------
create.select()
      .from(AUTHOR)
      .where(LAST_NAME.eq(inline("Poe")))
      .fetch();

// Or render the whole query with inlined values
// --------------------------------------------------
Settings settings = new Settings()
    .withStatementType(StatementType.STATIC_STATEMENT);

// Add the settings to the Configuration
DSLContext create = DSL.using(connection, SQLDialect.ORACLE, settings);

// Run queries that omit rendering schema names
create.select()
      .from(AUTHOR)
      .where(LAST_NAME.eq("Poe"))
      .fetch();
```

<a id="sql-injection"></a>
#### 3.24.4. SQL injection

##### SQL injection is serious

SQL injection is a serious problem that needs to be taken care of thoroughly. A single vulnerability can be enough for an attacker to dump your whole database, and potentially seize your database server. [We've blogged about the severity of this threat on the jOOQ blog](https://blog.jooq.org/using-sql-injection-vulnerabilities-to-dump-your-database/).

SQL injection happens because a programming language (SQL) is used to dynamically create arbitrary server-side statements based on user input. Programmers must take lots of care not to mix the language parts (SQL) with the user input ([bind variables](#bind-values))

##### SQL injection in jOOQ

With jOOQ, SQL is usually created via a type safe, non-dynamic Java abstract syntax tree, where bind variables are a part of that abstract syntax tree. It is not possible to expose SQL injection vulnerabilities this way.

However, jOOQ offers convenient ways of introducing [plain SQL strings](#plain-sql) in various places of the jOOQ API (which are annotated using [`org.jooq.PlainSQL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/PlainSQL.html) since jOOQ 3.6). While jOOQ's API allows you to specify bind values for use with plain SQL, you're not forced to do that. For instance, both of the following queries will lead to the same, valid result:

```java
// This query will use bind values, internally.
create.fetch("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", 5, "Animal Farm");

// This query will not use bind values, internally.
create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");
```

All methods in the jOOQ API that allow for plain (unescaped, untreated) SQL contain a warning message in their relevant Javadoc, to remind you of the risk of SQL injection in what is otherwise a SQL-injection-safe API.

<a id="queryparts"></a>
### 3.25. QueryParts

A [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html) and all its contained objects is a [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html). QueryParts essentially provide this functionality:

- they can [render SQL](#sql-rendering) using the [`accept(Context)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPartInternal.html#accept(org.jooq.Context)) method
- they can [bind variables](#variable-binding) using the [`accept(Context)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPartInternal.html#accept(org.jooq.Context)) method

Both of these methods are contained in jOOQ's internal API's [`org.jooq.QueryPartInternal`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPartInternal.html), which is internally implemented by every QueryPart.

The following sections explain some more details about [SQL rendering](#sql-rendering) and [variable binding](#variable-binding), as well as other implementation details about QueryParts in general.

<a id="sql-rendering"></a>
#### 3.25.1. SQL rendering

Every [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) must implement the [`accept(Context)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPartInternal.html#accept(org.jooq.Context)) method to render its SQL string to a [`org.jooq.RenderContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RenderContext.html). This RenderContext has two purposes:

- It provides some information about the "state" of SQL rendering.
- It provides a common API for constructing SQL strings on the context's internal [`java.lang.StringBuilder`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/StringBuilder.html)

An overview of the [`org.jooq.RenderContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RenderContext.html) API is given here:

```java
// These methods are useful for generating unique aliases within a RenderContext (and thus within a Query)
String peekAlias();
String nextAlias();

// These methods return rendered SQL
String render();
String render(QueryPart part);

// These methods allow for fluent appending of SQL to the RenderContext's internal StringBuilder
RenderContext keyword(String keyword);
RenderContext literal(String literal);
RenderContext sql(String sql);
RenderContext sql(char sql);
RenderContext sql(int sql);
RenderContext sql(QueryPart part);

// These methods allow for controlling formatting of SQL, if the relevant Setting is active
RenderContext formatNewLine();
RenderContext formatSeparator();
RenderContext formatIndentStart();
RenderContext formatIndentStart(int indent);
RenderContext formatIndentLockStart();
RenderContext formatIndentEnd();
RenderContext formatIndentEnd(int indent);
RenderContext formatIndentLockEnd();

// These methods control the RenderContext's internal state
boolean       inline();
RenderContext inline(boolean inline);
boolean       qualify();
RenderContext qualify(boolean qualify);
boolean       namedParams();
RenderContext namedParams(boolean renderNamedParams);
CastMode      castMode();
RenderContext castMode(CastMode mode);
Boolean       cast();
RenderContext castModeSome(SQLDialect... dialects);
```

The following additional methods are inherited from a common [`org.jooq.Context`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Context.html), which is shared among [`org.jooq.RenderContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RenderContext.html) and [`org.jooq.BindContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/BindContext.html):

```java
// These methods indicate whether fields or tables are being declared (MY_TABLE AS MY_ALIAS) or referenced (MY_ALIAS)
boolean declareFields();
Context declareFields(boolean declareFields);
boolean declareTables();
Context declareTables(boolean declareTables);

// These methods indicate whether a top-level query is being rendered, or a subquery
boolean subquery();
Context subquery(boolean subquery);

// These methods provide the bind value indices within the scope of the whole Context (and thus of the whole Query)
int nextIndex();
int peekIndex();
```

##### An example of rendering SQL

A simple example can be provided by checking out jOOQ's internal representation of a (simplified) [CompareCondition](#comparison-predicate). It is used for any [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html) comparing two fields as for example the `AUTHOR.ID = BOOK.AUTHOR_ID` condition here:

```sql
-- [...]
FROM AUTHOR
JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID
-- [...]
```

This is how jOOQ renders such a condition (simplified example):

```java
@Override
public final void accept(Context<?> context) {
    // The CompareCondition delegates rendering of the Fields to the Fields
    // themselves and connects them using the Condition's comparator operator:
    context.visit(field1)
           .sql(" ")
           .keyword(comparator.toSQL())
           .sql(" ")
           .visit(field2);
}
```

See the manual's sections about [custom QueryParts](#custom-queryparts) and [plain SQL QueryParts](#plain-sql-queryparts) to learn about how to write your own query parts in order to extend jOOQ.

<a id="declaration-vs-reference"></a>
#### 3.25.2. Declaration vs reference

A few types of [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) render different SQL depending on the context in which they are being rendered. The context is whether:

- The object is being declared
- The object is being referenced

A simple example is the aliasing of [tables](#aliased-tables) and [columns](#aliased-columns). For example:

```java
// Alias the table BOOK
Book b = BOOK.as("B");

// Use the alias as a reference
create.select(b.ID)

// Use the alias as a declaration
      .from(b)
      .fetch();
```

In the above example, when referencing the table alias, jOOQ renders the alias only, i.e. `B`. When declaring the table alias, jOOQ renders both the original table and its alias, i.e. `BOOK as B`.

While it may appear useful to occasionally enter in a third rendering mode, which renders the original table `BOOK` only, ignoring the alias, this isn't what is happening. If you want to access the original table (or column) reference, just keep a reference to that in your code, instead.

##### Types that expose this behaviour

The following types of [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) expose this kind of context sensitive rendering behaviour:

- [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html): Table expressions can be [aliased tables](#aliased-tables) which can be declared in the [FROM clause](#from-clause), or similar clauses of other statements.
- [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html): Field expressions can be [aliased columns](#aliased-columns) which can be declared in the [SELECT clause](#select-clause), or the [RETURNING clauses](#insert-returning) of various statements.
- [`org.jooq.CommonTableExpression`](https://www.jooq.org/javadoc/3.22.x/org/jooq/CommonTableExpression.html): [Common table expressions](#common-table-expressions) can be declared in the [WITH clause](#with-clause) of various statements.
- [`org.jooq.WindowDefinition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/WindowDefinition.html): Window definitions can be declared in the [WINDOW clause](#window-clause) of the [SELECT statement](#select-statement).
- [`org.jooq.Parameter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Parameter.html): Routine parameters can be declared in the [CREATE FUNCTION](#create-function-statement) or [CREATE PROCEDURE](#create-procedure-statement) statements.

<a id="pretty-printing"></a>
#### 3.25.3. Pretty printing SQL

> [!TIP]
> Did you know you can pretty print arbitrary SQL with our translator at [https://www.jooq.org/translate](https://www.jooq.org/translate)?

As mentioned in the previous chapter about [SQL rendering](#sql-rendering), there are some elements in the [`org.jooq.RenderContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RenderContext.html) that are used for formatting / pretty-printing rendered SQL. In order to obtain pretty-printed SQL, just use the following [custom settings](#custom-settings):

```java
// Create a DSLContext that will render "formatted" SQL
DSLContext pretty = DSL.using(dialect, new Settings().withRenderFormatted(true));
```

And then, use the above DSLContext to render pretty-printed SQL:

```sql
select
  "TEST"."AUTHOR"."LAST_NAME",
  count(*) "c"
from "TEST"."BOOK"
  join "TEST"."AUTHOR"
  on "TEST"."BOOK"."AUTHOR_ID" = "TEST"."AUTHOR"."ID"
where "TEST"."BOOK"."TITLE" <> '1984'
group by "TEST"."AUTHOR"."LAST_NAME"
having count(*) = 2
```

```java
String sql = pretty.select(
                       AUTHOR.LAST_NAME, count().as("c"))
                   .from(BOOK)
                   .join(AUTHOR)
                   .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
                   .where(BOOK.TITLE.ne("1984"))
                   .groupBy(AUTHOR.LAST_NAME)
                   .having(count().eq(2))
                   .getSQL();
```

The section about [ExecuteListeners](#execute-listeners) shows an example of how such pretty printing can be used to log readable SQL to the stdout.

<a id="variable-binding"></a>
#### 3.25.4. Variable binding

Every [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) must implement the [`accept(Context<?>)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPartInternal.html#accept(org.jooq.Context)) method. This Context has two purposes (among many others):

- It provides some information about the "state" of the variable binding in process.
- It provides a common API for binding values to the context's internal [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html)

An overview of the [`org.jooq.BindContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/BindContext.html) API is given here:

```java
// This method provides access to the PreparedStatement to which bind values are bound
PreparedStatement statement();

// These methods provide convenience to delegate variable binding
BindContext bind(QueryPart part) throws DataAccessException;
BindContext bind(Collection<? extends QueryPart> parts) throws DataAccessException;
BindContext bind(QueryPart[] parts) throws DataAccessException;

// These methods perform the actual variable binding
BindContext bindValue(Object value, Class<?> type) throws DataAccessException;
BindContext bindValues(Object... values) throws DataAccessException;
```

Some additional methods are inherited from a common [`org.jooq.Context`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Context.html), which is shared among [`org.jooq.RenderContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RenderContext.html) and [`org.jooq.BindContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/BindContext.html). Details are documented in the previous chapter about [SQL rendering](#sql-rendering)

##### An example of binding values to SQL

A simple example can be provided by checking out jOOQ's internal representation of a (simplified) [CompareCondition](#comparison-predicate). It is used for any [`org.jooq.Condition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Condition.html) comparing two fields as for example the `AUTHOR.ID = BOOK.AUTHOR_ID` condition here:

```sql
-- [...]
WHERE AUTHOR.ID = ?
-- [...]
```

This is how jOOQ binds values on such a condition:

```java
@Override
public final void bind(BindContext context) throws DataAccessException {
    // The CompareCondition itself does not bind any variables.
    // But the two fields involved in the condition might do so...
    context.bind(field1).bind(field2);
}
```

See the manual's sections about [custom QueryParts](#custom-queryparts) and [plain SQL QueryParts](#plain-sql-queryparts) to learn about how to write your own query parts in order to extend jOOQ.

<a id="custom-queryparts"></a>
#### 3.25.5. Custom syntax elements

To support simple vendor specific SQL syntax extensions, jOOQ offers the [plain SQL templating API](#plain-sql-templating-language). If a SQL clause is too complex to express with jOOQ or with this templating API, or you have a requirement to support different dialects, you can extend either one of the following types for use directly in a jOOQ query:

```java
// Simplified API description:
public abstract class CustomField<T> implements Field<T> {}
public abstract class CustomCondition implements Condition {}
public abstract class CustomStatement implements Statement {}
public abstract class CustomTable<R extends TableRecord<R>> implements Table<R> {}
public abstract class CustomRecord<R extends TableRecord<R>> implements TableRecord<R> {}
```

##### An example for implementing a custom table and its record.

Here's an example [`org.jooq.impl.CustomTable`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/CustomTable.html) showing how to create a custom table with its field definitions, similar to what the code generator is doing.

```java
public class BookTable extends CustomTable<BookRecord> {
    public static final BookTable BOOK = new BookTable();

    public final TableField<BookRecord, String> FIRST_NAME = createField(name("FIRST_NAME"), VARCHAR);
    public final TableField<BookRecord, String> UNMATCHED  = createField(name("UNMATCHED"), VARCHAR);
    public final TableField<BookRecord, String> LAST_NAME  = createField(name("LAST_NAME"), VARCHAR);
    public final TableField<BookRecord, Short>  ID         = createField(name("ID"), SMALLINT);
    public final TableField<BookRecord, String> TITLE      = createField(name("TITLE"), VARCHAR);

    protected BookTable() {
        super(name("BOOK"));
    }

    @Override
    public Class<? extends BookRecord> getRecordType() {
        return BookRecord.class;
    }
}

public class BookRecord extends CustomRecord<BookRecord> {
    protected BookRecord() {
        super(BookTable.BOOK);
    }
}
```

##### An example for implementing custom multiplication.

Here's an example [`org.jooq.impl.CustomField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/CustomField.html) showing how to create a field multiplying another field by 2

```java
// Create an anonymous CustomField, initialised with BOOK.ID arguments
final Field<Integer> IDx2 = new CustomField<Integer>(BOOK.ID.getName(), BOOK.ID.getDataType()) {
    @Override
    public void accept(Context<?> context) {
        context.visit(BOOK.ID).sql(" * ").visit(DSL.val(2));
    }
};

// Use the above field in a SQL statement:
create.select(IDx2).from(BOOK);
```

##### An example for implementing vendor-specific functions.

Many vendor-specific functions are not officially supported by jOOQ, but you can implement such support yourself using `CustomField`, for instance. Here's an example showing how to implement Oracle's `TO_CHAR()` function, emulating it in SQL Server using `CONVERT()`:

```java
// Create a CustomField implementation taking two arguments in its constructor
class ToChar extends CustomField<String> {

    final Field<?> arg0;
    final Field<?> arg1;

    ToChar(Field<?> arg0, Field<?> arg1) {
        super("to_char", VARCHAR);

        this.arg0 = arg0;
        this.arg1 = arg1;
    }

    @Override
    public void accept(RenderContext context) {
        context.visit(delegate(context.configuration()));
    }

    private QueryPart delegate(Configuration configuration) {
        switch (configuration.family()) {
            case ORACLE:
                return DSL.field("TO_CHAR({0}, {1})", String.class, arg0, arg1);

            case SQLSERVER:
                return DSL.field("CONVERT(VARCHAR(8), {0}, {1})", String.class, arg0, arg1);

            default:
                throw new UnsupportedOperationException("Dialect not supported");
        }
    }
}
```

The above `CustomField` implementation can be exposed from your own custom DSL class:

```java
public class MyDSL {
    public static Field<String> toChar(Field<?> field, String format) {
        return new ToChar(field, DSL.inline(format));
    }
}
```

Alternatively, implement it using a simple lambda:

```java
public class MyDSL {
    public static Field<String> toChar(Field<?> field, String format) {
        return CustomField.of("to_char", VARCHAR, ctx -> {
            switch (ctx.family()) {
                case ORACLE:
                    ctx.visit(DSL.field("TO_CHAR({0}, {1})", String.class, arg0, arg1));
                    break;

                case SQLSERVER:
                    ctx.visit(DSL.field("CONVERT(VARCHAR(8), {0}, {1})", String.class, arg0, arg1));
                    break;

                default:
                    throw new UnsupportedOperationException("Dialect not supported");
            }
        });
    }
}
```

<a id="plain-sql-queryparts"></a>
#### 3.25.6. Plain SQL QueryParts

If you don't need the integration of rather complex QueryParts into jOOQ, then you might be safer using simple [Plain SQL](#plain-sql) functionality, where you can provide jOOQ with a simple String representation of your embedded SQL. Plain SQL methods in jOOQ's API come in two flavours.

- **method(String, Object...)**: This is a method that accepts a SQL string and a list of bind values that are to be bound to the variables contained in the SQL string
- **method(String, QueryPart...)**: This is a method that accepts a SQL string and a list of QueryParts that are "injected" at the position of their respective placeholders in the SQL string

The above distinction is best explained using an example:

```java
// Plain SQL using bind values. The value 5 is bound to the first variable, "Animal Farm" to the second variable:
create.selectFrom(BOOK).where(
    "BOOK.ID = ? AND TITLE = ?",     // The SQL string containing bind value placeholders ("?")
    5,                               // The bind value at index 1
    "Animal Farm"                    // The bind value at index 2
).fetch();

// Plain SQL using embeddable QueryPart placeholders (counting from zero).
// The QueryPart "index" is substituted for the placeholder {0}, the QueryPart "title" for {1}
Field<Integer> id   = val(5);
Field<String> title = val("Animal Farm");
create.selectFrom(BOOK).where(
    "BOOK.ID = {0} AND TITLE = {1}", // The SQL string containing QueryPart placeholders ("{N}")
    id,                              // The QueryPart at index 0
    title                            // The QueryPart at index 1
).fetch();
```

Note that for historic reasons the two API usages can also be mixed, although this is not recommended and the exact behaviour is unspecified.

##### Plain SQL templating specification

Templating with QueryPart placeholders (or bind value placeholders) requires a simple parsing logic to be applied to SQL strings. The jOOQ template parser behaves according to the following rules:

- Single-line comments (starting with `--` in all databases (or `#`) in MySQL) are rendered without modification. Any bind variable or QueryPart placeholders in such comments are ignored.
- Multi-line comments (starting with `/*` and ending with `*/` in all databases) are rendered without modification. Any bind variable or QueryPart placeholders in such comments are ignored.
- String literals (starting and ending with `'` in all databases, where all databases support escaping of the quote character by duplication as such: `''`, or in MySQL by escaping as such: `\'` (if [`Settings.backslashEscaping`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#backslashEscaping) is turned on)) are rendered without modification. Any bind variable or QueryPart placeholders in such comments are ignored.
- Quoted names (starting and ending with `"` in most databases, with `` ` `` in MySQL, or with `[` and `]` in T-SQL databases) are rendered without modification. Any bind variable or QueryPart placeholders in such comments are ignored.
- JDBC escape syntax (`{fn ...}`, `{d ...}`, `{t ...}`, `{ts ...}`) is rendered without modification. Any bind variable or QueryPart placeholders in such comments are ignored.
- Bind variable placeholders (`?` or `:name` for named bind variables) are replaced by the matching bind value in case inlining is activated, e.g. through [`Settings.statementType == STATIC_STATEMENT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#statementType).
- QueryPart placeholders (`{number}`) are replaced by the matching QueryPart.
- Keywords (`{identifier}`) are treated like keywords and rendered in the correct case according to [`Settings.renderKeywordStyle`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#renderKeywordStyle).

##### Tools for templating

A variety of API is provided to create template elements that are intended for use with the above templating mechanism. These tools can be found in [`org.jooq.impl.DSL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html)

```java
// Keywords (which are rendered according to Settings.renderKeywordStyle) can be specified as such:
public static Keyword keyword(String keyword) { ... }

// Identifiers / names (which are rendered according to Settings.renderNameStyle) can be specified as such:
public static Name name(String... qualifiedName) { ... }

// QueryPart lists (e.g. IN-lists for the IN predicate) can be generated via these methods:
public static QueryPart list(QueryPart... parts) { ... }
public static QueryPart list(Collection<? extends QueryPart> parts) { ... }
```

<a id="serializability"></a>
#### 3.25.7. Serializability

A lot of jOOQ types extend and implement the [`java.io.Serializable`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/io/Serializable.html) interface for your convenience. Beware, however, that jOOQ will make no guarantees related to the serialisation format, and its backwards compatible evolution. This means that while it is generally safe to rely on jOOQ types being serialisable when two processes using the exact same jOOQ version transfer jOOQ state over some network, it is not safe to rely on persisting serialised jOOQ state to be deserialised again at a later time - **even after a patch release upgrade**!

As always with Java's serialisation, if you want reliable serialisation of Java objects, please use your own serialisation protocol, or use one of the [official export formats](#exporting).

##### What types are serializable?

The only transient, non-serializable element in any jOOQ object is the [Configuration's](#dsl-context) underlying [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html). When you want to execute queries after de-serialisation, or when you want to store/refresh/delete [Updatable Records](#crud-with-updatablerecords), you may have to "re-attach" them to a Configuration

```java
// Deserialise a SELECT statement
ObjectInputStream in = new ObjectInputStream(...);
Select<?> select = (Select<?>) in.readObject();

// This will throw a DetachedException:
select.execute();

// In order to execute the above select, attach it first
DSLContext create = DSL.using(connection, SQLDialect.ORACLE);
create.attach(select);
```

##### Automatically attaching QueryParts

Another way of attaching QueryParts automatically, or rather providing them with a new [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html) at will, is to hook into the [Execute Listener support](#execute-listeners). More details about this can be found in the manual's chapter about [ExecuteListeners](#execute-listeners)

<a id="sql-transformation"></a>
#### 3.25.8. SQL transformation

jOOQ supports a few built in SQL transformations, which can be enabled through a variety of settings. These transformations will produce transformed SQL output regardless if the input was created using the DSL API, or the parser.

<a id="ansi-join-to-table-lists"></a>
##### 3.25.8.1. ANSI JOIN to table lists

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Almost all SQL dialects support [ANSI 92 JOIN syntax](#join-clause), but sometimes, users may wish to generate SQL that is compatible e.g. with older Oracle releases that did not yet support this syntax, or had limited optimiser support for them. As a workaround, the `Settings.transformAnsiJoinToTableLists` flag can be turned on to produce the following type of transformation:

```sql
-- Input
SELECT *
FROM a
JOIN b ON a.id = b.id
```

```sql
-- Output
SELECT *
FROM a, b
WHERE a.id = b.id
```

This also works for `OUTER JOIN`:

```sql
-- Input
SELECT *
FROM a
LEFT JOIN b ON a.id = b.id
```

```sql
-- Output
SELECT *
FROM a, b
WHERE a.id = b.id(+)
```

**Example configuration**

```java
Settings settings = new Settings()
    .withTransformAnsiJoinToTableLists(true);
```

<a id="table-lists-to-ansi-join"></a>
##### 3.25.8.2. Table lists to ANSI JOIN

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

When upgrading from legacy join syntax to the "new" (1992!) ANSI JOIN syntax, the `Settings.transformTableListsToAnsiJoin` flag can be turned on to produce the following type of transformation:

```sql
-- Input
SELECT *
FROM a, b
WHERE a.id = b.id
```

```sql
-- Output
SELECT *
FROM a
JOIN b ON a.id = b.id
```

This also works for `OUTER JOIN`:

```sql
-- Input
SELECT *
FROM a, b
WHERE a.id = b.id(+)
```

```sql
-- Output
SELECT *
FROM a
LEFT JOIN b ON a.id = b.id
```

**Example configuration**

```java
Settings settings = new Settings()
    .withTransformTableListsToAnsiJoin(true);
```

<a id="transform-rownum"></a>
##### 3.25.8.3. ROWNUM to LIMIT

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Old Oracle SQL statements may use `ROWNUM` filtering to paginate, as Oracle has introduced support for [FETCH FIRST](#limit-clause) only in Oracle 12c.

This transformation allows for transforming some of these syntaxes to equivalent, standard syntax using [window functions](#window-functions) or [FETCH FIRST](#limit-clause):

```sql
-- Input
SELECT * FROM t WHERE rownum = 1
```

```sql
-- Output
SELECT * FROM t LIMIT 1
```

**Example configuration**

```java
Settings settings = new Settings()
    .withTransformRownum(Transformation.WHEN_NEEDED);
```

<a id="transform-qualify"></a>
##### 3.25.8.4. QUALIFY to derived table

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Teradata introduced the useful [QUALIFY clause](#qualify-clause), which has since been reproduced by a number of implementations. jOOQ can transform a query containing the `QUALIFY` clause to an equivalent query filtering on a [derived table](#derived-tables)

This transformation allows for transforming some of these syntaxes to equivalent, standard syntax using [window functions](#window-functions) and [derived tables](#derived-tables):

```sql
-- Input
SELECT *
FROM
  t
QUALIFY
  row_number () OVER (ORDER BY id) <= 5
```

```sql
-- Output
SELECT *
FROM (
  SELECT *, row_number () OVER (ORDER BY id) AS rn FROM t
) AS t
WHERE t.rn <= 5
```

**Example configuration**

```java
Settings settings = new Settings()
    .withTransformQualify(Transformation.WHEN_NEEDED);
```

<a id="transform-in-with-limit-to-derived-table"></a>
##### 3.25.8.5. IN condition subquery with LIMIT to derived table

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Some dialects do not support a [LIMIT clause](#limit-clause) in a subquery of an [IN predicate](#in-predicate). jOOQ can transform such a subquery to an equivalent [derived table](#derived-tables):

```sql
-- Input
SELECT *
FROM t
WHERE id IN (SELECT id FROM u ORDER BY id LIMIT 5)
```

```sql
-- Output
SELECT *
FROM t
WHERE id IN (SELECT * FROM (SELECT id FROM u ORDER BY id LIMIT 5) AS u)
```

**Example configuration**

```java
Settings settings = new Settings()
    .setTransformInConditionSubqueryWithLimitToDerivedTable(Transformation.WHEN_NEEDED);
```

<a id="transform-group-by-column-index"></a>
##### 3.25.8.6. GROUP BY <column index>

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A lot of dialects support [GROUP BY <column index>](#group-by-clause) where the (1 based) column index references a column from the [SELECT clause](#select-clause) (if it is an expression that does not contain an aggregate or window function).

This transformation allows for transforming some of these syntaxes to equivalent, standard syntax by repeating the expression:

```sql
-- Input
SELECT t.col FROM t GROUP BY 1
```

```sql
-- Output
SELECT t.col FROM t GROUP BY t.col
```

**Example configuration**

```java
Settings settings = new Settings()
    .setTransformGroupByColumnIndex(Transformation.WHEN_NEEDED);
```

<a id="transform-inline-cte"></a>
##### 3.25.8.7. Inline CTE

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A few dialects do not support the [WITH clause](#with-clause) ("[common table expressions](#common-table-expressions)", or CTEs). Others may have a limited implementation, where nesting of `WITH` clauses isn't supported.

This transformation allows for inlining non-recursive CTE to [derived tables](#derived-tables) wherever they're referenced.

```sql
-- Input
WITH t (x) AS (SELECT 1) SELECT x FROM t
```

```sql
-- Output
SELECT x FROM (SELECT 1) AS t (x)
```

**Example configuration**

```java
Settings settings = new Settings()
    .setTransformInlineCTE(Transformation.WHEN_NEEDED);
```

<a id="transform-unnecessary-arithmetic"></a>
##### 3.25.8.8. Unnecessary arithmetic expressions

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The jOOQ expression tree may contain unnecessary arithmetic expressions, which may not be desirable in generated SQL output. These expressions may originate from user written jOOQ API, or from internal emulations.

```sql
-- Input
SELECT -1 - (1 + 1)
```

```sql
-- Output
SELECT -3
```

**Example configuration**

```java
Settings settings = new Settings()
    .withTransformUnneededArithmeticExpressions(TransformUnneededArithmeticExpressions.ALWAYS);
```

These options are available:

- `NEVER` (default): Don't transform arithmetic expressions
- `INTERNAL`: Transform only arithmetic expressions produced by jOOQ's internals, e.g. for emulations
- `ALWAYS`: Always transform arithmetic expressions, if possible

<a id="transform-patterns"></a>
##### 3.25.8.9. Pattern based transformation

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Starting with jOOQ 3.16, a new [Query Object Model (QOM) API](#model-api) has been added, which features [traversal](#model-api-traversal) and [replacement](#model-api-replacement) SPIs. One out of the box application of replacement are pattern transformations, where we recognise common patterns in a query's expressions and allow for replacing them by a better expression.

For example, the following transformations are possible:

```sql
-- With Settings.transformPatternsTrim active, this:
SELECT RTRIM(LTRIM(col)) FROM tab;

-- ... is transformed into the equivalent expression:
SELECT TRIM(col) FROM tab;
```

The whole feature set is deactivated by default using the [`Settings.transformPatterns`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatterns) flag as the traversal overhead does not warrant activation by default. Common use-cases for the activation of this feature include:

- SQL linting, including as part of an [ExecuteListener](#custom-execute-listeners), where the effort can be controlled in a utility run only during integration testing, for example.
- SQL cleanup, including as part of a [ParsingConnection](#parsing-connection), where inputs/outputs are cached by default.
- Dialect migration, when moving from a less powerful dialect to a more powerful one, or to a new version, manually written emulations may become obsolete.
- Patching specific SQL features only

Individual features can either be turned on in bulk and opted out of individually, or each feature is turned on individually, depending on the use case.

###### Repetition of pattern replacement

As any [replacement](#model-api-replacement) SPI implementation, the algorithm iterates over the jOOQ expression tree until it can no longer replace anything, i.e. until the transformations stabilise. For example, the following sequence of transformations is possible:

```sql
-- Original SQL
SELECT NOT(1 = 0) AND 1 = 1;

-- Step 1: Settings.transformPatternsNotComparison
SELECT 1 != 0 AND 1 = 1;

-- Step 2: Settings.transformPatternsTrivialPredicates
SELECT TRUE AND TRUE;

-- Step 3: Settings.transformPatternsTrivialPredicates
SELECT TRUE;
```

###### Dialect specific result

The following sections will make claims like `1 / TAN(x)` or `COS(x) / SIN(x)` being replaced by `COT(x)`, see e.g. [Trigonometric functions](#transform-patterns-trigonometric-functions). Some dialects may not have native support for [COT()](#cot-function), so this is going to be emulated on those dialects, making the transformation effectively redundant. But these things happen at different times:

- This pattern transformation feature can either be invoked explicitly by users, or it is enabled by configuration and then happens *before* all the rendering takes place, only once for the top level [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html)
- The rendering of SQL invokes emulations as the above, *after* the SQL has been transformed.

In other words, the two operations do not know about each other.

<a id="transform-patterns-and-ne-to-not-in"></a>
###### 3.25.8.9.1. AND to NOT IN

A concatenation of [AND predicates](#boolean-operators) combining non-equalities that always use the same operand on one side can be replaced by a more concise, but equivalent [NOT IN predicate](#in-predicate).

Using [`Settings.transformPatternsAndNeToNotIn`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsAndNeToNotIn), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsAndNeToNotIn active, this:
SELECT * FROM tab WHERE x != 1 AND x != 2 AND x != 3;

-- ... is transformed into the equivalent expression:
SELECT * FROM tab WHERE x NOT IN (1, 2, 3);
```

See also [OR to IN](#transform-patterns-or-eq-to-in)

<a id="transform-patterns-arithmetic-comparisons"></a>
###### 3.25.8.9.2. Arithmetic comparisons

Some arithmetic comparisons can be reorganised such that single column expressions are on one side of an equation, and thus benefit index usage more. While function based indexes could help work around the issue, it's usually better to rely on ordinary indexes, which are more generally reusable.

Using [`Settings.transformPatternsArithmeticComparisons`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsArithmeticComparisons), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsArithmeticComparisons active, this:
SELECT * FROM tab WHERE c + 1 = 3;

-- ... is transformed into the equivalent expression:
SELECT * FROM tab WHERE c = 3 - 1;
```

<a id="transform-patterns-arithmetic-expressions"></a>
###### 3.25.8.9.3. Arithmetic expressions

Some arithmetic expressions are unnecessary and may obscure the SQL query, possibly preventing optimisations that are otherwise possible. Sometimes, this is used as a trick, e.g. to prevent index access where such index access is undersirable

Using [`Settings.transformPatternsArithmeticExpressions`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsArithmeticExpressions), the following transformations can be achieved:

###### Identities

```sql
-- With Settings.transformPatternsArithmeticExpressions active, this:
SELECT 0 + x, 1 * x, POWER(x, 1)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT x, x, x FROM tab;
```

###### Negation

```sql
-- With Settings.transformPatternsArithmeticExpressions active, this:
SELECT
  0 - x,
  x + (-y),
  x - (-y),
  (-x) * (-y),
  (-x) / (-y),
  (-1) * x,
  -(x - y)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  -x,     -- 0 - x
  x - y,  -- x + (-y)
  x + y,  -- x - (-y)
  x * y,  -- (-x) * (-y)
  x / y,  -- (-x) / (-y)
  -x      -- (-1) * x
  (y - x) -- -(x - y)
FROM tab;
```

###### Other

```sql
-- With Settings.transformPatternsArithmeticExpressions active, this:
SELECT
  1 / y * x,
  x * x,
  x + const,
  x * const
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  x / y,     -- 1 / y * x
  SQUARE(x), -- x * x
  const + x, -- x + const
  const * x  -- x * const
FROM tab;
```

<a id="transform-patterns-bit-get"></a>
###### 3.25.8.9.4. BIT_GET function

[bitwise operations](#bitwise-functions) can be matched to represent the [BIT_GET function](#bit-get-function).

Using [`Settings.transformPatternsBitGet`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsBitGet), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsBitGet active, this:
SELECT
  (a & (1 << b)) >> b
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  bit_get(a, b)
FROM tab;
```

<a id="transform-patterns-bit-set"></a>
###### 3.25.8.9.5. BIT_SET function

[bitwise operations](#bitwise-functions) can be matched to represent the [BIT_SET function](#bit-set-function).

Using [`Settings.transformPatternsBitSet`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsBitSet), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsBitSet active, this:
SELECT
  a | (1 << b),
  a & ~(1 << b)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  bit_set(a, b),
  bit_set(a, b, 0)
FROM tab;
```

<a id="transform-patterns-case-searched-to-simple"></a>
###### 3.25.8.9.6. CASE searched to CASE simple

A [searched CASE expression](#case-expressions) can be simplified into a simple `CASE` expression, if it always equality compares the same expression.

Using [`Settings.transformPatternsCaseSearchedToCaseSimple`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsCaseSearchedToCaseSimple), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsCaseSearchedToCaseSimple active, this:
SELECT
  CASE WHEN a = b THEN 1 END,
  CASE WHEN a = b THEN 1 WHEN a = c THEN 2 ELSE 3 END
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  CASE a WHEN b THEN 1 END,
  CASE a WHEN b THEN 1 WHEN c THEN 2 ELSE 3 END
FROM tab;
```

<a id="transform-patterns-case-to-case-abbreviation"></a>
###### 3.25.8.9.7. CASE to CASE abbreviation

Some case [CASE expressions](#case-expressions) can be turned into [COALESCE](#coalesce-function), [NULLIF](#nullif-function), [NVL2](#nvl2-function) or other "case abbreviations".

Using [`Settings.transformPatternsCaseToCaseAbbreviation`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsCaseToCaseAbbreviation), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsCaseToCaseAbbreviation active, this:
SELECT
  CASE WHEN x IS NULL THEN y ELSE x END,
  CASE WHEN x = y THEN NULL ELSE x END,
  CASE WHEN x IS NOT NULL THEN y ELSE z END,
  CASE WHEN x IS NULL THEN y ELSE z END,
  CASE WHEN x = 1 THEN y WHEN x = 2 THEN z END,
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  NVL(x, y),
  NULLIF(x, y),
  NVL2(x, y, z),
  NVL2(x, z, y),
  CHOOSE(x, y, z)
FROM tab;
```

Some additional special cases appear with `BOOLEAN` types involved:

```sql
-- With Settings.transformPatternsCaseToCaseAbbreviation active, this:
SELECT
  CASE WHEN x = y THEN TRUE ELSE FALSE END,
  CASE WHEN x = y THEN FALSE ELSE TRUE END,
  CASE x WHEN y THEN TRUE ELSE FALSE END,
  CASE x WHEN y THEN FALSE ELSE TRUE END
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  NVL(x = y, FALSE),
  NVL(x <> y, TRUE),
  NVL(x = y, FALSE),
  NVL(x <> y, TRUE)
FROM tab;
```

<a id="transform-patterns-case-distinct-to-decode"></a>
###### 3.25.8.9.8. CASE with DISTINCT FROM to DECODE

When a searched [CASE expression](#case-expressions) contains [DISTINCT predicates](#distinct-predicate), which always share the same operand, the expression might be replaced by the shorter [DECODE function](#decode-function)

Using [`Settings.transformPatternsCaseDistinctToDecode`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsCaseDistinctToDecode), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsCaseDistinctToDecode active, this:
SELECT
  CASE WHEN a IS NOT DISTINCT FROM b THEN 1 END,
  CASE WHEN a IS NOT DISTINCT FROM b THEN 1 ELSE 2 END,
  CASE WHEN a IS NOT DISTINCT FROM b THEN 1 WHEN a IS NOT DISTINCT FROM c THEN 2 END,
  CASE WHEN a IS NOT DISTINCT FROM b THEN 1 WHEN a IS NOT DISTINCT FROM c THEN 2 ELSE 3 END
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  DECODE(a, b, 1),         -- CASE WHEN a IS NOT DISTINCT FROM b THEN 1 END,
  DECODE(a, b, 1, 2),      -- CASE WHEN a IS NOT DISTINCT FROM b THEN 1 ELSE 2 END,
  DECODE(a, b, 1, c, 2),   -- CASE WHEN a IS NOT DISTINCT FROM b THEN 1 WHEN a IS NOT DISTINCT FROM c THEN 2 END,
  DECODE(a, b, 1, c, 2, 3) -- CASE WHEN a IS NOT DISTINCT FROM b THEN 1 WHEN a IS NOT DISTINCT FROM c THEN 2 ELSE 3 END,
FROM tab;
```

<a id="transform-patterns-case-else-null"></a>
###### 3.25.8.9.9. CASE with ELSE NULL

When [CASE expressions](#case-expressions) have no `ELSE` clause, the default is `ELSE NULL`. There is no need to explicitly set that clause to `NULL`.

Using [`Settings.transformPatternsCaseElseNull`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsCaseElseNull), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsCaseElseNull active, this:
SELECT
  CASE a WHEN b THEN 1 ELSE NULL END,  -- Simple CASE
  CASE WHEN a = b THEN 1 ELSE NULL END -- Searched CASE
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  CASE a WHEN b THEN 1 END,
  CASE WHEN a = b THEN 1 END
FROM tab;
```

<a id="transform-patterns-scalar-subquery-count-asterisk-gt-zero"></a>
###### 3.25.8.9.10. COUNT(*) scalar subquery comparison

When comparing a [scalar subquery](#scalar-subqueries) that calculates [COUNT(*)](#count-function) with a single value, then chances are that weaker optimisers might be better off with an equivalent [EXISTS predicate](#exists-predicate) as can be seen in [this blog post about COUNT(*) vs EXISTS](https://blog.jooq.org/avoid-using-count-in-sql-when-you-could-use-exists/).

This transformation is only applied under certain circumstances, including:

- In the absence of `UNION` and other set operations
- In the absence of `GROUP BY` and `HAVING`
- Only with `COUNT(*)`, not with `COUNT(expr)` (see [COUNT(expr) scalar subquery comparison](#transform-patterns-scalar-subquery-count-expression-gt-zero) for that case)

Using [`Settings.transformPatternsScalarSubqueryCountAsteriskGtZero`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsScalarSubqueryCountAsteriskGtZero), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsScalarSubqueryCountAsteriskGtZero active, this:
SELECT
  (SELECT COUNT(*) FROM tab) > 0;

-- ... is transformed into the equivalent expression:
SELECT
  EXISTS (SELECT 1 FROM tab);
```

<a id="transform-patterns-count-constant"></a>
###### 3.25.8.9.11. COUNT(const)

The [COUNT(expression) aggregate function](#count-function) counts the number of non-`NULL` `expression` evaluations in the group. If the `expression` is a [constant](#inlined-parameters), then there are only two options:

- The constant is `NULL`, in case of which the `COUNT(NULL)` value is always `0` (but that's not an aggregate function, so we're currently not replacing it yet)
- The constant is anything else, in case of which the `COUNT(const)` value is always `COUNT(*)`

For clarity reasons, and in some RDBMS also for [(slight) performance reasons](https://blog.jooq.org/whats-faster-count-or-count1/), `COUNT(*)` should be preferred.

Using [`Settings.transformPatternsCountConstant`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsCountConstant), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsCountConstant active, this:
SELECT
  COUNT(NULL),
  COUNT(1);

-- ... is transformed into the equivalent expression:
SELECT
  COUNT(NULL), -- Might be replaced by 0 in the future, if other aggregates are present
  COUNT(*);
```

<a id="transform-patterns-count-distinct-multiple-redundant"></a>
###### 3.25.8.9.12. COUNT(DISTINCT ..) with redundant args

The [COUNT(DISTINCT ..) aggregate function](#count-function) counts the number of distinct non-`NULL` argument `expression` evaluations in the group. If the argument, then the redundant arguments can be removed.

Using [`Settings.transformPatternsCountDistinctMultipleRedundant`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsCountDistinctMultipleRedundant), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsCountDistinctMultipleRedundant active, this:
SELECT
  COUNT(DISTINCT a, a),
  COUNT(DISTINCT a, b, a);

-- ... is transformed into the equivalent expression:
SELECT
  COUNT(DISTINCT a),
  COUNT(DISTINCT a, b);
```

<a id="transform-patterns-scalar-subquery-count-expression-gt-zero"></a>
###### 3.25.8.9.13. COUNT(expr) scalar subquery comparison

When comparing a [scalar subquery](#scalar-subqueries) that calculates [COUNT(expr)](#count-function) with a single value, then chances are that weaker optimisers might be better off with an equivalent [EXISTS predicate](#exists-predicate) as can be seen in [this blog post about COUNT(expr) vs EXISTS](https://blog.jooq.org/avoid-using-count-in-sql-when-you-could-use-exists/).

This transformation is only applied under certain circumstances, including:

- In the absence of `UNION` and other set operations
- In the absence of `GROUP BY` and `HAVING`

Using [`Settings.transformPatternsScalarSubqueryCountExpressionGtZero`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsScalarSubqueryCountExpressionGtZero), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsScalarSubqueryCountExpressionGtZero active, this:
SELECT
  (SELECT COUNT(col) FROM tab) > 0;

-- ... is transformed into the equivalent expression:
SELECT
  EXISTS (SELECT 1 FROM tab WHERE col IS NOT NULL);
```

<a id="transform-patterns-distinct-from-null"></a>
###### 3.25.8.9.14. DISTINCT FROM NULL

The [DISTINCT predicate](#distinct-predicate) is a verbose way of `NULL` safe comparisons. If one of the operands is `NULL`, then it can be simplified to the [NULL predicate](#null-predicate).

Using [`Settings.transformPatternsDistinctFromNull`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsDistinctFromNull), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsDistinctFromNull active, this:
SELECT
  a IS NOT DISTINCT FROM NULL,
  a IS DISTINCT FROM NULL
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  a IS NULL,
  a IS NOT NULL
FROM tab;
```

<a id="transform-patterns-empty-scalar-subquery"></a>
###### 3.25.8.9.15. Empty scalar subquery

When a [scalar subquery](#scalar-subqueries) is provably empty, we can replace it with `NULL`.

Using [`Settings.transformPatternsEmptyScalarSubquery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsEmptyScalarSubquery), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsEmptyScalarSubquery active, this:
SELECT
  (SELECT c FROM tab WHERE FALSE);

-- ... is transformed into the equivalent expression:
SELECT
  NULL -- (SELECT c FROM tab WHERE FALSE);
```

<a id="transform-patterns-flatten-case"></a>
###### 3.25.8.9.16. Flatten CASE

When a searched [CASE expression](#case-expressions) nests another `CASE` expression in its `ELSE` clause, that can be flattened into the top level `CASE` expression. This does not affect the simple `CASE` expression.

Using [`Settings.transformPatternsFlattenCase`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsFlattenCase), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsFlattenCase active, this:
SELECT
  CASE
    WHEN a = b THEN 1
    ELSE CASE
      WHEN c = d THEN 2
    END
  END
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  CASE
    WHEN a = b THEN 1
    WHEN c = d THEN 2
  END
FROM tab;
```

<a id="transform-patterns-flatten-case-abbreviation"></a>
###### 3.25.8.9.17. Flatten CASE abbreviations

The [NVL](#nvl-function) or [COALESCE](#coalesce-function) `CASE` abbreviations can be nested, but this doesn't add any value or clarity to the query. Hence, we flatten them.

Using [`Settings.transformPatternsFlattenCaseAbbreviation`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsFlattenCaseAbbreviation), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsFlattenCaseAbbreviation active, this:
SELECT
  NVL(NVL(a, b), c),
  COALESCE(NVL(a, b), c, NVL(d, e))
  COALESCE(a, COALESCE(b, c, d), e)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  COALESCE(a, b, c),
  COALESCE(a, b, c, d, e),
  COALESCE(a, b, c, d, e)
FROM tab;
```

<a id="transform-patterns-flatten-decode"></a>
###### 3.25.8.9.18. Flatten DECODE

The [DECODE function](#decode-function) can be nested. In some cases, however, that nesting is unnecessary. Hence, we flatten the function calls.

Using [`Settings.transformPatternsFlattenDecode`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsFlattenDecode), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsFlattenDecode active, this:
SELECT
  DECODE(a, b, c, DECODE(a, d, e)),
  DECODE(a, b, c, DECODE(a, d, e, f))
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  DECODE(a, b, c, d, e),
  DECODE(a, b, c, d, e, f)
FROM tab;
```

<a id="transform-patterns-hyperbolic-functions"></a>
###### 3.25.8.9.19. Hyperbolic functions

Some dialects may not support all hyperbolic functions, or they are derived from other, much more complex maths expressions.

Using [`Settings.transformPatternsHyperbolicFunctions`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsHyperbolicFunctions), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsTrigonometricFunctions active, this:
SELECT
  (EXP(x) - EXP(-x)) / 2
  (EXP(2 * x) - 1) / (2 * EXP(x))
  (1 - EXP(-2 * x)) / (2 * EXP(-x))
  (EXP(x) + EXP(-x)) / 2
  (EXP(2 * x) + 1) / (2 * EXP(x))
  (1 + EXP(-2 * x)) / (2 * EXP(-x))
  SINH(x) / COSH(x)
  1 / COTH(x)
  (EXP(x) - EXP(-x)) / (EXP(x) + EXP(-x))
  (EXP(2 * x) - 1) / (EXP(2 * x) + 1)
  COSH(x) / SINH(x)
  1 / TANH(x)
  (EXP(x) + EXP(-x)) / (EXP(x) - EXP(-x))
  (EXP(2 * x) + 1) / (EXP(2 * x) - 1)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  SINH(x), -- (EXP(x) - EXP(-x)) / 2,
  SINH(x), -- (EXP(2 * x) - 1) / (2 * EXP(x)),
  SINH(x), -- (1 - EXP(-2 * x)) / (2 * EXP(-x)),
  COSH(x), -- (EXP(x) + EXP(-x)) / 2,
  COSH(x), -- (EXP(2 * x) + 1) / (2 * EXP(x)),
  COSH(x), -- (1 + EXP(-2 * x)) / (2 * EXP(-x)),
  TANH(x), -- SINH(x) / COSH(x),
  TANH(x), -- 1 / COTH(x),
  TANH(x), -- (EXP(x) - EXP(-x)) / (EXP(x) + EXP(-x)),
  TANH(x), -- (EXP(2 * x) - 1) / (EXP(2 * x) + 1),
  COTH(x), -- COSH(x) / SINH(x),
  COTH(x), -- 1 / TANH(x),
  COTH(x), -- (EXP(x) + EXP(-x)) / (EXP(x) - EXP(-x)),
  COTH(x)  -- (EXP(2 * x) + 1) / (EXP(2 * x) - 1)
FROM tab;
```

These transformations in particular may not appear to be complete, as many other intermediary steps may be required to achieve the above documented starting expressions. More work might be implemented in the future.

<a id="transform-patterns-idempotent-function-repetition"></a>
###### 3.25.8.9.20. Idempotent function repetition

When SQL is complex or generated, there may be accidental repetitions of functions that do not have any effects on the result. Such repetitions can be removed by a single function application.

Using [`Settings.transformPatternsIdempotentFunctionRepetition`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsIdempotentFunctionRepetition), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsIdempotentFunctionRepetition active, this:
SELECT
  LTRIM(LTRIM(x)),
  RTRIM(RTRIM(x)),
  TRIM(TRIM(x)),
  TRIM(LTRIM(x)),
  TRIM(RTRIM(x)),
  RTRIM(TRIM(x)),
  LTRIM(TRIM(x)),
  UPPER(UPPER(x)),
  LOWER(LOWER(x)),
  ABS(ABS(x)),
  SIGN(SIGN(x)),
  CEIL(CEIL(x)),
  FLOOR(FLOOR(x)),
  ROUND(ROUND(x)),
  TRUNC(TRUNC(x)),
  CAST(CAST(x AS type) AS type)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  LTRIM(x),       -- LTRIM(LTRIM(x))
  RTRIM(x),       -- RTRIM(RTRIM(x))
  TRIM(x),        -- TRIM(TRIM(x))
  TRIM(x),        -- TRIM(LTRIM(x))
  TRIM(x),        -- TRIM(RTRIM(x))
  TRIM(x),        -- RTRIM(TRIM(x))
  TRIM(x),        -- LTRIM(TRIM(x))
  UPPER(x),       -- UPPER(UPPER(x))
  LOWER(x),       -- LOWER(LOWER(x))
  ABS(x),         -- ABS(ABS(x))
  SIGN(x),        -- SIGN(SIGN(x))
  CEIL(x),        -- CEIL(CEIL(x))
  FLOOR(x),       -- FLOOR(FLOOR(x))
  ROUND(x),       -- ROUND(ROUND(x))
  TRUNC(x),       -- TRUNC(TRUNC(x))
  CAST(x AS type) -- CAST(CAST(x AS type) AS type)
FROM tab;
```

<a id="transform-patterns-inverse-hyperbolic-functions"></a>
###### 3.25.8.9.21. Inverse hyperbolic functions

Some dialects may not support all trigonometric functions.

Using [`Settings.transformPatternsInverseHyperbolicFunctions`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsInverseHyperbolicFunctions%20), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsInverseHyperbolicFunctions active, this:
SELECT
  LN(x + SQRT(SQUARE(x) + 1)),
  LN(x + SQRT(SQUARE(x) - 1)),
  LN((1 + x) / (1 - x)) / 2),
  LN((x + 1) / (x - 1)) / 2)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  ASINH(x), -- LN(x + SQRT(SQUARE(x) + 1))
  ACOSH(x), -- LN(x + SQRT(SQUARE(x) - 1))
  ATANH(x), -- LN((1 + x) / (1 - x)) / 2)
  ACOTH(x)  -- LN((x + 1) / (x - 1)) / 2)
FROM tab;
```

<a id="transform-patterns-logarithmic-functions"></a>
###### 3.25.8.9.22. Logarithmic functions

Some dialects may not support all trigonometric functions.

Using [`Settings.transformPatternsLogarithmicFunctions`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsLogarithmicFunctions), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsLogarithmicFunctions active, this:
SELECT
  LN(value) / LN(base),
  EXP(1),
  LOG(e, x),
  LOG(10, x),
  POWER(e, x)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  LOG(base, value), -- LN(value) / LN(base)
  e,                -- EXP(1)
  LN(x),            -- LOG(e, x)
  LOG10(x),         -- LOG(10, x)
  EXP(x)            -- POWER(e, x)
FROM tab;
```

<a id="transform-patterns-merge-and-comparison"></a>
###### 3.25.8.9.23. Merge AND predicates

An [AND predicate](#boolean-operators) combining [comparison predicates](#comparison-predicate) that share the same operands can often be merged into a single comparison predicate.

Using [`Settings.transformPatternsMergeAndComparison`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsMergeAndComparison), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsMergeAndComparison active, this:
SELECT
  x = a AND x >= a,
  x = a AND x <= a,
  x > a AND x < a,
  x > a AND x != a,
  x < a AND x != a
  -- And many more
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  x = a,  -- x = a AND x >= a,
  x = a,  -- x = a AND x <= a,
  x != x, -- x > a AND x < a,
  x > a,  -- x > a AND x != a,
  x < a   -- x < a AND x != a
  -- And many more
FROM tab;
```

<a id="transform-patterns-merge-bit-not-bit-nand"></a>
###### 3.25.8.9.24. Merge BIT_NOT with BIT_NAND

The [BIT_NOT function](#bit-not-function) bitwise inverts its argument value. If the argument value is a [BIT_NAND function](#bit-nand-function), we can simply merge the two functions.

Using [`Settings.transformPatternsBitNotNand`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsBitNotNand), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsBitNotNand active, this:
SELECT
  ~(bitnand(a, b)),
  ~(bitand(a, b))
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  bitand(a, b), -- ~(bitnand(a, b))
  bitnand(a, b) -- ~(bitand(a, b))
FROM tab;
```

<a id="transform-patterns-merge-bit-not-bit-nor"></a>
###### 3.25.8.9.25. Merge BIT_NOT with BIT_NOR

The [BIT_NOT function](#bit-not-function) bitwise inverts its argument value. If the argument value is a [BIT_NOR function](#bit-nor-function), we can simply merge the two functions.

Using [`Settings.transformPatternsBitNotNor`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsBitNotNor), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsBitNotNor active, this:
SELECT
  ~(bitnor(a, b)),
  ~(bitor(a, b))
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  bitor(a, b), -- ~(bitnor(a, b))
  bitnor(a, b) -- ~(bitor(a, b))
FROM tab;
```

<a id="transform-patterns-merge-bit-not-bit-xnor"></a>
###### 3.25.8.9.26. Merge BIT_NOT with BIT_XNOR

The [BIT_NOT function](#bit-not-function) bitwise inverts its argument value. If the argument value is a [BIT_XNOR function](#bit-xnor-function), we can simply merge the two functions.

Using [`Settings.transformPatternsBitNotXNor`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsBitNotXNor), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsBitNotXNor active, this:
SELECT
  ~(bitxnor(a, b)),
  ~(bitxor(a, b))
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  bitxor(a, b), -- ~(bitxnor(a, b))
  bitxnor(a, b) -- ~(bitxor(a, b))
FROM tab;
```

<a id="transform-patterns-case-merge-when-else"></a>
###### 3.25.8.9.27. Merge CASE .. WHEN and ELSE clauses

When a searched [CASE expression](#case-expressions)'s last `WHEN` clause returns the same value as the `ELSE` clause, then the `WHEN` clause is redundant. If it's the only `WHEN` clause, then the entire `CASE` exression is redundant.

Using [`Settings.transformPatternsCaseMergeWhenElse`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsCaseMergeWhenElse), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsCaseMergeWhenElse active, this:
SELECT
  CASE WHEN a = b THEN x WHEN c = d THEN y ELSE y END,
  CASE WHEN a = b THEN x ELSE x END
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  CASE WHEN a = b THEN x ELSE y END,
  x
FROM tab;
```

<a id="transform-patterns-case-merge-when-when"></a>
###### 3.25.8.9.28. Merge CASE .. WHEN clauses

When a searched [CASE expression](#case-expressions) contains consecutive `WHEN` clauses returning the same value, then those `WHEN` clauses can be merged.

Using [`Settings.transformPatternsCaseMergeWhenWhen`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsCaseMergeWhenWhen), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsCaseMergeWhenWhen active, this:
SELECT
  CASE
    WHEN a = b THEN 1
    WHEN c = d THEN 1
  END
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  CASE
    WHEN a = b OR c = d THEN 1
  END
FROM tab;
```

<a id="transform-patterns-merge-in-predicates"></a>
###### 3.25.8.9.29. Merge IN predicates

An [AND predicate](#boolean-operators) combining [IN predicates](#in-predicate) that share the same operands can often be merged into a single IN predicate comparing the left operand with the intersection of the right IN lists.

Using [`Settings.transformPatternsMergeInPredicates`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsMergeInPredicates), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsMergeInPredicates active, this:
SELECT * FROM tab WHERE x IN (a, b, c) AND x IN (b, c, d);

-- ... is transformed into the equivalent expression:
SELECT * FROM tab WHERE x IN (b, c);
```

<a id="transform-patterns-merge-not-comparison"></a>
###### 3.25.8.9.30. Merge NOT with comparison predicates

The [NOT predicate](#boolean-operators) inverts its argument predicate. If the argument predicate is a [comparison predicate](#comparison-predicate), we can simply merge the two operators to invert the argument into the inverse [comparison predicate](#comparison-predicate).

Using [`Settings.transformPatternsNotComparison`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNotComparison), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNotComparison active, this:
SELECT
  NOT (a = b),
  NOT (a != b),
  NOT (a > b),
  NOT (a >= b),
  NOT (a < b),
  NOT (a <= b)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  a != b, -- NOT (a = b)
  a = b,  -- NOT (a != b)
  a <= b, -- NOT (a > b)
  a < b,  -- NOT (a >= b)
  a >= b, -- NOT (a < b)
  a > b   -- NOT (a <= b)
FROM tab;
```

<a id="transform-patterns-merge-not-not-distinct"></a>
###### 3.25.8.9.31. Merge NOT with DISTINCT predicate

The [NOT predicate](#boolean-operators) inverts its argument predicate. If the argument predicate is a [DISTINCT predicate](#distinct-predicate), we can simply merge the two operators to invert the argument into the inverse [DISTINCT predicate](#distinct-predicate).

Using [`Settings.transformPatternsNotNotDistinct`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNotNotDistinct), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNotNotDistinct active, this:
SELECT
  NOT (a IS NOT DISTINCT FROM b),
  NOT (a IS DISTINCT FROM b)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  a IS DISTINCT FROM b,    -- NOT (a IS NOT DISTINCT FROM b)
  a IS NOT DISTINCT FROM b -- NOT (a IS DISTINCT FROM b)
FROM tab;
```

<a id="transform-patterns-merge-or-comparison"></a>
###### 3.25.8.9.32. Merge OR predicates

An [OR predicate](#boolean-operators) combining [comparison predicates](#comparison-predicate) that share the same operands can often be merged into a single comparison predicate.

Using [`Settings.transformPatternsMergeOrComparison`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsMergeOrComparison), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsMergeOrComparison active, this:
SELECT
  x = a OR x > a,
  x = a OR x < a,
  x > a OR x < a,
  x > a OR x != a,
  x < a OR x != a
  -- And many more
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  x >= a, -- x = a OR x > a
  x <= a, -- x = a OR x < a
  x != a, -- x > a OR x < a
  x != a, -- x > a OR x != a
  x != a  -- x < a OR x != a
  -- And many more
FROM tab;
```

<a id="transform-patterns-merge-range-predicates"></a>
###### 3.25.8.9.33. Merge range predicates

An [AND predicate](#boolean-operators) combining [range predicates](#comparison-predicate) that share the same operands can often be merged into a single [BETWEEN predicate](#between-predicate) predicate comparing the left operand with the two right operands.

Using [`Settings.transformPatternsMergeRangePredicates`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsMergeRangePredicates), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsMergeRangePredicates active, this:
SELECT * FROM tab WHERE x >= a AND x <= b;

-- ... is transformed into the equivalent expression:
SELECT * FROM tab WHERE x BETWEEN a AND b;
```

<a id="transform-patterns-normalise-associative-ops"></a>
###### 3.25.8.9.34. Normalise associative operations

Associative operations are operations whose chaining can be done as `(a op b) op c` or `a op (b op c)` without changing the result. Examples of such operations are:

- `+`
- `*`
- `AND`
- `OR`

In order to simplify all of these pattern replacements, we normalise associative ops to always flatten tree structures into lists.

Using [`Settings.transformPatternsNormaliseAssociativeOps`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNormaliseAssociativeOps), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNormaliseAssociativeOps active, this:
SELECT
  (a + b) + (c + d),
  (a * b) * (c * d),
  (a AND b) AND (c AND d),
  (a OR b) OR (c OR d)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  ((a + b) + c) + d,       -- (a + b) + (c + d)
  ((a + b) + c) + d,       -- (a * b) * (c * d)
  ((a AND b) AND c) AND d, -- (a AND b) AND (c AND d)
  ((a OR b) OR c) OR d     -- (a OR b) OR (c OR d)
FROM tab;
```

Note that the unnecesary parentheses may not be generated in either case, but the in-memory data structure still looks as though the parentheses were there.

<a id="transform-patterns-normalise-field-compare-value"></a>
###### 3.25.8.9.35. Normalise fields compared to values

When comparing [column expressions](#column-expressions) with [values](#bind-values), the various pattern replacements profit from a simplification where we normalise the order of operands to have the value on the right side of the operator.

Using [`Settings.transformPatternsNormaliseFieldCompareValue`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNormaliseFieldCompareValue), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNormaliseFieldCompareValue active, this:
SELECT * FROM tab WHERE 1 = a;

-- ... is transformed into the equivalent expression:
SELECT * FROM tab WHERE a = 1;
```

<a id="transform-patterns-in-list-single-element-to-comparison"></a>
###### 3.25.8.9.36. Normalise IN list with single element to comparison

When comparing an [IN predicate](#in-predicate) with a single value, then it may be beneficial for other pattern replacement if that expression is normalised to a [comparison predicate](#comparison-predicate).

Using [`Settings.transformPatternsNormaliseInListSingleElementToComparison`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNormaliseInListSingleElementToComparison), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNormaliseInListSingleElementToComparison active, this:
SELECT
  x IN (a),
  x NOT IN (a)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  x = a, -- x IN (a),
  x != a -- x NOT IN (a)
FROM tab;
```

<a id="transform-patterns-not-and"></a>
###### 3.25.8.9.37. NOT AND

The [NOT unary operator](#boolean-operators) applied to `AND` can be distributed applying De Morgan's law.

Using [`Settings.transformPatternsNotAnd`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNotAnd), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNotAnd active, this:
SELECT
  NOT (x = 1 AND y = 2),
  NOT (x = 1 AND y = 2 AND z = 3)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  NOT (x = 1) OR NOT (y = 2),
  NOT (x = 1) OR NOT (y = 2) OR NOT (z = 3)
FROM tab;
```

<a id="transform-patterns-not-or"></a>
###### 3.25.8.9.38. NOT OR

The [NOT unary operator](#boolean-operators) applied to `OR` can be distributed applying De Morgan's law.

Using [`Settings.transformPatternsNotAnd`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNotAnd), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNotAnd active, this:
SELECT
  NOT (x = 1 OR y = 2),
  NOT (x = 1 OR y = 2 OR z = 3)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  NOT (x = 1) AND NOT (y = 2),
  NOT (x = 1) AND NOT (y = 2) AND NOT (z = 3)
FROM tab;
```

<a id="transform-patterns-null-on-null-input"></a>
###### 3.25.8.9.39. NULL ON NULL INPUT

Just like [stored functions](#create-function-statement), built-in functions have a [NULL ON NULL INPUT](#create-function-characteristics-on-null-input) characteristic, which allows for short circuiting function calls whose argument list contains at least one `NULL` value, knowing the result will be `NULL` as well. This transformation is available to jOOQ as well.

Using [`Settings.transformPatternsNullOnNullInput`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNullOnNullInput), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNullOnNullInput active, this:
SELECT
  UPPER(NULL),
  LOWER(NULL),
  -- Many more
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  NULL,
  NULL,
  -- Many more
FROM tab;
```

<a id="transform-patterns-or-eq-to-in"></a>
###### 3.25.8.9.40. OR to IN

A concatenation of [OR predicates](#boolean-operators) combining equalities that always use the same operand on one side can be replaced by a more concise, but equivalent [IN predicate](#in-predicate).

Using [`Settings.transformPatternsOrEqToIn`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsOrEqToIn), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsOrEqToIn active, this:
SELECT * FROM tab WHERE x = 1 OR x = 2 OR x = 3;

-- ... is transformed into the equivalent expression:
SELECT * FROM tab WHERE x IN (1, 2, 3);
```

See also [AND to NOT IN](#transform-patterns-and-ne-to-not-in)

<a id="transform-patterns-neg-neg"></a>
###### 3.25.8.9.41. Repeated arithmetic negation

The [negation unary operator](#neg-function) reverses itself, when called repeatedly, meaning that redundant `NEG()` operators can be removed.

Using [`Settings.transformPatternsNegNeg`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNegNeg), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNegNeg active, this:
SELECT
  -(-(x)),
  -(-(-(x)))
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  x,  -- -(-(x))
  -x, -- -(-(-(x)))
FROM tab;
```

<a id="transform-patterns-bit-not-bit-not"></a>
###### 3.25.8.9.42. Repeated bitwise negation

The [bitwise negation unary operator](#bit-not-function) reverses itself, when called repeatedly, meaning that redundant `BIT_NOT()` operators can be removed.

Using [`Settings.transformPatternsBitNotBitNot`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsBitNotBitNot), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNegNeg active, this:
SELECT
  ~(~(x)),
  ~(~(~(x)))
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  x,  -- ~(~(x))
  ~x, -- ~(~(~(x)))
FROM tab;
```

<a id="transform-patterns-not-not"></a>
###### 3.25.8.9.43. Repeated NOT

The [NOT unary operator](#boolean-operators) reverses itself, when called repeatedly, meaning that redundant `NOT` operators can be removed.

Using [`Settings.transformPatternsNotNot`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsNotNot), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsNotNot active, this:
SELECT
  NOT (NOT (x = 1)),
  NOT (NOT (NOT (x = 1)))
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  x = 1,       -- NOT (NOT (x = 1))
  NOT (x = 1), -- NOT (NOT (NOT (x = 1)))
FROM tab;
```

<a id="transform-patterns-simplify-case-abbreviation"></a>
###### 3.25.8.9.44. Simplify CASE abbreviations

The [NVL](#nvl-function) or [COALESCE](#coalesce-function) `CASE` abbreviations may appear in expressions that have more simple counterparts using a simpler `CASE` abbreviation.

Using [`Settings.transformPatternsSimplifyCaseAbbreviation`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsSimplifyCaseAbbreviation), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsSimplifyCaseAbbreviation active, this:
SELECT
  a IS NULL OR NVL(a = b, FALSE),
  COALESCE(a = b, a IS NULL),
  COALESCE(a, b) IS NOT DISTINCT FROM b,
  a IS NOT NULL AND NVL(a != b, TRUE),
  COALESCE(a != b, a IS NOT NULL),
  COALESCE(a, b) IS DISTINCT FROM b
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  NULLIF(a, b) IS NULL,
  NULLIF(a, b) IS NULL,
  NULLIF(a, b) IS NULL,
  NULLIF(a, b) IS NOT NULL,
  NULLIF(a, b) IS NOT NULL,
  NULLIF(a, b) IS NOT NULL
FROM tab;
```

<a id="transform-patterns-trigonometric-functions"></a>
###### 3.25.8.9.45. Trigonometric functions

Some dialects may not support all trigonometric functions.

Using [`Settings.transformPatternsTrigonometricFunctions`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsTrigonometricFunctions), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsTrigonometricFunctions active, this:
SELECT
  SIN(x) / COS(x),
  COS(x) / SIN(x),
  1 / TAN(x),
  1 / COT(x)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  TAN(x), -- SIN(x) / COS(x)
  COT(x), -- COS(x) / SIN(x)
  COT(x), -- 1 / TAN(x)
  TAN(x)  -- 1 / COT(x)
FROM tab;
```

<a id="transform-patterns-trim"></a>
###### 3.25.8.9.46. Trim

Some dialects may not have supported [TRIM()](#trim-function) natively, so users emulated it by combining [RTRIM()](#rtrim-function) and [LTRIM()](#ltrim-function) manually.

Using [`Settings.transformPatternsTrim`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsTrim), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsTrim active, this:
SELECT RTRIM(LTRIM(col)), LTRIM(RTRIM(col)) FROM tab;

-- ... is transformed into the equivalent expression:
SELECT TRIM(col), TRIM(col) FROM tab;
```

<a id="transform-patterns-trivial-bitwise-operations"></a>
###### 3.25.8.9.47. Trivial bitwise operations

[bitwise operations](#bitwise-functions) can be trivial, in case of which the expression can be removed and replaced by one of the arguments.

Using [`Settings.transformPatternsTrivialBitwiseOperations`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsTrivialBitwiseOperations), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsTrivialBitwiseOperations active, this:
SELECT
  bitor(a, 0),
  bitand(a, -1),
  bitxor(a, 0),
  bitxor(a, -1)
  -- and many more
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  a,        -- bitor(a, 0),
  a,        -- bitand(a, -1),
  a,        -- bitxor(a, 0),
  bitnot(a) -- bitxor(a, -1)
  -- and many more
FROM tab;
```

<a id="transform-patterns-trivial-case-abbreviations"></a>
###### 3.25.8.9.48. Trivial CASE abbreviations

[Case](#case-expressions) abbreviations like [NULLIF()](#nullif-function) can be trivial, in case of which the function call can be removed.

Using [`Settings.transformPatternsTrivialCaseAbbreviation`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsTrivialCaseAbbreviation), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsTrivialCaseAbbreviation active, this:
SELECT
  NVL(NULL, a),
  NVL(1, a),
  COALESCE(NULL, NULL, a),
  COALESCE(1, a, b),
  NULLIF(a, a),
  NULLIF(NULL, a),
  NULLIF(a, NULL)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  a,    -- NVL(NULL, a),
  1,    -- NVL(1, a),
  a,    -- COALESCE(NULL, NULL, a),
  1,    -- COALESCE(1, a, b),
  NULL, -- NULLIF(a, a),
  NULL, -- NULLIF(NULL, a),
  a     -- NULLIF(a, NULL)
FROM tab;
```

<a id="transform-patterns-trivial-predicates"></a>
###### 3.25.8.9.49. Trivial predicates

[predicates](#conditional-expressions) can be trivial, in case of which the expression can be removed and replaced by a [TRUE or FALSE condition](#true-false-no-condition).

Using [`Settings.transformPatternsTrivialPredicates`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsTrivialPredicates), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsTrivialPredicates active, this:
SELECT
  a IS NOT DISTINCT FROM a,
  a IS DISTINCT FROM a,
  a >= a,
  a <= a,
  a > a,
  a < a,
  const IS NOT NULL,
  const IS NULL,
  TRUE AND FALSE,
  TRUE OR FALSE,
  NOT TRUE,
  NOT FALSE,
  p = TRUE,
  p <> TRUE,
  p = FALSE,
  p <> FALSE,
  p AND (q OR p),
  p OR (q AND p)
  -- and many more
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  TRUE,    -- a IS NOT DISTINCT FROM a
  FALSE,   -- a IS DISTINCT FROM a
  a = a,   -- a >= a
  a = a,   -- a <= a
  a != a,  -- a > a
  a != a,  -- a < a
  TRUE,    -- const IS NOT NULL
  FALSE,   -- const IS NULL
  FALSE,   -- TRUE AND FALSE
  TRUE,    -- TRUE OR FALSE
  FALSE,   -- NOT TRUE
  TRUE,    -- NOT FALSE
  p,       -- p = TRUE
  NOT (p), -- p <> TRUE
  NOT (p), -- p = FALSE
  p,       -- p <> FALSE,
  p,       -- p AND (q OR p)
  p        -- p OR (q AND p)
  -- and many more
FROM tab;
```

<a id="transform-patterns-unnecessary-distinct"></a>
###### 3.25.8.9.50. Unnecessary DISTINCT

When every [GROUP BY expression](#group-by-clause) is also projected in a [SELECT DISTINCT clause](#select-clause-distinct) at least once, in any order, then the `DISTINCT` keyword is unnecessary.

Using [`Settings.transformPatternsUnnecessaryDistinct`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsUnnecessaryDistinct), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsUnnecessaryDistinct active, this:
SELECT DISTINCT b, a, count(*) FROM t GROUP BY a, b;

-- ... is transformed into the equivalent expression:
SELECT b, a, count(*) FROM t GROUP BY a, b;
```

In simpler cases, such as projection only queries, `DISTINCT` is also never necessary:

```sql
-- With Settings.transformPatternsUnnecessaryDistinct active, this:
SELECT DISTINCT 1, count(*);

-- ... is transformed into the equivalent expression:
SELECT 1, count(*);
```

<a id="transform-patterns-unnecessary-exists-subquery-clauses"></a>
###### 3.25.8.9.51. Unnecessary EXISTS subquery clauses

The [EXISTS predicate](#exists-predicate) can safely ignore a few of its subquery clauses without changing semantics, including:

- The [SELECT clause](#select-clause)
- The [DISTINCT clause](#select-clause-distinct)
- The [ORDER BY clause](#order-by-clause)
- The [LIMIT clause](#limit-clause), if it is non-zero

All of the above applies only if there are no [aggregate functions](#aggregate-functions) in the `EXISTS` subquery.

Using [`Settings.transformPatternsUnnecessaryExistsSubqueryClauses`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsUnnecessaryExistsSubqueryClauses), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsUnnecessaryExistsSubqueryClauses active, this:
SELECT EXISTS (SELECT DISTINCT a, b FROM t);

-- ... is transformed into the equivalent expression:
SELECT EXISTS (SELECT 1 FROM t);
```

<a id="transform-patterns-unnecessary-group-by-expressions"></a>
###### 3.25.8.9.52. Unnecessary GROUP BY expressions

When an ordinary grouping set expression is repeated in the [GROUP BY clause](#group-by-clause) (i.e. not [ROLLUP, CUBE, or GROUPING SETS](#group-by-grouping-sets)), then one of the expressions can be removed as it has no effect.

Using [`Settings.transformPatternsUnnecessaryGroupByExpressions`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsUnnecessaryGroupByExpressions), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsUnnecessaryGroupByExpressions active, this:
SELECT a, b, count(*) FROM t GROUP BY a, b, a;

-- ... is transformed into the equivalent expression:
SELECT a, b, count(*) FROM t GROUP BY a, b;
```

<a id="transform-patterns-unnecessary-inner-join"></a>
###### 3.25.8.9.53. Unnecessary INNER JOIN

An [INNER JOIN](#join-clause) whose `ON` clause is always `TRUE`, or which doesn't actually join on both sides of the `JOIN` operator can be turned into a `CROSS JOIN`. In most cases, the `CROSS JOIN` is accidental, but with that syntax, at least the error can be more easily recognised.

Using [`Settings.transformPatternsUnnecessaryInnerJoin`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsUnnecessaryInnerJoin), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsUnnecessaryInnerJoin active, this:
SELECT * FROM t JOIN u ON TRUE;

-- ... is transformed into the equivalent expression:
SELECT * FROM t CROSS JOIN u;
```

<a id="transform-patterns-unnecessary-order-by-expressions"></a>
###### 3.25.8.9.54. Unnecessary ORDER BY expressions

When an expression is repeated in the [ORDER BY clause](#order-by-clause), then the second one can be removed as it has no effect - even if it has a different value for `ASC`, `DESC`, `NULLS`.

Using [`Settings.transformPatternsUnnecessaryOrderByExpressions`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsUnnecessaryOrderByExpressions), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsUnnecessaryOrderByExpressions active, this:
SELECT a, b FROM t ORDER BY a DESC, b, a ASC;

-- ... is transformed into the equivalent expression:
SELECT a, b FROM t GROUP BY a DESC, b;
```

<a id="transform-patterns-unnecessary-scalar-subquery"></a>
###### 3.25.8.9.55. Unnecessary scalar subquery

A [scalar subquery](#scalar-subqueries) that contains only a projection is unnecessary. While it is unlikely for users to implement such projection only scalar subqueries, they may appear as a result of other transformations. This rule excludes scalar subqueries:

- Containing [aggregate functions](#aggregate-functions)
- Containing [window functions](#window-functions)
- Contained in the [GROUP BY clause](#group-by-clause) (`GROUP BY (SELECT 1)` may have a different meaning from `GROUP BY 1`)
- Contained in the [ORDER BY clause](#order-by-clause) (`ORDER BY (SELECT 1)` has a different meaning from `ORDER BY 1`)

Using [`Settings.transformPatternsUnnecessaryScalarSubquery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsUnnecessaryScalarSubquery), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsUnnecessaryScalarSubquery active, this:
SELECT (SELECT a) FROM t WHERE (SELECT a) = b;

-- ... is transformed into the equivalent expression:
SELECT a FROM t WHERE a = b;
```

<a id="transform-patterns-unreachable-case-clauses"></a>
###### 3.25.8.9.56. Unreachable CASE clauses

When a searched [CASE expression](#case-expressions) contains unreachable `WHEN` or `ELSE` clauses, we can remove them.

Using [`Settings.transformPatternsUnreachableCaseClauses`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsUnreachableCaseClauses), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsUnreachableCaseClauses active, this:
SELECT
  CASE WHEN a = b THEN 1 WHEN TRUE THEN 2 WHEN c = d THEN 3 END,
  CASE WHEN a = b THEN 1 WHEN FALSE THEN 2 WHEN c = d THEN 3 END
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  CASE WHEN a = b THEN 1 ELSE 2 END,
  CASE WHEN a = b THEN 1 WHEN c = d THEN 3 END
FROM tab;
```

A more subtle unreachable `WHEN` clause is a clause that has already been listed, irrespective of the `THEN` clause. While removing it is a correct transformation, the duplicate might be likely due to a typo.

```sql
-- With Settings.transformPatternsUnreachableCaseClauses active, this:
SELECT
  CASE
    WHEN a = b THEN 1
    WHEN c = d THEN 2
    WHEN a = b THEN 3
  END
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  CASE
    WHEN a = b THEN 1
    WHEN c = d THEN 2
  END
FROM tab;
```

<a id="transform-patterns-unreachable-decode-clauses"></a>
###### 3.25.8.9.57. Unreachable DECODE clauses

When a [DECODE functino](#decode-function) contains unreachable arguments, we can remove them.

Using [`Settings.transformPatternsUnreachableDecodeClauses`](https://www.jooq.org/javadoc/3.22.x/org/jooq/conf/Settings.html#transformPatternsUnreachableDecodeClauses), the following transformations can be achieved:

```sql
-- With Settings.transformPatternsUnreachableDecodeClauses active, this:
SELECT
  DECODE(a, b, 1, c, 2, b, 3),
  DECODE(a, b, 1, c, 2, b, 3, 4)
FROM tab;

-- ... is transformed into the equivalent expression:
SELECT
  DECODE(a, b, 1, c, 2),
  DECODE(a, b, 1, c, 2, 4)
FROM tab;
```

<a id="custom-sql-transformation"></a>
#### 3.25.9. Custom SQL transformation with VisitListener

With the [`org.jooq.VisitListener`](https://www.jooq.org/javadoc/3.22.x/org/jooq/VisitListener.html) SPI, it is possible to perform custom SQL transformation to implement things like shared-schema multi-tenancy, or a security layer centrally preventing access to certain data. This SPI is extremely powerful, as you can make ad-hoc decisions at runtime regarding local or global transformation of your SQL statement. The following sections show a couple of simple, yet real-world use-cases.

<a id="transformation-bind-value-abbreviation"></a>
##### 3.25.9.1. Example: Logging abbreviated bind values

When implementing a logger, one needs to carefully assess how much information should really be disclosed on what logger level. In log4j and similar frameworks, we distinguish between `FATAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`, and `TRACE`. In `DEBUG` level, jOOQ's [internal default logger](#logging) logs all executed statements including inlined bind values as such:

```text
Executing query          : select * from "BOOK" where "BOOK"."TITLE" like ?
-> with bind values      : select * from "BOOK" where "BOOK"."TITLE" like 'How I stopped worrying%'
```

But textual or binary bind values can get quite long, quickly filling your log files with irrelevant information. It would be good to be able to abbreviate such long values (and possibly add a remark to the logged statement). Instead of patching jOOQ's internals, we can just transform the SQL statements in the logger implementation, cleanly separating concerns. This can be done with the following `VisitListener`:

```java
// This listener is inserted into a Configuration through a VisitListenerProvider that creates a
// new listener instance for every rendering lifecycle
public class BindValueAbbreviator implements VisitListener {

    private boolean anyAbbreviations = false;

    @Override
    public void visitStart(VisitContext context) {

        // Transform only when rendering values
        if (context.renderContext() != null) {
            QueryPart part = context.queryPart();

            // Consider only bind variables, leave other QueryParts untouched
            if (part instanceof Param<?>) {
                Param<?> param = (Param<?>) part;
                Object value = param.getValue();

                // If the bind value is a String (or Clob) of a given length, abbreviate it
                // e.g. using commons-lang's StringUtils.abbreviate()
                if (value instanceof String && ((String) value).length() > maxLength) {
                    anyAbbreviations = true;

                    // ... and replace it in the current rendering context (not in the Query)
                    context.queryPart(val(abbreviate((String) value, maxLength)));
                }

                // If the bind value is a byte[] (or Blob) of a given length, abbreviate it
                // e.g. by removing bytes from the array
                else if (value instanceof byte[] && ((byte[]) value).length > maxLength) {
                    anyAbbreviations = true;

                    // ... and replace it in the current rendering context (not in the Query)
                    context.queryPart(val(Arrays.copyOf((byte[]) value, maxLength)));
                }
            }
        }
    }

    @Override
    public void visitEnd(VisitContext context) {

        // If any abbreviations were performed before...
        if (anyAbbreviations) {

            // ... and if this is the top-level QueryPart, then append a SQL comment to indicate the abbreviation
            if (context.queryPartsLength() == 1) {
                context.renderContext().sql(" -- Bind values may have been abbreviated");
            }
        }
    }
}
```

If maxLength were set to 5, the above listener would produce the following log output:

```text
Executing query          : select * from "BOOK" where "BOOK"."TITLE" like ?
-> with bind values      : select * from "BOOK" where "BOOK"."TITLE" like 'Ho...' -- Bind values may have been abbreviated
```

The above `VisitListener` is in place since jOOQ 3.3 in the [`org.jooq.tools.LoggerListener`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/LoggerListener.html).

<a id="policies"></a>
#### 3.25.10. Policies

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Policies are jOOQ's primary way to implement client side row level security by transforming [DML statements](#sql-statements) such that certain rows will become invisible to clients running jOOQ queries. A popular example use-case is row based multi-tenancy, e.g. by specifying [a condition](#conditional-expressions) on a `TENANT_ID` column on all tables.

For example, a `Configuration` may declare a [`org.jooq.Policy`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Policy.html) on a `CUSTOMER` table to filter out `CUSTOMER.TENANT_ID = 42`. Users write queries like:

```java
create.select(CUSTOMER.ID, CUSTOMER.NAME)
      .from(CUSTOMER)
      .fetch();
```

But with the policy in place, jooq will render this query instead:

```sql
SELECT CUSTOMER.ID, CUSTOMER.NAME
FROM CUSTOMER
WHERE CUSTOMER.TENANT_ID = 42
```

Not just queries but all DML statements are affected. It is easy to see how this also applies to [UPDATE statements](#update-statement) or [DELETE statements](#delete-statement), which have a `WHERE` clause, but it also applies to [INSERT statements](#insert-statement).

The following sections explain the feature more in detail.

<a id="policies-configuration"></a>
##### 3.25.10.1. Configuration

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A [`org.jooq.Policy`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Policy.html) is a configuration consisting of a:

- [`Policy.table()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Policy.html#table()): The table that it applies to
- [`Policy.condition()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Policy.html#condition()): The condition to apply to the query that uses the table
- [`Policy.inherited()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Policy.html#inherited()): Whether a policy on a parent table is inherited by child tables

Policies are provided to jOOQ via the usual SPI configuration point, the [Configuration](#dsl-context). As with all jOOQ SPIs, this means that multiple `Configurations` are possible in parallel, depending on your database interaction use-case. For example:

- A super user may be able to access all data
- A staff user may be able to access only 1-2 tenants
- A customer user may be able to access only their own customer data

In such a setup, you'll already have different database users with different privileges (see also [security considerations](#policies-security)), so you can attach one set of policies to each database user.

One way to create policies is by using the [`org.jooq.impl.DefaultPolicyProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultPolicyProvider.html):

```java
Configuration configuration = ...;
configuration.set(new DefaultPolicyProvider()

    // Append a Policy to the PolicyProvider
    .append(

        // The table on which to apply a policy
        TENANT,

        // The condition to apply to queries against the table
        TENANT.TENANT_ID.eq(42))

    // Append another Policy to the PolicyProvider
    .append(CUSTOMER, CUSTOMER.CUSTOMER_ID.eq(40183))
);
```

<a id="policies-implementation"></a>
##### 3.25.10.2. Implementation

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A policy is implemented while rendering your jOOQ query. It always adds the `Policy` condition to the query in a meaningful way, which means that rows are filtered out of the query.

> [!TIP]
> There is never any exception thrown by the application of a `Policy`! A policy only ever filters out rows of queries or DML statements.

With a policy implementing `TENANT.TENANT_ID = 42`, we might write queries like these:

###### SELECT

```sql
SELECT CUSTOMER.ID, CUSTOMER.NAME
FROM CUSTOMER
WHERE CUSTOMER.TENANT_ID = 42
```

```java
create.select(CUSTOMER.ID, CUSTOMER.NAME)
                     .from(CUSTOMER)
                     .fetch();
```

###### INSERT

The `INSERT` case is curious, because it is unusual for a single-row [INSERT .. VALUES](#insert-values) statement not to actually insert anything (producing an update count of `0`), but it makes perfect sense with a policy.

```sql
INSERT INTO CUSTOMER (ID, NAME, TENANT_ID)
SELECT t.ID, t.NAME, t.TENANT_ID
FROM (

  -- These are the values from the VALUES () clause
  SELECT 1, 'John Doe', 42
) t (ID, NAME, TENANT_ID)

-- This is the policy condition
WHERE t.TENANT_ID = 42
```

```java
create.insertInto(CUSTOMER)
      .columns(
          CUSTOMER.ID,
          CUSTOMER.NAME,
          CUSTOMER.TENANT_ID)
      .values(
         1,
         "John Doe",
         42)
      .execute();
```

The example above shows that the inserted `CUSTOMER.TENANT_ID` value must match the value from the policy condition, otherwise, the row won't be inserted.

###### UPDATE

Policies are applied to an `UPDATE` statement in 2 ways. First, via `WHERE` clause, preventing updates to rows that can't be selected:

```sql
UPDATE CUSTOMER
SET NAME = 'John Doe'
WHERE CUSTOMER.ID = 5
AND CUSTOMER.TENANT_ID = 42
```

```java
create.update(CUSTOMER)
      .set(CUSTOMER.NAME, "John Doe")
      .where(CUSTOMER.ID.eq(5))
      .execute();
```

But, if necessary also to the `SET` clause, preventing an `UPDATE` to a value that is not allowed, *after* the update.

```sql
UPDATE CUSTOMER
SET TENANT_ID = 1
WHERE CUSTOMER.ID = 5
-- Preventing access to some rows
AND CUSTOMER.TENANT_ID = 42
-- Preventing updates to certain values
AND 1 = 42
```

```java
create.update(CUSTOMER)
      .set(
         CUSTOMER.TENANT_ID,
         1
      )
      .where(CUSTOMER.ID.eq(5))
      .execute();
```

The weird looking predicate `1 = 42` is achieved from substituting the `SET` clause element `TENANT_ID = 1` into the policy condition `CUSTOMER.TENANT_ID = 42`. If the policy allowed `CUSTOMER.TENANT_ID IN (1, 42)`, then the update would be legal again:

```sql
UPDATE CUSTOMER
SET TENANT_ID = 1
WHERE CUSTOMER.ID = 5
-- Preventing access to some rows
AND CUSTOMER.TENANT_ID IN (1, 42)
-- Preventing updates to certain values
AND 1 IN (1, 42)
```

```java
create.update(CUSTOMER)
      .set(
         CUSTOMER.TENANT_ID,
         1
      )
      .where(CUSTOMER.ID.eq(5))
      .execute();
```

###### DELETE

A policy only affects the `WHERE` clause of a `DELETE` statement, similar to a `WHERE` clause of a `SELECT` statement.

```sql
DELETE FROM CUSTOMER
WHERE CUSTOMER.ID = 5
AND CUSTOMER.TENANT_ID = 42
```

```java
create.deleteFrom(CUSTOMER)
      .where(CUSTOMER.ID.eq(5))
      .execute();
```

<a id="policies-inheritance"></a>
##### 3.25.10.3. Inheritance

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A policy on a parent table can be inherited by its child tables, which greatly simplifies the task of defining policies across a schema.

For example, assuming there's a `TENANT` table with a `TENANT_ID` primary key, to which a policy is being applied to form a predicate like `TENANT.TENANT_ID = 42`. Now, with a schema like this:

```sql
CREATE TABLE TENANT (
  TENANT_ID BIGINT NOT NULL PRIMARY KEY
  ...
);

CREATE TABLE CUSTOMER (
  CUSTOMER_ID BIGINT NOT NULL PRIMARY KEY,
  TENANT_ID BIGINT NOT NULL REFERENCES TENANT,
  ...
);

CREATE TABLE INVOICE (
  INVOICE_ID BIGINT NOT NULL PRIMARY KEY,
  CUSTOMER_ID BIGINT NOT NULL REFERENCES CUSTOMER,
  ...
)
```

> [!TIP]
> For performance reasons, it is probably useful to denormalise your schema a bit by repeating the `TENANT_ID` column also on the `INVOICE` table and all the other tables, even if it is not necessary from a schema design perspective. This example deliberately avoided this approach to show the feature's capabilities.

Now, naturally, if a user can access only `TENANT.TENANT_ID = 42`, then all the other tenants' customers and invoices should be inaccessible as well. How easily is this forgotten when implementing row level security manually? Not with this feature! Just declare inheritance on your policies like this:

```java
Configuration configuration = ...;
configuration.set(new DefaultPolicyProvider().append(

    // The table on which to apply a policy
    TENANT,

    // The condition to apply to queries against the table
    TENANT.TENANT_ID.eq(42),

    // Implicit join paths from a child table to the TENANT table
    // All child tables will automatically inherit the policy
    CUSTOMER.tenant(),
    INVOICE.customer().tenant()
));
```

This is equivalent to declaring 3 policies:

```java
Configuration configuration = ...;
configuration.set(new DefaultPolicyProvider()
    .append(TENANT, TENANT.TENANT_ID.eq(42))
    .append(CUSTOMER, CUSTOMER.tenant().TENANT_ID.eq(42))
    .append(INVOICE, INVOICE.customer().tenant().TENANT_ID.eq(42))
);
```

Now, if you query the invoice table like this:

```java
create.select(INVOICE.ID, INVOICE.AMOUNT)
      .from(INVOICE)
      .fetch();
```

Then the above policy will add a `INVOICE.customer().tenant().TENANT_ID.eq(42)` predicate, effectively adding an [implicit JOIN](#implicit-join) to your query:

```sql
SELECT INVOICE.ID, INVOICE.AMOUNT
FROM (
  INVOICE
    JOIN (
      CUSTOMER
        JOIN (
          SELECT *
          FROM TENANT
          TENANT_ID = 42
        ) TENANT
          ON CUSTOMER.TENANT_ID = TENANT.TENANT_ID
    )
      ON INVOICE.CUSTOMER_ID = CUSTOMER.CUSTOMER_ID
  )
```

The same is true for all other DML statements as well. For example, it won't be possible to `INSERT`, `UPDATE`, or `DELETE` an invoice from a different `TENANT`

<a id="policies-security"></a>
##### 3.25.10.4. Security considerations

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

While policies are a great way to implement row level *security*, please beware that there are some significant limitations to this feature being implemented at the client side, instead of the server side. If you can, please consider using also (additionally), any vendor specific policy implementation, such as e.g.:

- Oracle's Virtual Private Database feature
- PostgreSQL's `POLICY` feature
- Any custom implementation based on views and context variables

Some specific limitations of jOOQ's implementation include:

- Policies only work on jOOQ expression trees. They do not work on [plain SQL templates](#plain-sql), which are "opaque" to jOOQ. You can prevent most accidental plain SQL template usage by using a [compile time checker](#checker-framework), but these can be circumvented easily as well. This is particularly true also for views and stored functions, to which policies do not apply automatically.
- Anyone with access to your JDBC driver can run queries against JDBC directly, and jOOQ will not be aware of those.
- Anyone with access to your [Configuration](#dsl-context) can remove the [`org.jooq.PolicyProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/PolicyProvider.html) and run an unrestricted query against your schema again.
- Policies do not prevent executing statement types, including [DDL statements](#ddl-statements). Use [(server side) privileges](#grant-statement) for that.
- While policies may be able to access expressions from column [DEFAULTs](#create-table-default) or [computed column expressions](#create-table-computed-columns), policies cannot access trigger logic or any other logic that will interact with your DML statements, and as such, it would be possible for a trigger to produce a value that wouldn't be allowed by the policy, for example. The same is true for [IDENTITY](#create-table-identity) values or any other values generated from an expression with side effects, which cannot be predicted before an `INSERT` statement.
- While jOOQ will prevent access to data outside of the scope of a policy, there are always means of deducing data from secondary effects, such as time-based searches that check for the presence or absence of data based on the execution time of certain predicates.

As the above list illustrates, while jOOQ's `POLICY` feature does provide a lot of value, it is unwise to expect it to provide a very high level of security to your application. Security best practices should be applied on every layer of your application, including within the database, at the query layer, service layer, and in the UI.

See also [related limitations of other code generation features here](#codegen-feature-dependencies).

<a id="zero-based-vs-one-based"></a>
### 3.26. Zero-based vs one-based APIs

Any API that bridges two languages / mind sets, such as Java / SQL will inevitably face the difficulty of finding a consistent strategy to solving the "based-ness" problem. Should arrays be one-based or zero-based?

Clearly, Java is zero-based and SQL is one-based, and the best strategy for jOOQ is to keep things this way. The following are a set of rules that you should remember if this ever confuses you:

#### All SQL API is one-based

When using SQL API, such as the index-based [ORDER BY clause](#order-by-clause), or [window functions](#window-functions) such as in the example below, jOOQ will not interpret indexes but send them directly as-is to the SQL engine. For instance:

```sql
SELECT nth_value(title, 3) OVER (ORDER BY id)
FROM book
ORDER BY 1
```

```java
create.select(nthValue(BOOK.TITLE, 3).over(orderBy(BOOK.ID)))
      .from(BOOK)
      .orderBy(1).fetch();
```

In the above example, we're looking for the 3rd value of X in T ordered by Y. Clearly, this window function uses one-based indexing. The same is true for the `ORDER BY` clause, which orders the result by the 1st column - again one-based counting. There is no column zero in SQL.

#### All jOOQ API is zero-based

jOOQ is a Java API and as such, one-basedness would be quite surprising despite the fact that JDBC is one-based (see below). For instance, when you access a record by index in a jOOQ [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html), given that the result extends [`java.util.List`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html), you will use zero-based index access:

```java
Result<?> result = create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(1)
      .fetch();

for (int i = 0; i < result.size(); i++)
    System.out.println(result.get(i));
```

Unlike in JDBC, where [`java.sql.ResultSet#absolute(int)`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html#absolute(int)) positions the underlying cursor at the one-based index, we Java developers really don't like that way of thinking. As can be seen in the above loop, we iterate over this result as we do over any other Java collection.

#### All JDBC API is one-based

An exception to the above rule is, obviously, all jOOQ API that is JDBC-interfacing. E.g. when you implement a [custom data type binding](#converted-data-types), you will work with JDBC API directly from within jOOQ, which is one-based.

<a id="kotlin-sql-building"></a>
### 3.27. SQL building in Kotlin

`jOOQ-kotlin` is a maven module used for leveraging some advanced Kotlin features for those users that wish to use jOOQ with Kotlin.

You can integrate it using the following dependency:

**Maven:**

```xml
<dependency>
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>
  <artifactId>jooq-kotlin</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation("org.jooq:jooq-kotlin:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation "org.jooq:jooq-kotlin:3.22.0-SNAPSHOT"
}
```

The following sections highlight a few useful extensions from that module.

Note that even without that module, you can take advantage of a lot of kotlin language features using vanilla jOOQ API, which has been designed with a strong kotlin focus, in mind. [For more details, see this blog post](https://blog.jooq.org/10-nice-examples-of-writing-sql-in-kotlin-with-jooq/).

<a id="kotlin-multiset-collectors"></a>
#### 3.27.1. Kotlin MULTISET Collectors

jOOQ's runtime API implements a few useful [`Collectors`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collector.html) that can be used to fetch data into a map, for example:

```java
public class Records {

    // [...]

    public static final <K, V, R extends Record2<K, V>> Collector<R, ?, Map<K, V>> intoMap() {
        return intoMap(Record2::value1, Record2::value2);
    }

    // [...]

}
```

These can be used with [MULTISET](#multiset-value-constructor) or [MULTISET_AGG](#multiset-agg-function) as follows:

```kotlin
val map: Field<Map<Int, String>> =
multisetAgg(LANGUAGE.ID, LANGUAGE.CD).convertFrom { r -> r.collect(Records.intoMap()) }
```

The `Collector` leverages the query's type safety, such that it works only for queries projecting exactly 2 columns. Using the kotlin extensions module, a few useful extension functions are made available as follows:

```kotlin
package org.jooq.kotlin

inline fun <reified E> Field<Result<Record1<E>>>.intoArray(): Field<Array<E>> = collecting(Records.intoArray(E::class.java))
fun <K, V, R : Record2<K, V>> Field<Result<R>>.intoGroups(): Field<Map<K, List<V>>> = collecting(Records.intoGroups())
fun <E, R : Record1<E>> Field<Result<R>>.intoList(): Field<List<E>> = collecting(Records.intoList())
fun <K, V> Field<Result<Record2<K, V>>>.intoMap(): Field<Map<K, V>> = collecting(Records.intoMap())
fun <E, R : Record1<E>> Field<Result<R>>.intoSet(): Field<Set<E>> = collecting(Records.intoSet())

// [... and more]
```

This allows for the leaner version below:

```kotlin
val map: Field<Map<Int, String>> =
multisetAgg(LANGUAGE.ID, LANGUAGE.CD).intoMap()
```

<a id="kotlin-resultquery-collectors"></a>
#### 3.27.2. Kotlin ResultQuery Collectors

jOOQ's runtime API implements a few useful [`Collectors`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collector.html) that can be used to fetch data into a map, for example:

```java
public class Records {

    // [...]

    public static final <K, V, R extends Record2<K, V>> Collector<R, ?, Map<K, V>> intoMap() {
        return intoMap(Record2::value1, Record2::value2);
    }

    // [...]

}
```

These can be used with the `collect()` method as follows:

```kotlin
val map: Map<Int, String> =
create.select(LANGUAGE.ID, LANGUAGE.CD)
      .from(LANGUAGE)
      .collect(intoMap())
```

The `Collector` leverages the query's type safety, such that it works only for queries projecting exactly 2 columns. Using the kotlin extensions module, a few useful extension functions are made available as follows:

```kotlin
package org.jooq.kotlin

inline fun <reified E> ResultQuery<Record1<E>>.fetchArray(): Array<E> = collect(Records.intoArray(E::class.java))
fun <K, V, R : Record2<K, V>> ResultQuery<R>.fetchGroups(): Map<K, List<V>> = collect(Records.intoGroups())
fun <E, R : Record1<E>> ResultQuery<R>.fetchList(): List<E> = collect(Records.intoList())
fun <K, V> ResultQuery<Record2<K, V>>.fetchMap(): Map<K, V> = collect(Records.intoMap())
fun <E, R : Record1<E>> ResultQuery<R>.fetchSet(): Set<E> = collect(Records.intoSet())
```

This allows for the leaner version below:

```kotlin
val map: Map<Int, String> =
create.select(LANGUAGE.ID, LANGUAGE.CD)
      .from(LANGUAGE)
      .fetchMap()
```

<a id="kotlin-boolean-fields"></a>
#### 3.27.3. Kotlin BOOLEAN value expressions

A [BOOLEAN column](#boolean-column) (`Field<Boolean>`) and a [conditional expression](#conditional-expressions) (`Condition`) are not really too different, especially when the dialect supports standard SQL `BOOLEAN` types.

In jOOQ, the two things can often be used exchangeably, but there are some exceptions, mainly when [BOOLEAN operators](#boolean-operators) should be used with (`Field<Boolean>`):

```kotlin
condition(BOOLEAN_COLUMN1).and(BOOLEAN_COLUMN2)
```

At least the left side of the expression has to be wrapped with [`DSL.condition(Field)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#condition(Field)), which is cumbersome.

Using the kotlin extensions module, these operators are also made available on `Field<Boolean>` directly:

```kotlin
package org.jooq.kotlin

fun Field<Boolean>.and(other: Condition): Condition = condition(this).and(other)
fun Field<Boolean>.or(other: Condition): Condition = condition(this).or(other)
fun Field<Boolean>.not(): Condition = condition(this).not()

// [... and more]
```

This allows for the leaner version below:

```kotlin
BOOLEAN_COLUMN1.and(BOOLEAN_COLUMN2)
```

<a id="kotlin-array-access"></a>
#### 3.27.4. Kotlin ARRAY access

Array elements can be accessed using the [ARRAY_GET function](#array-get-function), which translates to the `ARRAY` subscript syntax:

```sql
SELECT (ARRAY[1, 2])[1]
```

```kotlin
create.select(arrayGet(array(1, 2), 1)).fetch();
```

Using the kotlin extensions module, these operators are also made available on `Field<Array<T>>` directly:

```kotlin
package org.jooq.kotlin

operator fun <T> Field<Array<T>?>.get(index: Int) = arrayGet(this, index)
operator fun <T> Field<Array<T>?>.get(index: Field<Int>) = arrayGet(this, index)

// [... and more]
```

This allows for the leaner version below:

```kotlin
create.select(array(1, 2)[1]).fetch();
```

<a id="kotlin-json-access"></a>
#### 3.27.5. Kotlin JSON access

JSON array elements or object attributes can be accessed using the [JSON_GET_ELEMENT function](#json-element-access) or [JSON_GET_ATTRIBUTE function](#json-attribute-access) which translate to the JSON subscript syntax, or something equivalent:

```sql
SELECT
  JSON_ARRAY(1, 2)->1
  JSON_OBJECT(KEY 'a' VALUE 1)->'a'
```

```kotlin
create.select(
  jsonGetElement(jsonArray(value(1), value(2)), 1)
  jsonGetAttribute(jsonObject("a", value(1)), "a")).fetch();
```

Using the kotlin extensions module, these operators are also made available on `Field<JSON;>` and `Field<JSONB>` directly:

```kotlin
package org.jooq.kotlin

operator fun Field<JSON?>.get(index: Int) = jsonGetElement(this, index)
operator fun Field<JSON?>.get(index: Field<Int?>) = jsonGetElement(this, index)
operator fun Field<JSON?>.get(name: String) = jsonGetAttribute(this, name)
operator fun Field<JSON?>.get(name: Field<String?>) = jsonGetAttribute(this, name)

// [... and more]
```

This allows for the leaner version below:

```kotlin
create.select(
  jsonArray(value(1), value(2))[1],
  jsonObject("a", value(1))["a"]).fetch();
```

<a id="kotlin-coroutines"></a>
#### 3.27.6. Kotlin coroutine support

In kotlin, coroutines and suspending functions are a popular way to implement asynchronous, flow style logic. Starting from jOOQ 3.17, the `jooq-kotlin-coroutines` extension module allows for bridging between the [reactive streams API](#reactive-fetching) and the coroutine APIs. For this, simply add the following dependencies:

**Maven:**

```xml
<dependency>
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>
  <artifactId>jooq-kotlin</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jooq</groupId>
  <artifactId>jooq-kotlin-coroutines</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation("org.jooq:jooq-kotlin:3.22.0-SNAPSHOT")
    implementation("org.jooq:jooq-kotlin-coroutines:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation "org.jooq:jooq-kotlin:3.22.0-SNAPSHOT"
    implementation "org.jooq:jooq-kotlin-coroutines:3.22.0-SNAPSHOT"
}
```

And now, you can use jOOQ in a kotlin coroutine style:

```kotlin
suspend fun findActor(id: Long): ActorRecord? {
    return create
        .selectFrom(ACTOR)
        .where(ACTOR.ACTOR_ID.eq(id))

        // Turn any reactive streams Publisher<T> into a suspension result using the
        // kotlinx-coroutines-reactive extensions
        .awaitFirstOrNull()
}
```

And wrap your transactional code in the `org.jooq.kotlin.coroutines.transactionCoroutine()` extension function:

```kotlin
suspend fun insertActorTransaction(): ActorRecord {
    return ctx.transactionCoroutine(::insertActor)
}

suspend fun insertActor(c: Configuration): ActorRecord = c.dsl()
    .insertInto(ACTOR)
    .columns(ACTOR.ACTOR_ID, ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
    .values(201L, "A", "A")
    .returning()
    .awaitFirst()
```

> [!TIP]
> While jOOQ implements the [reactive streams API](#reactive-fetching) on top of JDBC by default (in a blocking way), we recommend you consider switching to R2DBC driver usage, if you want your coroutines to be truly non-blocking.

<a id="scala-sql-building"></a>
### 3.28. SQL building in Scala

`jOOQ-scala` is a maven module used for leveraging some advanced Scala features for those users that wish to use jOOQ with Scala.

You can integrate it using the following dependency:

**Maven:**

```xml
<dependency>
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>

  <!-- Scala 2.12 and 2.13 are also supported -->
  <artifactId>jooq-scala_3.5</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    // Scala 2.12 and 2.13 are also supported
    implementation("org.jooq:jooq-scala_3.5:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    // Scala 2.12 and 2.13 are also supported
    implementation "org.jooq:jooq-scala_3.5:3.22.0-SNAPSHOT"
}
```

#### Using Scala's implicit defs to allow for operator overloading

The most obvious Scala feature to use in jOOQ are implicit defs for implicit conversions in order to enhance the [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) type with SQL-esque operators.

The following depicts a trait which wraps all fields:

```scala
/**
 * A Scala-esque representation of {@link org.jooq.Field}, adding overloaded
 * operators for common jOOQ operations to arbitrary fields
 */
trait SAnyField[T] extends Field[T] {

    // String operations
    // -----------------

    def ||(value : String)            : Field[String]
    def ||(value : Field[_])          : Field[String]

    // Comparison predicates
    // ---------------------

    def ===(value : T)                : Condition
    def ===(value : Field[T])         : Condition

    def !==(value : T)                : Condition
    def !==(value : Field[T])         : Condition

    def <>(value : T)                 : Condition
    def <>(value : Field[T])          : Condition

    def >(value : T)                  : Condition
    def >(value : Field[T])           : Condition

    def >=(value : T)                 : Condition
    def >=(value : Field[T])          : Condition

    def <(value : T)                  : Condition
    def <(value : Field[T])           : Condition

    def <=(value : T)                 : Condition
    def <=(value : Field[T])          : Condition

    def <=>(value : T)                : Condition
    def <=>(value : Field[T])         : Condition
}
```

The following depicts a trait which wraps numeric fields:

```scala
/**
 * A Scala-esque representation of {@link org.jooq.Field}, adding overloaded
 * operators for common jOOQ operations to numeric fields
 */
trait SNumberField[T <: Number] extends SAnyField[T] {

    // Arithmetic operations
    // ---------------------

    def unary_-                       : Field[T]

    def +(value : Number)             : Field[T]
    def +(value : Field[_ <: Number]) : Field[T]

    def -(value : Number)             : Field[T]
    def -(value : Field[_ <: Number]) : Field[T]

    def *(value : Number)             : Field[T]
    def *(value : Field[_ <: Number]) : Field[T]

    def /(value : Number)             : Field[T]
    def /(value : Field[_ <: Number]) : Field[T]

    def %(value : Number)             : Field[T]
    def %(value : Field[_ <: Number]) : Field[T]

    // Bitwise operations
    // ------------------

    def unary_~                       : Field[T]

    def &(value : T)                  : Field[T]
    def &(value : Field[T])           : Field[T]

    def |(value : T)                  : Field[T]
    def |(value : Field[T])           : Field[T]

    def ^(value : T)                  : Field[T]
    def ^(value : Field[T])           : Field[T]

    def <<(value : T)                 : Field[T]
    def <<(value : Field[T])          : Field[T]

    def >>(value : T)                 : Field[T]
    def >>(value : Field[T])          : Field[T]
}
```

An example query using such overloaded operators would then look like this:

```scala
select (
  BOOK.ID * BOOK.AUTHOR_ID,
  BOOK.ID + BOOK.AUTHOR_ID * 3 + 4,
  BOOK.TITLE || " abc" || " xy")
from BOOK
leftOuterJoin (
  select (x.ID, x.YEAR_OF_BIRTH)
  from x
  limit 1
  asTable x.getName()
)
on BOOK.AUTHOR_ID === x.ID
where (BOOK.ID <> 2)
or (BOOK.TITLE in ("O Alquimista", "Brida"))
fetch
```

#### Scala 2.10 Macros

This feature is still being experimented with. With Scala Macros, it might be possible to inline a true SQL dialect into the Scala syntax, backed by the jOOQ API. Stay tuned!

<a id="checker-framework"></a>
### 3.29. Compile time validation

Java 8 introduced JSR 308 (type annotations) and with it, the [Checker Framework](https://checkerframework.org/) was born. The Checker Framework allows for implementing compiler plugins that run sophisticated checks on your Java AST to introduce rich annotation based type semantics, e.g.

```java
// This still compiles
@Positive int value1 = 1;

// This no longer compiles:
@Positive int value2 = -1;
```

jOOQ has two annotations that are very interesting for the Checker Framework to type check, namely:

- [`org.jooq.Support`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Support.html): This annotation documents jOOQ DSL API with valuable information about which database supports a given SQL clause or function, etc. For instance, only Informix and Oracle currently support [the CONNECT BY clause](#connect-by-clause).
- [`org.jooq.PlainSQL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/PlainSQL.html): This annotation documents jOOQ DSL API which operates on [plain SQL](#plain-sql). Plain SQL being string-based SQL that is injected into a jOOQ expression tree, these API elements introduce a certain SQL injection risk (just like JDBC in general), if users are not careful.

Using the optional `jooq-checker` module (available only from Maven Central), users can now type-check their code to work only with a given set of dialects, or to forbid access to plain SQL.

#### Example:

[A detailed blog post shows how this works in depth](https://blog.jooq.org/jsr-308-and-the-checker-framework-add-even-more-typesafety-to-jooq-3-9/). By adding a simple dependency to your Maven build:

**Maven:**

```xml
<dependency>
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>
  <artifactId>jooq-checker</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation("org.jooq:jooq-checker:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation "org.jooq:jooq-checker:3.22.0-SNAPSHOT"
}
```

... you can now include one of the two checkers:

#### SQLDialectChecker

The SQLDialect checker reads all of the [`org.jooq.Allow`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Allow.html) and [`org.jooq.Require`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Require.html) annotations in your source code and checks if the jOOQ API you're using is allowed and/or required in a given context, where that context can be any scope, including:

- A package
- A class
- A method

Configure this compiler plugin:

```xml
<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.3</version>
  <configuration>
    <source>1.8</source>
    <target>1.8</target>
    <fork>true</fork>
    <annotationProcessors>
      <annotationProcessor>org.jooq.checker.SQLDialectChecker</annotationProcessor>
    </annotationProcessors>
    <compilerArgs>
      <arg>-Xbootclasspath/p:1.8</arg>

      <!-- Optionally, provide a default allowed dialect -->
      <arg>-J-Dorg.jooq.checker.dialects.allow=H2</arg>

      <!-- And/or a default required dialect -->
      <arg>-J-Dorg.jooq.checker.dialects.require=H2</arg>
    </compilerArgs>
  </configuration>
</plugin>
```

... annotate your packages, e.g.

```java
// Scope: entire package (put in package-info.java)
@Allow(ORACLE)
package org.jooq.example.checker;
```

And now, you'll no longer be able to use any SQL Server specific functionality that is not available in Oracle, for instance. Perfect!

There are quite some delicate rules that play into this when you nest these annotations. [Please refer to this blog post for details.](https://blog.jooq.org/jsr-308-and-the-checker-framework-add-even-more-typesafety-to-jooq-3-9/)

#### PlainSQLChecker

This checker is much simpler. Just add the following compiler plugin to deactivate plain SQL usage by default:

```xml
<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.3</version>
  <configuration>
    <source>1.8</source>
    <target>1.8</target>
    <fork>true</fork>
    <annotationProcessors>
      <annotationProcessor>org.jooq.checker.PlainSQLChecker</annotationProcessor>
    </annotationProcessors>
    <compilerArgs>
      <arg>-Xbootclasspath/p:1.8</arg>
    </compilerArgs>
  </configuration>
</plugin>
```

From now on, you won't risk any SQL injection in your jOOQ code anymore, because your compiler will reject all such API usage. If, however, you need to place an exception on a given package / class / method, simply add the [`org.jooq.Allow.PlainSQL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Allow.PlainSQL.html) annotation, as such:

```java
// Scope: Single method.
@Allow.PlainSQL
public List<Integer> iKnowWhatImDoing() {
    return DSL.using(configuration)
              .select(level())
              .connectBy("level < ?", bindValue)
              .fetch(0, int.class);
}
```

The [Checker Framework](https://checkerframework.org/) does add some significant overhead in terms of compilation speed, and its IDE tooling is not yet at a level where such checks can be fed into IDEs for real user feedback, but the framework does work pretty well if you integrate it in your CI, nightly builds, etc.

<a id="sql-execution"></a>
## 4. SQL execution

In a previous section of the manual, we've seen how jOOQ can be used to [build SQL](#sql-building) that can be executed with any API including JDBC or ... jOOQ. This section of the manual deals with various means of actually executing SQL with jOOQ.

### SQL execution with JDBC

JDBC calls executable objects "[`java.sql.Statement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html)". It distinguishes between three types of statements:

- [`java.sql.Statement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html), or "static statement": This statement type is used for any arbitrary type of SQL statement. It is particularly useful with [inlined parameters](#inlined-parameters)
- [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html): This statement type is used for any arbitrary type of SQL statement. It is particularly useful with [indexed parameters](#indexed-parameters) (note that JDBC does not support [named parameters](#named-parameters))
- [`java.sql.CallableStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/CallableStatement.html): This statement type is used for SQL statements that are "called" rather than "executed". In particular, this includes calls to [stored procedures](#stored-procedures). Callable statements can register OUT parameters

Today, the JDBC API may look weird to users being used to object-oriented design. While statements hide a lot of SQL dialect-specific implementation details quite well, they assume a lot of knowledge about the internal state of a statement. For instance, you can use the [`PreparedStatement.addBatch()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html#addBatch()) method, to add a the prepared statement being created to an "internal list" of batch statements. Instead of returning a new type, this method forces user to reflect on the prepared statement's internal state or "mode".

### jOOQ is wrapping JDBC

These things are abstracted away by jOOQ, which exposes such concepts in a more object-oriented way. For more details about jOOQ's batch query execution, see the manual's section about [batch execution](#batch-execution).

The following sections of this manual will show how jOOQ is wrapping JDBC for SQL execution

### Alternative execution modes

Just because you can, doesn't mean you must. At the end of this chapter, we'll show how you can use jOOQ to generate SQL statements that are then executed with other APIs, such as Spring's JdbcTemplate, or Hibernate. For more information see the [section about alternative execution models](#alternative-execution-models).

<a id="comparison-with-jdbc"></a>
### 4.1. Comparison between jOOQ and JDBC

#### Similarities with JDBC

Even if there are [two general types of Query](#query-vs-resultquery), there are a lot of similarities between JDBC and jOOQ. Just to name a few:

- Both APIs return the number of affected records in non-result queries. JDBC: [`Statement.executeUpdate()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#executeUpdate(java.lang.String)), jOOQ: [`Query.execute()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html#execute())
- Both APIs return a scrollable result set type from result queries. JDBC: [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), jOOQ: [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html)

#### Differences to JDBC

Some of the most important differences between JDBC and jOOQ are listed here:

- [Query vs. ResultQuery](#query-vs-resultquery): JDBC does not formally distinguish between queries that can return results, and queries that cannot. The same API is used for both. This greatly reduces the possibility for [fetching convenience methods](#fetching)
- [Exception handling](#exception-handling): While SQL uses the checked [`java.sql.SQLException`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/SQLException.html), jOOQ wraps all exceptions in an unchecked [`org.jooq.exception.DataAccessException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataAccessException.html)
- [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html): Unlike its JDBC counter-part, this type implements [`java.util.List`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html) and is fully loaded into Java memory, freeing resources as early as possible. Just like statements, this means that users don't have to deal with a "weird" internal result set state.
- [`org.jooq.Cursor`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Cursor.html): If you want more fine-grained control over how many records are fetched into memory at once, you can still do that using jOOQ's [lazy fetching](#lazy-fetching) feature
- [Statement type](#statement-type): jOOQ does not formally distinguish between static statements and prepared statements. By default, all statements are prepared statements in jOOQ, internally. Executing a statement as a static statement can be done simply using a [custom settings flag](#custom-settings)
- [Closing Statements](#reusing-statements): JDBC keeps open resources even if they are already consumed. With JDBC, there is a lot of verbosity around safely closing resources. In jOOQ, resources are closed after consumption, by default. If you want to keep them open after consumption, you have to explicitly say so.
- [JDBC flags](#jdbc-flags): JDBC execution flags and modes are not modified. They can be set fluently on a [Query](#query-vs-resultquery)
- [Zero-based vs one-based APIs](#zero-based-vs-one-based): JDBC is a one-based API, jOOQ is a zero-based API. While this makes sense intuitively (JDBC is the less intuitive API from a Java perspective), it can lead to confusion in certain cases.

<a id="query-vs-resultquery"></a>
### 4.2. Query vs. ResultQuery

Unlike JDBC, jOOQ has a lot of knowledge about a SQL query's structure and internals (see the manual's section about [SQL building](#sql-building)). Hence, jOOQ distinguishes between these two fundamental types of queries. While every [`org.jooq.Query`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html) can be executed, only [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) can return results (see the manual's section about [fetching](#fetching) to learn more about fetching results). With plain SQL, the distinction can be made clear most easily:

```java
// Create a Query object and execute it:
Query query = create.query("DELETE FROM BOOK");
query.execute();

// Create a ResultQuery object and execute it, fetching results:
ResultQuery<Record> resultQuery = create.resultQuery("SELECT * FROM BOOK");
Result<Record> result = resultQuery.fetch();
```

<a id="fetching"></a>
### 4.3. Fetching

Fetching is something that has been completely neglected by JDBC and also by various other database abstraction libraries. Fetching is much more than just looping or listing records or mapped objects. There are so many ways you may want to fetch data from a database, it should be considered a first-class feature of any database abstraction API. Just to name a few, here are some of jOOQ's fetching modes:

- [Untyped vs. typed fetching](#record-vs-tablerecord): Sometimes you care about the returned type of your records, sometimes (with arbitrary projections) you don't.
- [Fetching arrays, maps, or lists](#arrays-maps-and-lists): Instead of letting you transform your result sets into any more suitable data type, a library should do that work for you.
- [Fetching through mapper callbacks](#recordmapper): This is an entirely different fetching paradigm. With Java 8's lambda expressions, this will become even more powerful.
- [Fetching custom POJOs](#pojos): This is what made Hibernate and JPA so strong. Automatic mapping of tables to custom POJOs.
- [Lazy vs. eager fetching](#lazy-fetching): It should be easy to distinguish these two fetch modes.
- [Fetching many results](#many-fetching): Some databases allow for returning many result sets from a single query. JDBC can handle this but it's very verbose. A list of results should be returned instead.
- [Fetching data asynchronously](#later-fetching): Some queries take too long to execute to wait for their results. You should be able to spawn query execution in a separate process.
- [Fetching data reactively](#reactive-fetching): In a reactive programming model, you will want to fetch results from a publisher into a subscription. jOOQ implements different `Publisher` APIs.

#### Convenience and how ResultQuery, Result, and Record share API

The term "fetch" is always reused in jOOQ when you can fetch data from the database. An [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) provides many overloaded means of fetching data:

#### Various modes of fetching

These modes of fetching are also documented in subsequent sections of the manual

```java
// The "standard" fetch
Result<R> fetch();

// The "standard" fetch when you know your query returns at most one record. This may return null.
R fetchOne();

// The "standard" fetch when you know your query returns exactly one record. This never returns null.
R fetchSingle();

// The "standard" fetch when you know your query returns at most one record.
Optional<R> fetchOptional();

// The "standard" fetch when you only want to fetch the first record
R fetchAny();

// Create a "lazy" Cursor, that keeps an open underlying JDBC ResultSet
Cursor<R> fetchLazy();
Cursor<R> fetchLazy(int fetchSize);
Stream<R> stream();

// Fetch several results at once
List<Result<Record>> fetchMany();

// Fetch records into a custom callback
<H extends RecordHandler<R>> H fetchInto(H handler);

// Map records using a custom callback
<E> List<E> fetch(RecordMapper<? super R, E> mapper);

// Execute a ResultQuery with jOOQ, but return a JDBC ResultSet, not a jOOQ object
ResultSet fetchResultSet();
```

#### Fetch convenience

These means of fetching are also available from [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) and [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) APIs

```java
// These methods are convenience for fetching only a single field,
// possibly converting results to another type
<T>    List<T> fetch(Field<T> field);
<T>    List<T> fetch(Field<?> field, Class<? extends T> type);
<T, U> List<U> fetch(Field<T> field, Converter<? super T, U> converter);
       List<?> fetch(int fieldIndex);
<T>    List<T> fetch(int fieldIndex, Class<? extends T> type);
<U>    List<U> fetch(int fieldIndex, Converter<?, U> converter);
       List<?> fetch(String fieldName);
<T>    List<T> fetch(String fieldName, Class<? extends T> type);
<U>    List<U> fetch(String fieldName, Converter<?, U> converter);

// These methods are convenience for fetching only a single field, possibly converting results to another type
// Instead of returning lists, these return arrays
<T>    T[]      fetchArray(Field<T> field);
<T>    T[]      fetchArray(Field<?> field, Class<? extends T> type);
<T, U> U[]      fetchArray(Field<T> field, Converter<? super T, U> converter);
       Object[] fetchArray(int fieldIndex);
<T>    T[]      fetchArray(int fieldIndex, Class<? extends T> type);
<U>    U[]      fetchArray(int fieldIndex, Converter<?, U> converter);
       Object[] fetchArray(String fieldName);
<T>    T[]      fetchArray(String fieldName, Class<? extends T> type);
<U>    U[]      fetchArray(String fieldName, Converter<?, U> converter);

// These methods are convenience for fetching only a single field from a single record,
// possibly converting results to another type
<T>    T      fetchOne(Field<T> field);
<T>    T      fetchOne(Field<?> field, Class<? extends T> type);
<T, U> U      fetchOne(Field<T> field, Converter<? super T, U> converter);
       Object fetchOne(int fieldIndex);
<T>    T      fetchOne(int fieldIndex, Class<? extends T> type);
<U>    U      fetchOne(int fieldIndex, Converter<?, U> converter);
       Object fetchOne(String fieldName);
<T>    T      fetchOne(String fieldName, Class<? extends T> type);
<U>    U      fetchOne(String fieldName, Converter<?, U> converter);
```

#### Fetch transformations

These means of fetching are also available from [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) and [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) APIs

```java
// Transform your Records into arrays, Results into matrices
       Object[][] fetchArrays();
       Object[]   fetchOneArray();

// Reduce your Result object into maps
<K>    Map<K, R>      fetchMap(Field<K> key);
<K, V> Map<K, V>      fetchMap(Field<K> key, Field<V> value);
<K, E> Map<K, E>      fetchMap(Field<K> key, Class<E> value);
       Map<Record, R> fetchMap(Field<?>[] key);
<E>    Map<Record, E> fetchMap(Field<?>[] key, Class<E> value);

// Transform your Result object into maps
       List<Map<String, Object>> fetchMaps();
       Map<String, Object>       fetchOneMap();

// Transform your Result object into groups
<K>    Map<K, Result<R>>      fetchGroups(Field<K> key);
<K, V> Map<K, List<V>>        fetchGroups(Field<K> key, Field<V> value);
<K, E> Map<K, List<E>>        fetchGroups(Field<K> key, Class<E> value);
       Map<Record, Result<R>> fetchGroups(Field<?>[] key);
<E>    Map<Record, List<E>>   fetchGroups(Field<?>[] key, Class<E> value);

// Transform your Records into custom POJOs
<E>    List<E> fetchInto(Class<? extends E> type);

// Transform your records into another table type
<Z extends Record> Result<Z> fetchInto(Table<Z> table);
```

Note, that apart from the [`fetchLazy()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html#fetchLazy()) methods, all fetch() methods will immediately close underlying JDBC result sets.

<a id="record-vs-tablerecord"></a>
#### 4.3.1. Record vs. TableRecord

jOOQ understands that SQL is much more expressive than Java, when it comes to the declarative typing of [table expressions](#table-expressions). As a declarative language, SQL allows for creating ad-hoc row value expressions (records with indexed columns, or tuples) and records (records with named columns). In Java, this is not possible to the same extent.

Yet, still, sometimes you wish to use strongly typed records, when you know that you're selecting only from a single table:

##### Fetching strongly or weakly typed records

When fetching data only from a single table, the [table expression's](#table-expressions) type is known to jOOQ if you use jOOQ's [code generator](#code-generation) to generate [TableRecords](#codegen-records) for your database tables. In order to fetch such strongly typed records, you will have to use the [simple select API](#select-statement):

```java
// Use the selectFrom() method:
BookRecord book = create.selectFrom(BOOK).where(BOOK.ID.eq(1)).fetchOne();

// Typesafe field access is now possible:
System.out.println("Title       : " + book.getTitle());
System.out.println("Published in: " + book.getPublishedIn());
```

When you use the [`DSLContext.selectFrom()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#selectFrom(org.jooq.Table)) method, jOOQ will return the record type supplied with the argument table. Beware though, that you will no longer be able to use any clause that modifies the type of your [table expression](#table-expressions). This includes:

- [The SELECT clause](#select-clause)
- [The JOIN clause](#join-clause)

##### Mapping custom row types to strongly typed records

Sometimes, you may want to explicitly select only a subset of your columns, but still use strongly typed records. Alternatively, you may want to join a one-to-one relationship and receive the two individual strongly typed records after the join.

In both of the above cases, you can map your [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) "into" a [`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html) type by using [`Record.into(Table)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#into(org.jooq.Table)).

```java
// Join two tables
Record record = create.select()
                      .from(BOOK)
                      .join(AUTHOR).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
                      .where(BOOK.ID.eq(1))
                      .fetchOne();

// "extract" the two individual strongly typed TableRecord types from the denormalised Record:
BookRecord book = record.into(BOOK);
AuthorRecord author = record.into(AUTHOR);

// Typesafe field access is now possible:
System.out.println("Title       : " + book.getTitle());
System.out.println("Published in: " + book.getPublishedIn());
System.out.println("Author      : " + author.getFirstName() + " " + author.getLastName();
```

<a id="record-n"></a>
#### 4.3.2. Record1 to Record22

jOOQ's [row value expression (or tuple)](#row-value-expressions) support has been explained earlier in this manual. It is useful for constructing row value expressions where they can be used in SQL. The same typesafety is also applied to records for degrees up to 22. To express this fact, [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) is extended by [`org.jooq.Record1`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record1.html) to [`org.jooq.Record22`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record22.html). Apart from the fact that these extensions of the R type can be used throughout the [jOOQ DSL](#dsl-api), they also provide a useful API. Here is [`org.jooq.Record2`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record2.html), for instance:

```java
public interface Record2<T1, T2> extends Record {

    // Access fields and values as row value expressions
    Row2<T1, T2> fieldsRow();
    Row2<T1, T2> valuesRow();

    // Access fields by index
    Field<T1> field1();
    Field<T2> field2();

    // Access values by index
    T1 value1();
    T2 value2();
}
```

> [!TIP]
> [Generated records](#codegen-records) can be made to implement `Record[N]` types using the `<recordsImplementingRecordN/>`. Because this may have significant effects on compilation speeds, the flag's default value has been changed to `false` in jOOQ 3.19.

##### Higher-degree records

jOOQ chose to explicitly support degrees up to 22 to match Scala 2's typesafe tuple, function and product support. Just like in Scala, 22 is an arbitrary choice of number as good as any other (though, in the case of jOOQ, reasonably high for most SQL queries). Unlike Scala 2, however, jOOQ also supports higher degrees without the additional typesafety.

<a id="arrays-maps-and-lists"></a>
#### 4.3.3. Arrays, Maps and Lists

By default, jOOQ returns an [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) object, which is essentially a [`java.util.List`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html) of [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html). Often, you will find yourself wanting to transform this result object into a type that corresponds more to your specific needs. Or you just want to list all values of one specific column. Here are some examples to illustrate those use cases:

```java
// Fetching only book titles (the two calls are equivalent):
List<String> titles1 = create.select().from(BOOK).fetch().getValues(BOOK.TITLE);
List<String> titles2 = create.select().from(BOOK).fetch(BOOK.TITLE);
String[]     titles3 = create.select().from(BOOK).fetchArray(BOOK.TITLE);

// Fetching only book IDs, converted to Long
List<Long> ids1 = create.select().from(BOOK).fetch().getValues(BOOK.ID, Long.class);
List<Long> ids2 = create.select().from(BOOK).fetch(BOOK.ID, Long.class);
Long[]     ids3 = create.select().from(BOOK).fetchArray(BOOK.ID, Long.class);

// Fetching book IDs and mapping each ID to their records or titles
Map<Integer, BookRecord> map1 = create.selectFrom(BOOK).fetch().intoMap(BOOK.ID);
Map<Integer, BookRecord> map2 = create.selectFrom(BOOK).fetchMap(BOOK.ID);
Map<Integer, String>     map3 = create.selectFrom(BOOK).fetch().intoMap(BOOK.ID, BOOK.TITLE);
Map<Integer, String>     map4 = create.selectFrom(BOOK).fetchMap(BOOK.ID, BOOK.TITLE);

// Group by AUTHOR_ID and list all books written by any author:
Map<Integer, Result<BookRecord>> group1 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID);
Map<Integer, Result<BookRecord>> group2 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID);
Map<Integer, List<String>>       group3 = create.selectFrom(BOOK).fetch().intoGroups(BOOK.AUTHOR_ID, BOOK.TITLE);
Map<Integer, List<String>>       group4 = create.selectFrom(BOOK).fetchGroups(BOOK.AUTHOR_ID, BOOK.TITLE);
```

Note that most of these convenience methods are available both through [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) and [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html), some are even available through [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) as well.

<a id="iterable-fetching"></a>
#### 4.3.4. ResultQuery as Iterable

The [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) type extends [`java.lang.Iterable`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Iterable.html), and as such, inherits the JDK's [`Iterable.forEach()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)) method, as well as it being a possible `foreach` loop source:

```java
// External iteration, fetching records eagerly
for (var r : create.select(BOOK.TITLE).from(BOOK))
    System.out.println(r.get(BOOK.TITLE));

// Internal iteration, fetching records lazily
create.select(BOOK.TITLE).from(BOOK).forEach(r -> {
    System.out.println(r.get(BOOK.TITLE));
});
```

> [!TIP]
> Note that unlike when [lazy fetching](#lazy-fetching) using the [`org.jooq.Cursor`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Cursor.html) API, the external iteration style will eager-fetch the entire intermediate [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) into memory as jOOQ has no control over the lifecycle of the [`java.util.Iterator`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Iterator.html), and the JDK doesn't know an [`java.lang.AutoCloseable`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/AutoCloseable.html) iterator.

<a id="recordmapper"></a>
#### 4.3.5. RecordMapper

In a more functional operating mode, you might want to write callbacks that map records from your select statement results in order to do some processing. This is a common data access pattern in Spring's JdbcTemplate, and it is also available in jOOQ. With jOOQ, you can implement your own [`org.jooq.RecordMapper`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RecordMapper.html) classes and plug them into jOOQ's [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html):

```java
// Write callbacks to receive records from select statements
List<Integer> ids =
create.selectFrom(BOOK)
      .orderBy(BOOK.ID)
      .fetch()
      .map(BookRecord::getId);

// Or more concisely, as fetch().map(mapper) can be written as fetch(mapper):
create.selectFrom(BOOK)
      .orderBy(BOOK.ID)
      .fetch(BookRecord::getId);

// Or using a lambda expression:
create.selectFrom(BOOK)
      .orderBy(BOOK.ID)
      .fetch(book -> book.getId());

// Of course, the lambda could be expanded into the following anonymous RecordMapper:
create.selectFrom(BOOK)
      .orderBy(BOOK.ID)
      .fetch(new RecordMapper<BookRecord, Integer>() {
          @Override
          public Integer map(BookRecord book) {
              return book.getId();
          }
      });
```

An alternative utility is offered by [`org.jooq.Records`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Records.html), which is very useful when working with [type safe Record[N] types](#record-n) and constructor references:

```java
// Use Java 16 record types as simple DTOs
record Book (int id, String title) {}

List<Book> books =
create.select(BOOK.ID, BOOK.TITLE)
      .from(BOOK)
      .orderBy(BOOK.ID)
      .fetch(Records.mapping(Book::new));
```

Your custom `RecordMapper` types can be used automatically through jOOQ's [POJO mapping APIs](#pojos), by injecting a [RecordMapperProvider](#recordmapperprovider) into your [Configuration](#dsl-context).

<a id="pojos"></a>
#### 4.3.6. POJOs

Fetching data in records is fine as long as your application is not really layered, or as long as you're still writing code in the DAO layer. But if you have a more advanced application architecture, you may not want to allow for jOOQ artefacts to leak into other layers. You may choose to write POJOs (Plain Old Java Objects) as your primary DTOs (Data Transfer Objects), without any dependencies on jOOQ's [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) types, which may even potentially hold a reference to a [Configuration](#dsl-context), and thus a JDBC [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html). Like Hibernate/JPA, jOOQ allows you to operate with POJOs. Unlike Hibernate/JPA, jOOQ does not "attach" those POJOs or create proxies with any magic in them.

If you're using jOOQ's [code generator](#code-generation), you can configure it to [generate POJOs](#codegen-pojos) for you, but you're not required to use those generated POJOs. You can use your own. See the manual's section about [POJOs with custom RecordMappers](#recordmapperprovider) to see how to modify jOOQ's standard POJO mapping behaviour.

> [!TIP]
> While POJOs don't have a connection to jOOQ API, they also don't have any notion of dirty flags and other useful record-based features. They're dumb POJOs. While some people like "clean" separation of concerns, this really isn't always necessary. It's perfectly fine to be pragmatic and mostly work with jOOQ's [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html), even in the UI layer!

##### equals() and hashCode()

[Generated POJOs](#codegen-pojos) provide entirely value-based `equals()` and `hashCode()` semantics out of the box, as jOOQ operates on data in a similar way as SQL does, where rows are "equal" when they're "[NOT DISTINCT](#select-clause-distinct)." Custom built POJOs or DTOs can have different opinions about the implementation of `equals()` and `hashCode()`, including approaches where POJOs are more similar to JPA entities (if primary key present: use that only for comparison, if absent, all instances are distinct). jOOQ doesn't impose one approach over the other.

##### Using JPA-annotated POJOs

jOOQ tries to find JPA annotations on your POJO types. If it finds any, they are used as the primary source for mapping meta-information. Only the [`jakarta.persistence.Column`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/Column) annotation is used and understood by jOOQ. An example:

```java
// A JPA-annotated POJO class
public class MyBook {
  @Column(name = "ID")
  public int myId;

  @Column(name = "TITLE")
  public String myTitle;
}

// The various "into()" methods allow for fetching records into your custom POJOs:
MyBook myBook        = create.select().from(BOOK).fetchAny().into(MyBook.class);
List<MyBook> myBooks = create.select().from(BOOK).fetch().into(MyBook.class);
List<MyBook> myBooks = create.select().from(BOOK).fetchInto(MyBook.class);
```

Just as with any other JPA implementation, you can put the [`jakarta.persistence.Column`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/Column) annotation on any class member, including attributes, setters and getters. Please refer to the [`Record.into()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#into(java.lang.Class)) Javadoc for more details.

##### Using simple POJOs

If jOOQ does not find any JPA-annotations, columns are mapped to the "best-matching" constructor, attribute or setter. An example illustrates this:

```java
// A "mutable" POJO class
public class MyBook1 {
  public int id;
  public String title;
}

// The various "into()" methods allow for fetching records into your custom POJOs:
MyBook1 myBook        = create.select().from(BOOK).fetchAny().into(MyBook1.class);
List<MyBook1> myBooks = create.select().from(BOOK).fetch().into(MyBook1.class);
List<MyBook1> myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);
```

Please refer to the [`Record.into()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#into(java.lang.Class)) Javadoc for more details.

##### Using "immutable" POJOs

If jOOQ does not find any default constructor, columns are mapped to the "best-matching" constructor. This allows for using "immutable" POJOs with jOOQ. An example illustrates this:

```java
// An "immutable" POJO class
public class MyBook2 {
  public final int id;
  public final String title;

  public MyBook2(int id, String title) {
    this.id = id;
    this.title = title;
  }
}

// With "immutable" POJO classes, there must be an exact match between projected fields and available constructors:
MyBook2 myBook        = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchAny().into(MyBook2.class);
List<MyBook2> myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook2.class);
List<MyBook2> myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook2.class);

// An "immutable" POJO class with a java.beans.ConstructorProperties annotation
public class MyBook3 {
  public final String title;
  public final int id;

  @ConstructorProperties({ "title", "id" })
  public MyBook3(String title, int id) {
    this.title = title;
    this.id = id;
  }
}

// With annotated "immutable" POJO classes, there doesn't need to be an exact match between fields and constructor arguments.
// In the below cases, only BOOK.ID is really set onto the POJO, BOOK.TITLE remains null and BOOK.AUTHOR_ID is ignored
MyBook3 myBook        = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchAny().into(MyBook3.class);
List<MyBook3> myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetch().into(MyBook3.class);
List<MyBook3> myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchInto(MyBook3.class);
```

Please refer to the [`Record.into()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#into(java.lang.Class)) Javadoc for more details.

##### Using proxyable types

jOOQ also allows for fetching data into abstract classes or interfaces, or in other words, "proxyable" types. This means that jOOQ will return a [`java.util.HashMap`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/HashMap.html) wrapped in a [`java.lang.reflect.Proxy`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/reflect/Proxy.html) implementing your custom type. An example of this is given here:

```java
// A "proxyable" type
public interface MyBook3 {
  int getId();
  void setId(int id);

  String getTitle();
  void setTitle(String title);
}

// The various "into()" methods allow for fetching records into your custom POJOs:
MyBook3 myBook        = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchAny().into(MyBook3.class);
List<MyBook3> myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook3.class);
List<MyBook3> myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);
```

Please refer to the [`Record.into()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#into(java.lang.Class)) Javadoc for more details.

##### Loading POJOs back into Records to store them

The above examples show how to fetch data into your own custom POJOs / DTOs. When you have modified the data contained in POJOs, you probably want to store those modifications back to the database. An example of this is given here:

```java
// A "mutable" POJO class
public class MyBook {
  public int id;
  public String title;
}

// Create a new POJO instance
MyBook myBook = new MyBook();
myBook.id = 10;
myBook.title = "Animal Farm";

// Load a jOOQ-generated BookRecord from your POJO
BookRecord book = create.newRecord(BOOK, myBook);

// Insert it (implicitly)
book.store();

// Insert it (explicitly)
create.executeInsert(book);

// or update it (ID = 10)
create.executeUpdate(book);
```

Note: Because of your manual setting of ID = 10, jOOQ's store() method will asume that you want to insert a new record. See the manual's section about [CRUD with UpdatableRecords](#crud-with-updatablerecords) for more details on this.

##### Interaction with DAOs

If you're using jOOQ's [code generator](#code-generation), you can configure it to [generate DAOs](#codegen-daos) for you. Those DAOs operate on [generated POJOs](#codegen-pojos). An example of using such a DAO is given here:

```java
// Initialise a Configuration
Configuration configuration = new DefaultConfiguration().set(connection).set(SQLDialect.ORACLE);

// Initialise the DAO with the Configuration
BookDao bookDao = new BookDao(configuration);

// Start using the DAO
Book book = bookDao.findById(5);

// Modify and update the POJO
book.setTitle("1984");
book.setPublishedIn(1948);
bookDao.update(book);

// Delete it again
bookDao.delete(book);
```

> [!TIP]
> While these [`org.jooq.DAO`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DAO.html) types look useful for trivial operations, they quickly become less interesting as your SQL interactions grow more complex. Just like POJOs themselves, DAOs are very dumb and simple. It's perfectly fine to work with [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) directly, or with SQL statements, instead!

##### More complex data structures

jOOQ currently doesn't support more complex data structures, the way Hibernate/JPA attempt to map relational data onto POJOs. While future developments in this direction are not excluded, jOOQ claims that generic mapping strategies lead to an enormous additional complexity that only serves very few use cases. You are likely to find a solution using any of jOOQ's various [fetching modes](#fetching), with only little boiler-plate code on the client side.

<a id="recordmapperprovider"></a>
#### 4.3.7. RecordMapperProvider

In the previous sections we have seen how to create [RecordMapper](#recordmapper) types to map jOOQ records onto arbitrary objects. We have also seen how jOOQ provides default algorithms to map jOOQ records onto [POJOs](#pojos). Your own custom domain model might be much more complex, but you want to avoid looking up the most appropriate `RecordMapper` every time you need one. For this, you can provide jOOQ's [Configuration](#dsl-context) with your own implementation of the [`org.jooq.RecordMapperProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RecordMapperProvider.html) interface. An example is given here:

```java
DSL.using(new DefaultConfiguration()
   .set(connection)
   .set(SQLDialect.ORACLE)
   .set(
       new RecordMapperProvider() {
           @Override
           public <R extends Record, E> RecordMapper<R, E> provide(RecordType<R> recordType, Class<? extends E> type) {

               // UUID mappers will always try to find the ID column
               if (type == UUID.class) {
                   return new RecordMapper<R, E>() {
                       @Override
                       public E map(R record) {
                           return (E) record.getValue("ID");
                       }
                   }
               }

               // Books might be joined with their authors, create a 1:1 mapping
               if (type == Book.class) {
                   return new BookMapper();
               }

               // Fall back to jOOQ's DefaultRecordMapper, which maps records onto
               // POJOs using reflection.
               return new DefaultRecordMapper(recordType, type);
           }
       }
   ))
   .selectFrom(BOOK)
   .orderBy(BOOK.ID)
   .fetchInto(UUID.class);
```

The above is a very simple example showing that you will have complete flexibility in how to override jOOQ's record to POJO mapping mechanisms.

<a id="ad-hoc-converter"></a>
#### 4.3.8. Ad-hoc Converter

Sometimes, you want to attach an ad-hoc converter to some column, just for a single query or a few local queries. This is possible through a variety of ways. The most convenient one is to call [`Field.convert()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#convert(org.jooq.Converter)) and related methods. Assuming you have a converter like this to convert your SQL `VARCHAR` columns to `Language`:

```java
enum Language { de, en, fr, it, pt; }
Converter<String, Language> converter = new EnumConverter<>(String.class, Language.class);
```

Now, instead of [attaching them to your generated code](#codegen-database-forced-types-converter), you may keep your generated code as `Field<String>`, and convert them on the fly to `Field<Language>` for the purpose of a single query:

```java
Result<Record2<Integer, Language>> result =
create.select(LANGUAGE.ID, LANGUAGE.CD.convert(converter))
      .from(LANGUAGE)
      .fetch();
```

Alternatively, if you don't even have a `Converter` instance ready, you can attach conversion logic to fields like this:

```java
Result<Record2<Integer, Language>> result =
create.select(LANGUAGE.ID, LANGUAGE.CD.convert(Language.class, Language::valueOf, Language::name))
      .from(LANGUAGE)
      .fetch();
```

Or, since in this case, conversions only happen from the database type (the `T` type) to the user type (the `U` type), you can omit the inverse conversion function using [`Field.convertFrom()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#convertFrom(java.lang.Class,java.util.function.Function)) ("from" as in "reading *from* the database"):

```java
Result<Record2<Integer, Language>> result =
create.select(LANGUAGE.ID, LANGUAGE.CD.convertFrom(Language.class, Language::valueOf))
      .from(LANGUAGE)
      .fetch();
```

The inverse is possible too, e.g. when you only need to convert from the user type (the `U` type) to the database type (the `T` type) using [`Field.convertTo()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html#convertTo(java.lang.Class,java.util.function.Function)) ("to" as in "writing *to* the database"):

```java
Result<Record2<Integer, Language>> result =
create.insertInto(LANGUAGE)
      .columns(LANGUAGE.ID, LANGUAGE.CD.convertTo(Language.class, Language::name))
      .values(5, Language.it)
      .execute();
```

##### Using ad hoc converters on nested collections

Ad-hoc converters are extremely powerful when used on nested collections, e.g. those constructed with the [MULTISET value constructor](#multiset-value-constructor)

```java
// Structurally typed result
Result<Record4<
    String,          // AUTHOR.FIRST_NAME
    String,          // AUTHOR.LAST_NAME
    Result<Record2<
        String,      // LANGUAGE.CD
        String       // LANGUAGE.DESCRIPTION
    >>,              // books
    Result<Record1<
        String       // BOOK_TO_BOOK_STORE.BOOK_STORE_NAME
    >>               // book_stores
>> result = create.select(
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME,
          multiset(
              selectDistinct(
                  BOOK.language().CD,
                  BOOK.language().DESCRIPTION)
              .from(BOOK)
              .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
          ).as("books"),
          multiset(
              selectDistinct(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
              .from(BOOK_TO_BOOK_STORE)
              .where(BOOK_TO_BOOK_STORE.tBook().AUTHOR_ID
                  .eq(AUTHOR.ID))
          ).as("book_stores"))
      .from(AUTHOR)
      .orderBy(AUTHOR.ID)
      .fetch();
```

For details about `MULTISET`, refer to the section about the [MULTISET value constructor](#multiset-value-constructor). Now, instead of the above structurally typed result, it may be desirable to map things into Java 16 `record` types instead, or some other form of DTO:

```java
record Book(String cd, String description) {}
record BookStore(String name) {}
record Author(String firstName, String lastName, List<Book> books, List<BookStore> bookStores) {}
```

And now, using the static-import friendly [`org.jooq.Records`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Records.html) utility:

```java
// Nominally typed result, all type checked!
List<Author> result = create.select(
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME,

          // This is now a Field<List<Book>>
          multiset(
              selectDistinct(
                  BOOK.language().CD,
                  BOOK.language().DESCRIPTION)
              .from(BOOK)
              .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
          ).as("books").convertFrom(r -> r.map(Records.mapping(Book::new))),

          // This is now a Field<List<BookStore>>
          multiset(
              selectDistinct(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
              .from(BOOK_TO_BOOK_STORE)
              .where(BOOK_TO_BOOK_STORE.tBook().AUTHOR_ID.eq(AUTHOR.ID))
          ).as("book_stores").convertFrom(r -> r.map(Records.mapping(BookStore::new))))
      .from(AUTHOR)
      .orderBy(AUTHOR.ID)
      .fetch(Records.mapping(Author::new));
```

Try adding or removing a column from the projections, or adding or removing an attribute from your records, and the query no longer type-checks!

Of course, the usual reflective [RecordMapper](#recordmapper) API can still be used just the same with these ad-hoc converters.

```java
// Nominally typed result, but not strongly type checked
List<Author> result = create.select(
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME,

          // This is now a Field<List<Book>>
          multiset(
              selectDistinct(
                  BOOK.language().CD,
                  BOOK.language().DESCRIPTION)
              .from(BOOK)
              .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
          ).as("books").convertFrom(r -> r.into(Book.class)),

          // This is now a Field<List<BookStore>>
          multiset(
              selectDistinct(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
              .from(BOOK_TO_BOOK_STORE)
              .where(BOOK_TO_BOOK_STORE.tBook().AUTHOR_ID.eq(AUTHOR.ID))
          ).as("book_stores").convertFrom(r -> r.into(BookStore.class)))
      .from(AUTHOR)
      .orderBy(AUTHOR.ID)
      .fetchInto(Author.class);
```

<a id="converter-provider"></a>
#### 4.3.9. ConverterProvider

jOOQ supports some useful default data type conversion between common JDBC data types in [`org.jooq.tools.Convert`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/Convert.html). These conversions include, for example:

```java
int i = Convert.convert("1", int.class); // Yields 1
Date d = Convert.convert("2000-01-01", Date.class); // Yields Date.valueOf("2000-01-01")
```

These auto-conversions are made available throughout the jOOQ API, for example when writing

```java
Record record = create.fetchSingle(field("current_date"));
LocalDate d1 = record.get(0, LocalDate.class);
LocalDate d2 = create.fetchSingle(field("current_date"), LocalDate.class);
```

These auto-conversions are also applied implicitly when mapping [POJOs](#pojos) as the previous sections have shown:

```java
class POJO {
    LocalDate date;
}

POJO pojo = create.fetchSingle(field("current_date").as("date")).into(POJO.class);
```

##### Overriding the DefaultConverterProvider

Sometimes, it may be desireable to override the default behaviour provided by the [`org.jooq.impl.DefaultConverterProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultConverterProvider.html) via a custom [`org.jooq.ConverterProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ConverterProvider.html). For example, assume you have an object like this:

```java
public class Name {
    public String firstName;
    public String lastName;
}

public class Book {
    public String title;
}

public class Author {
    public Name name;
    public List<Book> books;
}
```

Now, imagine projecting some [JSON functions](#json-functions) or [XML functions](#xml-functions). You would probably want them to be mapped hierarchically to your above data structure:

```java
List<Author> authors = create()
  .select(jsonObject(
     key("name").value(jsonObject(
       key("firstName").value(AUTHOR.FIRST_NAME),
       key("lastName").value(AUTHOR.LAST_NAME)
     )),
     key("books").value(jsonArrayAgg(
       jsonObject("title", BOOK.TITLE)
     ))
  ))
  .from(AUTHOR)
  .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
  .groupBy(AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
  .orderBy(AUTHOR.ID)
  .fetchInto(Author.class);
```

If jOOQ finds Jackson or Gson on your classpath, the above works out of the box. If you want to override jOOQ's out of the box binding, you can easily provide your own by implementing a [`org.jooq.ConverterProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ConverterProvider.html) as follows, e.g. using the Jackson library:

```java
class JSONConverterProvider implements ConverterProvider {
    final ConverterProvider delegate = new DefaultConverterProvider();
    final ObjectMapper mapper = new ObjectMapper();

    @Override
    public <T, U> Converter<T, U> provide(Class<T> tType, Class<U> uType) {

        // Our specialised implementation can convert from JSON (optionally, add JSONB, too)
        if (tType == JSON.class) {
            return Converter.ofNullable(tType, uType,
                t -> {
                    try {
                        return mapper.readValue(((JSON) t).data(), uType);
                    }
                    catch (Exception e) {
                        throw new DataTypeException("JSON mapping error", e);
                    }
                },
                u -> {
                    try {
                        return (T) JSON.valueOf(mapper.writeValueAsString(u));
                    }
                    catch (Exception e) {
                        throw new DataTypeException("JSON mapping error", e);
                    }
                }
            );
        }

        // Delegate all other type pairs to jOOQ's default
        else
            return delegate.provide(tType, uType);
    }
}
```

##### Configuration

The above provider can then be supplied to your [Configuration](#dsl-context) as follows, for example:

```java
configuration.set(new JSONConverterProvider());
```

Note: For best results with Jackson and kotlin, please also put the `jackson-module-kotlin` on the classpath.

<a id="lazy-fetching"></a>
#### 4.3.10. Lazy fetching

Unlike JDBC's [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), jOOQ's [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) does not represent an open database cursor with various fetch modes and scroll modes, that needs to be closed after usage. jOOQ's results are simple in-memory Java [`java.util.List`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html) objects, containing all of the result values. If your result sets are large, or if you have a lot of network latency, you may wish to fetch records one-by-one, or in small chunks. jOOQ supports a [`org.jooq.Cursor`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Cursor.html) type for that purpose. In order to obtain such a reference, use the [`ResultQuery.fetchLazy()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html#fetchLazy()) method. An example is given here:

```java
// Obtain a Cursor reference:
try (Cursor<BookRecord> cursor = create.selectFrom(BOOK).fetchLazy()) {

    // Cursor has similar methods as Iterator<R>
    while (cursor.hasNext()) {
        BookRecord book = cursor.fetchOne();

        Util.doThingsWithBook(book);
    }
}
```

As a [`org.jooq.Cursor`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Cursor.html) holds an internal reference to an open [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), it may need to be closed at the end of iteration. If a cursor is completely scrolled through, it will conveniently close the underlying ResultSet. However, you should not rely on that.

##### Fetch sizes

While using a `Cursor` prevents jOOQ from eager fetching all data into memory, your underlying JDBC driver may still do that. To configure a fetch size in your JDBC driver, use [`ResultQuery.fetchSize(int)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html#fetchSize-int-), which specifies the JDBC [`Statement.setFetchSize(int)`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#setFetchSize-int-) when executing the query. Please refer to your JDBC driver manual to learn about fetch sizes and their possible defaults and limitations.

##### Cursors ship with all the other fetch features

Like [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) or [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html), [`org.jooq.Cursor`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Cursor.html) gives access to all of the other fetch features that we've seen so far, i.e.

- [Strongly or weakly typed records](#record-vs-tablerecord): Cursors are also typed with the <R> type, allowing to fetch custom, generated [`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html) or plain [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) types.
- [RecordMapper callbacks](#recordmapper): You can use your own [`org.jooq.RecordMapper`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RecordMapper.html) callbacks to map lazily fetched records.
- [POJOs](#pojos): You can fetch data into your own custom POJO types.

<a id="lazy-fetching-with-streams"></a>
#### 4.3.11. Lazy fetching with Streams

jOOQ 3.7+ supports Java 8, and with Java 8, it supports [`java.util.stream.Stream`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Stream.html). This opens up a range of possibilities of combining the declarative aspects of SQL with the functional aspects of the new `Stream` API. Much like [the Cursors from the previous section](#lazy-fetching), such a `Stream` keeps an internal reference to a JDBC [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), which means that the `Stream` has to be treated like a resource. Here's an example of using such a stream:

```java
// Obtain a Stream reference:
try (Stream<BookRecord> stream = create.selectFrom(BOOK).stream()) {
    stream.forEach(Util::doThingsWithBook);
}
```

A more sophisticated example would be using streams to transform the results and add business logic to it. For instance, to generate a DDL script with `CREATE TABLE` statements from the `INFORMATION_SCHEMA` of an H2 database:

```java
create.select(
          COLUMNS.TABLE_NAME,
          COLUMNS.COLUMN_NAME,
          COLUMNS.TYPE_NAME)
      .from(COLUMNS)
      .orderBy(
          COLUMNS.TABLE_CATALOG,
          COLUMNS.TABLE_SCHEMA,
          COLUMNS.TABLE_NAME,
          COLUMNS.ORDINAL_POSITION)
      .fetch() // Eagerly load the whole ResultSet into memory first
      .stream()
      .collect(groupingBy(
          r -> r.getValue(COLUMNS.TABLE_NAME),
          LinkedHashMap::new,
          mapping(
              r -> new SimpleEntry(
                  r.getValue(COLUMNS.COLUMN_NAME),
                  r.getValue(COLUMNS.TYPE_NAME)
              ),
              toList()
          )))
      .forEach(
          (table, columns) -> {
              // Just emit a CREATE TABLE statement
              System.out.println("CREATE TABLE " + table + " (");

              // Map each "Column" type into a String containing the column specification,
              // and join them using comma and newline. Done!
              System.out.println(
                  columns.stream()
                         .map(col -> "  " + col.getKey() +
                                      " " + col.getValue())
                         .collect(Collectors.joining(",\n"))
              );

              System.out.println(");");
          });
```

The above combination of SQL and functional programming will produce the following output:

```sql
CREATE TABLE CATALOGS(
  CATALOG_NAME VARCHAR
);
CREATE TABLE COLLATIONS(
  NAME VARCHAR,
  KEY VARCHAR
);
CREATE TABLE COLUMNS(
  TABLE_CATALOG VARCHAR,
  TABLE_SCHEMA VARCHAR,
  TABLE_NAME VARCHAR,
  COLUMN_NAME VARCHAR,
  ORDINAL_POSITION INTEGER,
  COLUMN_DEFAULT VARCHAR,
  IS_NULLABLE VARCHAR,
  DATA_TYPE INTEGER,
  CHARACTER_MAXIMUM_LENGTH INTEGER,
  CHARACTER_OCTET_LENGTH INTEGER,
  NUMERIC_PRECISION INTEGER,
  NUMERIC_PRECISION_RADIX INTEGER,
  NUMERIC_SCALE INTEGER,
  CHARACTER_SET_NAME VARCHAR,
  COLLATION_NAME VARCHAR,
  TYPE_NAME VARCHAR,
  NULLABLE INTEGER,
  IS_COMPUTED BOOLEAN,
  SELECTIVITY INTEGER,
  CHECK_CONSTRAINT VARCHAR,
  SEQUENCE_NAME VARCHAR,
  REMARKS VARCHAR,
  SOURCE_DATA_TYPE SMALLINT
);
```

<a id="many-fetching"></a>
#### 4.3.12. Many fetching

Many databases support returning several result sets, or cursors, from single queries. An example for this is Sybase ASE's sp_help command:

```text
> sp_help 'author'

+--------+-----+-----------+-------------+-------------------+
|Name    |Owner|Object_type|Object_status|Create_date        |
+--------+-----+-----------+-------------+-------------------+
|  author|dbo  |user table | -- none --  |Sep 22 2011 11:20PM|
+--------+-----+-----------+-------------+-------------------+

+-------------+-------+------+----+-----+-----+
|Column_name  |Type   |Length|Prec|Scale|...  |
+-------------+-------+------+----+-----+-----+
|id           |int    |     4|NULL| NULL|    0|
|first_name   |varchar|    50|NULL| NULL|    1|
|last_name    |varchar|    50|NULL| NULL|    0|
|date_of_birth|date   |     4|NULL| NULL|    1|
|year_of_birth|int    |     4|NULL| NULL|    1|
+-------------+-------+------+----+-----+-----+
```

The correct (and verbose) way to do this with JDBC is as follows:

```java
ResultSet rs = statement.executeQuery();

// Repeat until there are no more result sets
for (;;) {

  // Empty the current result set
  while (rs.next()) {
    // [ .. do something with it .. ]
  }

  // Get the next result set, if available
  if (statement.getMoreResults()) {
    rs = statement.getResultSet();
  }
  else {
    break;
  }
}

// Be sure that all result sets are closed
statement.getMoreResults(Statement.CLOSE_ALL_RESULTS);
statement.close();
```

As previously discussed in the chapter about [differences between jOOQ and JDBC](#comparison-with-jdbc), jOOQ does not rely on an internal state of any JDBC object, which is "externalised" by Javadoc. Instead, it has a straight-forward API allowing you to do the above in a one-liner:

```java
// Get some information about the author table, its columns, keys, indexes, etc
Results results = create.fetchMany("sp_help 'author'");
```

The returned [`org.jooq.Results`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Results.html) type extends the `List<Result<Record>>` type for backwards-compatibility reasons, but it also allows to access individual update counts that may have been returned by the database in between result sets.

<a id="later-fetching"></a>
#### 4.3.13. Later fetching

##### Using Java 8 CompletableFutures

Java 8 has introduced the new [`java.util.concurrent.CompletableFuture`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/CompletableFuture.html) type, which allows for functional composition of asynchronous execution units. When applying this to SQL and jOOQ, you might be writing code as follows:

```java
// Initiate an asynchronous call chain
CompletableFuture

    // This lambda will supply an int value indicating the number of inserted rows
    .supplyAsync(() ->
        DSL.using(configuration)
           .insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
           .values(3, "Hitchcock")
           .execute()
    )

    // This will supply an AuthorRecord value for the newly inserted author
    .handleAsync((rows, throwable) ->
        DSL.using(configuration)
           .fetchOne(AUTHOR, AUTHOR.ID.eq(3))
    )

    // This should supply an int value indicating the number of rows,
    // but in fact it'll throw a constraint violation exception
    .handleAsync((record, throwable) -> {
        record.changed(true);
        return record.insert();
    })

    // This will supply an int value indicating the number of deleted rows
    .handleAsync((rows, throwable) ->
        DSL.using(configuration)
           .delete(AUTHOR)
           .where(AUTHOR.ID.eq(3))
           .execute()
    )
    .join();
```

The above example will execute four actions one after the other, but asynchronously in the JDK's default or common [`java.util.concurrent.ForkJoinPool`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ForkJoinPool.html).

For more information, please refer to the [`java.util.concurrent.CompletableFuture`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/CompletableFuture.html) Javadoc and official documentation.

##### Using deprecated API

Some queries take very long to execute, yet they are not crucial for the continuation of the main program. For instance, you could be generating a complicated report in a Swing application, and while this report is being calculated in your database, you want to display a background progress bar, allowing the user to pursue some other work. This can be achived simply with jOOQ, by creating a [`org.jooq.FutureResult`](https://www.jooq.org/javadoc/3.22.x/org/jooq/FutureResult.html), a type that extends [`java.util.concurrent.Future`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Future.html). An example is given here:

```java
// Spawn off this query in a separate process:
FutureResult<BookRecord> future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater();

// This example actively waits for the result to be done
while (!future.isDone()) {
    progressBar.increment(1);
    Thread.sleep(50);
}

// The result should be ready, now
Result<BookRecord> result = future.get();
```

Note, that instead of letting jOOQ spawn a new thread, you can also provide jOOQ with your own [`java.util.concurrent.ExecutorService`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ExecutorService.html):

```java
// Spawn off this query in a separate process:
ExecutorService service = // [...]
FutureResult<BookRecord> future = create.selectFrom(BOOK).where(... complex predicates ...).fetchLater(service);
```

<a id="reactive-fetching"></a>
#### 4.3.14. Reactive Fetching

In a reactive programming model, a query will not be executed eagerly and blocking the current thread. Instead a query implements a `Publisher` API, such as JDK 9's [`java.util.concurrent.Flow.Publisher`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Flow.Publisher.html) or the [Reactive Streams](https://www.reactive-streams.org) `Publisher` API.

When using a third party reactive stream API like [project reactor](https://projectreactor.io), jOOQ queries can easily be embedded in a `Flux` or `Mono` type, such as:

```java
List<String> authors =
Flux.from(create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
                .from(AUTHOR))
                .map(r -> r.get(AUTHOR.FIRST_NAME) + " " + r.get(AUTHOR.LAST_NAME))
                .collectList()
                .block();
```

Out of the box, all jOOQ provided publishers will block on the underlying JDBC connection, but if you provide jOOQ with a [`io.r2dbc.spi.Connection`](https://r2dbc.io/spec/0.9.0.M2/api/io/r2dbc.spi/Connection.html) or [`io.r2dbc.spi.ConnectionFactory`](https://r2dbc.io/spec/0.9.0.M2/api/io/r2dbc.spi/ConnectionFactory.html), then the publishers will execute queries in a non-blocking fashion on an [R2DBC](https://r2dbc.io) driver.

<a id="resultset-fetching"></a>
#### 4.3.15. ResultSet fetching

When interacting with legacy applications, you may prefer to have jOOQ return a [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), rather than jOOQ's own [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) types. This can be done simply, in two ways:

```java
try (

    // jOOQ's Cursor type exposes the underlying ResultSet:
    ResultSet rs1 = create.selectFrom(BOOK).fetchLazy().resultSet();

    // But you can also directly access that ResultSet from ResultQuery:
    ResultSet rs2 = create.selectFrom(BOOK).fetchResultSet()) {

// ...
}
```

##### Transform jOOQ's Result into a JDBC ResultSet

Instead of operating on a JDBC ResultSet holding an open resource from your database, you can also let jOOQ's [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) wrap itself in a [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html). The advantage of this is that the so-created ResultSet has no open connection to the database. It is a completely in-memory ResultSet:

```java
// Transform a jOOQ Result into a ResultSet
Result<BookRecord> result = create.selectFrom(BOOK).fetch();
ResultSet rs = result.intoResultSet();
```

##### The inverse: Fetch data from a legacy ResultSet using jOOQ

The inverse of the above is possible too. Maybe, a legacy part of your application produces JDBC [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), and you want to turn them into a [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html):

```java
// Transform a JDBC ResultSet into a jOOQ Result
ResultSet rs = connection.createStatement().executeQuery("SELECT * FROM BOOK");

// As a Result:
Result<Record> result = create.fetch(rs);

// As a Cursor
Cursor<Record> cursor = create.fetchLazy(rs);
```

You can also tighten the interaction with jOOQ's data type system and [data type conversion](#data-type-conversion) features, by passing the record type to the above fetch methods:

```java
// Pass an array of types:
Result<Record> result = create.fetch    (rs, Integer.class, String.class);
Cursor<Record> result = create.fetchLazy(rs, Integer.class, String.class);

// Pass an array of data types:
Result<Record> result = create.fetch    (rs, INTEGER, VARCHAR);
Cursor<Record> result = create.fetchLazy(rs, INTEGER, VARCHAR);

// Pass an array of fields:
Result<Record> result = create.fetch    (rs, BOOK.ID, BOOK.TITLE);
Cursor<Record> result = create.fetchLazy(rs, BOOK.ID, BOOK.TITLE);
```

If supplied, the additional information is used to override the information obtained from the [`ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html)'s [`java.sql.ResultSetMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSetMetaData.html) information.

<a id="auto-type-conversion"></a>
#### 4.3.16. Auto data type conversion

Many native SQL data types can be automatically converted from one another, such as `VARCHAR` to `INTEGER` and vice versa.

The jOOQ API also supports a variety of such auto conversions through the [`org.jooq.tools.Convert`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/Convert.html) utility API, which implements the following rules:

- `null` is always converted to `null`, or the primitive default value, or `Optional.empty()`, regardless of the target type.
- Identity conversion (converting a value to its own type) is always possible.
- Primitive types can be converted to their wrapper types and vice versa
- All types can be converted to String
- All types can be converted to Object
- All Number types can be converted to other Number types
- All `Number` or `String` types can be converte to `Boolean`. Possible (case-insensitive) values for `true`:
  - `1`
  - `1.0`
  - `y`
  - `yes`
  - `true`
  - `on`
  - `enabled`

  Possible (case-insensitive) values for `false`:
  - `0`
  - `0.0`
  - `n`
  - `no`
  - `false`
  - `off`
  - `disabled`

  All other values evaluate to `null`

- All [`java.util.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Date.html) subtypes ([`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html), [`java.sql.Time`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Time.html), [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html)), as well as most [`java.time.temporal.Temporal`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/temporal/Temporal.html) subtypes ([`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html), [`java.time.LocalTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalTime.html), [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html), [`java.time.OffsetTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetTime.html), [`java.time.OffsetDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetDateTime.html), as well as [`java.time.Instant`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/Instant.html)) can be converted into each other.
- `byte[]` can be converted into `String`, using the platform's default charset
- `Object[]` can be converted into any other array type, if array elements can be converted, too

This auto conversion can be applied explicitly, but is also available through a variety of API, in particular anywhere a [`java.lang.Class`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Class.html) reference can be provided, such as:

```java
Record record = ...
int i = record.get(0, int.class);
String s = record.get(1, String.class);
```

<a id="data-type-conversion"></a>
#### 4.3.17. Custom data type conversion

jOOQ supports a variety of [built-in data types](#built-in-data-types) as well as [user-defined types](#codegen-udts). If you prefer your own domain types(see also SQL domain types) to be used with your [table columns](#table-columns) or other [column expressions](#column-expressions), you can use jOOQ's [`org.jooq.Converter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html) API.

A `Converter` allows for two-way conversion between two Java data types `T` and `U`. By convention, the `T` type corresponds to the built-in type in your database whereas the `U` type corresponds to your own user type. The `Converter` API is summarised here:

```java
public interface Converter<T, U> extends Serializable {

    /**
     * Convert a database object to a user object
     */
    U from(T databaseObject);

    /**
     * Convert a user object to a database object
     */
    T to(U userObject);

    /**
     * The database type
     */
    Class<T> fromType();

    /**
     * The user type
     */
    Class<U> toType();
}
```

Such a `Converter` can be used in many parts of the jOOQ API. While they're most powerful when attached to [generated code](#codegen-database-forced-types-converter), you can also attach them to arbitrary expressions as follows:

```java
record IntegerWrapper(Integer wrapped) {}
DataType<Integer> t = SQLDataType.INTEGER;

// This DataType can now be used everywhere in jOOQ. It will remember how to
// convert between Integer and the user type IntegerWrapper
DataType<IntegerWrapper> u = t.asConvertedDataType(Converter.of(
    Integer.class,
    IntegerWrapper.class,
    IntegerWrapper::new,
    IntegerWrapper::wrapped
));

// For example, you can attach it to a plain SQL template:
Field<IntegerWrapper> f1 = field("ID", u);

// Or you can coerce any expression to your type:
Field<IntegerWrapper> f2 = BOOK.ID.coerce(u);
```

<a id="data-type-lookups"></a>
#### 4.3.18. Data type lookups

In a lot of cases, it's unnecessary to provide an explicit [built-in data type](#built-in-data-types) or [user-defined data type](#data-type-conversion) with a [column expression](#column-expressions) in general, or a [bind value](#bind-values) in particular. For example, assuming a user-defined data type was attached to generated code using a [forced type](#codegen-database-forced-types), or to a [plain SQL template](#plain-sql-templating-language) using an explicit [converted data type](#data-type-conversion), the following expressions can infer the user-defined data type from context:

```java
// Comparison predicates with TableField/bind value pairs:
TABLE.COLUMN.eq(new MyType(1));

// Comparison predicates with TableField/bind value pairs in row value expressions in various forms:
row(TABLE.COLUMN1, TABLE.COLUMN2).eq(new MyType(1), new MyOtherType(2));
row(TABLE.COLUMN1, TABLE.COLUMN2).eq(row(new MyType(1), new MyOtherType(2)));
```

More complex expressions may be able to do the same thing, depending on your jOOQ version.

In some cases, however, the `DataType` cannot be looked up from query context. This includes, for example, [plain SQL templates](#plain-sql-templating-language):

```java
// Plain SQL with bind values:
DSL.condition("column = ?", new MyType(1));

// Plain SQL with expressions:
DSL.condition("column = {0}", DSL.val(new MyType(1)));

// With Class<?> literals:
DSL.field("column", MyType.class);
```

jOOQ historically can still look up the *first* statically registered `Converter` or `Binding` for such a user-defined data type, which is why historically, these expressions may still work. Starting from jOOQ 3.19, this usage is discouraged, and a warning will be logged.

```text
org.jooq.impl.DefaultDataType$DiscouragedStaticTypeRegistryUsage: null
    at org.jooq.impl.DefaultDataType.check(DefaultDataType.java)
    at org.jooq.impl.Val.accept(Val.java)
    at org.jooq.impl.AbstractBindContext.bindInternal(AbstractBindContext.java)
    at org.jooq.impl.AbstractBindContext.visit0(AbstractBindContext.java)
    at org.jooq.impl.AbstractContext.visit(AbstractContext.java)
    at ...
```

When this warning is encountered, users are encouraged to avoid the practice of relying on this lookup for the following reasons:

- There may be race conditions between usages of the user-defined data type and registrations of the `Converter` / `Binding` in the static type registry
- There may be multiple `Converter` or `Binding` for the same user-defined type `Class<U>` (as well as race conditions between their registrations!)
- A future version of jOOQ may unsupport this static type registry for user-defined types in favour of a dynamic type registry.

If you encounter this warning and think it shouldn't appear in your query (jOOQ should be able to infer the `DataType` from context), or if you struggle to address the issue, please report an issue here: [https://jooq.org/bug](https://jooq.org/bug).

<a id="context-converter"></a>
#### 4.3.19. Context Converter

The previous section discussed the generic [data type conversion](#data-type-conversion) API represented by the [`org.jooq.Converter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html) type. Unlike [`org.jooq.Binding`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Binding.html), a `Converter` does not get access to a [`org.jooq.Configuration`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Configuration.html) in any way, and as such, makes dependency injection of third party logic into converters difficult. A common use-case is to implement a Jackson based converter for JSON processing, and to configure that Jackson `ObjectMapper` somewhere. With `Converter`, the only ways to do this include:

- Creating a `static` global variable somewhere and accessing that.
- Resorting to [`java.lang.ThreadLocal`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/ThreadLocal.html) usage, before executing a query.

Both of these options are certainly viable, but don't feel right. This is why a new [`org.jooq.ContextConverter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ContextConverter.html) has been introduced, a subtype of the [`org.jooq.Converter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html), exposing additional methods:

```java
// A ContextConverter can be used wherever a Converter can be used
public interface ContextConverter<T, U> extends Converter<T, U> {

    // Additional, specialised from(T):U and to(U):T methods receive a ConverterContext type,
    // which gives access to your Configuration from within the ContextConverter
    U from(T databaseObject, ConverterContext ctx);
    T to(U userObject, ConverterContext ctx);

    // The usual Converter methods don't have to be implemented and won't be called by
    // jOOQ internals, if you're implementing ContextConverter. The default implementation
    // uses an unspecified, internal ConverterContext
    @Override
    default T to(U userObject) {
        return to(userObject, converterContext());
    }

    @Override
    default U from(T databaseObject) {
        return from(databaseObject, converterContext());
    }
}
```

If you provide jOOQ with an [`org.jooq.ContextConverter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ContextConverter.html), then jOOQ will guarantee that the more specialised `from()` and `to()` methods are called, which are receiving a [`org.jooq.converterContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/converterContext.html), which provides access to the ubiquitous [`org.jooq.Configuration`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Configuration.html). In order to provide your `ContextConverter` with custom configuration, just use [`Configuration::data`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Configuration.html#data()):

```java
// Configuring your Configuration, e.g. with Spring:
Configuration configuration = new DefaultConfiguration();
configuration.data("my-configuration-key", myConfigurationValue);

// And then:
public class MyContextConverter implements ContextConverter<Integer, String> {
    @Override
    public String from(Integer databaseObject, ConverterContext ctx) {
        if (ctx.configuration().data("my-configuration-key") != null)
            return "configuration enabled";
        else
            return "configuration disabled";
    }
}
```

<a id="statement-type"></a>
### 4.4. Static statements vs. Prepared Statements

With JDBC, you have full control over your SQL statements. You can decide yourself, if you want to execute a static [`java.sql.Statement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html) without bind values, or a [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html) with (or without) bind values. But you have to decide early, which way to go. And you'll have to prevent SQL injection and syntax errors manually, when inlining your bind variables.

With jOOQ, this is easier. As a matter of fact, it is plain simple. With jOOQ, you can just set a flag in your [Configuration's](#dsl-context) [Settings](#custom-settings), and all queries produced by that configuration will be executed as static statements, with all bind values inlined. An example is given here:

```sql
-- These statements are rendered by the two factories:
SELECT ? FROM DUAL WHERE ? = ?
SELECT 1 FROM DUAL WHERE 1 = 1
```

```java
// This DSLContext executes PreparedStatements
DSLContext prepare = DSL.using(connection, SQLDialect.ORACLE);

// This DSLContext executes static Statements
DSLContext inlined = DSL.using(connection, SQLDialect.ORACLE,
  new Settings().withStatementType(StatementType.STATIC_STATEMENT));

prepare.select(val(1)).where(val(1).eq(1)).fetch();
inlined.select(val(1)).where(val(1).eq(1)).fetch();
```

#### Reasons for choosing one or the other

Not all databases are equal. Some databases show improved performance if you use [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html), as the database will then be able to re-use execution plans for identical SQL statements, regardless of actual bind values. This heavily improves the time it takes for soft-parsing a SQL statement. In other situations, assuming that bind values are irrelevant for SQL execution plans may be a bad idea, as you might run into "bind value peeking" issues. You may be better off spending the extra cost for a new hard-parse of your SQL statement and instead having the database fine-tune the new plan to the concrete bind values.

Whichever aproach is more optimal for you cannot be decided by jOOQ. In most cases, prepared statements are probably better. But you always have the option of forcing jOOQ to render inlined bind values.

#### Inlining bind values on a per-bind-value basis

Note that you don't have to inline all your bind values at once. If you know that a bind value is not really a variable and should be inlined explicitly, you can do so by using [`DSL.inline()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#inline(Object)), as documented in the manual's section about [inlined parameters](#inlined-parameters)

<a id="reusing-statements"></a>
### 4.5. Reusing a Query's PreparedStatement

As previously discussed in the chapter about [differences between jOOQ and JDBC](#comparison-with-jdbc), reusing PreparedStatements is handled a bit differently in jOOQ from how it is handled in JDBC

#### Keeping open PreparedStatements with JDBC

With JDBC, you can easily reuse a [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html) by not closing it between subsequent executions. An example is given here:

```java
// Execute the statement
try (PreparedStatement stmt = connection.prepareStatement("SELECT 1 FROM DUAL")) {

    // Fetch a first ResultSet
    try (ResultSet rs1 = stmt.executeQuery()) { ... }

    // Without closing the statement, execute it again to fetch another ResultSet
    try (ResultSet rs2 = stmt.executeQuery()) { ... }
}
```

The above technique can be quite useful when you want to reuse expensive database resources. This can be the case when your statement is executed very frequently and your database would take non-negligible time to soft-parse the prepared statement and generate a new statement / cursor resource.

#### Keeping open PreparedStatements with jOOQ

This is also modeled in jOOQ. However, the difference to JDBC is that closing a statement is the default action, whereas keeping it open has to be configured explicitly. This is better than JDBC, because the default action should be the one that is used most often. Keeping open statements is rarely done in average applications. Here's an example of how to keep open PreparedStatements with jOOQ:

```java
// Create a query which is configured to keep its underlying PreparedStatement open
try (ResultQuery<Record> query = create.selectOne().keepStatement(true)) {
    Result<Record> result1 = query.fetch(); // This will lazily create a new PreparedStatement
    Result<Record> result2 = query.fetch(); // This will reuse the previous PreparedStatement
}
```

The above example shows how a query can be executed twice against the same underlying [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html). Notice how the `Query` must now be treated like a resource, i.e. it must be managed in a try-with-resources statement, or [`Query.close()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Query.html#close()) must be called explicitly.

<a id="jdbc-flags"></a>
### 4.6. JDBC flags

JDBC knows a couple of execution flags and modes, which can be set through the jOOQ API as well. jOOQ essentially supports these flags and execution modes:

```java
public interface Query extends QueryPart, Attachable {

    // [...]

    // The query execution timeout.
    // -----------------------------------------------------------
    Query queryTimeout(int timeout);

}
```

```java
public interface ResultQuery<R extends Record> extends Query {

    // [...]

    // The query execution timeout.
    // -----------------------------------------------------------
    @Override
    ResultQuery<R> queryTimeout(int timeout);

    // Flags allowing to specify the resulting ResultSet modes
    // -----------------------------------------------------------
    ResultQuery<R> resultSetConcurrency(int resultSetConcurrency);
    ResultQuery<R> resultSetType(int resultSetType);
    ResultQuery<R> resultSetHoldability(int resultSetHoldability);

    // The buffer size for JDBC cursors
    // -----------------------------------------------------------
    ResultQuery<R> fetchSize(int size);

    // The maximum number of rows to be fetched by JDBC
    // -----------------------------------------------------------
    ResultQuery<R> maxRows(int rows);

}
```

#### Using ResultSet concurrency with ExecuteListeners

An example of why you might want to manually set a ResultSet's concurrency flag to something non-default is given here:

```java
DSL.using(new DefaultConfiguration()
   .set(connection)
   .set(SQLDialect.ORACLE)
   .set(ExecuteListener.onRecordStart(ctx -> {
        try {

            // Change values in the cursor before reading a record
            ctx.resultSet().updateString(BOOK.TITLE.getName(), "New Title");
            ctx.resultSet().updateRow();
        }
        catch (SQLException e) {
            throw new DataAccessException("Exception", e);
        }
   )))
   .select(BOOK.ID, BOOK.TITLE)
   .from(BOOK)
   .orderBy(BOOK.ID)
   .resultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE)
   .resultSetConcurrency(ResultSet.CONCUR_UPDATABLE)
   .fetch(BOOK.TITLE);
```

In the above example, your custom [ExecuteListener callback](#execute-listeners) is triggered before jOOQ loads a new `Record` from the [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html). With the concurrency being set to `ResultSet.CONCUR_UPDATABLE`, you can now modify the database cursor through the standard [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html) API.

<a id="batch-execution"></a>
### 4.7. Using JDBC batch operations

With JDBC, you can easily execute several statements at once using the addBatch() method. Essentially, there are two modes in JDBC

- Execute several queries without bind values
- Execute one query several times with bind values

#### Using JDBC

In code, this looks like the following snippet:

```java
// 1. several queries
// ------------------
try (Statement stmt = connection.createStatement()) {
    stmt.addBatch("INSERT INTO author(id, first_name, last_name) VALUES (1, 'Erich', 'Gamma')");
    stmt.addBatch("INSERT INTO author(id, first_name, last_name) VALUES (2, 'Richard', 'Helm')");
    stmt.addBatch("INSERT INTO author(id, first_name, last_name) VALUES (3, 'Ralph', 'Johnson')");
    stmt.addBatch("INSERT INTO author(id, first_name, last_name) VALUES (4, 'John', 'Vlissides')");
    int[] result = stmt.executeBatch();
}

// 2. a single query
// -----------------
try (PreparedStatement stmt = connection.prepareStatement("INSERT INTO author(id, first_name, last_name) VALUES (?, ?, ?)")) {
    stmt.setInt(1, 1);
    stmt.setString(2, "Erich");
    stmt.setString(3, "Gamma");
    stmt.addBatch();

    stmt.setInt(1, 2);
    stmt.setString(2, "Richard");
    stmt.setString(3, "Helm");
    stmt.addBatch();

    stmt.setInt(1, 3);
    stmt.setString(2, "Ralph");
    stmt.setString(3, "Johnson");
    stmt.addBatch();

    stmt.setInt(1, 4);
    stmt.setString(2, "John");
    stmt.setString(3, "Vlissides");
    stmt.addBatch();

    int[] result = stmt.executeBatch();
}
```

#### Using jOOQ

jOOQ supports executing queries in batch mode as follows:

```java
// 1. several queries
// ------------------
create.batch(
	create.insertInto(AUTHOR, ID, FIRST_NAME, LAST_NAME).values(1, "Erich"  , "Gamma"    ),
	create.insertInto(AUTHOR, ID, FIRST_NAME, LAST_NAME).values(2, "Richard", "Helm"     ),
	create.insertInto(AUTHOR, ID, FIRST_NAME, LAST_NAME).values(3, "Ralph"  , "Johnson"  ),
	create.insertInto(AUTHOR, ID, FIRST_NAME, LAST_NAME).values(4, "John"   , "Vlissides"))
.execute();

// 2. a single query
// -----------------
create.batch(create.insertInto(AUTHOR, ID, FIRST_NAME, LAST_NAME  ).values((Integer) null, null, null))
      .bind(                           1 , "Erich"   , "Gamma"    )
      .bind(                           2 , "Richard" , "Helm"     )
      .bind(                           3 , "Ralph"   , "Johnson"  )
      .bind(                           4 , "John"    , "Vlissides")
      .execute();
```

When creating a batch execution with a single query and multiple bind values, you will still have to provide jOOQ with dummy bind values for the original query. In the above example, these are set to `null`. For subsequent calls to `bind()`, there will be no type safety provided by jOOQ.

<a id="sequence-execution"></a>
### 4.8. Sequence execution

Most databases support sequences of some sort, to provide you with unique values to be used for primary keys and other enumerations. If you're using jOOQ's [code generator](#code-generation), it will generate a sequence object per sequence for you. There are two ways of using such a sequence object:

#### Standalone calls to sequences

Instead of actually phrasing a select statement, you can also use the [DSLContext's](#dsl-context) convenience methods:

```java
// Fetch the next value from a sequence
BigInteger nextID = create.nextval(S_AUTHOR_ID);

// Fetch the current value from a sequence
BigInteger currID = create.currval(S_AUTHOR_ID);
```

#### Inlining sequence references in SQL

You can inline sequence references in jOOQ SQL statements. The following are examples of how to do that:

```java
// Reference the sequence in a SELECT statement:
Field<BigInteger> s = S_AUTHOR_ID.nextval();
BigInteger nextID = create.select(s).fetchOne(s);

// Reference the sequence in an INSERT statement:
create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .values(S_AUTHOR_ID.nextval(), val("William"), val("Shakespeare"))
      .execute();
```

For more info about inlining sequence references in SQL statements, please refer to the manual's section about [sequences and serials](#sequences-and-serials).

<a id="stored-procedures"></a>
### 4.9. Stored procedures and functions

Many RDBMS support the concept of "routines", usually calling them procedures and/or functions. These concepts have been around in programming languages for a while, also outside of databases. Famous languages distinguishing procedures from functions are:

- Ada
- BASIC
- Pascal
- etc...

The general distinction between (stored) procedures and (stored) functions can be summarised like this:

#### Procedures

- Are called using JDBC CallableStatement
- Have no return value
- Usually support OUT parameters

#### Functions

- Can be used in SQL statements
- Have a return value
- Usually don't support OUT parameters

#### Exceptions to these rules

- DB2, H2, and HSQLDB don't allow for JDBC escape syntax when calling functions. Functions must be used in a SELECT statement
- H2 only knows functions (without OUT parameters)
- Oracle functions may have OUT parameters
- Oracle knows functions that must not be used in SQL statements for transactional reasons
- Postgres only knows functions (with all features combined). OUT parameters can also be interpreted as return values, which is quite elegant/surprising, depending on your taste
- The Sybase jconn3 JDBC driver doesn't handle null values correctly when using the JDBC escape syntax on functions

In general, it can be said that the field of routines (procedures / functions) is far from being standardised in modern RDBMS even if the SQL:2008 standard specifies things quite well. Every database has its ways and JDBC only provides little abstraction over the great variety of procedures / functions implementations, especially when advanced data types such as cursors / UDT's / arrays are involved.

To simplify things a little bit, jOOQ handles both procedures and functions the same way, using a more general [`org.jooq.Routine`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Routine.html) type.

#### Using jOOQ for standalone calls to stored procedures and functions

If you're using jOOQ's [code generator](#code-generation), it will generate [`org.jooq.Routine`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Routine.html) objects for you. Let's consider the following example:

```sql
-- Check whether there is an author in AUTHOR by that name and get his ID
CREATE OR REPLACE PROCEDURE author_exists (author_name VARCHAR2, result OUT NUMBER, id OUT NUMBER);
```

The generated artefacts can then be used as follows:

```java
// Make an explicit call to the generated procedure object:
AuthorExists procedure = new AuthorExists();

// All IN and IN OUT parameters generate setters
procedure.setAuthorName("Paulo");
procedure.execute(configuration);

// All OUT and IN OUT parameters generate getters
assertEquals(new BigDecimal("1"), procedure.getResult());
assertEquals(new BigDecimal("2"), procedure.getId();
```

But you can also call the procedure using a generated convenience method in a global Routines class:

```java
// The generated Routines class contains static methods for every procedure.
// Results are also returned in a generated object, holding getters for every OUT or IN OUT parameter.
AuthorExists procedure = Routines.authorExists(configuration, "Paulo");

// All OUT and IN OUT parameters generate getters
assertEquals(new BigDecimal("1"), procedure.getResult());
assertEquals(new BigDecimal("2"), procedure.getId();
```

For more details about [code generation](#code-generation) for procedures, see the manual's section about [procedures and code generation](#codegen-procedures).

#### Inlining stored function references in SQL

Unlike procedures, functions can be inlined in SQL statements to generate [column expressions](#column-expressions) or [table expressions](#table-expressions), if you're using [unnesting operators](#array-and-cursor-unnesting). Assume you have a function like this:

```sql
-- Check whether there is an author in AUTHOR by that name and get his ID
CREATE OR REPLACE FUNCTION author_exists (author_name VARCHAR2) RETURN NUMBER;
```

The generated artefacts can then be used as follows:

```sql
-- This is the rendered SQL

SELECT AUTHOR_EXISTS('Paulo') FROM DUAL
```

```java
// Use the static-imported method from Routines:
boolean exists =
create.select(authorExists("Paulo")).fetchOne(0, boolean.class);
```

For more info about inlining stored function references in SQL statements, please refer to the manual's section about [user-defined functions](#user-defined-functions).

<a id="oracle-packages"></a>
#### 4.9.1. Oracle Packages

Oracle uses the concept of a PACKAGE to group several procedures/functions into a sort of namespace. The [SQL 92 standard](https://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt) talks about "modules", to represent this concept, even if this is rarely implemented as such. This is reflected in jOOQ by the use of Java sub-packages in the [source code generation](#code-generation) destination package. Every Oracle package will be reflected by

- A Java package holding classes for formal Java representations of the procedure/function in that package
- A Java class holding convenience methods to facilitate calling those procedures/functions

Apart from this, the generated source code looks exactly like the one for standalone procedures/functions.

For more details about [code generation](#code-generation) for procedures and packages see the manual's section about [procedures and code generation](#codegen-procedures).

<a id="oracle-member-procedures"></a>
#### 4.9.2. Oracle member procedures

Oracle UDTs can have object-oriented structures including member functions and procedures. With Oracle, you can do things like this:

```sql
CREATE OR REPLACE TYPE u_author_type AS OBJECT (
  id NUMBER(7),
  first_name VARCHAR2(50),
  last_name VARCHAR2(50),

  MEMBER PROCEDURE LOAD,
  MEMBER FUNCTION counBOOKs RETURN NUMBER
)

-- The type body is omitted for the example
```

These member functions and procedures can simply be mapped to Java methods:

```java
// Create an empty, attached UDT record from the DSLContext
UAuthorType author = create.newRecord(U_AUTHOR_TYPE);

// Set the author ID and load the record using the LOAD procedure
author.setId(1);
author.load();

// The record is now updated with the LOAD implementation's content
assertNotNull(author.getFirstName());
assertNotNull(author.getLastName());
```

For more details about [code generation](#code-generation) for UDTs see the manual's section about [user-defined types and code generation](#codegen-udts).

<a id="exporting"></a>
### 4.10. Exporting to XML, CSV, JSON, HTML, Text, Charts

If you are using jOOQ for scripting purposes or in a slim, unlayered application server, you might be interested in using jOOQ's exporting functionality (see also the [importing functionality](#importing)). You can export any Result<Record> into the formats discussed in the subsequent chapters of the manual

Most of these formats can also be read back into a `Result`, as described in the section about [creating results and records in memory](#in-memory-results).

<a id="exporting-xml"></a>
#### 4.10.1. Exporting XML

```java
// Fetch books and format them as XML
String xml = create.selectFrom(BOOK).fetch().formatXML();
```

The above query will result in an XML document looking like the following one:

```xml
<result xmlns="http://www.jooq.org/xsd/jooq-export-3.10.0.xsd">
  <fields>
    <field schema="TEST" table="BOOK" name="ID" type="INTEGER"/>
    <field schema="TEST" table="BOOK" name="AUTHOR_ID" type="INTEGER"/>
    <field schema="TEST" table="BOOK" name="TITLE" type="VARCHAR"/>
  </fields>
  <records>
    <record>
      <value field="ID">1</value>
      <value field="AUTHOR_ID">1</value>
      <value field="TITLE">1984</value>
    </record>
    <record>
      <value field="ID">2</value>
      <value field="AUTHOR_ID">1</value>
      <value field="TITLE">Animal Farm</value>
    </record>
  </records>
</result>
```

The same result as an [`org.w3c.dom.Document`](https://docs.oracle.com/en/java/javase/25/docs/api/java.xml/org/w3c.dom/Document.html) can be obtained using the Result.intoXML() method:

```java
// Fetch books and format them as XML
Document xml = create.selectFrom(BOOK).fetch().intoXML();
```

See the XSD schema definition here, for a formal definition of the XML export format:  
[https://www.jooq.org/xsd/jooq-export-3.10.0.xsd](https://www.jooq.org/xsd/jooq-export-3.10.0.xsd)

<a id="exporting-csv"></a>
#### 4.10.2. Exporting CSV

```java
// Fetch books and format them as CSV
String csv = create.selectFrom(BOOK).fetch().formatCSV();
```

The above query will result in a CSV document looking like the following one:

```text
ID,AUTHOR_ID,TITLE
1,1,1984
2,1,Animal Farm
```

In addition to the standard behaviour, you can also specify a separator character, as well as a special string to represent NULL values (which cannot be represented in standard CSV):

```java
// Use ";" as the separator character
String csv = create.selectFrom(BOOK).fetch().formatCSV(';');

// Specify "{null}" as a representation for NULL values
String csv = create.selectFrom(BOOK).fetch().formatCSV(';', "{null}");
```

<a id="exporting-json"></a>
#### 4.10.3. Exporting JSON

```java
// Fetch books and format them as JSON
String json = create.selectFrom(BOOK).fetch().formatJSON();
```

The above query will result in a JSON document looking like the following one:

```text
{"fields":[{"schema":"schema-1","table":"table-1","name":"field-1","type":"type-1"},
           {"schema":"schema-2","table":"table-2","name":"field-2","type":"type-2"},
           ...,
           {"schema":"schema-n","table":"table-n","name":"field-n","type":"type-n"}],
 "records":[[value-1-1,value-1-2,...,value-1-n],
            [value-2-1,value-2-2,...,value-2-n]]}
```

Note: This format has been modified in jOOQ 2.6.0 and 3.7.0

<a id="exporting-html"></a>
#### 4.10.4. Exporting HTML

```java
// Fetch books and format them as HTML
String html = create.selectFrom(BOOK).fetch().formatHTML();
```

The above query will result in an HTML document looking like the following one

```xml
<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>AUTHOR_ID</th>
      <th>TITLE</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>1</td>
      <td>1984</td>
    </tr>
    <tr>
      <td>2</td>
      <td>1</td>
      <td>Animal Farm</td>
    </tr>
  </tbody>
</table>
```

<a id="exporting-text"></a>
#### 4.10.5. Exporting Text

```java
// Fetch books and format them as text
String text = create.selectFrom(BOOK).fetch().format();
```

The above query will result in a text document looking like the following one

```text
+---+---------+-----------+
| ID|AUTHOR_ID|TITLE      |
+---+---------+-----------+
|  1|        1|1984       |
|  2|        1|Animal Farm|
+---+---------+-----------+
```

A simple text representation can also be obtained by calling toString() on a Result object. See also the manual's section about [DEBUG logging](#logging)

> [!TIP]
> [Redacted columns](#redacted-columns) allow for masking certain data in this formatted representation to avoid accidental logging of sensitive data.

<a id="exporting-charts"></a>
#### 4.10.6. Exporting Charts

```java
// Count books per book store and format them as charts
String chart =
create.select(
           BOOK_TO_BOOK_STORE.BOOK_STORE_NAME,
           count(BOOK_TO_BOOK_STORE.BOOK_ID).as("books")
       )
       .from(BOOK_TO_BOOK_STORE)
       .groupBy(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
       .fetch()
       .formatChart();
```

When formatted, the result is this:

```text
+-------------------------+-----+
|BOOK_STORE_NAME          |books|
+-------------------------+-----+
|Buchhandlung im Volkshaus|    1|
|Ex Libris                |    2|
|Orell Füssli             |    3|
+-------------------------+-----+
```

And the chart will be looking like the following one

```text
3.00|                                                  █████████████████████████
2.91|                                                  █████████████████████████
2.82|                                                  █████████████████████████
2.73|                                                  █████████████████████████
2.64|                                                  █████████████████████████
2.55|                                                  █████████████████████████
2.45|                                                  █████████████████████████
2.36|                                                  █████████████████████████
2.27|                                                  █████████████████████████
2.18|                                                  █████████████████████████
2.09|                                                  █████████████████████████
2.00|                         ██████████████████████████████████████████████████
1.91|                         ██████████████████████████████████████████████████
1.82|                         ██████████████████████████████████████████████████
1.73|                         ██████████████████████████████████████████████████
1.64|                         ██████████████████████████████████████████████████
1.55|                         ██████████████████████████████████████████████████
1.45|                         ██████████████████████████████████████████████████
1.36|                         ██████████████████████████████████████████████████
1.27|                         ██████████████████████████████████████████████████
1.18|                         ██████████████████████████████████████████████████
1.09|                         ██████████████████████████████████████████████████
1.00|███████████████████████████████████████████████████████████████████████████
----+---------------------------------------------------------------------------
    | Buchhandlung im Volkshaus         Ex Libris               Orell Füssli
```

It is possible to specify a variety of [`org.jooq.ChartFormat`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ChartFormat.html) formatting specifications, such as the width, height, display type (default, stacked, 100% stacked), the column index of the category and value columns, etc.

<a id="formatting-provider"></a>
#### 4.10.7. FormattingProvider

Most types of export formats discussed in the previous sections have an associated formatting configuration object, which can be passed on a per-formatting call, including:

- [`org.jooq.ChartFormat`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ChartFormat.html) for formatting the [chart export](#exporting-charts)
- [`org.jooq.CSVFormat`](https://www.jooq.org/javadoc/3.22.x/org/jooq/CSVFormat.html) for formatting the [CSV export](#exporting-csv)
- [`org.jooq.JSONFormat`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONFormat.html) for formatting the [JSON export](#exporting-json)
- [`org.jooq.TXTFormat`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TXTFormat.html) for formatting the [text export](#exporting-text)
- [`org.jooq.XMLFormat`](https://www.jooq.org/javadoc/3.22.x/org/jooq/XMLFormat.html) for formatting the [XML export](#exporting-xml)

For example, when you want to specify the JSON record layout, as well as remove the header information you can write code like this:

```java
System.out.println("Using the object layout");
System.out.println(result.formatJSON(new JSONFormat().header(false).recordFormat(JSONFormat.RecordFormat.OBJECT)));

System.out.println("Using the array layout");
System.out.println(result.formatJSON(new JSONFormat().header(false).recordFormat(JSONFormat.RecordFormat.ARRAY)));
```

The output is the following (see also [JSON export](#exporting-json) for details):

```text
Using the object layout
[{"col1": "string1", "col2": 1}, {"col1": "string2", "col2": 2}]

Using the array layout
[["string1", 1],["string2", 2]]
```

Instead of passing this `JSONFormat` object to *every* formatting call, you can also register the [`org.jooq.FormattingProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/FormattingProvider.html) SPI to your [Configuration](#dsl-context) in order to specify the relevant formats that should be applied *by default* (in the absence of an explicit formatting configuration object).

For example, in order to turn off JSON headers and specify the array layout everywhere, do this:

```java
JSONFormat format = new JSONFormat().header(false).recordFormat(JSONFormat.RecordFormat.ARRAY);
Configuration configuration = create.configuration().derive(FormattingProvider

    // This specifies the format to be used for Record.formatJSON() calls
    .onJsonFormatForRecords(() -> format)

    // This specifies the format to be used for Result.formatJSON() calls
    .onJsonFormatForResults(() -> format));

System.out.println(
    configuration.dsl()
        .select(BOOK.ID, BOOK.TITLE)
        .from(BOOK)
        .fetch()
        .formatJSON() // No need to pass the format here anymore
);
```

<a id="importing"></a>
### 4.11. Importing data

jOOQ's loader API can be used to import tabular data into a table from a variety of data sources. It offers a simplified API to solve common data import challenges such as:

- Mapping different data sources, like CSV, JSON, XML, records to SQL tables
- Specifying behaviour when duplicate keys are encountered
- Fine tuning batch, bulk, and commit sizes
- Error handling

<a id="importing-api"></a>
#### 4.11.1. The Loader API

The loader API is implemented like any other DSL statement in jOOQ, following a few steps:

```text
create.loadInto(TARGET_TABLE)
      .[options]
      .[source and source to target mapping]
      .[listeners]
      .[execution and error handling]
```

For example:

```java
create.loadInto(BOOK)

      // Options
      .onDuplicateKeyError()
      .bulkAll()
      .batchAll()
      .commitAll()

      // Source and source to target mapping
      .loadCSV(inputStream)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)

      // Listeners
      .onRow(ctx -> { /* ... */ })

      // Execution and error handling
      .execute()
      .errors()
      .forEach(e -> { /* ... */ });
```

See the following sections for details about each step:

- [Import options](#importing-options)
- [Import data sources](#importing-sources)
- [Import listeners](#importing-listeners)
- [Import result and error handling](#importing-results)

<a id="importing-options"></a>
#### 4.11.2. Import options

Prior to specifing [data sources](#importing-sources), data source independent loading options can be specified. These include throttling, duplicate handling, and error handling:

<a id="importing-option-throttling"></a>
##### 4.11.2.1. Throttling

When importing large data sets, it may be beneficial to explicitly define the optimal size for each:

- **Bulk size:** The number of rows that are sent to the server in one SQL statement. Defaults to 1.
- **Batch size:** The number of statements that are sent to the server in one JDBC statement batch. Defaults to 1.
- **Commit size:** The number of statement batches that are committed in one transaction. Defaults to 1.

All of the three types of throttling can be combined.

Not all RDBMS offer the same optimisation capabilities. Please refer to your database manual to learn how these tuning capabilities may affect your data import performance. **Also, actual measurements may help improve these numbers. Do not optimise prematurely, or based on assumptions. Always measure if your optimisation has the desired effect!**

###### The bulk size

Bulk data processing is important in SQL, which is a set based language. It is possible to express bulk `INSERT` statements as well with [INSERT .. VALUES](#insert-values) or [INSERT .. SELECT](#insert-select). Sophisticated RDBMS may use these statements to improve the disk block allocation process, because if an `INSERT` statement has more than 1 row, the optimiser knows better how much space will be needed to store the incoming data. This approach also helps "clustering" inserted data (keeping data that is inserted at the same time in local disk block "clusters"), which may be beneficial if the same data is also frequently read, later on. While the benefit may be marginal on SSDs or other random access disks, it may be significant on HDDs.

There are 3 possible, mutually exclusive configurations of specifying the bulk size:

```java
create.loadInto(BOOK)

      // Put all the data in a single bulk statement.
      .bulkAll()

      // Put up to 32 rows in a single bulk statement.
      .bulkAfter(32)

      // Do not put more than 1 row in a statement.
      .bulkNone()

      .loadCSV(inputstream)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();
```

###### The batch size

Batch data processing allows for reducing the network traffic overhead, because it allows the JDBC driver to buffer bind values for several subsequent statement executions and send them all in one go.

There are 3 possible, mutually exclusive configurations of specifying the batch size:

```java
create.loadInto(BOOK)

      // Execute all statements (bulk or not) in a single large statement batch.
      .batchAll()

      // Put up to 32 statements (bulk or not) in a single statement batch.
      .batchAfter(32)

      // Execute each statement (bulk or not) individually.
      .batchNone()

      .loadCSV(inputstream)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();
```

###### The commit size

Committing a transaction can be a costly operation if done too often, or not often enough. If there are too many commits, this can lead to a lot of logging overhead on the server. If a too many changes are left uncommitted for too long, there may be too much locking in 2PL transaction models, or log contention in MVCC transaction models. An empirically discovered, optimal commit size that leads to committing e.g. 1000 rows (or 10000, or 100, please measure what works best for you) may produce best results.

There are 3 possible, mutually exclusive configurations of specifying the batch size:

```java
create.loadInto(BOOK)

      // Commit all statements (batch, bulk, or not) in a single large transaction.
      .commitAll()

      // Put up to 32 statements (batch, bulk, or not) in a transaction.
      .commitAfter(32)

      // Commit each statement (batch, bulk, or not) in a transaction, just like commitAfter(1)
      .commitEach()

      // Do not commit any statement, leave committing to client code
      .commitNone()

      .loadCSV(inputstream)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();
```

<a id="import-option-duplicates"></a>
##### 4.11.2.2. Duplicate handling

When importing data, some data may already be present and needs to be updated. jOOQ supports a variety of UPSERT style statements. The ideal statement to be used for imports is MySQL's [INSERT .. ON DUPLICATE KEY UPDATE](#insert-on-duplicate-key) statement, which can be emulated using standard SQL [MERGE](#merge-statement), or `INSERT .. ON CONFLICT` in PostgreSQL or SQLite.

```java
create.loadInto(BOOK)

      // Insert each row using INSERT .. ON DUPLICATE KEY UPDATE
      .onDuplicateKeyUpdate()

      // Insert each row using INSERT .. ON DUPLICATE KEY IGNORE
      .onDuplicateKeyIgnore()

      // Use ordinary INSERT statements, which will produce errors on duplicate keys
      .onDuplicateKeyError()

      .loadCSV(inputstream)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();
```

<a id="import-option-errors"></a>
##### 4.11.2.3. Error handling

When importing large amounts of data, errors may be inevitable and may need to be processed after the import, without impacting the entire import. In these cases, it may be useful to specify error handling. In all cases, errors will be reported after the execution of the import process:

```java
create.loadInto(BOOK)

      // Ignore any errors and continue inserting. Errors will be reported nonetheless.
      .onErrorIgnore()

      // Abort the import upon encountering the first error.
      .onErrorAbort()

      .loadCSV(inputstream)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();
```

<a id="importing-sources"></a>
#### 4.11.3. Import data sources

Different types of data sources are supported by jOOQ in the same formats as the [export API](#exporting). These include:

<a id="importing-source-csv"></a>
##### 4.11.3.1. Importing CSV

The below CSV data represents two author records that may have been exported previously, by jOOQ's [exporting functionality](#exporting), and then modified in Microsoft Excel or any other spreadsheet tool:

```text
ID,AUTHOR_ID,TITLE <-- Note the CSV header. By default, the first line is ignored
1,1,1984
2,1,Animal Farm
```

The following examples show how to map source and target tables.

```java
// Specify fields from the target table to be matched with fields from the source CSV by position.
// Positional matching is independent of the presence of a header row in the CSV content.
create.loadInto(BOOK)
      .loadCSV(inputstream, encoding)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();

// Use "null" field placeholders to ignore source columns by position.
create.loadInto(BOOK)
      .loadCSV(inputstream, encoding)
      .fields(BOOK.ID, null, BOOK.TITLE)
      .execute();

// Match target fields with source fields by "corresponding" name.
// This assumes that CSV row 1 is a header row containing the source field names.
create.loadInto(BOOK)
      .loadCSV(inputstream, encoding)
      .fieldsCorresponding()
      .execute();
```

###### CSV specific options

You may pass one of the following flags to specify how the CSV content should be parsed:

```java
create.loadInto(BOOK)
      .loadCSV(inputstream, encoding)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)

      // Ignore a certain number of header rows. By default, this is 1.
      .ignoreRows(1)

      // The quote character for use with string content containing quotes or separators. By default, this is "
      .quote('"')

      // The separator character that separates columns. By default, this is ,
      .separator(',')

      // The null string allows for distinguishing between empty strings and null. By default, there is no null string.
      .nullString("{null}")
      .execute();
```

<a id="importing-source-json"></a>
##### 4.11.3.2. Importing JSON

The below JSON data represents two author records that may have been exported previously, by jOOQ's [exporting functionality](#exporting):

```text
{"fields" :[{"name":"ID","type":"INTEGER"},
            {"name":"AUTHOR_ID","type":"INTEGER"},
            {"name":"TITLE","type":"VARCHAR"}],
 "records":[[1,1,"1984"],
            [2,1,"Animal Farm"]]}
```

The following examples show how to map source data and target table.

```java
// Specify fields from the target table to be matched with fields from the source JSON array by position.
// Positional matching is independent of the presence of a header information in the JSON content.
create.loadInto(BOOK)
      .loadJSON(inputstream, encoding)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();

// Use "null" field placeholders to ignore source columns by position.
create.loadInto(BOOK)
      .loadJSON(inputstream, encoding)
      .fields(BOOK.ID, null, BOOK.TITLE)
      .execute();

// Match target fields with source fields by "corresponding" name.
// This assumes that JSON content contains header information as exported by jOOQ
create.loadInto(BOOK)
      .loadJSON(inputstream, encoding)
      .fieldsCorresponding()
      .execute();
```

No other, JSON-specific options are currently available.

<a id="importing-source-records"></a>
##### 4.11.3.3. Importing records

A common use-case for importing records via jOOQ's `Loader` API is when data needs to be transferred between databases. For instance, when fetching the following data from database 1:

```java
Result<Record3<Integer, Integer, String>> result =
DSL.using(configuration1)
   .select(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
   .from(BOOK)
   .fetch();
```

Now, this result should be imported back into a database 2:

```java
// Specify fields from the target table to be matched with fields from the source result by position.
create.loadInto(BOOK)
      .loadRecords(result)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();

// Use "null" field placeholders to ignore source columns by position.
create.loadInto(BOOK)
      .loadRecords(result)
      .fields(BOOK.ID, null, BOOK.TITLE)
      .execute();

// Match target fields with source fields by "corresponding" name.
create.loadInto(BOOK)
      .loadRecords(result)
      .fieldsCorresponding()
      .execute();
```

No other, Record-specific options are currently available.

The records don't have to be fetched from a database. They can also be [created in memory](#in-memory-results), or read from formats like CSV, JSON, or text tables. See the section about [working with in-memory results](#in-memory-usage) for an example.

<a id="importing-source-arrays"></a>
##### 4.11.3.4. Importing arrays

A common use-case for importing arrays via jOOQ's `Loader` API is when data is fetched into memory from some data source, or even ad-hoc data, which needs to be imported into a database.

```java
// Specify fields from the target table to be matched with fields from the source result by position.
create.loadInto(BOOK)
      .loadArrays(
          new Object[] { 1, 1, "1984" },
          new Object[] { 2, 1, "Animal Farm" })
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();
```

No other, array-specific options are currently available.

<a id="importing-source-xml"></a>
##### 4.11.3.5. Importing XML

The below XML data represents two book records that may have been exported previously, by jOOQ's [exporting functionality](#exporting-xml):

```xml
<result xmlns="http://www.jooq.org/xsd/jooq-export-3.10.0.xsd">
  <fields>
    <field name="ID" type="INTEGER"/>
    <field name="AUTHOR_ID" type="INTEGER"/>
    <field name="TITLE" type="VARCHAR"/>
  </fields>
  <records>
    <record>
      <value field="ID">1</value>
      <value field="AUTHOR_ID">1</value>
      <value field="TITLE">1984</value>
    </record>
    <record>
      <value field="ID">2</value>
      <value field="AUTHOR_ID">1</value>
      <value field="TITLE">Animal Farm</value>
    </record>
  </records>
</result>
```

This is the same format that is read by [DSLContext.fetchFromXML()](#in-memory-xml). The following examples show how to map source data and target table.

```java
// Specify fields from the target table to be matched with fields from the source XML by position.
// The position of a source field is the position of its <field/> element in the <fields/> element.
create.loadInto(BOOK)
      .loadXML(inputstream, encoding)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();

// Use "null" field placeholders to ignore source columns by position.
create.loadInto(BOOK)
      .loadXML(inputstream, encoding)
      .fields(BOOK.ID, null, BOOK.TITLE)
      .execute();

// Match target fields with source fields by "corresponding" name.
// This uses the names of the <field/> elements in the XML content, as exported by jOOQ
create.loadInto(BOOK)
      .loadXML(inputstream, encoding)
      .fieldsCorresponding()
      .execute();
```

Apart from `File`, `InputStream`, `Reader`, `String`, and [`org.jooq.Source`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Source.html) content, XML data can also be loaded from an `org.xml.sax.InputSource`. If the source data type information is present in the `type` attribute of the `<field/>` elements, it is used to read the values. Otherwise, the values are read as strings and converted to the target table's column types.

Like the JSON format, the XML format is currently read into memory entirely before the data is loaded. No other, XML-specific options are currently available.

<a id="importing-listeners"></a>
#### 4.11.4. Import listeners

Import listeners allow for keeping track of import progress:

```java
create.loadInto(BOOK)
      .loadCSV(inputstream, encoding)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .onRow(ctx -> {
          log.info(
              "Executed: {}, ignored: {}, processed: {}, stored: {}",
              ctx.executed(), ctx.ignored(), ctx.processed(), ctx.stored()
          );
      })
      .execute();
```

<a id="importing-results"></a>
#### 4.11.5. Import result and error handling

After completed execution, a number of diagnostics are available to implement error handling:

```java
Loader<?> loader =
create.loadInto(BOOK)
      .loadCSV(inputstream, encoding)
      .fields(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
      .execute();

// The number of processed rows
int processed = loader.processed();

// The number of stored rows (INSERT or UPDATE)
int stored = loader.stored();

// The number of ignored rows (due to errors, or duplicate rule)
int ignored = loader.ignored();

// The errors that may have occurred during loading
List<LoaderError> errors = loader.errors();
LoaderError error = errors.get(0);

// The exception that caused the error
DataAccessException exception = error.exception();

// The row that caused the error
int rowIndex = error.rowIndex();
String[] row = error.row();

// The query that caused the error
Query query = error.query();
```

<a id="in-memory-results"></a>
### 4.12. Creating results and records in memory

Most of the time, a jOOQ [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) or [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) is produced by [fetching data](#fetching) from a database. But both types can also be created entirely in memory, without any database interaction, using API on the [DSLContext](#dsl-context). This is useful for a variety of use-cases, including:

- Providing results to a [MockConnection](#mocking-connection) or to a [MockFileDatabase](#mock-file-database) in tests.
- Using ad-hoc data as a table in SQL queries, via the [VALUES() table constructor](#values).
- Reading data that was previously [exported by jOOQ](#exporting), or produced by some other system, e.g. in order to [import it into a database](#importing).
- Using any of jOOQ's [formatting](#exporting) and [mapping](#fetching) utilities on data that doesn't originate from a database.

None of the methods described in this section require a JDBC connection. A `DSLContext` created from a [SQLDialect](#sql-dialects) only, e.g. via `DSL.using(SQLDialect.POSTGRES)`, is sufficient.

<a id="in-memory-new-result"></a>
#### 4.12.1. Creating new results and records

The [`DSLContext.newResult()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#newResult(org.jooq.Table)) method creates a new, empty `Result`, which is a [`java.util.List`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html) that can be populated with records created from [`DSLContext.newRecord()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#newRecord(org.jooq.Table)). When working with [generated code](#code-generation), the record type of a table can be used:

```java
// Create an empty result of a generated table's record type
Result<BookRecord> books = create.newResult(BOOK);

// Create a new record and add it to the result
BookRecord book = create.newRecord(BOOK);
book.setId(1);
book.setAuthorId(1);
book.setTitle("1984");
books.add(book);

// Records can also be pre-filled from POJOs or other objects, see Record.from(Object)
books.add(create.newRecord(BOOK, myBook));
```

Records created this way have their [changed flags](#internal-flags) set for all values that were set, which means that a subsequent `UpdatableRecord.store()` call will execute an `INSERT` statement. See the section about [CRUD with UpdatableRecords](#crud-with-updatablerecords) for more details.

##### Ad-hoc results and records

Results and records are not tied to tables. Just like with [ad-hoc projections in SELECT statements](#record-n), a result or record can be created from an arbitrary set of [Field expressions](#column-expressions), producing `Result<Record1<T1>>` up to `Result<Record22<T1, ..., T22>>` types for up to 22 fields, or `Result<Record>` for more fields:

```java
// Using generated column references
Result<Record2<Integer, String>> result = create.newResult(AUTHOR.ID, AUTHOR.LAST_NAME);
result.add(create.newRecord(AUTHOR.ID, AUTHOR.LAST_NAME).values(1, "Orwell"));
result.add(create.newRecord(AUTHOR.ID, AUTHOR.LAST_NAME).values(2, "Coelho"));

// Without code generation, using plain SQL column references
Field<Integer> id = field(name("ID"), SQLDataType.INTEGER);
Field<String> title = field(name("TITLE"), SQLDataType.VARCHAR);

Result<Record2<Integer, String>> titles = create.newResult(id, title);
titles.add(create.newRecord(id, title).values(1, "1984"));

// With more than 22 fields, or with a dynamic set of fields
List<Field<?>> fields = ...;
Result<Record> dynamic = create.newResult(fields);
Record record = create.newRecord(fields);
record.set(id, 1);
dynamic.add(record);
```

Records of [user-defined types](#codegen-udts) can be created in a similar way, using [`DSLContext.newRecord(UDT)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#newRecord(org.jooq.UDT)).

##### Attachment

Results and records created by a `DSLContext` are [attached](#settings-attach-records) to its `Configuration` by default. This is relevant for operations like `UpdatableRecord.store()`, but also for any configuration dependent behaviour, such as [data type conversion](#data-type-conversion) or [formatting](#exporting).

<a id="in-memory-csv"></a>
#### 4.12.2. Reading CSV

[`DSLContext.fetchFromCSV()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromCSV(java.lang.String)) is the inverse operation of [exporting CSV](#exporting-csv). It parses a CSV string into a `Result<Record>`:

```java
Result<Record> result = create.fetchFromCSV(
    "ID,AUTHOR_ID,TITLE\n"
  + "1,1,1984\n"
  + "2,1,Animal Farm\n"
);
```

By default, the first line is interpreted as a header line, defining the field names, and values are expected to be separated by a comma. Both defaults can be overridden:

```java
// Use ";" as the delimiter
Result<Record> result = create.fetchFromCSV(csv, ';');

// The CSV content has no header line. Field names COL1, COL2, ..., COLn are generated
Result<Record> result = create.fetchFromCSV(csv, false);

// Both of the above
Result<Record> result = create.fetchFromCSV(csv, false, ';');
```

CSV has no notion of data types, so all fields of the resulting `Result` are of type `String`. Missing values produce `NULL`, empty values produce empty strings. See the section about [working with in-memory results](#in-memory-usage) to learn how to convert such results to other types.

If the goal is to load CSV data directly into a database table, the [Loader API's CSV support](#importing-source-csv) may be a better fit.

<a id="in-memory-json"></a>
#### 4.12.3. Reading JSON

[`DSLContext.fetchFromJSON()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromJSON(java.lang.String)) is the inverse operation of [exporting JSON](#exporting-json). It parses a JSON string in the format produced by `Result.formatJSON()` into a `Result<Record>`:

```java
Result<Record> result = create.fetchFromJSON(
    "{\"fields\":[{\"name\":\"ID\",\"type\":\"INTEGER\"},"
  + "            {\"name\":\"AUTHOR_ID\",\"type\":\"INTEGER\"},"
  + "            {\"name\":\"TITLE\",\"type\":\"VARCHAR\"}],"
  + " \"records\":[[1,1,\"1984\"],"
  + "            [2,1,\"Animal Farm\"]]}"
);
```

Records may be encoded as arrays (the default) or as objects (see [`org.jooq.JSONFormat.RecordFormat`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONFormat.RecordFormat.html)).

If the `"fields"` header contains `"type"` information, it is used to produce fields of the corresponding data types. Otherwise, fields are of type `String`. See the section about [working with in-memory results](#in-memory-usage) to learn how to convert such results to other types.

If the goal is to load JSON data directly into a database table, the [Loader API's JSON support](#importing-source-json) may be a better fit.

<a id="in-memory-xml"></a>
#### 4.12.4. Reading XML

[`DSLContext.fetchFromXML()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromXML(java.lang.String)) is the inverse operation of [exporting XML](#exporting-xml). It parses an XML string in the format produced by `Result.formatXML()` into a `Result<Record>`:

```java
Result<Record> result = create.fetchFromXML(
    "<result>"
  + "  <fields>"
  + "    <field name=\"ID\" type=\"INTEGER\"/>"
  + "    <field name=\"AUTHOR_ID\" type=\"INTEGER\"/>"
  + "    <field name=\"TITLE\" type=\"VARCHAR\"/>"
  + "  </fields>"
  + "  <records>"
  + "    <record><value field=\"ID\">1</value><value field=\"AUTHOR_ID\">1</value><value field=\"TITLE\">1984</value></record>"
  + "    <record><value field=\"ID\">2</value><value field=\"AUTHOR_ID\">1</value><value field=\"TITLE\">Animal Farm</value></record>"
  + "  </records>"
  + "</result>"
);
```

If a `<field/>` element contains a `type` attribute, it is used to produce a field of the corresponding data type. Otherwise, the field is of type `String`. See the section about [working with in-memory results](#in-memory-usage) to learn how to convert such results to other types.

If the goal is to load XML data directly into a database table, the [Loader API's XML support](#importing-source-xml) may be a better fit.

<a id="in-memory-html"></a>
#### 4.12.5. Reading HTML

[`DSLContext.fetchFromHTML()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromHTML(java.lang.String)) is the inverse operation of [exporting HTML](#exporting-html). It parses an HTML table into a `Result<Record>`:

```java
Result<Record> result = create.fetchFromHTML(
    "<table>"
  + "  <tr><th>ID</th><th>AUTHOR_ID</th><th>TITLE</th></tr>"
  + "  <tr><td>1</td><td>1</td><td>1984</td></tr>"
  + "  <tr><td>2</td><td>1</td><td>Animal Farm</td></tr>"
  + "</table>"
);
```

The input must be well-formed XML, but doesn't have to be valid XHTML. The following rules apply:

- Elements and attributes other than `<table>`, `<tr>`, `<th>`, and `<td>` (e.g. `<thead>` or `<tbody>`), as well as comments, are ignored.
- The `<table>` element is optional, and may appear at most once. Nested tables are not supported.
- The first row containing `<th>` elements defines the field names. Without such a row, field names are generated.
- The first row defines the number of columns. Shorter subsequent rows are padded, longer ones are truncated.

All fields of the resulting `Result` are of type `String`. See the section about [working with in-memory results](#in-memory-usage) to learn how to convert such results to other types.

<a id="in-memory-text"></a>
#### 4.12.6. Reading text

[`DSLContext.fetchFromTXT()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromTXT(java.lang.String)) is the inverse operation of [exporting text](#exporting-text). It parses a human-readable, formatted text table into a `Result<Record>`. Two formats are supported, the format produced by `Result.format()`:

```java
Result<Record> result = create.fetchFromTXT(
    "+---+---------+-----------+\n"
  + "| ID|AUTHOR_ID|TITLE      |\n"
  + "+---+---------+-----------+\n"
  + "|  1|        1|1984       |\n"
  + "|  2|        1|Animal Farm|\n"
  + "+---+---------+-----------+\n"
);
```

... and the format used by H2 in its test data, where column groups are delimited by dashes in the second line:

```java
Result<Record> result = create.fetchFromTXT(
    "ID AUTHOR_ID TITLE      \n"
  + "-- --------- -----------\n"
  + "1  1         1984       \n"
  + "2  1         Animal Farm\n"
);
```

In both formats, the width of each column is defined by its dashes, and values are trimmed. By default, the literal `{null}`, which is also what `Result.format()` produces for `NULL` values, is interpreted as `NULL`. A different literal can be specified explicitly:

```java
Result<Record> result = create.fetchFromTXT(text, "N/A");
```

All fields of the resulting `Result` are of type `String`. See the section about [working with in-memory results](#in-memory-usage) to learn how to convert such results to other types.

This format is particularly readable in test code. It is also one of the formats accepted by the [MockFileDatabase](#mock-file-database).

<a id="in-memory-string-data"></a>
#### 4.12.7. Reading string arrays

[`DSLContext.fetchFromStringData()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromStringData(java.lang.String[]...)) is the method that all of the previous text based methods are built upon. It is useful when data has already been split into rows and columns, e.g. by a third party CSV parser or spreadsheet library:

```java
// By default, the first array contains the field names
Result<Record> result = create.fetchFromStringData(
    new String[] { "ID", "AUTHOR_ID", "TITLE" },
    new String[] { "1", "1", "1984" },
    new String[] { "2", "1", "Animal Farm" }
);

// Data without header row. Field names COL1, COL2, ..., COLn are generated
List<String[]> data = ...;
Result<Record> result = create.fetchFromStringData(data, false);
```

The number of columns is defined by the first array. Excess data in subsequent arrays is ignored, and missing data is filled with `NULL`. All fields of the resulting `Result` are of type `String`.

Arrays of arbitrary objects, rather than strings, can also be [imported directly into a table using the Loader API](#importing-source-arrays).

<a id="in-memory-usage"></a>
#### 4.12.8. Working with in-memory results

A `Result` created in memory is no different from a `Result` fetched from a database. All of the usual API is available. This section shows a few common use-cases.

##### Converting to other data types

Most of the methods that read text based formats produce `String` typed fields. Using jOOQ's [data type conversion](#data-type-conversion) capabilities, such results can be converted into [TableRecords](#record-vs-tablerecord), [ad-hoc records](#record-n), [POJOs](#pojos), or just individual values:

```java
Result<Record> result = create.fetchFromCSV(csv);

// Convert to a generated TableRecord type. Fields are matched by name.
Result<BookRecord> books = result.into(BOOK);

// Convert to an ad-hoc record type. Fields are matched by name.
Result<Record2<Integer, String>> titles = result.into(BOOK.ID, BOOK.TITLE);

// Map to POJOs
List<Book> list = result.into(Book.class);

// Extract individual columns
List<Integer> ids = result.getValues("ID", Integer.class);
```

##### Using in-memory results in SQL queries

With [`DSL.table(Result)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DSL.html#table(org.jooq.Result)), any `Result` can be turned into a [table expression](#table-expressions) based on the [VALUES() table constructor](#values), e.g. to join ad-hoc data with database tables:

```sql
SELECT v.TITLE, AUTHOR.LAST_NAME
FROM (
  VALUES (1, 1, '1984'),
         (2, 1, 'Animal Farm')
) AS v (ID, AUTHOR_ID, TITLE)
JOIN AUTHOR
  ON AUTHOR.ID = v.AUTHOR_ID


 
```

```java
Table<Record3<Integer, Integer, String>> v = table(
    create.fetchFromCSV(csv)
          .into(BOOK.ID, BOOK.AUTHOR_ID, BOOK.TITLE)
);

create.select(v.field(BOOK.TITLE), AUTHOR.LAST_NAME)
      .from(v)
      .join(AUTHOR)
      .on(AUTHOR.ID.eq(v.field(BOOK.AUTHOR_ID)))
      .fetch();
```

Converting the data to the desired types first, as above, ensures that the `VALUES()` constructor produces correctly typed bind values.

##### Mocking

When implementing a [MockDataProvider](#mocking-connection), results have to be created in memory. Any of the methods in this section can be used for this:

```java
// A DSLContext without a connection, used only to create results
DSLContext mock = DSL.using(SQLDialect.POSTGRES);

MockDataProvider provider = ctx -> new MockResult[] {
    new MockResult(2, mock.fetchFromTXT(
        "+---+-----------+\n"
      + "| ID|TITLE      |\n"
      + "+---+-----------+\n"
      + "|  1|1984       |\n"
      + "|  2|Animal Farm|\n"
      + "+---+-----------+\n"
    ))
};
```

For a more declarative approach, consider using the [MockFileDatabase](#mock-file-database), which uses the same text based formats.

##### Importing

In-memory results can be [imported into a database table using the Loader API](#importing-source-records):

```java
create.loadInto(BOOK)
      .loadRecords(create.fetchFromCSV(csv))
      .fieldsCorresponding()
      .execute();
```

##### Converting between formats

Reading a format into a `Result`, and then [exporting](#exporting) it again, can be used to convert between formats:

```java
// Convert CSV to JSON
String json = create.fetchFromCSV(csv).formatJSON();

// Convert a text table to an HTML table
String html = create.fetchFromTXT(text).formatHTML();
```

<a id="crud-with-updatablerecords"></a>
### 4.13. UpdatableRecords

Your database application probably consists of 50% - 80% CRUD, whereas only the remaining 20% - 50% of querying is actual querying. Most often, you will operate on records of tables without using any advanced relational concepts. This is called CRUD for

- Create ([INSERT](#insert-statement))
- Read ([SELECT](#select-statement))
- Update ([UPDATE](#update-statement))
- Delete ([DELETE](#delete-statement))

CRUD always uses the same patterns, regardless of the nature of underlying tables. This again, leads to a lot of boilerplate code, if you have to issue your statements yourself. Like Hibernate / JPA and other ORMs, jOOQ facilitates CRUD using a specific API involving [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) types.

#### Primary keys and updatability

In normalised databases, every table has a primary key by which a tuple/record within that table can be uniquely identified. In simple cases, this is a (possibly auto-generated) number called ID. But in many cases, primary keys include several non-numeric columns. An important feature of such keys is the fact that in most databases, they are enforced using an index that allows for very fast random access to the table. A typical way to access / modify / delete a book is this:

```sql
-- Inserting uses a previously generated key value or generates it afresh
INSERT INTO BOOK (ID, TITLE) VALUES (5, 'Animal Farm');

-- Other operations can use a previously generated key value
SELECT * FROM BOOK WHERE ID = 5;
UPDATE BOOK SET TITLE = '1984' WHERE ID = 5;
DELETE FROM BOOK WHERE ID = 5;
```

Normalised databases assume that a primary key is unique "forever", i.e. that a key, once inserted into a table, will never be changed or re-inserted after deletion. In order to use jOOQ's [CRUD](#simple-crud) operations correctly, you should design your database accordingly.

<a id="simple-crud"></a>
#### 4.13.1. Simple CRUD

If you're using jOOQ's [code generator](#code-generation), it will generate [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) implementations for every table that has a primary key. When [fetching](#fetching) such a record form the database, these records are "attached" to the [Configuration](#dsl-context) that created them. This means that they hold an internal reference to the same database connection that was used to fetch them. This connection is used internally by any of the following methods of the UpdatableRecord:

```java
// Refresh a record from the database.
void refresh() throws DataAccessException;

// Store (insert or update) a record to the database.
int store() throws DataAccessException;

// Delete a record from the database
int delete() throws DataAccessException;
```

See the manual's section about [serializability](#serializability) for some more insight on "attached" objects.

<a id="crud-store"></a>
##### 4.13.1.1. CRUD: Store

Storing an [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) will perform a [INSERT](#crud-insert) or an [UPDATE](#crud-update) operation on the record. In general, new records are always inserted, whereas records fetched from the database are always updated.

This is best visualised in code:

```java
// Create a new record
BookRecord book1 = create.newRecord(BOOK);

// Insert the record: INSERT INTO BOOK (TITLE) VALUES ('1984');
book1.setTitle("1984");
book1.store();

// Update the record: UPDATE BOOK SET PUBLISHED_IN = 1984 WHERE ID = :id
book1.setPublishedIn(1948);
book1.store();

// Get the (possibly) auto-generated ID from the record
Integer id = book1.getId();

// Get another instance of the same book
BookRecord book2 = create.fetchOne(BOOK, BOOK.ID.eq(id));

// Update the record: UPDATE BOOK SET TITLE = 'Animal Farm' WHERE ID = :id
book2.setTitle("Animal Farm");
book2.store();
```

Some remarks about storing:

- jOOQ sets only modified values in [INSERT statements](#insert-statement) or [UPDATE statements](#update-statement). This allows for default values to be applied to inserted records, as specified in CREATE TABLE DDL statements.
- When `store()` performs an [INSERT statement](#insert-statement), jOOQ attempts to load any generated keys from the database back into the record. For more details, see the manual's section about [IDENTITY values](#identity-values).
- In addition to loading identity values, `store()` can also be configured to refresh the entire record. See [the returnAllOnUpdatableRecord setting](#settings-return-all-on-store) for details
- When loading records from [POJOs](#pojos), jOOQ will assume the record is a new record. It will hence attempt to INSERT it.
- When you activate [optimistic locking](#optimistic-locking), storing a record may fail, if the underlying database record has been changed in the mean time.

<a id="crud-insert"></a>
##### 4.13.1.2. CRUD: Insert

Calling [`UpdatableRecord.insert()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#insert()) will execute the same logic as [store()](#crud-store), but will enforce the `INSERT` behaviour regardless if the record was previously fetched from the database or not.

```java
// Create a new record
BookRecord book = create.newRecord(BOOK);

// Insert the record: INSERT INTO BOOK (TITLE) VALUES ('1984');
book.setTitle("1984");
book.insert();
```

> [!TIP]
> Unlike most other [CRUD](#simple-crud) operations, `INSERT` does not rely on the presence of a primary key, so it is also available for any other [`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html).

<a id="crud-update"></a>
##### 4.13.1.3. CRUD: Update

Calling [`UpdatableRecord.update()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#update()) will execute the same logic as [store()](#crud-store), but will enforce the `UPDATE` behaviour regardless if the record was previously fetched from the database or not.

```java
// Create a new record
BookRecord book = create.newRecord(BOOK);

// Set the primary key value of the record, but exclude it from the UPDATE .. SET clause
book.setId(1);
book.touched(false);

// Update the record: UPDATE BOOK SET PUBLISHED_IN = 1984 WHERE ID = :id
book1.setPublishedIn(1948);
book1.update();
```

<a id="crud-delete"></a>
##### 4.13.1.4. CRUD: Delete

An [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) can be deleted simply by calling [`UpdatableRecord.delete()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html#delete())

```java
// Get a book
BookRecord book = create.fetchOne(BOOK, BOOK.ID.eq(id));

// Delete the record: DELETE FROM BOOK WHERE ID = :id
book.delete();
```

<a id="crud-merge"></a>
##### 4.13.1.5. CRUD: Merge

A `MERGE` (or `UPSERT`) operation can be executed on an [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) when it is created in the client irrespective of whether the corresponding record already exists in the database. If it does not exist, the operation will have `INSERT` semantics. If it does exist, it will have `UPDATE` semantics.

This is different from [store()](#crud-store) as the decision will be made in the database, not in the client.

```java
// Create a new record
BookRecord book = create.newRecord(BOOK);

// Merge the record: 
// INSERT INTO BOOK (ID, TITLE)
// VALUES (1, '1984')
// ON CONFLICT (ID)
// DO UPDATE SET TITLE = excluded.TITLE
book.setId(1)
book.setTitle("1984");
book.merge();
```

Some variant of [INSERT .. ON DUPLICATE KEY UPDATE](#insert-on-duplicate-key) will be executed, or its emulation via [INSERT .. ON CONFLICT](#insert-on-conflict) or [MERGE](#merge-statement).

<a id="crud-refresh"></a>
##### 4.13.1.6. CRUD: Refresh

An [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) can be refreshed in case its client state is no longer in sync with the database state.

```java
// Get a book
BookRecord book = create.fetchOne(BOOK, BOOK.ID.eq(id));

// Refresh the record: SELECT * FROM BOOK WHERE ID = :id;
book.refresh();
```

<a id="internal-flags"></a>
#### 4.13.2. Record internal flags and dirty tracking

All of jOOQ's [Record types and subtypes](#record-vs-tablerecord) maintain an internal state for every column value. This state is composed of three elements:

- [`Record.get(Field)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#get(org.jooq.Field)): The value itself.
- [`Record.original(Field)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#original(org.jooq.Field)): The "original" value, i.e. the value as it was originally fetched from the database or `null`, if the record was never in the database.
- [`Record.touched(Field)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#touched(org.jooq.Field)): The "touched" flag, indicating if the value was ever touched (or modified) through the `Record` API. This is used for dirty tracking.
- [`Record.modified(Field)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#modified(org.jooq.Field)): The "modified" flag, indicating if the value was ever modified through the `Record` API. This can be used as an [alternative for dirty tracking](#settings-dirty-tracking).

An additional operation is available on records in order to reset a value to its original, as well as to reset the touched or changed flag:

- [`Record.reset(Field)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#reset(org.jooq.Field)): Reset the value to its "original" value.

The purpose of the above information is for jOOQ's [CRUD operations](#simple-crud) to know, which values need to be stored back to the database, and which values have been left untouched or unmodified, respectively.

<a id="identity-values"></a>
#### 4.13.3. IDENTITY values

Many databases support the concept of IDENTITY values, or [SEQUENCE-generated](#sequence-execution) key values. This is reflected by JDBC's [`getGeneratedKeys()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#getGeneratedKeys()) method. jOOQ abstracts using this method as many databases and JDBC drivers behave differently with respect to generated keys. Let's assume the following SQL Server BOOK table:

```sql
CREATE TABLE book (
  ID INTEGER IDENTITY(1,1) NOT NULL,

  -- [...]

  CONSTRAINT pk_book PRIMARY KEY (id)
)
```

If you're using jOOQ's [code generator](#code-generation), the above table will generate a [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) with an IDENTITY column. This information is used by jOOQ internally, to update IDs after calling [store()](#crud-with-updatablerecords):

```java
BookRecord book = create.newRecord(BOOK);
book.setTitle("1984");
book.store();

// The generated ID value is fetched after the above INSERT statement
System.out.println(book.getId());
```

##### Database compatibility

**DB2, Derby, HSQLDB, Ingres**

These SQL dialects implement the standard very neatly.

```sql
id INTEGER GENERATED BY DEFAULT AS IDENTITY
id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1)
```

**H2, MySQL, Postgres, SQL Server, Sybase ASE, Sybase SQL Anywhere**

These SQL dialects implement identities, but the DDL syntax doesn’t follow the standard

```sql
-- H2 mimics MySQL's and SQL Server's syntax
ID INTEGER IDENTITY(1,1)
ID INTEGER AUTO_INCREMENT
-- MySQL and SQLite
ID INTEGER NOT NULL AUTO_INCREMENT

-- Postgres serials implicitly create a sequence
-- Postgres also allows for selecting from custom sequences
-- That way, sequences can be shared among tables
id SERIAL NOT NULL

-- SQL Server
ID INTEGER IDENTITY(1,1) NOT NULL
-- Sybase ASE
id INTEGER IDENTITY NOT NULL
-- Sybase SQL Anywhere
id INTEGER NOT NULL IDENTITY
```

For databases where IDENTITY columns are only emulated (e.g. Oracle prior to 12c), the jOOQ generator can also be configured to generate [synthetic identities](#codegen-database-synthetic-ids).

<a id="navigation-methods"></a>
#### 4.13.4. Navigation methods

[`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html) and [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) contain foreign key navigation methods. These navigation methods allow for "navigating" inbound or outbound foreign key references by executing an appropriate query. An example is given here:

```sql
CREATE TABLE book (
  AUTHOR_ID NUMBER(7) NOT NULL,

  -- [...]

  FOREIGN KEY (AUTHOR_ID) REFERENCES author(ID)
)
```

```java
BookRecord book = create.fetch(BOOK, BOOK.ID.eq(5));

// Find the author of a book (static imported from Keys)
AuthorRecord author = book.fetchParent(FK_BOOK_AUTHOR);

// Find other books by that author
Result<BookRecord> books = author.fetchChildren(FK_BOOK_AUTHOR);
```

These fetch methods only work on "attached" records. See the manual's section about [serializability](#serializability) for some more insight on "attached" objects.

> [!TIP]
> While navigation methods can be occasionally useful to fetch additional data based on previously fetched data, using these methods extensively will quickly lead to [N+1 problems](#dont-do-this-n-plus-one), where way too many individual queries are run against the database instead of fetching all necessary data eagerly using [JOIN](#joined-tables) or [MULTISET](#multiset-value-constructor).

<a id="non-updatable-records"></a>
#### 4.13.5. Non-updatable records

Tables without a `PRIMARY KEY` are considered non-updatable by jOOQ, as jOOQ has no way of uniquely identifying such a record within the database. If you're using jOOQ's [code generator](#code-generation), such tables will generate [`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html) classes, instead of [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) classes. The following operations are not possible on `TableRecords`:

- [store()](#crud-store)
- [update()](#crud-update)
- [delete()](#crud-delete)
- [merge()](#crud-merge)
- [refresh()](#crud-refresh)

Only this operation is possible, as it does not rely on any `PRIMARY KEY` being present:

- [insert()](#crud-insert)

Note, that some databases use internal rowid or object-id values to identify such records. jOOQ does not support these vendor-specific record meta-data.

<a id="optimistic-locking"></a>
#### 4.13.6. Optimistic locking

jOOQ allows you to perform [CRUD](#crud-with-updatablerecords) operations using optimistic locking. You can immediately take advantage of this feature by activating the relevant [executeWithOptimisticLocking Setting](#custom-settings). Without any further knowledge of the underlying data semantics, this will have the following impact on store() and delete() methods:

- INSERT statements are not affected by this Setting flag
- Prior to UPDATE or DELETE statements, jOOQ will run a [SELECT .. FOR UPDATE](#for-update-clause) statement, pessimistically locking the record for the subsequent UPDATE / DELETE
- The data fetched with the previous SELECT will be compared against the data in the record being stored or deleted
- An [`org.jooq.exception.DataChangedException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataChangedException.html) is thrown if the record had been modified or deleted in the meantime, or if optimistic locking is performed on an unversioned record that hasn't been fetched from the database.
- The record is successfully stored / deleted, if the record had not been modified in the mean time.

The above changes to jOOQ's behaviour are transparent to the API, the only thing you need to do for it to be activated is to set the Settings flag. Here is an example illustrating optimistic locking:

```java
// Properly configure the DSLContext
DSLContext optimistic = DSL.using(connection, SQLDialect.ORACLE,
  new Settings().withExecuteWithOptimisticLocking(true));

// Fetch a book two times
BookRecord book1 = optimistic.fetchOne(BOOK, BOOK.ID.eq(5));
BookRecord book2 = optimistic.fetchOne(BOOK, BOOK.ID.eq(5));

// Change the title and store this book. The underlying database record has not been modified, it can be safely updated.
book1.setTitle("Animal Farm");
book1.store();

// Book2 still references the original TITLE value, but the database holds a new value from book1.store().
// This store() will thus fail:
book2.setTitle("1984");
book2.store();
```

##### Optimised optimistic locking using TIMESTAMP fields

If you're using jOOQ's [code generator](#code-generation), you can take indicate TIMESTAMP or UPDATE COUNTER fields for every generated table in the [code generation configuration](#codegen-advanced). Let's say we have this table:

```sql
CREATE TABLE book (

  -- This column indicates when each book record was modified for the last time
  MODIFIED TIMESTAMP NOT NULL,
  -- [...]
)
```

The MODIFIED column will contain a timestamp indicating the last modification timestamp for any book in the BOOK table. If you're using jOOQ and it's [store() methods on UpdatableRecords](#crud-with-updatablerecords), jOOQ will then generate this TIMESTAMP value for you, automatically. However, instead of running an additional [SELECT .. FOR UPDATE](#for-update-clause) statement prior to an UPDATE or DELETE statement, jOOQ adds a WHERE-clause to the UPDATE or DELETE statement, checking for TIMESTAMP's integrity. This can be best illustrated with an example:

```java
// Properly configure the DSLContext
DSLContext optimistic = DSL.using(connection, SQLDialect.ORACLE,
  new Settings().withExecuteWithOptimisticLocking(true));

// Fetch a book two times
BookRecord book1 = optimistic.fetchOne(BOOK, BOOK.ID.eq(5));
BookRecord book2 = optimistic.fetchOne(BOOK, BOOK.ID.eq(5));

// Change the title and store this book. The MODIFIED value has not been changed since the book was fetched.
// It can be safely updated
book1.setTitle("Animal Farm");
book1.store();

// Book2 still references the original MODIFIED value, but the database holds a new value from book1.store().
// This store() will thus fail:
book2.setTitle("1984");
book2.store();
```

As before, without the added TIMESTAMP column, optimistic locking is transparent to the API.

##### Optimised optimistic locking using VERSION fields

Instead of using TIMESTAMPs, you may also use numeric VERSION fields, containing version numbers that are incremented by jOOQ upon store() calls.

Note, for explicit pessimistic locking, please consider the manual's section about the [FOR UPDATE clause](#for-update-clause). For more details about how to configure TIMESTAMP or VERSION fields, consider the manual's section about [advanced code generator configuration](#codegen-advanced).

<a id="batch-execution-for-crud"></a>
#### 4.13.7. Batch execution

When inserting, updating, deleting a lot of records, you may wish to profit from JDBC batch operations, which can be performed by jOOQ. These are available through jOOQ's [DSLContext](#dsl-context) as shown in the following example:

```java
// Fetch a bunch of books
Result<BookRecord> books = create.fetch(BOOK);

// Modify the above books, and add some new ones:
modify(books);
addMore(books);

// Batch-update and/or insert all of the above books
create.batchStore(books).execute();
```

Internally, jOOQ will render all the required SQL statements and execute them as a regular [JDBC batch execution](#batch-execution).

<a id="crud-record-listener"></a>
#### 4.13.8. RecordListener SPI

When performing CRUD, you may want to be able to centrally register one or several listener objects that receive notification every time CRUD is performed on an [UpdatableRecord](#crud-with-updatablerecords). Example use cases of such a listener are:

- Adding a central ID generation algorithm, generating UUIDs for all of your records.
- Adding a central record initialisation mechanism, preparing the database prior to inserting a new record.

An example of such a `RecordListener` is given here:

```java
public class InsertListener implements RecordListener {

    @Override
    public void insertStart(RecordContext ctx) {

        // Generate an ID for inserted BOOKs
        if (ctx.record() instanceof BookRecord) {
            BookRecord book = (BookRecord) ctx.record();
            book.setId(IDTools.generate());
        }
    }
}
```

Now, configure jOOQ's runtime to load your listener

```java
// Create a configuration with an appropriate listener provider:
Configuration configuration = new DefaultConfiguration().set(connection).set(dialect);
configuration.set(new DefaultRecordListenerProvider(new InsertListener()));

// Create a DSLContext from the above configuration
DSLContext create = DSL.using(configuration);
```

Alternatively, just pass a lambda to a `RecordListener` constructor

```java
// Create a configuration with an appropriate listener provider:
Configuration configuration = new DefaultConfiguration().set(connection).set(dialect);
configuration.set(RecordListener.onInsertStart(ctx -> {

    // Generate an ID for inserted BOOKs
    if (ctx.record() instanceof BookRecord) {
        BookRecord book = (BookRecord) ctx.record();
        book.setId(IDTools.generate());
    }
}));

// Create a DSLContext from the above configuration
DSLContext create = DSL.using(configuration);
```

For a full documentation of what `RecordListener` can do, please consider the [`RecordListener Javadoc`](https://www.jooq.org/javadoc/3.22.x/org/jooq/RecordListener.html). Note that `RecordListener` instances can be registered with a [Configuration](#dsl-context) independently of [ExecuteListeners](#execute-listeners).

##### Triggers

A `RecordListener` does not act as a client-side trigger. As such, it does not affect any bulk DML statements (e.g. [UPDATE statement](#update-statement)), whose affected records are not available to clients. For those purposes, use a server-side trigger(see [CREATE TRIGGER](#create-trigger-statement)) if records should be changed, or a [`org.jooq.VisitListener`](https://www.jooq.org/javadoc/3.22.x/org/jooq/VisitListener.html) if the SQL query should be changed independently of data.

<a id="daos"></a>
### 4.14. DAOs

If you're using jOOQ's [code generator](#code-generation), you can configure it to generate [POJOs](#codegen-pojos) and [DAOs](#codegen-daos) for you. jOOQ then generates one DAO per [UpdatableRecord](#crud-with-updatablerecords), i.e. per table with a single-column primary key. Generated DAOs implement a common jOOQ type called [`org.jooq.DAO`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DAO.html).

> [!TIP]
> If you're used to working Spring Repositories, you may think this looks similar and you may be tempted to build everything using the [`org.jooq.DAO`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DAO.html) API. Beware that these DAOs (just like repositories) are very simple and dumb APIs granting access to the most trivial single-table based CRUD operations only. They quickly fail to help with more complex database interactions, for which the [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) or even better, actual SQL statements, would be much more suitable. As such, the [`org.jooq.DAO`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DAO.html) API may be one of the most controversial parts of the jOOQ API, which you can see also in this discussion: [#5984](https://github.com/jOOQ/jOOQ/issues/5984). The official recommendation is to use the DAO type only sparingly.

This type contains the following methods:

```java
// <R> corresponds to the DAO's related table
// <P> corresponds to the DAO's related generated POJO type
// <T> corresponds to the DAO's related table's primary key type.
// Note that multi-column primary keys are not yet supported by DAOs
public interface DAO<R extends TableRecord<R>, P, T> {

    // These methods allow for inserting POJOs
    void insert(P object) throws DataAccessException;
    void insert(P... objects) throws DataAccessException;
    void insert(Collection<P> objects) throws DataAccessException;

    // These methods allow for updating POJOs based on their primary key
    void update(P object) throws DataAccessException;
    void update(P... objects) throws DataAccessException;
    void update(Collection<P> objects) throws DataAccessException;

    // These methods allow for deleting POJOs based on their primary key
    void delete(P... objects) throws DataAccessException;
    void delete(Collection<P> objects) throws DataAccessException;
    void deleteById(T... ids) throws DataAccessException;
    void deleteById(Collection<T> ids) throws DataAccessException;

    // These methods allow for checking record existence
    boolean exists(P object) throws DataAccessException;
    boolean existsById(T id) throws DataAccessException;
    long count() throws DataAccessException;

    // These methods allow for retrieving POJOs by primary key or by some other field
    List<P> findAll() throws DataAccessException;
    P findById(T id) throws DataAccessException;
    <Z> List<P> fetch(Field<Z> field, Z... values) throws DataAccessException;
    <Z> P fetchOne(Field<Z> field, Z value) throws DataAccessException;

    // These methods provide DAO meta-information
    Table<R> getTable();
    Class<P> getType();
}
```

Besides these base methods, generated DAO classes implement various useful fetch methods. An incomplete example is given here, for the BOOK table:

```java
// An example generated BookDao class
public class BookDao extends DAOImpl<BookRecord, Book, Integer> {

    // Columns with primary / unique keys produce fetchOne() methods
    public Book fetchOneById(Integer value) { ... }

    // Other columns produce fetch() methods, returning several records
    public List<Book> fetchByAuthorId(Integer... values) { ... }
    public List<Book> fetchByTitle(String... values) { ... }
}
```

Note that you can further subtype those pre-generated DAO classes, to add more useful DAO methods to them. Using such a DAO is simple:

```java
// Initialise an Configuration
Configuration configuration = new DefaultConfiguration().set(connection).set(SQLDialect.ORACLE);

// Initialise the DAO with the Configuration
BookDao bookDao = new BookDao(configuration);

// Start using the DAO
Book book = bookDao.findById(5);

// Modify and update the POJO
book.setTitle("1984");
book.setPublishedIn(1948);
bookDao.update(book);

// Delete it again
bookDao.delete(book);
```

<a id="transaction-management"></a>
### 4.15. Transaction management

jOOQ can work with any pre-existing transaction model (e.g. JDBC, Spring, Jakarta EE), or alternatively, offers its own convenience transaction API. In particular:

- You can use third-party transaction management libraries like Spring TX
- You can use a JTA-compliant Java EE transaction manager from your container.
- You can call JDBC's [`Connection.commit()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html#commit()), [`Connection.rollback()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html#rollback()) and other methods on your JDBC driver, or use the equivalent methods on your [R2DBC](https://r2dbc.io/) driver.
- You can issue vendor-specific `COMMIT`, `ROLLBACK` and other statements directly in your database. See [the section about transactional statements for more details](#transactional-statements).
- You use jOOQ's transaction API.

> [!TIP]
> When using Spring Boot, its jOOQ starter already pre-configures the correct Spring transaction aware data source, so Spring JDBC transactions will work out of the box with jOOQ.

While jOOQ does not aim to replace any of the above, it offers a simple API (and a corresponding SPI) to provide you with jOOQ-style programmatic fluency to express your transactions. Below are some Java examples showing how to implement (nested) transactions with jOOQ. For these examples, we're using Java 8 syntax. Java 8 is not a requirement, though.

**Blocking (JDBC):**

```java
create.transaction((Configuration trx) -> {
    AuthorRecord author =
    trx.dsl()
       .insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
       .values("George", "Orwell")
       .returning()
       .fetchOne();

    trx.dsl()
       .insertInto(BOOK, BOOK.AUTHOR_ID, BOOK.TITLE)
       .values(author.getId(), "1984")
       .values(author.getId(), "Animal Farm")
       .execute();

    // Implicit commit executed here
});
```

**Non blocking (R2DBC):**

```java
// Examples use reactor, but you can use any other RS API, too
create.transactionPublisher((Configuration trx) -> Mono
    .from(trx.dsl()
        .insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
        .values("George", "Orwell")
        .returning())
    .flatMap((AuthorRecord author) -> trx.dsl()
        .insertInto(BOOK, BOOK.AUTHOR_ID, BOOK.TITLE)
        .values(author.getId(), "1984")
        .values(author.getId(), "Animal Farm"))

    // Implicit commit executed here
});
```

Note how the lambda expression receives a new, *derived* configuration which should be used within the local scope:

**Blocking (JDBC):**

```java
create.transaction((Configuration trx) -> {

    // Wrap configuration in a new DSLContext:
    trx.dsl().insertInto(...);
    trx.dsl().insertInto(...);

    // Or, reuse the new DSLContext within the transaction scope:
    DSLContext ctx = trx.dsl();
    ctx.insertInto(...);
    ctx.insertInto(...);

    // ... but avoid using the scope from outside the transaction:
    create.insertInto(...);
    create.insertInto(...);
});
```

**Non blocking (R2DBC):**

```java
create.transactionPublisher((Configuration trx) -> {

    // Wrap configuration in a new DSLContext:
    trx.dsl().insertInto(...);
    trx.dsl().insertInto(...);

    // Or, reuse the new DSLContext within the transaction scope:
    DSLContext ctx = trx.dsl();
    ctx.insertInto(...);
    ctx.insertInto(...);

    // ... but avoid using the scope from outside the transaction:
    create.insertInto(...);
    create.insertInto(...);
});
```

#### Rollbacks

Any uncaught checked or unchecked exception thrown from your transactional code (blocking), or unhandled error in a reactive stream (non-blocking) will rollback the transaction to the beginning of the transactional scope. This behaviour will allow for nesting transactions, if your configured [`org.jooq.TransactionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TransactionProvider.html) supports nesting of transactions. An example can be seen here:

**Blocking (JDBC):**

```java
create.transaction((Configuration outer) -> {
    final AuthorRecord author =
    outer.dsl()
       .insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
       .values("George", "Orwell")
       .returning()
       .fetchOne();

    // Implicit savepoint created here
    try {
        outer.dsl()
           .transaction((Configuration nested) -> {
               nested.dsl()
                  .insertInto(BOOK, BOOK.AUTHOR_ID, BOOK.TITLE)
                  .values(author.getId(), "1984")
                  .values(author.getId(), "Animal Farm")
                  .execute();

            // Rolls back the nested transaction
            if (oops)
                throw new RuntimeException("Oops");

            // Implicit savepoint is discarded, but no commit is issued yet.
        });
    }
    catch (RuntimeException e) {

        // We can decide whether an exception is "fatal enough" to roll back also the outer transaction
        if (isFatal(e))

            // Rolls back the outer transaction
            throw e;
    }

    // Implicit commit executed here
});
```

**Non blocking (R2DBC):**

```java
// Examples use reactor, but you can use any other RS API, too
create.transactionPublisher((Configuration outer) -> Mono
    .from(outer.dsl()
        .insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
        .values("George", "Orwell")
        .returning())
    .flatMap((AuthorRecord author) -> outer.dsl()

        // Implicit savepoint created here
        .transactionPublisher((Configuration nested) -> Mono
            .from(nested.dsl()
                .insertInto(BOOK, BOOK.AUTHOR_ID, BOOK.TITLE)
                .values(author.getId(), "1984")
                .values(author.getId(), "Animal Farm"))

            // Rolls back the nested transaction
            .<Integer>flatMap(i -> {
                throw new RuntimeException("Oops");
            }))

        // Implicit savepoint is discarded, but no commit is issued yet.
        .onErrorContinue((e, a) -> {
            log.info(e);
        }))

// Implicit commit executed here
);
```

#### Blocking only API considerations

While some [`org.jooq.TransactionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TransactionProvider.html) implementations (e.g. ones based on ThreadLocals, e.g. Spring or JTA) may allow you to reuse the globally scoped [DSLContext](#dsl-context) reference, the jOOQ transaction API design allows for `TransactionProvider` implementations that require your transactional code to use the new, locally scoped `Configuration`, instead.

Transactional code is wrapped in jOOQ's [`org.jooq.TransactionalRunnable`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TransactionalRunnable.html) or [`org.jooq.TransactionalCallable`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TransactionalCallable.html) types:

```java
public interface TransactionalRunnable {
    void run(Configuration configuration) throws Exception;
}

public interface TransactionalCallable<T> {
    T run(Configuration configuration) throws Exception;
}
```

Such transactional code can be passed to [`transaction(TransactionRunnable)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#transaction(org.jooq.TransactionalRunnable)) or [`transactionResult(TransactionCallable)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#transactionResult(org.jooq.TransactionalCallable)) methods. An example using `transactionResult()`:

```java
int updateCount = create.transactionResult(configuration -> {
    int result = 0;

    DSLContext ctx = DSL.using(configuration);
    result += ctx.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).values("John", "Doe").execute();
    result += ctx.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).values("Jane", "Doe").execute();

    return result;
});
```

#### TransactionProvider implementations

By default, jOOQ ships with the [`org.jooq.impl.DefaultTransactionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultTransactionProvider.html), which implements nested transactions using JDBC [`java.sql.Savepoint`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Savepoint.html). Spring Boot will configure an alternative `TransactionProvider` that should work for most use-cases. You can, however, still implement your own [`org.jooq.TransactionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TransactionProvider.html) and supply that to your [Configuration](#dsl-context) to override jOOQ's default behaviour. A simple example implementation using Spring's `DataSourceTransactionManager` can be seen here:

```java
import static org.springframework.transaction.TransactionDefinition.PROPAGATION_NESTED;

import org.jooq.Transaction;
import org.jooq.TransactionContext;
import org.jooq.TransactionProvider;
import org.jooq.tools.JooqLogger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class SpringTransactionProvider implements TransactionProvider {

    private static final JooqLogger log = JooqLogger.getLogger(SpringTransactionProvider.class);

    @Autowired
    DataSourceTransactionManager txMgr;

    @Override
    public void begin(TransactionContext ctx) {
        log.info("Begin transaction");

        // This TransactionProvider behaves like jOOQ's DefaultTransactionProvider,
        // which supports nested transactions using Savepoints
        TransactionStatus tx = txMgr.getTransaction(new DefaultTransactionDefinition(PROPAGATION_NESTED));
        ctx.transaction(new SpringTransaction(tx));
    }

    @Override
    public void commit(TransactionContext ctx) {
        log.info("commit transaction");

        txMgr.commit(((SpringTransaction) ctx.transaction()).tx);
    }

    @Override
    public void rollback(TransactionContext ctx) {
        log.info("rollback transaction");

        txMgr.rollback(((SpringTransaction) ctx.transaction()).tx);
    }
}

class SpringTransaction implements Transaction {
    final TransactionStatus tx;

    SpringTransaction(TransactionStatus tx) {
        this.tx = tx;
    }
}
```

<a id="exception-handling"></a>
### 4.16. Exception handling

#### Checked vs. unchecked exceptions

Pros and cons have been discussed time and again, and it is mostly still a matter of taste, today. In this topic, jOOQ clearly takes a side. jOOQ's exception strategy is simple:

- All "system exceptions" are unchecked. If in the middle of a transaction involving business logic, there is no way that you can recover sensibly from a lost database connection, or a constraint violation that indicates a bug in your understanding of your database model.
- All "business exceptions" are checked. Business exceptions are true exceptions that you should handle (e.g. not enough funds to complete a transaction). Other languages may have [union types or monads](https://blog.jooq.org/javas-checked-exceptions-are-just-weird-union-types/) to implement the same behaviour, minus the control flow implications of exceptions.

With jOOQ, it's simple. All of jOOQ's exceptions are "system exceptions", hence they are all unchecked.

#### jOOQ's DataAccessException

jOOQ uses its own [`org.jooq.exception.DataAccessException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataAccessException.html) to wrap any underlying [`java.sql.SQLException`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/SQLException.html) that might have occurred. Note that most methods in jOOQ that may cause such a DataAccessException document this both in the Javadoc as well as in their method signature, even if this isn't a requirement for unchecked exceptions in the Java language.

DataAccessException is subtyped several times as follows:

- [`ConfigurationException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/ConfigurationException.html): The [`org.jooq.Configuration`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Configuration.html) was set up in a way that does not allow for a particular operation.
- [`DataAccessException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataAccessException.html): General exception usually originating from a [`java.sql.SQLException`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/SQLException.html)
- [`DataChangedException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataChangedException.html): An exception indicating that the database's underlying record has been changed in the mean time (see [optimistic locking](#optimistic-locking))
- [`DataDefinitionException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataDefinitionException.html): An exception occurred when [interpreting DDL statements](#sql-interpreter).
- [`DataTypeException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataTypeException.html): Something went wrong during type conversion
- [`DataException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataException.html): jOOQ's equivalent to JDBC's [`java.sql.SQLDataException`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/SQLDataException.html).
- [`DetachedException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DetachedException.html): A SQL statement was executed on a "detached" [UpdatableRecord](#crud-with-updatablerecords) or a "detached" [SQL statement](#sql-statements).
- [`IntegrityConstraintViolationException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/IntegrityConstraintViolationException.html): jOOQ's equivalent to JDBC's [`java.sql.SQLIntegrityConstraintViolationException`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/SQLIntegrityConstraintViolationException.html).
- [`InvalidResultException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/InvalidResultException.html): An operation was performed expecting only one result, but several results were returned.
- [`LoaderConfigurationException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/LoaderConfigurationException.html): The [Loader API](#importing-api) was executed with an illegal loader configuration.
- [`MappingException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/MappingException.html): Something went wrong when loading a record from a [POJO](#pojos) or when mapping a record into a POJO
- [`NoDataFoundException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/NoDataFoundException.html): No rows were returned from an [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) when exactly one row was expected.
- [`TemplatingException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/TemplatingException.html): An exception occurred when doing [plain SQL templating](#plain-sql-templating-language).
- [`TooManyRowsException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/TooManyRowsException.html): More than one rows were returned from an [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html) when at most one row was expected.

#### Override jOOQ's exception handling

The following section about [execute listeners](#execute-listeners) documents means of overriding jOOQ's exception handling, if you wish to deal separately with some types of constraint violations, or if you raise business errors from your database, etc.

<a id="execute-listeners"></a>
### 4.17. ExecuteListeners

The [Configuration](#dsl-context) lets you specify a list of [`org.jooq.ExecuteListener`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ExecuteListener.html) instances. The ExecuteListener is essentially an event listener for Query, Routine, or ResultSet render, prepare, bind, execute, fetch steps. It is a base type for loggers, debuggers, profilers, data collectors, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods.

#### Example: Query statistics ExecuteListener

Here is a sample implementation of an ExecuteListener, that is simply counting the number of queries per type that are being executed using jOOQ:

```java
package com.example;

public class StatisticsListener implements ExecuteListener {

    /**
     * Generated UID
     */
    private static final long                     serialVersionUID = 7399239846062763212L;

    public static final Map<ExecuteType, Integer> STATISTICS       = new ConcurrentHashMap<>();

    @Override
    public void start(ExecuteContext ctx) {
        STATISTICS.compute(ctx.type(), (k, v) -> v == null ? 1 : v + 1);
    }
}
```

Now, configure jOOQ's runtime to load your listener

```java
// Create a configuration with an appropriate listener provider:
Configuration configuration = new DefaultConfiguration().set(connection).set(dialect);
configuration.set(new DefaultExecuteListenerProvider(new StatisticsListener()));

// Create a DSLContext from the above configuration
DSLContext create = DSL.using(configuration);
```

And log results any time with a snippet like this:

```java
log.info("STATISTICS");
log.info("----------");

for (ExecuteType type : ExecuteType.values()) {
    log.info(type.name(), StatisticsListener.STATISTICS.get(type) + " executions");
}
```

This may result in the following log output:

```
15:16:52,982  INFO - TEST STATISTICS
15:16:52,982  INFO - ---------------
15:16:52,983  INFO - READ                     : 919 executions
15:16:52,983  INFO - WRITE                    : 117 executions
15:16:52,983  INFO - DDL                      : 2 executions
15:16:52,983  INFO - BATCH                    : 4 executions
15:16:52,983  INFO - ROUTINE                  : 21 executions
15:16:52,983  INFO - OTHER                    : 30 executions
```

Please read the [`ExecuteListener Javadoc`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ExecuteListener.html) for more details

#### Example: Custom Logging ExecuteListener

The following depicts an example of a custom ExecuteListener, which pretty-prints all queries being executed by jOOQ to stdout:

```java
import org.jooq.DSLContext;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
import org.jooq.conf.Settings;
import org.jooq.tools.StringUtils;

public class PrettyPrinter implements ExecuteListener {

    /**
     * Hook into the query execution lifecycle before executing queries
     */
    @Override
    public void executeStart(ExecuteContext ctx) {

        // Create a new DSLContext for logging rendering purposes
        // This DSLContext doesn't need a connection, only the SQLDialect...
        DSLContext create = DSL.using(ctx.dialect(),

        // ... and the flag for pretty-printing
            new Settings().withRenderFormatted(true));

        // If we're executing a query
        if (ctx.query() != null) {
            System.out.println(create.renderInlined(ctx.query()));
        }

        // If we're executing a routine
        else if (ctx.routine() != null) {
            System.out.println(create.renderInlined(ctx.routine()));
        }
    }
}
```

See also the manual's sections about [logging](#logging) for more sample implementations of actual ExecuteListeners.

#### Example: Bad query execution ExecuteListener

You can also use ExecuteListeners to interact with your SQL statements, for instance when you want to check if executed [UPDATE](#update-statement) or [DELETE](#delete-statement) statements contain a `WHERE` clause. This can be achieved trivially with the following sample ExecuteListener:

```java
public class DeleteOrUpdateWithoutWhereListener implements ExecuteListener {

    @Override
    public void renderEnd(ExecuteContext ctx) {
        if (ctx.sql().matches("^(?i:(UPDATE|DELETE)(?!.* WHERE ).*)$")) {
            throw new DeleteOrUpdateWithoutWhereException();
        }
    }
}

public class DeleteOrUpdateWithoutWhereException extends RuntimeException {}
```

You might want to replace the above implementation with a more efficient and more reliable one, of course.

<a id="meta-data"></a>
### 4.18. Database meta data

Not only the code generator, but also the runtime library offers a way to access database meta data. This API is made available as [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html), and it has several implementations, out of the box:

- A JDBC backed implementation querying [`java.sql.DatabaseMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/DatabaseMetaData.html)
- A DDL interpreter backed implementation that parses and interprets a set of DDL scripts
- An XML backed implementation (implementing [https://www.jooq.org/xsd/jooq-meta-3.22.0.xsd](https://www.jooq.org/xsd/jooq-meta-3.22.0.xsd))
- A generated code backed implementation.

The following sections document each one of the above.

<a id="meta-jdbc"></a>
#### 4.18.1. JDBC meta data

This is the default implementation of [Database meta data](#meta-data), which is mainly backed by JDBC's [`java.sql.DatabaseMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/DatabaseMetaData.html), or by custom SQL queries against the database's `INFORMATION_SCHEMA` or vendor-specific dictionary views. If you configure your [DSLContext](#dsl-context) with a JDBC [Connection or DataSource](#connection-vs-datasource), you can access its meta data like this:

```java
create.meta()
      .getTables()
      .forEach(System.out::println);
```

The above may print the tables from our [sample database](#sample-database).

```text
AUTHOR
BOOK
BOOK_STORE
BOOK_TO_BOOK_STORE
LANGUAGE
```

Beware that by default, the entire catalog might be loaded to ensure referential integrity of all tables and their constraints. If you're only interested in a limited subset of your schema, you can use the various filter methods:

```java
create.meta()
      .filterSchema(s -> s.getName().equals("PUBLIC"))
      .getTables()
      .forEach(System.out::println);
```

<a id="meta-interpreter"></a>
#### 4.18.2. Interpreted meta data

jOOQ's [parser](#sql-parser) is used by a DDL interpreter to create an alternative implementation of [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) based on your DDL scripts:

```java
// Using strings:
create.meta(
         "create table a (i int);",
         "create table b (j int);",
         "create table c (k int);"
       )
      .getTables()
      .forEach(System.out::println);

// Using the jOOQ API:
create.meta(
         createTable("a").columns("i", INTEGER),
         createTable("b").columns("j", INTEGER),
         createTable("c").columns("k", INTEGER)
       )
      .getTables()
      .forEach(System.out::println);
```

The above prints all of the tables from the DDL scripts

```text
a
b
c
```

All the meta data is available, including column names, types, constraints, etc.

DDL can be interpreted from strings or from [`org.jooq.Source`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Source.html), which represents any string providing source, including files, input streams, etc.

##### Exporting DDL

Any [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) implementation can be exported back to DDL statements (translated to any dialect!) using [`Meta.ddl()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html#ddl())

<a id="meta-xml"></a>
#### 4.18.3. XML meta data

jOOQ offers a JAXB serialisable XML representation of the standard SQL `INFORMATION_SCHEMA`: [https://www.jooq.org/xsd/jooq-meta-3.22.0.xsd](https://www.jooq.org/xsd/jooq-meta-3.22.0.xsd). This format can be imported and exported as [`org.jooq.util.xml.jaxb.InformationSchema`](https://www.jooq.org/javadoc/3.22.x/org/jooq/util/xml/jaxb/InformationSchema.html), and converted to [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html):

```java
// Using strings:
create.meta(
         "<information_schema>...</information_schema>"
       )
      .getTables()
      .forEach(System.out::println);
```

Alternatively:

```java
// Using JAXB annotated API:
create.meta(informationSchema)
      .getTables()
      .forEach(System.out::println);
```

Assuming the following XML content:

```xml
<information_schema>
   <tables>
      <table>
         <table_name>a</table_name>
         <table_type>BASE TABLE</table_type>
      </table>
      <table>
         <table_name>b</table_name>
         <table_type>BASE TABLE</table_type>
      </table>
      <table>
         <table_name>c</table_name>
         <table_type>BASE TABLE</table_type>
      </table>
   </tables>
   <columns>
      <column>
         <table_name>a</table_name>
         <column_name>i</column_name>
         <data_type>int</data_type>
         <ordinal_position>1</ordinal_position>
         <is_nullable>true</is_nullable>
      </column>
      <column>
         <table_name>b</table_name>
         <column_name>j</column_name>
         <data_type>int</data_type>
         <ordinal_position>1</ordinal_position>
         <is_nullable>true</is_nullable>
      </column>
      <column>
         <table_name>c</table_name>
         <column_name>k</column_name>
         <data_type>int</data_type>
         <ordinal_position>1</ordinal_position>
         <is_nullable>true</is_nullable>
      </column>
   </columns>
</information_schema>
```

The above prints all of the tables from the DDL scripts

```text
a
b
c
```

All the meta data is available, including column names, types, constraints, etc.

XML can also be read from [`org.jooq.Source`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Source.html), which represents any string providing source, including files, input streams, etc.

##### Exporting XML

Any [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) implementation can be exported back to XML using [`Meta.informationSchema()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html#informationSchema()) (the JAXB annotated API, use JAXB to get the XML content).

<a id="meta-generated"></a>
#### 4.18.4. Generated meta data

Generated code already implements the usual meta data API, such as [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html), [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html), etc., but if you need to access the powerful [`org.jooq.Meta`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html) API, e.g. to export DDL or XML, or create a [schema diff](#schema-diff), you can wrap your generated code using:

```java
Meta meta = create.meta(BOOK, AUTHOR);
```

<a id="jdbc-connection"></a>
### 4.19. JDBC Connection

Sometimes, access to the JDBC [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html) is required from code that would otherwise use jOOQ. Your [DSLContext and Configuration](#dsl-context) is configured with a [JDBC Connection or DataSource](#connection-vs-datasource) via a [`org.jooq.ConnectionProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ConnectionProvider.html), but rather than going through those SPIs, you can access (and acquire) a [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html) directly from your `DSLContext`. This can be done easily using [`DSLContext.connection()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#connection(org.jooq.ConnectionRunnable)) or [`DSLContext.connectionResult()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#connectionResult(org.jooq.ConnectionCallable)). Just write:

```java
// When you don't produce any results:
create.connection((Connection c) -> {

    // Modify your JDBC connection or get information from it
    c.setClientInfo("key", "value");

    // Run statements directly with JDBC
    try (Statement s = c.createStatement()) {
        s.executeUpdate("INSERT INTO author (id, first_name, last_name) VALUES (3, 'William', 'Shakespeare')";
    }
});

// When you produce results
int rows = create.connectionResult(c -> {
    try (Statement s = c.createStatement()) {
        return s.executeUpdate("INSERT INTO author (id, first_name, last_name) VALUES (3, 'William', 'Shakespeare')";
    }
});
```

<a id="batched-connection"></a>
### 4.20. Batched Connection

jOOQ supports [JDBC batching](#batch-execution) through dedicated API to explicitly batch some statements, for improved performance. If performance is an "after thought" in some areas of your application, or batching doesn't work well for all environments (or even makes things worse, depending on the dialect), the [`org.jooq.tools.jdbc.BatchedConnection`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/BatchedConnection.html) can be used to transparently buffer all jOOQ (and other JDBC) statements and execute them lazily as batches.

Imagine you might have two services, which produce the following `INSERT` statements behind the scenes:

```java
// "Regular code":
// ---------------
module1.insertSomething(configuration);
module2.insertSomethingElse(configuration);

// The above might generate... (each line is a statement)
// INSERT INTO something (A, B) VALUES (?, ?)
// INSERT INTO something (A, B) VALUES (?, ?)
// INSERT INTO something (A, B) VALUES (?, ?)
// INSERT INTO something (A, B, C) VALUES (?, ?, ?)
// INSERT INTO something (A, B, C) VALUES (?, ?, ?)
// INSERT INTO something (A, B) VALUES (?, ?)
// INSERT INTO something_else (X, Y) VALUES (?, ?)
// INSERT INTO something_else (X, Y) VALUES (?, ?)
// INSERT INTO something_else (X, Y) VALUES (?, ?)
```

The business logic is complex, and you don't want to touch it again, just to improve performance. You can now either wrap your own JDBC connection in a [`org.jooq.tools.jdbc.BatchedConnection`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/BatchedConnection.html), or let jOOQ do that for you by calling [`DSLContext.batched()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#batched-org.jooq.BatchedRunnable-):

```java
// "Batch-collecting code".
// Alternatively, use DSLContext.batchedResult() to return a result from the lambda.
DSL.using(configuration).batched(c -> {
    module1.insertSomething(c);
    module2.insertSomethingElse(c);
});

// The above might now generate... (each line is a batch statement)
// INSERT INTO something (A, B) VALUES (?, ?)       -- With 3 calls to PreparedStatement.addBatch()
// INSERT INTO something (A, B, C) VALUES (?, ?, ?) -- With 2 calls to PreparedStatement.addBatch()
// INSERT INTO something (A, B) VALUES (?, ?)       -- With 1 calls to PreparedStatement.addBatch()
// INSERT INTO something_else (X, Y) VALUES (?, ?)  -- With 2 calls to PreparedStatement.addBatch()
```

Without changing the SQL strings, or the execution sequence, this way, it is now possible to buffer consecutive identical SQL strings and collect their bind values in a single batch.

As soon as any of the following events happens, the buffered batch is executed and a new batch is created:

- The SQL string changes (including "irrelevant" whitespace changes).
- A query producing results is executed.
- A [static statement](#statement-type) (as opposed to a prepared statement) is created.
- The connection is closed, or the transaction committed, or any other such interaction with JDBC is invoked.
- The [batch size](#settings-batch-size) threshold is reached.

#### Limitations

While this approach to batching is transparent to most use-cases, there are some limitations:

- With query execution being delayed, the JDBC [`PreparedStatement#executeUpdate()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html#executeUpdate--) calls cannot produce the correct row count value yet. They always produce `0`, instead, as no rows have (yet) been affected.
- If a query produces results (e.g. ordinary [SELECT statements](#select-statement), or [INSERT .. RETURNING statements](#insert-returning)), batching is prevented.

To track effectively batched statements, turn on [DEBUG logging](#settings-execute-logging).

For more known limitations of this functionality, please refer to [#10692](https://github.com/jOOQ/jOOQ/issues/10692).

<a id="mocking-connection"></a>
### 4.21. Mocking Connection

When writing unit tests for your data access layer, you have probably used some generic mocking tool offered by popular providers like [Mockito](https://site.mockito.org), [jmock](https://jmock.org), [mockrunner](https://mockrunner.github.io), or even [DBUnit](https://www.dbunit.org). With jOOQ, you can take advantage of the built-in JDBC mock API that allows you to emulate a simple database on the JDBC level for precisely those SQL/JDBC use cases supported by jOOQ.

> [!TIP]
> Disclaimer: The general idea of mocking a JDBC connection with this jOOQ API is to provide quick workarounds, injection points, etc. using a very simple JDBC abstraction. It is *NOT RECOMMENDED* to emulate an entire database (including complex state transitions, transactions, locking, etc.) using this mock API. Once you have this requirement, please consider using an actual database product instead for integration testing, rather than implementing your test database inside of a `MockDataProvider`.

#### Mocking the JDBC API

JDBC is a very complex API. It takes a lot of time to write a useful and correct mock implementation, implementing at least these interfaces:

- [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html)
- [`java.sql.Statement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html)
- [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html)
- [`java.sql.CallableStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/CallableStatement.html)
- [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html)
- [`java.sql.ResultSetMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSetMetaData.html)

Optionally, you may even want to implement interfaces, such as [`java.sql.Array`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Array.html), [`java.sql.Blob`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Blob.html), [`java.sql.Clob`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Clob.html), and many others. In addition to the above, you might need to find a way to simultaneously support incompatible JDBC minor versions, such as 4.0, 4.1

#### Using jOOQ's own mock API

This work is greatly simplified, when using jOOQ's own mock API. The `org.jooq.tools.jdbc` package contains all the essential implementations for both JDBC 4.0 and 4.1, which are needed to mock JDBC for jOOQ. In order to write mock tests, provide the jOOQ [Configuration](#dsl-context) with a [`MockConnection`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/MockConnection.html), and implement the [`MockDataProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/MockDataProvider.html):

```java
// Initialise your data provider (implementation further down):
MockDataProvider provider = new MyProvider();
MockConnection connection = new MockConnection(provider);

// Pass the mock connection to a jOOQ DSLContext:
DSLContext create = DSL.using(connection, SQLDialect.ORACLE);

// Execute queries transparently, with the above DSLContext:
Result<BookRecord> result = create.selectFrom(BOOK).where(BOOK.ID.eq(5)).fetch();
```

As you can see, the configuration setup is simple. Now, the `MockDataProvider` acts as your single point of contact with JDBC / jOOQ. It unifies any of these execution modes, transparently:

- Statements without results
- Statements without results but with generated keys
- Statements with results
- Statements with several results
- Batch statements with single queries and multiple bind value sets
- Batch statements with multiple queries and no bind values

The above are the execution modes supported by jOOQ. Whether you're using any of jOOQ's various fetching modes (e.g. [pojo fetching](#pojos), [lazy fetching](#lazy-fetching), [many fetching](#many-fetching), [later fetching](#later-fetching)) is irrelevant, as those modes are all built on top of the standard JDBC API.

#### Implementing MockDataProvider

Now, here's how to implement `MockDataProvider`:

```java
public class MyProvider implements MockDataProvider {

    @Override
    public MockResult[] execute(MockExecuteContext ctx) throws SQLException {

        // You might need a DSLContext to create org.jooq.Result and org.jooq.Record objects
        DSLContext create = DSL.using(SQLDialect.ORACLE);
        MockResult[] mock = new MockResult[1];

        // The execute context contains SQL string(s), bind values, and other meta-data
        String sql = ctx.sql();

        // Exceptions are propagated through the JDBC and jOOQ APIs
        if (sql.toUpperCase().startsWith("DROP")) {
            throw new SQLException("Statement not supported: " + sql);
        }

        // You decide, whether any given statement returns results, and how many
        else if (sql.toUpperCase().startsWith("SELECT")) {

            // Always return one record
            Result<Record2<Integer, String>> result = create.newResult(AUTHOR.ID, AUTHOR.LAST_NAME);
            result.add(create
                .newRecord(AUTHOR.ID, AUTHOR.LAST_NAME)
                .values(1, "Orwell"));
            mock[0] = new MockResult(1, result);
        }

        // You can detect batch statements easily
        else if (ctx.batch()) {
            // [...]
        }

        return mock;
    }
}
```

Essentially, the [`MockExecuteContext`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/MockExecuteContext.html) contains all the necessary information for you to decide, what kind of data you should return. The [`MockResult`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/MockResult.html) wraps up two pieces of information:

- [`Statement.getUpdateCount()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#getUpdateCount): The number of affected rows
- [`Statement.getResultSet()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Statement.html#getResultSet()): The result set

You should return as many `MockResult` objects as there were query executions (in [batch mode](#batch-execution)) or results (in [fetch-many mode](#many-fetching)). Instead of an awkward [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), however, you can construct a "friendlier" [`org.jooq.Result`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html) with your own record types. The jOOQ mock API will use meta data provided with this `Result` in order to create the necessary JDBC [`java.sql.ResultSetMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSetMetaData.html)

Such results can be created using `DSLContext.newResult()` and `DSLContext.newRecord()`, as in the above example, or by reading them from human-readable formats like CSV, JSON, or text tables, e.g. using `DSLContext.fetchFromTXT()`. See the section about [creating results and records in memory](#in-memory-results) for details and [an example mock implementation](#in-memory-usage).

See the [`MockDataProvider Javadoc`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/MockDataProvider.html) for a list of rules that you should follow.

<a id="mock-file-database"></a>
### 4.22. Mock File Database

An alternative to the previous [programmatic implementation of a mocking connection](#mocking-connection) is the more declarative approach using a [`org.jooq.tools.jdbc.MockFileDatabase`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/MockFileDatabase.html), which reads SQL statements and their corresponding result sets directly from a file.

> [!TIP]
> Disclaimer: The general idea of mocking a JDBC connection with this jOOQ API is to provide quick workarounds, injection points, etc. using a very simple JDBC abstraction. It is *NOT RECOMMENDED* to emulate an entire database (including complex state transitions, transactions, locking, etc.) using this mock API. Once you have this requirement, please consider using an actual database product instead for integration testing, rather than implementing your test database inside of a `MockDataProvider`.

Assuming the following file content:

```text
# All lines with a leading hash are ignored. This is the MockFileDatabase comment syntax
-- SQL comments are parsed and passed to the SQL statement
/* The same is true for multi-line SQL comments */
select 'A';
> A
> -
> A
@ rows: 1

select 'A', 'B' union all 'C', 'D';
> A B
> - -
> A B
> C D
@ rows: 2

# Statements without result sets just leave that section empty
update t set x = 1;
@ rows: 3

# Statements producing specific exceptions can indicate them as such
select * from t;
@ exception: ACCESS TO TABLE T FORBIDDEN
```

The above syntax consists of the following elements to define an individual statement:

- `MockFileDatabase` comments are any line with a leading hash (`"#"`) symbol. They are ignored when reading the file
- SQL comments are part of the SQL statement
- A SQL statement always starts on a new line and ends with a semi colon (`;`), which is the last symbol on the line (apart from whitespace)
- If the statement has a result set, it immediately succeeds the SQL statement and is prefixed by angle brackets and a whitespace (`"> "`). Any format that is accepted by [`DSLContext.fetchFromTXT()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromTXT(java.lang.String)), [`DSLContext.fetchFromJSON()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromJSON(java.lang.String)), or [`DSLContext.fetchFromXML()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#fetchFromXML(java.lang.String)) is accepted. See the section about [creating results in memory](#in-memory-results) for details about these formats.
- The statement is always terminated by the row count, which is prefixed by an at symbol, the "rows" keyword, and a double colon (`"@ rows:"`).

The above database supports exactly two statements in total, and is completely stateless (e.g. an `INSERT` statement cannot be made to affect the results of a subsequent `SELECT` statement on the same table). It can be loaded through the `MockFileDatabase` can be used as follows:

```java
// Initialise your data provider:
MockFileDatabase provider = new MockFileDatabase(new File("/path/to/db.txt"));
MockConnection connection = new MockConnection(provider);

// Pass the mock connection to a jOOQ DSLContext:
DSLContext create = DSL.using(connection, SQLDialect.POSTGRES);

// Execute queries transparently, with the above DSLContext:
Result<?> result = create.select(inline("A")).fetch();
Result<?> result = create.select(inline("A"), inline("B")).fetch();

// Queries that are not listed in the MockFileDatabase will simply fail
Result<?> result = create.select(inline("C")).fetch();
```

In situations where the expected set of queries are well-defined, the `MockFileDatabase` can offer a very effective way of mocking parts of the database engine, without offering the complete functionality of the [programmatic mocking connection](#mocking-connection).

#### Matching statements using regular expressions

Alternatively, regular expressions can be used to match statements in order of definition in the file.

```text
# Regardless of the number of columns, if selecting 'A' as the first column,
# always return a single row containing columns A and B
select 'A', .*;
> A B
> - -
> A B
@ rows: 1

# All other select statements are assumed to return only a column A
select .*;
> A
> -
> A
@ rows: 1
```

The same rules apply as before. The first matching statement will be applied for any given input statement.

This feature is "opt-in", so it has to be configured appropriately:

```java
// Initialise your data provider:
MockFileDatabase provider = new MockFileDatabase(new MockFileDatabaseConfiguration()
    .source(new File("/path/to/db.txt"))
    .patterns(true) // Turn on regular expressions here
);
MockConnection connection = new MockConnection(provider);

// Pass the mock connection to a jOOQ DSLContext:
DSLContext create = DSL.using(connection, SQLDialect.POSTGRES);

// This returns a column A only
Result<?> result = create.select(inline("X")).fetch();

// This returns columns A and B
Result<?> result = create.select(inline("A"), inline("B"), inline("C")).fetch();
```

<a id="parsing-connection"></a>
### 4.23. Parsing Connection

As previously discussed in the [manual's section about the SQL parser](#sql-parser), jOOQ exposes a full-fledged SQL parser through [`DSLContext.parser()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#parser()), and often more interestingly: Through [`DSLContext.parsingConnection()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DSLContext.html#parsingConnection()).

A parsing connection is a JDBC [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html), which proxies all commands through the jOOQ parser, transforming the inbound SQL statement (and bind variables) given the entirety of jOOQ's [Configuration](#dsl-context), including [SQLDialect](#sql-dialects), [Settings](#custom-settings) (e.g. formatting SQL or inlining bind variables) and much more. This allows for transparent SQL transformation of the SQL produced by any JDBC client (including JPA!). Here's a simple usage example:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (Connection c = DSL.using(configuration).parsingConnection();
     Statement s = c.createStatement();

     // This syntax is not supported in Oracle, but thanks to the parser and jOOQ,
     // it will run on Oracle and produce the expected result
     ResultSet rs = s.executeQuery("SELECT * FROM (VALUES (1, 'a'), (2, 'b')) t(x, y)")) {

    while (rs.next())
        System.out.println("x: " + rs.getInt(1) + ", y: " + rs.getString());
}
```

Running the above statement will yield:

```text
x: 1, y: a
x: 2, y: b
```

The parsing connection caches input/output SQL string pairs and bind variable index mappings according to the [`org.jooq.CacheProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/CacheProvider.html).

<a id="diagnostics"></a>
### 4.24. Diagnostics

jOOQ includes a powerful diagnostics SPI, which can be used to detect problems and inefficiencies on different levels of your database interaction:

- On the jOOQ API level
- On the JDBC level
- On the SQL level

Just like the [parsing connection](#parsing-connection), which was documented in the previous section, this functionality does not depend on using the jOOQ API in a client application, but can expose itself through a JDBC [`java.sql.Connection`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Connection.html) that proxies your real database connection.

```java
// A custom DiagnosticsListener SPI implementation
class MyDiagnosticsListener implements DiagnosticsListener {
    // Override methods here
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (Connection c = DSL.using(configuration.derive(new MyDiagnosticsListener()))
                       .diagnosticsConnection();
     Statement s = c.createStatement()) {

    // The tooManyRowsFetched() event is triggered.
    // --------------------------------------------
    // This logic does not consume the entire ResultSet. There is more than one row
    // ready to be fetched into the client, but the client only fetches one row.
    try (ResultSet rs = s.executeQuery("SELECT id, title FROM book WHERE id > 1")) {
        if (rs.next())
            System.out.println("ID: " + rs.getInt(1) + ", title: " + rs.getInt(2));
    }

    // The duplicateStatements() event is triggered.
    // ---------------------------------------------
    // The statement is the same as the previous one, apart from a different "bind variable".
    // Unfortunately, no actual bind variables were used, which may
    // 1) hint at a SQL injection risk
    // 2) can cause a lot of pressure / contention on execution plan caches and SQL parsers
    //
    // The tooManyColumnsFetched() event is triggered.
    // -----------------------------------------------
    // When iterating the ResultSet, we're actually only ever reading the TITLE column, never
    // the ID column. This means we probably should not have projected it in the first place
    try (ResultSet rs = s.executeQuery("SELECT id, title FROM book WHERE id > 2")) {
        while (rs.next())
            System.out.println("Title: " + rs.getString(2));
    }
}
```

This feature incurs a certain overhead over normal operation as it requires:

- Parsing SQL statements and re-rendering them back to normalised SQL.
- Storing a limited size list of such normalised SQL in a cache to gather statistics on that cache.

This is why it isn't active by default on all `Connections`, only when proxying a connection explicitly as above. However, using [Settings.diagnosticsConnection](#settings-diagnostics-connection), this can be changed. To turn on debug logging, refer to [Settings.diagnosticsLogging](#settings-diagnostics-logging).

The following sections describe each individual event, how it can happen, how and why it should be remedied.

<a id="diagnostics-too-many-rows"></a>
#### 4.24.1. Too Many Rows

The SPI method handling this event is [`tooManyRowsFetched()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#tooManyRowsFetched(DiagnosticsContext))

If you're using jOOQ (or an ORM) to eagerly fetch your entire result set, then this will not be a problem in your code base, but when working with jOOQ's [lazy fetching API](#lazy-fetching) or [lazy streaming support](#lazy-fetching-with-streams), or as well as with JDBC [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html) directly, then it may certainly be possible that client code is aborting the iteration over the entire result set prematurely.

##### Why is it bad?

While it is definitely good not to fetch too many rows from a [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), it would be even better to communicate to the database that only a limited number of rows are going to be needed in the client, by using the [LIMIT clause](#limit-clause). Not only will this prevent the pre-allocation of some resources both in the client and in the server, but it opens up the possibility of much better execution plans. For instance, the optimiser may prefer to chose nested loop joins over hash joins if it knows that the loops can be aborted early.

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class TooManyRows implements DiagnosticsListener {
    @Override
    public void tooManyRowsFetched(DiagnosticsContext ctx) {
        System.out.println("Consumed rows: " + ctx.resultSetConsumedRows());

        // This incurs overhead by consuming the ResultSet! Use only if needed.
        System.out.println("Fetched rows: " + ctx.resultSetFetchedRows());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (Connection c = DSL.using(configuration.derive(new TooManyRows()))
                       .diagnosticsConnection();
     Statement s = c.createStatement()) {

    try (ResultSet rs = s.executeQuery("SELECT id FROM book")) {

        // Unlike "while", "if" only consumes the first row, here.
        if (rs.next())
            System.out.println("ID: " + rs.getInt(1));
    }
}
```

<a id="diagnostics-too-many-columns"></a>
#### 4.24.2. Too Many Columns

The SPI method handling this event is [`tooManyColumnsFetched()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#tooManyColumnsFetched(DiagnosticsContext))

A common problem with SQL is the high probability of having too many columns in the [projection](#select-clause). This may be due to reckless usage of `SELECT *` or some refactoring which removes the need to select some of the projected columns, but the query was not adapted.

If the columns are consumed by some client (e.g. an ORM), then the jOOQ diagnostics have no way of knowing whether they were actually needed or not. But if they are never consumed from the JDBC [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html), then we can say with certainty that too many columns have been projected.

##### Why is it bad?

The drawbacks of projecting too many columns are manifold:

- Too much data is loaded, cached, transferred between server and client. The overall resource consumption of a system is too high if too many columns are projected. This can cause orders of magnitude of overhead in extreme cases!
- Locking could occur in cases where it otherwise wouldn't happen, because two conflicting queries actually don't really need to touch the same columns.
- The probability of using "covering indexes" (or "index only scans") on some tables decreases because of the unnecessary projection. This can have drastic effects!
- The probability of applying [JOIN elimination](https://blog.jooq.org/join-elimination-an-essential-optimiser-feature-for-advanced-sql-usage/) decreases, because of the unnecessary projection. This is particularly true if you're querying views.

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class TooManyColumns implements DiagnosticsListener {
    @Override
    public void tooManyColumnsFetched(DiagnosticsContext ctx) {
        System.out.println("Consumed columns: " + ctx.resultSetConsumedColumnCount());
        System.out.println("Fetched columns: " + ctx.resultSetFetchedColumnCount());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (Connection c = DSL.using(configuration.derive(new TooManyColumns()))
                       .diagnosticsConnection();
     Statement s = c.createStatement()) {

    try (ResultSet rs = s.executeQuery("SELECT id, title FROM book")) {

        // On none of the rows, we retrieve the TITLE column, so selecting it would not have been necessary.
        while (rs.next())
            System.out.println("ID: " + rs.getInt(1));
    }
}
```

<a id="diagnostics-duplicate-statements"></a>
#### 4.24.3. Duplicate Statements

The SPI method handling this event is [`duplicateStatements()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#duplicateStatements(DiagnosticsContext)).If the feature is available, then [pattern based SQL transformations](#transform-patterns) will be used to further normalise possibly duplicate SQL.

A common source of overhead in databases that have an execution plan cache (or "cursor cache", etc.) are static statements, or prepared statements that differ only by "irrelevant" things:

- They may differ by white space
- They may differ by irrelevant syntactic elements (e.g. excess parentheses, or object name qualification, table aliasing, etc.)
- They may differ by input values, which are inlined into the statement rather than parameterised as bind values
- They may differ by the length of their [IN predicate's IN-list sizes](#in-predicate)

##### Why is it bad?

There are two main problems:

- If the duplicate SQL appears in [dynamic SQL](#dynamic-sql) (i.e. in generated SQL), then there is an indication that the database's parser and optimiser may have to do too much work parsing the various similar (but not identical) SQL queries and finding an execution plan for them, each time. In fact, it will find the *same* execution plan most of the time, but with some significant overhead. Depending on the query complexity, this overhead can easily go from milliseconds into several seconds, blocking important resources in the database. If duplicate SQL happens at peak load times, this problem can have a significant impact in production. It never affects your (single user) development environments, where the overhead of parsing duplicate SQL is manageable.
- If the duplicate SQL appears in static SQL, this can simply indicate that the query was copy pasted, and you might be able to refactor it. There's probably not any performance issue arising from duplicate static SQL

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class DuplicateStatements implements DiagnosticsListener {
    @Override
    public void duplicateStatements(DiagnosticsContext ctx) {

        // The statement that is being executed and which has duplicates
        System.out.println("Actual statement: " + ctx.actualStatement());

        // A normalised version of the actual statement, which is shared by all duplicates
        // This statement has "normal" whitespace, bind variables, IN-lists, etc.
        System.out.println("Normalised statement: " + ctx.normalisedStatement());

        // All the duplicate actual statements that have produced the same normalised
        // statement in the recent past.
        System.out.println("Duplicate statements: " + ctx.duplicateStatements());
    }
}
```

And then:

```java
// Utility to run SQL on a new JDBC Statement
void run(String sql) {

    // Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
    try (Connection c = DSL.using(configuration.derive(new DuplicateStatements()))
                           .diagnosticsConnection();
         Statement s = c.createStatement();
         ResultSet rs = s.executeQuery(sql)) {

        while (rs.next()) {
            // Consume result set
        }
    }
}
    // Everything is fine with the first execution
    run("SELECT title FROM book WHERE id = 1");

    // This query is identical to the previous one, differing only in irrelevant white space
    run("SELECT title FROM book WHERE  id = 1");

    // This query is identical to the previous one, differing only in irrelevant additional parentheses
    run("SELECT title FROM book WHERE (id = 1)");

    // This query is identical to the previous one, differing only in what should be a bind variable
    run("SELECT title FROM book WHERE id = 2");

    // Everything is fine with the first execution of a new query that has never been seen
    run("SELECT title FROM book WHERE id IN (1, 2, 3, 4, 5)");

    // This query is identical to the previous one, differing only in what should be bind variables
    run("SELECT title FROM book WHERE id IN (1, 2, 3, 4, 5, 6)");
}
```

Unlike when detecting [repeated statements](#diagnostics-repeated-statements), duplicate statement statistics are performed globally over all JDBC connections and data sources.

<a id="diagnostics-repeated-statements"></a>
#### 4.24.4. Repeated statements

The SPI method handling this event is [`repeatedStatements()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#repeatedStatements(DiagnosticsContext))

Sometimes, there is no other option than to repeat an identical (or similar, see [duplicate statements](#diagnostics-duplicate-statements)) statement many times in a row, but often, it is a sign that your queries can be rewritten and your repeated statements should really be joined to a larger query.

##### Why is it bad?

This problem is usually referred to as the N+1 problem. A parent entity is loaded (often by an ORM), and its child entities are loaded lazily. Unfortunately, there were several parent instances, so for each parent instance, we're now loading a set of child instances, resulting in many many queries. This diagnostic detects if on the same connection, there is repeated execution of the same statement, even if it is not exactly identical.

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class RepeatedStatement implements DiagnosticsListener {
    @Override
    public void repeatedStatements(DiagnosticsContext ctx) {

        // The statement that is being executed and which has duplicates
        System.out.println("Actual statement: " + ctx.actualStatement());

        // A normalised version of the actual statement, which is shared by all duplicates
        // This statement has "normal" whitespace, bind variables, IN-lists, etc.
        System.out.println("Normalised statement: " + ctx.normalisedStatement());

        // All the duplicate actual statements that have produced the same normalised
        // statement in the recent past.
        System.out.println("Repeated statements: " + ctx.repeatedStatements());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (Connection c = DSL.using(configuration.derive(new RepeatedStatement()))
                       .diagnosticsConnection();
     Statement s1 = c.createStatement();
     ResultSet a = s1.executeQuery("SELECT id FROM author WHERE first_name LIKE 'A%'")) {

    while (a.next()) {
        int id = a.getInt(1);

        // This query is run once for every author, when we could have joined the author table
        try (PreparedStatement s2 = c.prepareStatement("SELECT title FROM book WHERE author_id = ?")) {
            s2.setInt(1, id);

            try (ResultSet b = s2.executeQuery()) {
                while (b.next())
                    System.out.println("ID: " + id + ", title: " + b.getString(1));
            }
        }
    }
}
```

Unlike when detecting [duplicate statements](#diagnostics-duplicate-statements), repeated statement statistics are performed locally only, for a single JDBC Connection, or, if possible, for a transaction. Repeated statements in different transactions are usually not an indication of a problem.

<a id="diagnostics-consecutive-aggregation"></a>
#### 4.24.5. Consecutive aggregation

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The SPI method handling this event is [`consecutiveAggregation()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#consecutiveAggregation(DiagnosticsContext))

Multiple consecutive [aggregate queries](#aggregate-functions) that are similar (same [FROM clause](#from-clause)), but use different aggregate functions each, and different [WHERE clauses](#where-clause) might be unified into a single query aggregating everything in one go.

##### Why is it bad?

Instead of running N queries, it is possible to run just 1 query.

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class ConsecutiveAggregation implements DiagnosticsListener {
    @Override
    public void consecutiveAggregation(DiagnosticsContext ctx) {

        // The statement that is being executed and which has similar aggregate queries.
        System.out.println("Actual statement: " + ctx.actualStatement());

        // A normalised version of the actual statement, which is shared by all duplicates
        // This statement has its SELECT and WHERE clause removed.
        System.out.println("Normalised statement: " + ctx.normalisedStatement());

        // All the duplicate actual statements that have produced the same normalised
        // statement in the recent past.
        System.out.println("Repeated statements: " + ctx.repeatedStatements());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (
    Connection c = DSL.using(configuration.derive(new ConsecutiveAggregation()))
                      .diagnosticsConnection();
    Statement s = c.createStatement()
) {
    try (ResultSet a = s.executeQuery("SELECT count(*) FROM author")) {
        while (a.next())
            println(a.getInt(1));
    }

    // This query could be merged into the previous one e.g.:
    // SELECT count(*), count(*) FILTER (WHERE last_name LIKE 'A%') FROM author
    try (ResultSet a = s.executeQuery("SELECT count(*) FROM author WHERE last_name LIKE 'A%'")) {
        while (a.next())
            println(a.getInt(1));
    }
}
```

Unlike when detecting [duplicate statements](#diagnostics-duplicate-statements), repeated statement statistics are performed locally only, for a single JDBC Connection, or, if possible, for a transaction. Repeated statements in different transactions are usually not an indication of a problem.

<a id="diagnostics-was-null-calls"></a>
#### 4.24.6. WasNull calls

The SPI methods handling these events are [`unnecessaryWasNullCall()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#unnecessaryWasNullCall(DiagnosticsContext)) and [`missingWasNullCall()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#missingWasNullCall(DiagnosticsContext))

This problem appears only when using the JDBC API directly, as both jOOQ and most ORMs abstract over this JDBC legacy correctly. In JDBC, when fetching a primitive types (and some types are available only in their primitive form), a subsequent call to [`ResultSet.wasNull()`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html#wasNull()) is required, to see if the previous primitive type was really a `NULL` value, not a `0` or `false` value.

##### Why is it bad?

There are two misuses that can arise in this area:

- The call to `wasNull()` wasn't made when it should have been (nullable type, fetched as a primitive type), possibly resulting in wrong results in the client.
- The call to `wasNull()` was made too often, or when it did not need to have been made (non-nullable type, or types fetched as reference types), possibly resulting in a very slight performance overhead, depending on the driver.

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class WasNull implements DiagnosticsListener {
    @Override
    public void unnecessaryWasNullCall(DiagnosticsContext ctx) {
        System.out.println("Unnecessary wasNull() call: " + ctx.resultSetUnnecessaryWasNullCall());
    }

    @Override
    public void missingWasNullCall(DiagnosticsContext ctx) {
        System.out.println("Missing wasNull() call: " + ctx.resultSetMissingWasNullCall());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (Connection c = DSL.using(configuration.derive(new WasNull()))
                       .diagnosticsConnection();
     Statement s = c.createStatement()) {

    try (ResultSet rs = s.executeQuery("SELECT year_of_birth FROM author")) {

        // The YEAR_OF_BIRTH column is nullable, so a 0 int could really mean null
        while (rs.next())
            System.out.println("Year of birth: " + rs.getInt(1));
    }
}
```

<a id="diagnostics-concatenation-in-predicates"></a>
#### 4.24.7. Concatenation in predicates

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The SPI method handling this event is [`consecutiveAggregation()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#concatenationInPredicates(DiagnosticsContext))

Using [CONCAT](#concat-function) inside of predicate is often a sign of potentially slow and/or wrong queries.

##### Why is it bad?

Ordinary indexes cannot be used this way. Even if it's possible to define function based indexes that cover such a predicate, it's usually better not to use concatenation in predicates because:

- Ordinary indexes on concatenated columns are more likely to be reusable by other queries.
- Unless there's a separation token that is known not to be present in actual data, these concatenations produce the same value: `'John Taylor' || 'Doe'` and `'John' || 'Taylor Doe'`. But they might be different first and last names.

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class ConcatenationInPredicate implements DiagnosticsListener {
    @Override
    public void concatenationInPredicate(DiagnosticsContext ctx) {

        // The statement that is being executed and which has a concatenation in a predicate.
        System.out.println("Actual statement: " + ctx.actualStatement());

        // The predicate containing the concatenation.
        System.out.println("Predicate       : " + ctx.part());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (
    Connection c = DSL.using(configuration.derive(new ConcatenationInPredicate()))
                      .diagnosticsConnection();
    Statement s = c.createStatement()
) {
    try (ResultSet a = s.executeQuery("SELECT id FROM author WHERE first_name || last_name = ?")) {
        while (a.next())
            println(a.getInt(1));
    }
}
```

<a id="diagnostics-possibly-wrong-expressions"></a>
#### 4.24.8. Possibly wrong expressions

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The SPI method handling this event is [`possiblyWrongExpression()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#possiblyWrongExpression(DiagnosticsContext))

Some expressions have a high likelyhood of being wrong, even if they're correct most of the time, or within the domain known by the developer who wrote the expression.

##### Why is it bad?

Murphy's Law dictates that the slight risk of the expression turning wrong eventually means that it should better be fixed as soon as possible. Various examples of possibly wrong expressions include:

- `MOD(x, 2) = 1` for oddness checks doesn't work for negative numbers. Compare with zero instead: `MOD(x, 2) != 0`

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class PossiblyWrongExpression implements DiagnosticsListener {
    @Override
    public void possiblyWrongExpression(DiagnosticsContext ctx) {

        // The statement that is being executed and which has a possibly wrong expression.
        System.out.println("Actual statement: " + ctx.actualStatement());

        // The possibly wrong expression.
        System.out.println("Predicate       : " + ctx.part());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (
    Connection c = DSL.using(configuration.derive(new PossiblyWrongExpression()))
                      .diagnosticsConnection();
    Statement s = c.createStatement()
) {
    try (ResultSet a = s.executeQuery("SELECT id FROM author WHERE MOD(id, 2) = 1")) {
        while (a.next())
            println(a.getInt(1));
    }
}
```

<a id="diagnostics-incomplete-equi-join"></a>
#### 4.24.9. Incomplete equi join

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The SPI method handling this event is [`incompleteEquiJoin()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#incompleteEquiJoin(DiagnosticsContext))

When working with composite keys, it is easy to forget a column in a [JOIN predicate](#join-clause). For this to work, the parser must be configured with [meta lookups](#settings-parser) active, such that tables, columns, and constraints can be resolved in the diagnostic listener's parser.

##### Why is it bad?

A missing predicate in a [JOIN predicate](#join-clause) can lead to cartesian products and thus wrong results. Unlike absent join predicates, which can be detected due to jOOQ's DSL API not compiling, incomplete join predicates are very subtle and hard to detect. In the worst case, they start out being complete, but as the schema evolves, a constraint becomes composite and queries are not updated accordingly, leading to an incomplete predicate.

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class IncompleteJoinPredicate implements DiagnosticsListener {
    @Override
    public void incompleteJoinPredicate(DiagnosticsContext ctx) {

        // The statement that is being executed and which has a incomplete join predicate.
        System.out.println("Actual statement: " + ctx.actualStatement());

        // The incomplete join predicate.
        System.out.println("Predicate       : " + ctx.part());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (
    Connection c = DSL.using(configuration.derive(new IncompleteJoinPredicate()))
                      .diagnosticsConnection();
    Statement s = c.createStatement()
) {
    try (ResultSet a = s.executeQuery("SELECT * FROM child JOIN parent ON child.key1 = parent.key1")) {
        while (a.next())
            println(a.getInt(1));
    }
}
```

> [!TIP]
> [Implicit JOIN](#implicit-join) will never suffer from this problem, as the join predicate is generated by jOOQ always based on the complete available constraint meta data.

<a id="diagnostics-trivial-condition"></a>
#### 4.24.10. Trivial condition

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The SPI methods handling these events are [`trivialCondition()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#trivialCondition(DiagnosticsContext)). This diagnostic depends on the [transform patterns feature](#transform-patterns).

This problem appears with JDBC, jOOQ or with any ORM. A predicate of arbitrary complexity can sometimes be reduced to a simple [TRUE or FALSE condition](#true-false-no-condition).

##### Why is it bad?

A trivial condition is bad for your application for multiple reasons:

- It could just be a typo (e.g. a `JOIN` predicate of the form `A.ID = A.ID` instead of `A.ID = B.ID`), in case of which it's simply wrong.
- The redundant predicate might be a subtle cause for [duplicate statements](#diagnostics-duplicate-statements).

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class TrivialCondition implements DiagnosticsListener {
    @Override
    public void trivialCondition(DiagnosticsContext ctx) {
        System.out.println("Trivial condition: " + ctx.part());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (Connection c = DSL.using(configuration.derive(new TrivialCondition()))
                       .diagnosticsConnection();
     Statement s = c.createStatement()) {

    try (ResultSet rs = s.executeQuery("SELECT * FROM author WHERE id = id")) {
        // ..
    }
}
```

<a id="diagnostics-transform-patterns"></a>
#### 4.24.11. Transform patterns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The SPI methods handling these events are [`transformPattern()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DiagnosticsListener.html#transformPattern(DiagnosticsContext)). This diagnostic depends entirely on the [transform patterns feature](#transform-patterns).

A variety of patterns can be recognised and transformed into something better for any of these reasons:

- The resulting expression is more "normalised". This doesn't objectively affect the query execution on most RDBMS and is purely a stylistic improvement.
- The resulting expression is simpler. This also doesn't objectively affect the query execution on most RDBMS.
- The resulting expression removes unnecessary parts. Unless the RDBMS can transform such expressions itself, this is likely to improve query execution objectively.

##### Why is it bad?

Expressions that aren't normalised and simplified this way generate too much work in your RDBMS:

- In the case of there being unnecessary parts, some RDBMS may perform too much unnecessary work, if they do not also implement the same transformation as jOOQ does.
- Similar expressions may be equivalent, but not identical in syntax. As such, most RDBMS will have to parse the statement twice, resulting in [duplicate statements](#diagnostics-duplicate-statements). The duplicate statement diagnostic also detects these cases, but doesn't report on the exact reason why two statements are duplicate. This diagnostic here helps look into details.

An example is given here:

```java
// A custom DiagnosticsListener SPI implementation
class TransformPatterns implements DiagnosticsListener {
    @Override
    public void transformPattern(DiagnosticsContext ctx) {
        System.out.println("Pattern transformation is possible from: " + ctx.part() + " to: " + ctx.transformedPart());
    }
}
```

And then:

```java
// Configuration is configured with the target DataSource, SQLDialect, etc. for instance Oracle.
try (Connection c = DSL.using(configuration.derive(new TransformPatterns()))
                       .diagnosticsConnection();
     Statement s = c.createStatement()) {

    try (ResultSet rs = s.executeQuery("SELECT * FROM author WHERE x = 1 OR x > 1")) {
        // ..
    }
}
```

<a id="logging"></a>
### 4.25. Logging with LoggerListener

For development purposes, jOOQ logs all SQL queries and fetched result sets to its internal `DEBUG` logger, which is implemented as an [execute listener](#execute-listeners). By default, execute logging is activated in the [jOOQ Settings](#custom-settings). In order to see any DEBUG log output, put slf4j on jOOQ's classpath or module path along with their respective configuration. A sample log4j configuration can be seen here:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{ABSOLUTE} %5p [%-50c{4}] - %m%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <!-- SQL execution logging is logged to the LoggerListener logger at DEBUG level -->
        <Logger name="org.jooq.tools.LoggerListener" level="debug">
            <AppenderRef ref="Console"/>
        </Logger>

        <!-- Other jOOQ related debug log output -->
        <Logger name="org.jooq" level="debug">
            <AppenderRef ref="Console"/>
        </Logger>

        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>
```

With the above configuration, let's fetch some data with jOOQ

```java
create.select(BOOK.ID, BOOK.TITLE).from(BOOK).orderBy(BOOK.ID).limit(1, 2).fetch();
```

The above query may result in the following log output:

```text
Executing query          : select "BOOK"."ID", "BOOK"."TITLE" from "BOOK" order by "BOOK"."ID" asc limit ? offset ?
-> with bind values      : select "BOOK"."ID", "BOOK"."TITLE" from "BOOK" order by "BOOK"."ID" asc limit 2 offset 1
Fetched result           : +----+------------+
                         : |  ID|TITLE       |
                         : +----+------------+
                         : |   2|Animal Farm |
                         : |   3|O Alquimista|
                         : +----+------------+
```

Essentially, jOOQ will log

- The SQL statement as rendered to the prepared statement
- The SQL statement with inlined bind values (for improved debugging)
- The first 5 records of the result. This is formatted using [jOOQ's text export](#exporting-text)

If you wish to use your own logger (e.g. avoiding printing out sensitive data), you can deactivate jOOQ's logger using [your custom settings](#settings-execute-logging) and implement your own [execute listener logger](#execute-listeners).

> [!TIP]
> [Redacted columns](#redacted-columns) are another option that allow for masking certain data in this formatted representation to avoid accidental logging of sensitive data.

<a id="logging-sql-exceptions"></a>
### 4.26. Logging with SQLExceptionLoggerListener

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

In addition to the [LoggerListener](#logging), which adds `DEBUG` logging to your development environments, there's an additional `SQLExceptionLoggerListener`, which is enabled by default to add additional exception context to your logs.

Many RDBMS are notoriously stingy with debug log information when something goes wrong. For example:

```sql
-- Depending on the dialect, use DECIMAL or NUMBER, instead
CREATE TABLE t (n1 numeric(3) NOT NULL, n2 numeric(3) NOT NULL);
INSERT INTO t (n1, n2) VALUES (123, null);
INSERT INTO t (n1, n2) VALUES (1234, 123);
```

Clearly, this is wrong for 2 reasons:

- The first row tries to insert `NULL` into the `NOT NULL` column `n2`.
- The second row tries to insert a number with precision 4 into a `NUMERIC(3)` column.

But what do RDBMS report?

```text
-- Db2
SQL Error [23502]: Assignment of a NULL value to a NOT NULL column "TBSPACEID=2, TABLEID=4, COLNO=1" is not allowed..
  SQLCODE=-407, SQLSTATE=23502, DRIVER=4.29.24
SQL Error [22003]: Overflow occurred during numeric data type conversion..
  SQLCODE=-413, SQLSTATE=22003, DRIVER=4.29.24

-- MySQL:
SQL Error [1048] [23000]: Column 'n2' cannot be null
SQL Error [1264] [22001]: Data truncation: Out of range value for column 'n1' at row 1

-- Oracle:
SQL Error [1400] [23000]: ORA-01400: cannot insert NULL into ("TEST"."T"."N2")
SQL Error [1438] [22003]: ORA-01438: value larger than specified precision allowed for this column

-- PostgreSQL:
SQL Error [23502]: ERROR: null value in column "n2" of relation "t" violates not-null constraint
  Detail: Failing row contains (123, null).
SQL Error [22003]: ERROR: numeric field overflow
  Detail: A field with precision 3, scale 0 must round to an absolute value less than 10^3.

-- SQL Server:
SQL Error [515] [23000]: Cannot insert the value NULL into column 'n2', table 'test.dbo.t';
  column does not allow nulls. INSERT fails.
SQL Error [8115] [S0008]: Arithmetic overflow error converting int to data type numeric.
```

While in this example, MySQL shows all the useful information, the other always omit the column name in at least one error message. Things get worse for multi row `INSERT` statements, where most RDBMS only report the error of one row, making things harder to debug in bulk insertion scenarios (e.g. when you [import data](#importing)).

This is how jOOQ's `SQLExceptionLoggerListener` will come in handy. Using this multi row [INSERT statement](#insert-statement):

```java
create.insertInto(T)
      .columns(T.N1, T.N2)
      .values(new BigDecimal("123"), null)
      .values(new BigDecimal("1234"), new BigDecimal("123"))
      .execute();
```

The following logs will be produced:

```text
NOT NULL column "public"."t"."n2" cannot have an explicit NULL value in row 1 with values: (123, null)
Column "public"."t"."n1" of type numeric(3) cannot accept number of precision 4: 1234 in row 2 with values: (1234, 123)
```

The errors shouldn't be seen as formal validation, just as auxiliary debug information. Some statements cannot produce these errors, including [UPDATE statements](#update-statement) based on expressions, for example. Only [INSERT statement](#insert-statement) and [UPDATE statement](#update-statement) where the value to be set is a [bind value](#bind-values) can be logged.

> [!TIP]
> This logger relies on type information being available to query meta data, meaning that using the [code generator](#code-generation) will be a prerequisite.

If you wish to use your own logger (e.g. avoiding printing out sensitive data), you can deactivate jOOQ's logger using [your custom settings](#settings-execute-logging-sql-exceptions) and implement your own [execute listener logger](#execute-listeners).

<a id="logging-connection"></a>
### 4.27. Logging Connection

In addition to [logging things on a jOOQ level](#logging), there is also the option of logging things on the JDBC level using the [`org.jooq.tools.jdbc.LoggingConnection`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/jdbc/LoggingConnection.html). This connection acts as a JDBC proxy, intercepting all relevant calls in order to `DEBUG` log relevant information to slfj4 or `java.util.logging`.

```java
try (Connection logging = new LoggingConnection(datasource.getConnection())) {

    // Run statements directly with JDBC
    try (Statement s = c.createStatement()) {
        s.executeUpdate("INSERT INTO author (id, first_name, last_name) VALUES (3, 'William', 'Shakespeare')";
    }

    // ... or wrap the connection with jOOQ
    DSL.using(logging, dialect)
       .insertInto(AUTHOR)
       .columns(AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
       .values(3, "William", "Shakespeare")
       .execute();
}
```

<a id="logging-system-properties"></a>
### 4.28. Logging system properties

The [`org.jooq.tools.JooqLogger`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/JooqLogger.html) is used throughout jOOQ as an abstraction to delegate logging to `slf4j` (if found on the classpath), or `java.util.logging`. The relevant backend can be configured to mute and format jOOQ logs in any way you please.

In the rare event where you don't have access to the logging backend's configuration (e.g. when you build a library on top of jOOQ, to be consumed by other end users), you can still specify logging thresholds for the [`org.jooq.tools.JooqLogger`](https://www.jooq.org/javadoc/3.22.x/org/jooq/tools/JooqLogger.html) by using system properties with the following prefix: `org.jooq.log.<logger-name>`. For example, to mute the following logger, which logs [RDBMS version compatibility](https://www.jooq.org/download/support-matrix):

```text
org.jooq.impl.DefaultExecuteContext.logVersionSupport
```

Just set:

```java
System.setProperty("org.jooq.log.org.jooq.impl.DefaultExecuteContext.logVersionSupport", "ERROR");
```

Possible values include:

- [`TRACE`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Log.Level.html#TRACE)
- [`DEBUG`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Log.Level.html#DEBUG)
- [`INFO`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Log.Level.html#INFO)
- [`WARN`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Log.Level.html#WARN)
- [`ERROR`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Log.Level.html#ERROR)
- [`FATAL`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Log.Level.html#FATAL)

<a id="performance-considerations"></a>
### 4.29. Performance considerations

Many users may have switched from higher-level abstractions such as Hibernate to jOOQ, because of Hibernate's difficult-to-manage performance, when it comes to large database schemas and complex second-level caching strategies. However, jOOQ itself is not a lightweight database abstraction framework, and it comes with its own overhead. Please be sure to consider the following points:

- It takes some time to construct jOOQ queries. If you can reuse the same queries, you might cache them. Beware of thread-safety issues, though, as jOOQ's [Configuration](#dsl-context) is not necessarily threadsafe, and queries are "attached" to their creating DSLContext
- It takes some time to render SQL strings. Internally, jOOQ reuses the same [`java.lang.StringBuilder`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/StringBuilder.html) for the complete query, but some rendering elements may take their time. You could, of course, cache SQL generated by jOOQ and prepare your own [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html) objects
- It takes some time to bind values to prepared statements. jOOQ does not keep any open prepared statements, internally. Use a sophisticated connection pool, that will cache prepared statements and inject them into jOOQ through the standard JDBC API
- It takes some time to fetch results. By default, jOOQ will always fetch the complete [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html) into memory. Use [lazy fetching](#lazy-fetching) to prevent that, and scroll over an open underlying database cursor

#### Optimise wisely

Don't be put off by the above paragraphs. You should optimise wisely, i.e. only in places where you really need very high throughput to your database. jOOQ's overhead compared to plain JDBC is typically less than 1ms per query.

<a id="alternative-execution-models"></a>
### 4.30. Alternative execution models

Just because you can, doesn't mean you must. In this chapter, we'll show how you can use jOOQ to generate SQL statements that are then executed with other APIs, such as Spring's JdbcTemplate, or Hibernate.

> [!TIP]
> Please note that we strongly recommend [executing queries directly with jOOQ](https://blog.jooq.org/why-you-should-execute-jooq-queries-with-jooq/) and to [use jOOQ's code generator](https://blog.jooq.org/why-you-should-use-jooq-with-code-generation/)!

<a id="using-jooq-with-jdbctemplate"></a>
#### 4.30.1. Using jOOQ with Spring's JdbcTemplate

A lot of people are using Spring's useful [org.springframework.jdbc.core.JdbcTemplate](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html) in their projects to simplify common JDBC interaction patterns, such as:

- Variable binding
- Result mapping
- Exception handling

When adding jOOQ to a project that is using JdbcTemplate extensively, a pragmatic first step is to use jOOQ as a SQL builder and pass the query string and bind variables to `JdbcTemplate` for execution. For instance, you may have the following class to store authors and their number of books in our stores:

```java
public class AuthorAndBooks {
    public final String firstName;
    public final String lastName;
    public final int books;

    public AuthorAndBooks(String firstName, String lastName, int books) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.books = books;
    }
}
```

You can then write the following code

```java
// The jOOQ part stays the same as always:
Book b = BOOK.as("b");
Author a = AUTHOR.as("a");
BookStore s = BOOK_STORE.as("s");
BookToBookStore t = BOOK_TO_BOOK_STORE.as("t");

ResultQuery<Record3<String, String, Integer>> query =
create.select(a.FIRST_NAME, a.LAST_NAME, countDistinct(s.NAME))
      .from(a)
      .join(b).on(b.AUTHOR_ID.equal(a.ID))
      .join(t).on(t.BOOK_ID.equal(b.ID))
      .join(s).on(t.BOOK_STORE_NAME.equal(s.NAME))
      .groupBy(a.FIRST_NAME, a.LAST_NAME)
      .orderBy(countDistinct(s.NAME).desc());

// But instead of executing the above query, we'll send the SQL string and the bind values to JdbcTemplate:
JdbcTemplate template = new JdbcTemplate(dataSource);
List<AuthorAndBooks> result = template.query(
    query.getSQL(),
    (r, i) -> new AuthorAndBooks(
        r.getString(1),
        r.getString(2),
        r.getInt(3)
    ),
    query.getBindValues().toArray()
);
```

This approach helps you gradually migrate from using JdbcTemplate to a jOOQ-only execution model.

<a id="using-jooq-with-jpa"></a>
#### 4.30.2. Using jOOQ with JPA

These sections will show how to use jOOQ with JPA's native query API in order to fetch tuples or managed entities using the Java EE standards.

> [!TIP]
> The goal of these sections is to describe how to do this, if you have strong reasons to do so. Mostly, however, you're better off executing your queries directly with jOOQ, especially if you want to use jOOQ's more advanced features. [This blog post illustrates various reason why it's better to execute queries directly with jOOQ](https://blog.jooq.org/why-you-should-execute-jooq-queries-with-jooq/).

In all of the following sections, let's assume we have the following JPA entities to model our database:

```java
@Entity
@Table(name = "book")
public class JPABook {

    @Id
    public int id;

    @Column(name = "title")
    public String title;

    @ManyToOne
    public JPAAuthor author;

    @Override
    public String toString() {
        return "JPABook [id=" + id + ", title=" + title + ", author=" + author + "]";
    }
}

@Entity
@Table(name = "author")
public class JPAAuthor {

    @Id
    public int id;

    @Column(name = "first_name")
    public String firstName;

    @Column(name = "last_name")
    public String lastName;

    @OneToMany(mappedBy = "author")
    public Set<JPABook> books;

    @Override
    public String toString() {
        return "JPAAuthor [id=" + id + ", firstName=" + firstName +
               ", lastName=" + lastName + ", book size=" + books.size() + "]";
    }
}
```

<a id="using-jooq-with-jpa-native"></a>
##### 4.30.2.1. Using jOOQ with JPA Native Query

> [!TIP]
> The goal of these sections is to describe how to do this, if you have strong reasons to do so. Mostly, however, you're better off executing your queries directly with jOOQ, especially if you want to use jOOQ's more advanced features. [This blog post illustrates various reason why it's better to execute queries directly with jOOQ](https://blog.jooq.org/why-you-should-execute-jooq-queries-with-jooq/).

If your query doesn't really map to JPA entities, you can fetch ordinary, untyped `Object[]` representations for your database records by using the following utility method:

```java
static List<Object[]> nativeQuery(EntityManager em, org.jooq.Query query) {

    // Extract the SQL statement from the jOOQ query:
    Query result = em.createNativeQuery(query.getSQL());

    // Extract the bind values from the jOOQ query:
    List<Object> values = query.getBindValues();
    for (int i = 0; i < values.size(); i++) {
        result.setParameter(i + 1, values.get(i));
    }

    return result.getResultList();
}
```

Note, if you're using [custom data types](#codegen-database-forced-types-converter) or [bindings](#codegen-database-forced-types-binding), make sure to take those into account as well. E.g. as follows:

```java
static List<Object[]> nativeQuery(EntityManager em, org.jooq.Query query) {

    // Extract the SQL statement from the jOOQ query:
    Query result = em.createNativeQuery(query.getSQL());

    // Extract the bind values from the jOOQ query:
    int i = 1;
    for (Param<?> param : query.getParams().values())
        if (!param.isInline())
            result.setParameter(i++, convertToDatabaseType(param));

    return result.getResultList();
}

static <T> Object convertToDatabaseType(Param<T> param) {
    return param.getBinding().converter().to(param.getValue());
}
```

This way, you can construct complex, type safe queries using the jOOQ API and have your [`jakarta.persistence.EntityManager`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/EntityManager) execute it with all the transaction semantics attached:

```java
List<Object[]> books =
nativeQuery(em, DSL.using(configuration)
    .select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, BOOK.TITLE)
    .from(AUTHOR)
    .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
    .orderBy(BOOK.ID));

books.forEach((Object[] book) -> System.out.println(book[0] + " " + book[1] + " wrote " + book[2]));
```

<a id="using-jooq-with-jpa-entities"></a>
##### 4.30.2.2. Using jOOQ with JPA entities

> [!TIP]
> The goal of these sections is to describe how to do this, if you have strong reasons to do so. Mostly, however, you're better off executing your queries directly with jOOQ, especially if you want to use jOOQ's more advanced features. [This blog post illustrates various reason why it's better to execute queries directly with jOOQ](https://blog.jooq.org/why-you-should-execute-jooq-queries-with-jooq/).

The simplest way to fetch entities via the native query API is by passing the entity class along to the native query method. The following example maps jOOQ query results to JPA entities ([from the previous section](#using-jooq-with-jpa)). Just add the following utility method:

```java
public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, Class<E> type) {

    // Extract the SQL statement from the jOOQ query:
    Query result = em.createNativeQuery(query.getSQL(), type);

    // Extract the bind values from the jOOQ query:
    List<Object> values = query.getBindValues();
    for (int i = 0; i < values.size(); i++) {
        result.setParameter(i + 1, values.get(i));
    }

    // There's an unsafe cast here, but we can be sure that we'll get the right type from JPA
    return result.getResultList();
}
```

Note, if you're using [custom data types](#codegen-database-forced-types-converter) or [bindings](#codegen-database-forced-types-binding), make sure to take those into account as well. E.g. as follows:

```java
static List<Object[]> nativeQuery(EntityManager em, org.jooq.Query query, Class<E> type) {

    // Extract the SQL statement from the jOOQ query:
    Query result = em.createNativeQuery(query.getSQL(), type);

    // Extract the bind values from the jOOQ query:
    int i = 1;
    for (Param<?> param : query.getParams().values())
        if (!param.isInline())
            result.setParameter(i++, convertToDatabaseType(param));

    return result.getResultList();
}

static <T> Object convertToDatabaseType(Param<T> param) {
    return param.getBinding().converter().to(param.getValue());
}
```

With the above simple API, we're ready to write complex jOOQ queries and map their results to JPA entities:

```java
List<JPAAuthor> authors =
nativeQuery(em,
    DSL.using(configuration)
       .select()
       .from(AUTHOR)
       .orderBy(AUTHOR.ID)
, JPAAuthor.class);

authors.forEach(author -> {
    System.out.println(author.firstName + " " + author.lastName + " wrote");

    books.forEach(book -> {
        System.out.println("  " + book.title);
    });
});
```

<a id="using-jooq-with-jpa-entityresult"></a>
##### 4.30.2.3. Using jOOQ with JPA EntityResult

> [!TIP]
> The goal of these sections is to describe how to do this, if you have strong reasons to do so. Mostly, however, you're better off executing your queries directly with jOOQ, especially if you want to use jOOQ's more advanced features. [This blog post illustrates various reason why it's better to execute queries directly with jOOQ](https://blog.jooq.org/why-you-should-execute-jooq-queries-with-jooq/).

While JPA specifies how the mapping should be implemented (e.g. using [`jakarta.persistence.SqlResultSetMapping`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/SqlResultSetMapping)), there are no limitations regarding how you want to generate the SQL statement. The following, simple example shows how you can produce `JPABook` and `JPAAuthor` entities ([from the previous section](#using-jooq-with-jpa)) from a jOOQ-generated SQL statement.

In order to do so, we'll need to specify the [`SqlResultSetMapping`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/SqlResultSetMapping). This can be done on any entity, and in this case, we're using [`jakarta.persistence.EntityResult`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/EntityResult):

```java
@SqlResultSetMapping(
    name = "bookmapping",
    entities = {
        @EntityResult(
            entityClass = JPABook.class,
            fields = {
                @FieldResult(name = "id", column = "b_id"),
                @FieldResult(name = "title", column = "b_title"),
                @FieldResult(name = "author", column = "b_author_id")
            }
        ),
        @EntityResult(
            entityClass = JPAAuthor.class,
            fields = {
                @FieldResult(name = "id", column = "a_id"),
                @FieldResult(name = "firstName", column = "a_first_name"),
                @FieldResult(name = "lastName", column = "a_last_name")
            }
        )
    }
)
```

Note how we need to map between:

- [`FieldResult.name()`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/FieldResult#name()), which corresponds to the entity's attribute name
- [`FieldResult.column()`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/FieldResult#column()), which corresponds to the SQL result's column name

With the above boilerplate in place, we can now fetch entities using jOOQ and JPA:

```java
public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, String resultSetMapping) {

    // Extract the SQL statement from the jOOQ query:
    Query result = em.createNativeQuery(query.getSQL(), resultSetMapping);

    // Extract the bind values from the jOOQ query:
    List<Object> values = query.getBindValues();
    for (int i = 0; i < values.size(); i++) {
        result.setParameter(i + 1, values.get(i));
    }

    return result.getResultList();
}
```

Note, if you're using [custom data types](#codegen-database-forced-types-converter) or [bindings](#codegen-database-forced-types-binding), make sure to take those into account as well. E.g. as follows:

```java
public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, String resultSetMapping) {

    // Extract the SQL statement from the jOOQ query:
    Query result = em.createNativeQuery(query.getSQL(), resultSetMapping);

    // Extract the bind values from the jOOQ query:
    int i = 1;
    for (Param<?> param : query.getParams().values())
        if (!param.isInline())
            result.setParameter(i++, convertToDatabaseType(param));

    return result.getResultList();
}

static <T> Object convertToDatabaseType(Param<T> param) {
    return param.getBinding().converter().to(param.getValue());
}
```

###### Using the above API

Now that we have everything setup, we can use the above API to run a jOOQ query to fetch JPA entities like this:

```java
List<Object[]> result =
nativeQuery(em,
    DSL.using(configuration
       .select(
           AUTHOR.ID.as("a_id"),
           AUTHOR.FIRST_NAME.as("a_first_name"),
           AUTHOR.LAST_NAME.as("a_last_name"),
           BOOK.ID.as("b_id"),
           BOOK.AUTHOR_ID.as("b_author_id"),
           BOOK.TITLE.as("b_title")
       )
       .from(AUTHOR)
       .join(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
       .orderBy(BOOK.ID)),
    "bookmapping" // The name of the SqlResultSetMapping
);

result.forEach((Object[] entities) -> {
    JPAAuthor author = (JPAAuthor) entities[1];
    JPABook book = (JPABook) entities[0];

    System.out.println(author.firstName + " " + author.lastName + " wrote " + book.title);
});
```

The entities are now ready to be modified and persisted again.

Caveats:

- We have to reference the result set mapping by name (a String) - there is no type safety involved here
- We don't know the type contained in the resulting `List` - there is a potential for `ClassCastException`
- The results are in fact a list of `Object[]`, with the individual entities listed in the array, which need explicit casting

<a id="code-generation"></a>
## 5. Code generation

While optional, source code generation is one of jOOQ's main assets if you wish to increase developer productivity. jOOQ's code generator takes your database schema and reverse-engineers it into a set of Java classes modelling [tables](#table-expressions), [records](#record-vs-tablerecord), [sequences](#sequence-execution), [POJOs](#pojos), [DAOs](#daos), [stored procedures](#stored-procedures), user-defined types and many more.

The essential ideas behind source code generation are these:

- **Increased IDE support**: Type your Java code directly against your database schema, with all type information available
- **Type-safety**: When your database schema changes, your generated code will change as well. Removing columns will lead to compilation errors, which you can detect early.

The following chapters will show how to configure the code generator and how to generate various artefacts.

<a id="codegen-configuration"></a>
### 5.1. Configuration and setup of the generator

There are three binaries available with jOOQ, to be downloaded from [https://www.jooq.org/download](https://www.jooq.org/download) or from Maven central:

- **jooq-3.22.0-SNAPSHOT.jar**  
  The main library that you will include in your application to run jOOQ
- **jooq-meta-3.22.0-SNAPSHOT.jar**  
  The utility that you will include in your build to navigate your database schema for code generation. This can be used as a schema crawler as well.
- **jooq-codegen-3.22.0-SNAPSHOT.jar**  
  The utility that you will include in your build to generate your database schema

#### Configure jOOQ's code generator

You need to tell jOOQ some things about your database connection. Here's an example of how to do it for an Oracle database

**XML (standalone and maven):**

```xml
<configuration>
  <!-- Configure the database connection here -->
  <jdbc>
    <driver>oracle.jdbc.OracleDriver</driver>
    <url>jdbc:oracle:thin:@[your jdbc connection parameters]</url>
    <user>[your database user]</user>
    <password>[your database password]</password>

    <!-- You can also pass user/password and other JDBC properties in the optional properties tag: -->
    <properties>
      <property><key>user</key><value>[db-user]</value></property>
      <property><key>password</key><value>[db-password]</value></property>
    </properties>
  </jdbc>

  <generator>
    <database>
      <!-- The database dialect from jooq-meta. Available dialects are
           named org.jooq.meta.[database].[database]Database.

           Natively supported values are:

               org.jooq.meta.ase.ASEDatabase
               org.jooq.meta.auroramysql.AuroraMySQLDatabase
               org.jooq.meta.aurorapostgres.AuroraPostgresDatabase
               org.jooq.meta.clickhouse.ClickHouseDatabase
               org.jooq.meta.cockroachdb.CockroachDBDatabase
               org.jooq.meta.databricks.DatabricksDatabase
               org.jooq.meta.db2.DB2Database
               org.jooq.meta.derby.DerbyDatabase
               org.jooq.meta.firebird.FirebirdDatabase
               org.jooq.meta.h2.H2Database
               org.jooq.meta.hana.HANADatabase
               org.jooq.meta.hsqldb.HSQLDBDatabase
               org.jooq.meta.ignite.IgniteDatabase
               org.jooq.meta.informix.InformixDatabase
               org.jooq.meta.ingres.IngresDatabase
               org.jooq.meta.mariadb.MariaDBDatabase
               org.jooq.meta.mysql.MySQLDatabase
               org.jooq.meta.oracle.OracleDatabase
               org.jooq.meta.postgres.PostgresDatabase
               org.jooq.meta.redshift.RedshiftDatabase
               org.jooq.meta.snowflake.SnowflakeDatabase
               org.jooq.meta.sqldatawarehouse.SQLDataWarehouseDatabase
               org.jooq.meta.sqlite.SQLiteDatabase
               org.jooq.meta.sqlserver.SQLServerDatabase
               org.jooq.meta.sybase.SybaseDatabase
               org.jooq.meta.teradata.TeradataDatabase
               org.jooq.meta.trino.TrinoDatabase
               org.jooq.meta.vertica.VerticaDatabase

           This value can be used to reverse-engineer generic JDBC DatabaseMetaData (e.g. for MS Access)

               org.jooq.meta.jdbc.JDBCDatabase

           This value can be used to reverse-engineer standard jOOQ-meta XML formats

               org.jooq.meta.xml.XMLDatabase

           This value can be used to reverse-engineer schemas defined by SQL files
           (requires jooq-meta-extensions dependency)

               org.jooq.meta.extensions.ddl.DDLDatabase

           This value can be used to reverse-engineer schemas defined by JPA annotated entities
           (requires jooq-meta-extensions-hibernate dependency)

               org.jooq.meta.extensions.jpa.JPADatabase

           You can also provide your own org.jooq.meta.Database implementation
           here, if your database is currently not supported -->
      <name>org.jooq.meta.oracle.OracleDatabase</name>

      <!-- All elements that are generated from your schema (A Java regular expression.
           Use the pipe to separate several expressions) Watch out for
           case-sensitivity. Depending on your database, this might be
           important!

           You can create case-insensitive regular expressions using this syntax: (?i:expr)

           Whitespace is ignored and comments are possible.
           -->
      <includes>.*</includes>

      <!-- All elements that are excluded from your schema (A Java regular expression.
           Use the pipe to separate several expressions). Excludes match before
           includes, i.e. excludes have a higher priority -->
      <excludes>
           UNUSED_TABLE                # This table (unqualified name) should not be generated
         | PREFIX_.*                   # Objects with a given prefix should not be generated
         | SECRET_SCHEMA\.SECRET_TABLE # This table (qualified name) should not be generated
         | SECRET_ROUTINE              # This routine (unqualified name) ...
      </excludes>

      <!-- The schema that is used locally as a source for meta information.
           This could be your development schema or the production schema, etc
           This cannot be combined with the schemata element.

           If left empty, jOOQ will generate all available schemata. See the
           manual's next section to learn how to generate several schemata -->
      <inputSchema>[your database schema / owner / name]</inputSchema>
    </database>

    <!-- Generation flags: See advanced configuration properties -->
    <generate/>

    <target>
      <!-- The destination package of your generated classes (within the
           destination directory)

           jOOQ may append the schema name to this package if generating multiple schemas,
           e.g. org.jooq.your.packagename.schema1
                org.jooq.your.packagename.schema2 -->
      <packageName>org.jooq.your.packagename</packageName>

      <!-- The destination directory of your generated classes -->
      <directory>/path/to/your/dir</directory>
    </target>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // Configure the database connection here
  .withJdbc(new Jdbc()
    .withDriver("oracle.jdbc.OracleDriver")
    .withUrl("jdbc:oracle:thin:@[your jdbc connection parameters]")
    .withUser("[your database user]")
    .withPassword("[your database password]")

    // You can also pass user/password and other JDBC properties in the optional properties tag:
    .withProperties(
      new Property()
        .withKey("user")
        .withValue("[db-user]"),
      new Property()
        .withKey("password")
        .withValue("[db-password]")
    )
  )
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // The database dialect from jooq-meta. Available dialects are
      // named org.jooq.meta.[database].[database]Database.
      // 
      // Natively supported values are:
      // 
      // org.jooq.meta.ase.ASEDatabase
      // org.jooq.meta.auroramysql.AuroraMySQLDatabase
      // org.jooq.meta.aurorapostgres.AuroraPostgresDatabase
      // org.jooq.meta.clickhouse.ClickHouseDatabase
      // org.jooq.meta.cockroachdb.CockroachDBDatabase
      // org.jooq.meta.databricks.DatabricksDatabase
      // org.jooq.meta.db2.DB2Database
      // org.jooq.meta.derby.DerbyDatabase
      // org.jooq.meta.firebird.FirebirdDatabase
      // org.jooq.meta.h2.H2Database
      // org.jooq.meta.hana.HANADatabase
      // org.jooq.meta.hsqldb.HSQLDBDatabase
      // org.jooq.meta.ignite.IgniteDatabase
      // org.jooq.meta.informix.InformixDatabase
      // org.jooq.meta.ingres.IngresDatabase
      // org.jooq.meta.mariadb.MariaDBDatabase
      // org.jooq.meta.mysql.MySQLDatabase
      // org.jooq.meta.oracle.OracleDatabase
      // org.jooq.meta.postgres.PostgresDatabase
      // org.jooq.meta.redshift.RedshiftDatabase
      // org.jooq.meta.snowflake.SnowflakeDatabase
      // org.jooq.meta.sqldatawarehouse.SQLDataWarehouseDatabase
      // org.jooq.meta.sqlite.SQLiteDatabase
      // org.jooq.meta.sqlserver.SQLServerDatabase
      // org.jooq.meta.sybase.SybaseDatabase
      // org.jooq.meta.teradata.TeradataDatabase
      // org.jooq.meta.trino.TrinoDatabase
      // org.jooq.meta.vertica.VerticaDatabase
      // 
      // This value can be used to reverse-engineer generic JDBC DatabaseMetaData (e.g. for MS Access)
      // 
      // org.jooq.meta.jdbc.JDBCDatabase
      // 
      // This value can be used to reverse-engineer standard jOOQ-meta XML formats
      // 
      // org.jooq.meta.xml.XMLDatabase
      // 
      // This value can be used to reverse-engineer schemas defined by SQL files
      // (requires jooq-meta-extensions dependency)
      // 
      // org.jooq.meta.extensions.ddl.DDLDatabase
      // 
      // This value can be used to reverse-engineer schemas defined by JPA annotated entities
      // (requires jooq-meta-extensions-hibernate dependency)
      // 
      // org.jooq.meta.extensions.jpa.JPADatabase
      // 
      // You can also provide your own org.jooq.meta.Database implementation
      // here, if your database is currently not supported
      .withName("org.jooq.meta.oracle.OracleDatabase")

      // All elements that are generated from your schema (A Java regular expression.
      // Use the pipe to separate several expressions) Watch out for
      // case-sensitivity. Depending on your database, this might be
      // important!
      // 
      // You can create case-insensitive regular expressions using this syntax: (?i:expr)
      // 
      // Whitespace is ignored and comments are possible.
      .withIncludes(".*")

      // All elements that are excluded from your schema (A Java regular expression.
      // Use the pipe to separate several expressions). Excludes match before
      // includes, i.e. excludes have a higher priority
      .withExcludes("""
           UNUSED_TABLE                # This table (unqualified name) should not be generated
         | PREFIX_.*                   # Objects with a given prefix should not be generated
         | SECRET_SCHEMA\.SECRET_TABLE # This table (qualified name) should not be generated
         | SECRET_ROUTINE              # This routine (unqualified name) ...
      """)

      // The schema that is used locally as a source for meta information.
      // This could be your development schema or the production schema, etc
      // This cannot be combined with the schemata element.
      // 
      // If left empty, jOOQ will generate all available schemata. See the
      // manual's next section to learn how to generate several schemata
      .withInputSchema("[your database schema / owner / name]")
    )

    // Generation flags: See advanced configuration properties
    .withGenerate()
    .withTarget(new Target()

      // The destination package of your generated classes (within the
      // destination directory)
      // 
      // jOOQ may append the schema name to this package if generating multiple schemas,
      // e.g. org.jooq.your.packagename.schema1
      // org.jooq.your.packagename.schema2
      .withPackageName("org.jooq.your.packagename")

      // The destination directory of your generated classes
      .withDirectory("/path/to/your/dir")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // Configure the database connection here
  jdbc {
    driver = "oracle.jdbc.OracleDriver"
    url = "jdbc:oracle:thin:@[your jdbc connection parameters]"
    user = "[your database user]"
    password = "[your database password]"

    // You can also pass user/password and other JDBC properties in the optional properties tag:
    properties {
      property {
        key = "user"
        value = "[db-user]"
      }
      property {
        key = "password"
        value = "[db-password]"
      }
    }
  }
  generator {
    database {

      // The database dialect from jooq-meta. Available dialects are
      // named org.jooq.meta.[database].[database]Database.
      // 
      // Natively supported values are:
      // 
      // org.jooq.meta.ase.ASEDatabase
      // org.jooq.meta.auroramysql.AuroraMySQLDatabase
      // org.jooq.meta.aurorapostgres.AuroraPostgresDatabase
      // org.jooq.meta.clickhouse.ClickHouseDatabase
      // org.jooq.meta.cockroachdb.CockroachDBDatabase
      // org.jooq.meta.databricks.DatabricksDatabase
      // org.jooq.meta.db2.DB2Database
      // org.jooq.meta.derby.DerbyDatabase
      // org.jooq.meta.firebird.FirebirdDatabase
      // org.jooq.meta.h2.H2Database
      // org.jooq.meta.hana.HANADatabase
      // org.jooq.meta.hsqldb.HSQLDBDatabase
      // org.jooq.meta.ignite.IgniteDatabase
      // org.jooq.meta.informix.InformixDatabase
      // org.jooq.meta.ingres.IngresDatabase
      // org.jooq.meta.mariadb.MariaDBDatabase
      // org.jooq.meta.mysql.MySQLDatabase
      // org.jooq.meta.oracle.OracleDatabase
      // org.jooq.meta.postgres.PostgresDatabase
      // org.jooq.meta.redshift.RedshiftDatabase
      // org.jooq.meta.snowflake.SnowflakeDatabase
      // org.jooq.meta.sqldatawarehouse.SQLDataWarehouseDatabase
      // org.jooq.meta.sqlite.SQLiteDatabase
      // org.jooq.meta.sqlserver.SQLServerDatabase
      // org.jooq.meta.sybase.SybaseDatabase
      // org.jooq.meta.teradata.TeradataDatabase
      // org.jooq.meta.trino.TrinoDatabase
      // org.jooq.meta.vertica.VerticaDatabase
      // 
      // This value can be used to reverse-engineer generic JDBC DatabaseMetaData (e.g. for MS Access)
      // 
      // org.jooq.meta.jdbc.JDBCDatabase
      // 
      // This value can be used to reverse-engineer standard jOOQ-meta XML formats
      // 
      // org.jooq.meta.xml.XMLDatabase
      // 
      // This value can be used to reverse-engineer schemas defined by SQL files
      // (requires jooq-meta-extensions dependency)
      // 
      // org.jooq.meta.extensions.ddl.DDLDatabase
      // 
      // This value can be used to reverse-engineer schemas defined by JPA annotated entities
      // (requires jooq-meta-extensions-hibernate dependency)
      // 
      // org.jooq.meta.extensions.jpa.JPADatabase
      // 
      // You can also provide your own org.jooq.meta.Database implementation
      // here, if your database is currently not supported
      name = "org.jooq.meta.oracle.OracleDatabase"

      // All elements that are generated from your schema (A Java regular expression.
      // Use the pipe to separate several expressions) Watch out for
      // case-sensitivity. Depending on your database, this might be
      // important!
      // 
      // You can create case-insensitive regular expressions using this syntax: (?i:expr)
      // 
      // Whitespace is ignored and comments are possible.
      includes = ".*"

      // All elements that are excluded from your schema (A Java regular expression.
      // Use the pipe to separate several expressions). Excludes match before
      // includes, i.e. excludes have a higher priority
      excludes = """
           UNUSED_TABLE                # This table (unqualified name) should not be generated
         | PREFIX_.*                   # Objects with a given prefix should not be generated
         | SECRET_SCHEMA\.SECRET_TABLE # This table (qualified name) should not be generated
         | SECRET_ROUTINE              # This routine (unqualified name) ...
      """

      // The schema that is used locally as a source for meta information.
      // This could be your development schema or the production schema, etc
      // This cannot be combined with the schemata element.
      // 
      // If left empty, jOOQ will generate all available schemata. See the
      // manual's next section to learn how to generate several schemata
      inputSchema = "[your database schema / owner / name]"
    }

    // Generation flags: See advanced configuration properties
    generate {}
    target {

      // The destination package of your generated classes (within the
      // destination directory)
      // 
      // jOOQ may append the schema name to this package if generating multiple schemas,
      // e.g. org.jooq.your.packagename.schema1
      // org.jooq.your.packagename.schema2
      packageName = "org.jooq.your.packagename"

      // The destination directory of your generated classes
      directory = "/path/to/your/dir"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // Configure the database connection here
  jdbc {
    driver = "oracle.jdbc.OracleDriver"
    url = "jdbc:oracle:thin:@[your jdbc connection parameters]"
    user = "[your database user]"
    password = "[your database password]"

    // You can also pass user/password and other JDBC properties in the optional properties tag:
    properties {
      property {
        key = "user"
        value = "[db-user]"
      }
      property {
        key = "password"
        value = "[db-password]"
      }
    }
  }
  generator {
    database {

      // The database dialect from jooq-meta. Available dialects are
      // named org.jooq.meta.[database].[database]Database.
      // 
      // Natively supported values are:
      // 
      // org.jooq.meta.ase.ASEDatabase
      // org.jooq.meta.auroramysql.AuroraMySQLDatabase
      // org.jooq.meta.aurorapostgres.AuroraPostgresDatabase
      // org.jooq.meta.clickhouse.ClickHouseDatabase
      // org.jooq.meta.cockroachdb.CockroachDBDatabase
      // org.jooq.meta.databricks.DatabricksDatabase
      // org.jooq.meta.db2.DB2Database
      // org.jooq.meta.derby.DerbyDatabase
      // org.jooq.meta.firebird.FirebirdDatabase
      // org.jooq.meta.h2.H2Database
      // org.jooq.meta.hana.HANADatabase
      // org.jooq.meta.hsqldb.HSQLDBDatabase
      // org.jooq.meta.ignite.IgniteDatabase
      // org.jooq.meta.informix.InformixDatabase
      // org.jooq.meta.ingres.IngresDatabase
      // org.jooq.meta.mariadb.MariaDBDatabase
      // org.jooq.meta.mysql.MySQLDatabase
      // org.jooq.meta.oracle.OracleDatabase
      // org.jooq.meta.postgres.PostgresDatabase
      // org.jooq.meta.redshift.RedshiftDatabase
      // org.jooq.meta.snowflake.SnowflakeDatabase
      // org.jooq.meta.sqldatawarehouse.SQLDataWarehouseDatabase
      // org.jooq.meta.sqlite.SQLiteDatabase
      // org.jooq.meta.sqlserver.SQLServerDatabase
      // org.jooq.meta.sybase.SybaseDatabase
      // org.jooq.meta.teradata.TeradataDatabase
      // org.jooq.meta.trino.TrinoDatabase
      // org.jooq.meta.vertica.VerticaDatabase
      // 
      // This value can be used to reverse-engineer generic JDBC DatabaseMetaData (e.g. for MS Access)
      // 
      // org.jooq.meta.jdbc.JDBCDatabase
      // 
      // This value can be used to reverse-engineer standard jOOQ-meta XML formats
      // 
      // org.jooq.meta.xml.XMLDatabase
      // 
      // This value can be used to reverse-engineer schemas defined by SQL files
      // (requires jooq-meta-extensions dependency)
      // 
      // org.jooq.meta.extensions.ddl.DDLDatabase
      // 
      // This value can be used to reverse-engineer schemas defined by JPA annotated entities
      // (requires jooq-meta-extensions-hibernate dependency)
      // 
      // org.jooq.meta.extensions.jpa.JPADatabase
      // 
      // You can also provide your own org.jooq.meta.Database implementation
      // here, if your database is currently not supported
      name = "org.jooq.meta.oracle.OracleDatabase"

      // All elements that are generated from your schema (A Java regular expression.
      // Use the pipe to separate several expressions) Watch out for
      // case-sensitivity. Depending on your database, this might be
      // important!
      // 
      // You can create case-insensitive regular expressions using this syntax: (?i:expr)
      // 
      // Whitespace is ignored and comments are possible.
      includes = ".*"

      // All elements that are excluded from your schema (A Java regular expression.
      // Use the pipe to separate several expressions). Excludes match before
      // includes, i.e. excludes have a higher priority
      excludes = """
           UNUSED_TABLE                # This table (unqualified name) should not be generated
         | PREFIX_.*                   # Objects with a given prefix should not be generated
         | SECRET_SCHEMA\.SECRET_TABLE # This table (qualified name) should not be generated
         | SECRET_ROUTINE              # This routine (unqualified name) ...
      """

      // The schema that is used locally as a source for meta information.
      // This could be your development schema or the production schema, etc
      // This cannot be combined with the schemata element.
      // 
      // If left empty, jOOQ will generate all available schemata. See the
      // manual's next section to learn how to generate several schemata
      inputSchema = "[your database schema / owner / name]"
    }

    // Generation flags: See advanced configuration properties
    generate {}
    target {

      // The destination package of your generated classes (within the
      // destination directory)
      // 
      // jOOQ may append the schema name to this package if generating multiple schemas,
      // e.g. org.jooq.your.packagename.schema1
      // org.jooq.your.packagename.schema2
      packageName = "org.jooq.your.packagename"

      // The destination directory of your generated classes
      directory = "/path/to/your/dir"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

There are also lots of advanced configuration parameters, which will be treated in the [manual's section about advanced code generation features](#codegen-advanced). Note, you can find the official XSD file for a formal specification at:  
[https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd)

#### Run jOOQ code generation

Code generation works by calling this class with the above property file as argument.

```
org.jooq.codegen.GenerationTool /jooq-config.xml
```

Be sure that these elements are located on the classpath:

- jooq-3.22.0-SNAPSHOT.jar, jooq-meta-3.22.0-SNAPSHOT.jar, jooq-codegen-3.22.0-SNAPSHOT.jar, reactive-streams-1.0.3.jar, r2dbc-spi-1.0.0.RELEASE.jar
- The JDBC driver you configured

#### A command-line example (for Windows, OSX/Linux/etc. will be similar)

- Put the XML configuration file, jooq*.jar and the JDBC driver into a directory, e.g. C:\temp\jooq
- Go to C:\temp\jooq
- Run `java -cp jooq-3.22.0-SNAPSHOT.jar;jooq-meta-3.22.0-SNAPSHOT.jar;jooq-codegen-3.22.0-SNAPSHOT.jar;reactive-streams-1.0.3.jar;r2dbc-spi-1.0.0.RELEASE.jar;[JDBC-driver].jar org.jooq.codegen.GenerationTool <XML-file>`

Note that the XML configuration file can also be loaded from the classpath, in which case the path should be given as `/path/to/my-configuration.xml`

#### Run code generation from Eclipse

Of course, you can also run code generation from your IDE. In Eclipse, set up a project like this. Note that:

- this example uses jOOQ's log4j support by adding log4j.xml and log4j.jar to the project classpath.
- the actual jooq-3.22.0-SNAPSHOT.jar, jooq-meta-3.22.0-SNAPSHOT.jar, jooq-codegen-3.22.0-SNAPSHOT.jar artefacts may contain version numbers in the file names.

![Eclipse configuration](https://www.jooq.org/img/eclipse-example-01.png)

Once the project is set up correctly with all required artefacts on the classpath, you can configure an Eclipse Run Configuration for org.jooq.codegen.GenerationTool.

![Eclipse configuration](https://www.jooq.org/img/eclipse-example-02.png)

With the XML file as an argument

![Eclipse configuration](https://www.jooq.org/img/eclipse-example-03.png)

And the classpath set up correctly

![Eclipse configuration](https://www.jooq.org/img/eclipse-example-04.png)

Finally, run the code generation and see your generated artefacts

![Eclipse configuration](https://www.jooq.org/img/eclipse-example-05.png)

#### Integrate generation with Maven

Using the official jOOQ-codegen-maven plugin, you can integrate source code generation in your Maven build process:

```xml
<plugin>

  <!-- Specify the maven code generator plugin -->
  <!-- Use org.jooq                for the Open Source Edition
           org.jooq.pro            for commercial editions with Java 17 support,
           org.jooq.pro-java-11    for commercial editions with Java 11 support,
           org.jooq.pro-java-8     for commercial editions with Java 8 support,
           org.jooq.trial          for the free trial edition with Java 17 support,
           org.jooq.trial-java-11  for the free trial edition with Java 11 support,
           org.jooq.trial-java-8   for the free trial edition with Java 8 support

       Note: Only the Open Source Edition is hosted on Maven Central.
             Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org -->
  <groupId>org.jooq</groupId>
  <artifactId>jooq-codegen-maven</artifactId>
  <version>3.22.0-SNAPSHOT</version>

  <!-- The plugin should hook into the generate goal -->
  <executions>
    <execution>
      <goals>
        <goal>generate</goal>
      </goals>
    </execution>
  </executions>

  <!-- Manage the plugin's dependency. In this example, we'll use a PostgreSQL database -->
  <dependencies>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.7.3</version>
    </dependency>
  </dependencies>

  <!-- Specify the plugin configuration.
       The configuration format is the same as for the standalone code generator -->
  <configuration>

    <!-- JDBC connection parameters -->
    <jdbc>
      <driver>org.postgresql.Driver</driver>
      <url>jdbc:postgresql:postgres</url>
      <user>postgres</user>
      <password>test</password>
    </jdbc>

    <!-- Generator parameters -->
    <generator>
      <database>
        <name>org.jooq.meta.postgres.PostgresDatabase</name>
        <includes>.*</includes>
        <excludes></excludes>
        <!-- In case your database supports catalogs, e.g. SQL Server:
        <inputCatalog>public</inputCatalog>
          -->
        <inputSchema>public</inputSchema>
      </database>
      <target>
        <packageName>org.jooq.codegen.maven.example</packageName>
        <directory>target/generated-sources/jooq</directory>
      </target>
    </generator>
  </configuration>
</plugin>
```

#### Use jOOQ generated classes in your application

Be sure, both jooq-3.22.0-SNAPSHOT.jar and your generated package (see configuration) are located on your classpath. Once this is done, you can execute SQL statements with your generated classes.

<a id="codegen-advanced"></a>
### 5.2. Advanced generator configuration

In the [previous section](#codegen-configuration) we have seen how jOOQ's source code generator is configured and run within a few steps. In this chapter we'll cover some advanced settings, individually.

<a id="codegen-config-logging"></a>
#### 5.2.1. Logging

This optional top level configuration element simply allows for overriding the log level of anything that has been specified by the runtime, e.g. in log4j or slf4j and is helpful for per-code-generation log configuration. For example, in order to mute everything that is less than WARN level, write:

**XML (standalone and maven):**

```xml
<configuration>
  <logging>WARN</logging>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withLogging(Logging.WARN)
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  logging = Logging.WARN
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  logging = "WARN"
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Available log levels are

- `TRACE`
- `DEBUG`
- `INFO`
- `WARN`
- `ERROR`
- `FATAL`

<a id="codegen-config-onerror"></a>
#### 5.2.2. Error handling

This optional top level configuration element allows configuring the action to be taken by the generator in case of unexpected exceptions encountered during the code generation.

**XML (standalone and maven):**

```xml
<configuration>

  <!-- Behaviour when encountering an exception outside of jOOQ's control. Defaults to FAIL -->
  <onError>FAIL</onError>

  <!-- Behaviour when encountering an unused configuration element. Defaults to LOG -->
  <onUnused>LOG</onUnused>

  <!-- Behaviour when encountering deprecated configuration. Defaults to LOG -->
  <onDeprecated>LOG</onDeprecated>

  <!-- Behaviour when encountering experimental configuration. Defaults to LOG -->
  <onExperimental>LOG</onExperimental>

  <!-- Behaviour when encountering unsupported configuration. Defaults to FAIL -->
  <onMisconfiguration>FAIL</onMisconfiguration>

  <!-- Behaviour when encountering meta data that causes problems with configuration. Defaults to LOG -->
  <onMetadataProblem>LOG</onMetadataProblem>
  
  <!-- Behaviour when encountering a slow meta data query. Defaults to LOG -->
  <onPerformanceProblem>LOG</onPerformanceProblem>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // Behaviour when encountering an exception outside of jOOQ's control. Defaults to FAIL
  .withOnError(OnError.FAIL)

  // Behaviour when encountering an unused configuration element. Defaults to LOG
  .withOnUnused(OnError.LOG)

  // Behaviour when encountering deprecated configuration. Defaults to LOG
  .withOnDeprecated(OnError.LOG)

  // Behaviour when encountering experimental configuration. Defaults to LOG
  .withOnExperimental(OnError.LOG)

  // Behaviour when encountering unsupported configuration. Defaults to FAIL
  .withOnMisconfiguration(OnError.FAIL)

  // Behaviour when encountering meta data that causes problems with configuration. Defaults to LOG
  .withOnMetadataProblem(OnError.LOG)

  // Behaviour when encountering a slow meta data query. Defaults to LOG
  .withOnPerformanceProblem(OnError.LOG)
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // Behaviour when encountering an exception outside of jOOQ's control. Defaults to FAIL
  onError = OnError.FAIL

  // Behaviour when encountering an unused configuration element. Defaults to LOG
  onUnused = OnError.LOG

  // Behaviour when encountering deprecated configuration. Defaults to LOG
  onDeprecated = OnError.LOG

  // Behaviour when encountering experimental configuration. Defaults to LOG
  onExperimental = OnError.LOG

  // Behaviour when encountering unsupported configuration. Defaults to FAIL
  onMisconfiguration = OnError.FAIL

  // Behaviour when encountering meta data that causes problems with configuration. Defaults to LOG
  onMetadataProblem = OnError.LOG

  // Behaviour when encountering a slow meta data query. Defaults to LOG
  onPerformanceProblem = OnError.LOG
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // Behaviour when encountering an exception outside of jOOQ's control. Defaults to FAIL
  onError = "FAIL"

  // Behaviour when encountering an unused configuration element. Defaults to LOG
  onUnused = "LOG"

  // Behaviour when encountering deprecated configuration. Defaults to LOG
  onDeprecated = "LOG"

  // Behaviour when encountering experimental configuration. Defaults to LOG
  onExperimental = "LOG"

  // Behaviour when encountering unsupported configuration. Defaults to FAIL
  onMisconfiguration = "FAIL"

  // Behaviour when encountering meta data that causes problems with configuration. Defaults to LOG
  onMetadataProblem = "LOG"

  // Behaviour when encountering a slow meta data query. Defaults to LOG
  onPerformanceProblem = "LOG"
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

The available error actions are:

- `FAIL` - The exception will be thrown and handled by the caller (e.g. Maven)
- `LOG` - The exception will be handled by the generator by logging it as a warning
- `SILENT` - The exception will be silently ignored by the generator

<a id="codegen-config-jdbc"></a>
#### 5.2.3. Jdbc

This optional top level configuration element allows for configuring a JDBC connection. By default, the jOOQ code generator requires an active JDBC connection to reverse engineer your database schema. For example, if you want to connect to a MySQL database, write this:

**XML (standalone and maven):**

```xml
<configuration>
  <jdbc>
    <driver>com.mysql.cj.jdbc.Driver</driver>
    <url>jdbc:mysql://localhost/testdb</url>

    <!-- "username" is a valid synonym for "user" -->
    <user>root</user>
    <password>secret</password>
  </jdbc>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withJdbc(new Jdbc()
    .withDriver("com.mysql.cj.jdbc.Driver")
    .withUrl("jdbc:mysql://localhost/testdb")

    // "username" is a valid synonym for "user"
    .withUser("root")
    .withPassword("secret")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  jdbc {
    driver = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://localhost/testdb"

    // "username" is a valid synonym for "user"
    user = "root"
    password = "secret"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  jdbc {
    driver = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://localhost/testdb"

    // "username" is a valid synonym for "user"
    user = "root"
    password = "secret"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Note that when using the programmatic configuration API through the `GenerationTool`, you can also pass a pre-existing JDBC connection to the `GenerationTool` and leave this configuration element alone.

> [!TIP]
> Make sure the JDBC driver is available to the code generator as a [code generator dependency](#codegen-dependencies)

##### Using system properties for JDBC parameters

Some configuration properties can be configured using [system properties](#codegen-system-properties). In particular, the JDBC URL may be important to configure via system property, if it is dynamic, e.g. based on a random testcontainers port, and shouldn't be configured eagerly in case Maven/Gradle can avoid starting the container when nothing has changed:

**XML (standalone and maven):**

```xml
<configuration>
  <jdbc>
    <driver>com.mysql.cj.jdbc.Driver</driver>

    <!-- The -Dcom.example.myproperty system property contains the JDBC URL -->
    <urlProperty>com.example.myproperty</urlProperty>

    <!-- "username" is a valid synonym for "user" -->
    <user>root</user>
    <password>secret</password>
  </jdbc>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withJdbc(new Jdbc()
    .withDriver("com.mysql.cj.jdbc.Driver")

    // The -Dcom.example.myproperty system property contains the JDBC URL
    .withUrlProperty("com.example.myproperty")

    // "username" is a valid synonym for "user"
    .withUser("root")
    .withPassword("secret")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  jdbc {
    driver = "com.mysql.cj.jdbc.Driver"

    // The -Dcom.example.myproperty system property contains the JDBC URL
    urlProperty = "com.example.myproperty"

    // "username" is a valid synonym for "user"
    user = "root"
    password = "secret"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  jdbc {
    driver = "com.mysql.cj.jdbc.Driver"

    // The -Dcom.example.myproperty system property contains the JDBC URL
    urlProperty = "com.example.myproperty"

    // "username" is a valid synonym for "user"
    user = "root"
    password = "secret"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Now, run the code generation with the JDBC URL specified as `-Dcom.example.myproperty=jdbc:mysql://localhost/testdb`, for example.

##### Optional JDBC properties

JDBC drivers allow for passing [`java.util.Properties`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Properties.html) to the JDBC driver when creating a connection. This is also supported in the code generator configuration with a list of key/value pairs as follows:

**XML (standalone and maven):**

```xml
<configuration>
  <jdbc>
    <driver>com.mysql.cj.jdbc.Driver</driver>
    <url>jdbc:mysql://localhost/testdb</url>
    <properties>
      <property>
        <key>user</key>
        <value>root</value>
      </property>
      <property>
        <key>password</key>
        <value>secret</value>
      </property>
    </properties>
  </jdbc>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withJdbc(new Jdbc()
    .withDriver("com.mysql.cj.jdbc.Driver")
    .withUrl("jdbc:mysql://localhost/testdb")
    .withProperties(
      new Property()
        .withKey("user")
        .withValue("root"),
      new Property()
        .withKey("password")
        .withValue("secret")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  jdbc {
    driver = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://localhost/testdb"
    properties {
      property {
        key = "user"
        value = "root"
      }
      property {
        key = "password"
        value = "secret"
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  jdbc {
    driver = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://localhost/testdb"
    properties {
      property {
        key = "user"
        value = "root"
      }
      property {
        key = "password"
        value = "secret"
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### Auto committing

jOOQ's code generator will use the driver's / connection's default auto commit flag. If for some reason you need to override this (e.g. in order to recover from failed transactions in PostgreSQL, by setting it to true), you can specify it here:

**XML (standalone and maven):**

```xml
<configuration>
  <jdbc>
    <autoCommit>true</autoCommit>
  </jdbc>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withJdbc(new Jdbc()
    .withAutoCommit(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  jdbc {
    isAutoCommit = true
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  jdbc {
    autoCommit = true
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### Init scripts

You can optionally provide a script to run after creating the JDBC connection, and before running the code generator.

**XML (standalone and maven):**

```xml
<configuration>
  <jdbc>
    <initScript>CREATE SCHEMA X//SET SCHEMA X</initScript>

    <!-- The separator between statements, defaulting to ";" -->
    <initSeparator>//</initSeparator>
  </jdbc>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withJdbc(new Jdbc()
    .withInitScript("CREATE SCHEMA X//SET SCHEMA X")

    // The separator between statements, defaulting to ";"
    .withInitSeparator("//")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  jdbc {
    initScript = "CREATE SCHEMA X//SET SCHEMA X"

    // The separator between statements, defaulting to ";"
    initSeparator = "//"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  jdbc {
    initScript = "CREATE SCHEMA X//SET SCHEMA X"

    // The separator between statements, defaulting to ";"
    initSeparator = "//"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### Security providers

You can optionally provide a [`java.security.Provider`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Provider.html) to load prior to connecting to JDBC, if your driver requires this.

**XML (standalone and maven):**

```xml
<configuration>
  <jdbc>
    <securityProvider>org.bouncycastle.jce.provider.BouncyCastleProvider</securityProvider>
  </jdbc>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withJdbc(new Jdbc()
    .withSecurityProvider("org.bouncycastle.jce.provider.BouncyCastleProvider")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  jdbc {
    securityProvider = "org.bouncycastle.jce.provider.BouncyCastleProvider"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  jdbc {
    securityProvider = "org.bouncycastle.jce.provider.BouncyCastleProvider"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### When the JDBC configuration is optional

There are some exceptions, where the JDBC connection does not need to be configured, for instance when using the [JPADatabase](#codegen-jpa) (to reverse engineer JPA annotated entities) or when using the [XMLDatabase](#codegen-xml) (to reverse engineer an XML file). Please refer to the respective sections for more details.

<a id="codegen-config-generator"></a>
#### 5.2.4. Generator

This mandatory top level configuration element wraps all the remaining configuration elements related to code generation, including the overridable code generator class.

**XML (standalone and maven):**

```xml
<configuration>
  <generator>

    <!-- Optional: The fully qualified class name of the code generator. Available generators:

         - org.jooq.codegen.JavaGenerator
         - org.jooq.codegen.KotlinGenerator
         - org.jooq.codegen.ScalaGenerator

         Defaults to org.jooq.codegen.JavaGenerator -->
    <name>...</name>

    <!-- Optional: The implementation of the code generator, written in Java -->
    <java>...</java>

    <!-- Optional: The programmatic or configurative generator strategy. -->
    <strategy/>

    <!-- Optional: The jooq-meta configuration, configuring the information schema source. -->
    <database/>

    <!-- Optional: The jooq-codegen configuration, configuring the generated output content. -->
    <generate/>

    <!-- Optional: The generation output target -->
    <target/>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()

    // Optional: The fully qualified class name of the code generator. Available generators:
    // 
    // - org.jooq.codegen.JavaGenerator
    // - org.jooq.codegen.KotlinGenerator
    // - org.jooq.codegen.ScalaGenerator
    // 
    // Defaults to org.jooq.codegen.JavaGenerator
    .withName(...)

    // Optional: The implementation of the code generator, written in Java
    .withJava(...)

    // Optional: The programmatic or configurative generator strategy.
    .withStrategy()

    // Optional: The jooq-meta configuration, configuring the information schema source.
    .withDatabase()

    // Optional: The jooq-codegen configuration, configuring the generated output content.
    .withGenerate()

    // Optional: The generation output target
    .withTarget()
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {

    // Optional: The fully qualified class name of the code generator. Available generators:
    // 
    // - org.jooq.codegen.JavaGenerator
    // - org.jooq.codegen.KotlinGenerator
    // - org.jooq.codegen.ScalaGenerator
    // 
    // Defaults to org.jooq.codegen.JavaGenerator
    name = ...

    // Optional: The implementation of the code generator, written in Java
    java = ...

    // Optional: The programmatic or configurative generator strategy.
    strategy {}

    // Optional: The jooq-meta configuration, configuring the information schema source.
    database {}

    // Optional: The jooq-codegen configuration, configuring the generated output content.
    generate {}

    // Optional: The generation output target
    target {}
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {

    // Optional: The fully qualified class name of the code generator. Available generators:
    // 
    // - org.jooq.codegen.JavaGenerator
    // - org.jooq.codegen.KotlinGenerator
    // - org.jooq.codegen.ScalaGenerator
    // 
    // Defaults to org.jooq.codegen.JavaGenerator
    name = ...

    // Optional: The implementation of the code generator, written in Java
    java = ...

    // Optional: The programmatic or configurative generator strategy.
    strategy {}

    // Optional: The jooq-meta configuration, configuring the information schema source.
    database {}

    // Optional: The jooq-codegen configuration, configuring the generated output content.
    generate {}

    // Optional: The generation output target
    target {}
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

##### Specifying your own generator

The `<name/>` element allows for specifying a user-defined generator implementation. This is mostly useful when generating [custom code sections](#codegen-custom-code), which can be added programmatically using the code generator's internal API. For more details, please refer to the relevant section of the manual.

This can either be done via loading a previously compiled class, or by providing an inline implementation (see [in-memory compilation](#codegen-in-memory-compilation) for more details):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <name>com.example.MyGenerator</name>
    <java>package com.example;

import org.jooq.codegen.JavaGenerator;

public class MyGenerator extends JavaGenerator {
    ...
}</java>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withName("com.example.MyGenerator")
    .withJava("""package com.example;

import org.jooq.codegen.JavaGenerator;

public class MyGenerator extends JavaGenerator {
    ...
}""")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    name = "com.example.MyGenerator"
    java = """package com.example;

import org.jooq.codegen.JavaGenerator;

public class MyGenerator extends JavaGenerator {
    ...
}"""
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    name = "com.example.MyGenerator"
    java = """package com.example;

import org.jooq.codegen.JavaGenerator;

public class MyGenerator extends JavaGenerator {
    ...
}"""
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> Make sure your custom generator's dependencies (or the generator itself, if referenced by name) is available to the code generator as a [code generator dependency](#codegen-dependencies)

##### Specifying a strategy

jOOQ by default applies standard Java naming schemes: `PascalCase` for classes, `camelCase` for members, methods, variables, parameters, `UPPER_CASE_WITH_UNDERSCORES` for constants and other literals. This may not be the desired default for your database, e.g. when you strongly rely on case-sensitive naming and if you wish to be able to search for names both in your Java code and in your database code (scripts, views, stored procedures) uniformly. For that purpose, you can override the `<strategy/>` element with your own implementation, either:

- [programmatically](#codegen-generatorstrategy)
- [configuratively](#codegen-matcherstrategy)

For more details, please refer to the relevant sections, above.

<a id="codegen-config-database"></a>
#### 5.2.5. Database

This element wraps all the configuration elements that are used for the jooq-meta module, which reads the configured database meta data. In its simplest form, it can be left empty, when meaningful defaults will apply.

The two main elements in the `<database/>` element are `<name/>` and `<properties>`, which specify the class to implement the database meta data source, and an optional list of key/value parameters, which are described in the [next chapter](#codegen-database-name)

Subsequent elements are:

<a id="codegen-database-name"></a>
##### 5.2.5.1. Database name and properties

The two main elements in the `<database/>` element are `<name/>` which specifies the class to implement the database meta data source, and depending on that class, an optional list of key/value `<properties/>` (see later sections for details). An example for the [XML Database](#codegen-xml):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.xml.XMLDatabase</name>
      <properties>
        <property>
          <key>dialect</key>
          <value>MYSQL</value>
        </property>
        <property>
          <key>xmlFile</key>
          <value>/path/to/database.xml</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.xml.XMLDatabase")
      .withProperties(
        new Property()
          .withKey("dialect")
          .withValue("MYSQL"),
        new Property()
          .withKey("xmlFile")
          .withValue("/path/to/database.xml")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.xml.XMLDatabase"
      properties {
        property {
          key = "dialect"
          value = "MYSQL"
        }
        property {
          key = "xmlFile"
          value = "/path/to/database.xml"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.xml.XMLDatabase"
      properties {
        property {
          key = "dialect"
          value = "MYSQL"
        }
        property {
          key = "xmlFile"
          value = "/path/to/database.xml"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

The default `<name/>` if no name is supplied will be derived from the JDBC connection. If you want to specifically specify your SQL dialect's database name, any of these values will be supported by jOOQ, out of the box:

- `org.jooq.meta.ase.ASEDatabase`
- `org.jooq.meta.auroramysql.AuroraMySQLDatabase`
- `org.jooq.meta.aurorapostgres.AuroraPostgresDatabase`
- `org.jooq.meta.cockroachdb.CockroachDBDatabase`
- `org.jooq.meta.databricks.DatabricksDatabase`
- `org.jooq.meta.db2.DB2Database`
- `org.jooq.meta.derby.DerbyDatabase`
- `org.jooq.meta.duckdb.DuckDBDatabase`
- `org.jooq.meta.firebird.FirebirdDatabase`
- `org.jooq.meta.h2.H2Database`
- `org.jooq.meta.hana.HanaDatabase`
- `org.jooq.meta.hsqldb.HSQLDBDatabase`
- `org.jooq.meta.ignite.IgniteDatabase`
- `org.jooq.meta.informix.InformixDatabase`
- `org.jooq.meta.ingres.IngresDatabase`
- `org.jooq.meta.mariadb.MariaDBDatabase`
- `org.jooq.meta.mysql.MySQLDatabase`
- `org.jooq.meta.oracle.OracleDatabase`
- `org.jooq.meta.postgres.PostgresDatabase`
- `org.jooq.meta.redshift.RedshiftDatabase`
- `org.jooq.meta.snowflake.SnowflakeDatabase`
- `org.jooq.meta.spanner.SpannerDatabase`
- `org.jooq.meta.sqldatawarehouse.SQLDataWarehouseDatabase`
- `org.jooq.meta.sqlite.SQLiteDatabase`
- `org.jooq.meta.sqlserver.SQLServerDatabase`
- `org.jooq.meta.sybase.SybaseDatabase`
- `org.jooq.meta.teradata.TeradataDatabase`
- `org.jooq.meta.trino.TrinoDatabase`
- `org.jooq.meta.vertica.VerticaDatabase`

Alternatively, you can also specify the following database if you want to reverse-engineer a generic JDBC [`java.sql.DatabaseMetaData`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/DatabaseMetaData.html) source for an unsupported database version / dialect / etc:

- `org.jooq.meta.jdbc.JDBCDatabase`

Furthermore, there are two out-of-the-box database meta data sources, that do not rely on a JDBC connection: the [JPADatabase](#codegen-jpa) (to reverse engineer JPA annotated entities) and the [XMLDatabase](#codegen-xml) (to reverse engineer an XML file). Please refer to the respective sections for more details.

Last, but not least, you can of course implement your own by implementing `org.jooq.meta.Database` from the jooq-meta module.

> [!TIP]
> If you're implementing your custome database, make sure it is available to the code generator as a [code generator dependency](#codegen-dependencies)

<a id="codegen-database-inline-implementation"></a>
##### 5.2.5.2. Inline database implementation

Instead of providing your own `Database` implementation as a pre-compiled class to the code generation classpath, you can also provide an inline implementation (see [in-memory compilation](#codegen-in-memory-compilation) for more details):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>com.example.MyDatabase</name>
      <java>package com.example;

import org.jooq.meta.AbstractDatabase;

public class MyDatabase extends AbstractDatabase {
    ...
}</java>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("com.example.MyDatabase")
      .withJava("""package com.example;

import org.jooq.meta.AbstractDatabase;

public class MyDatabase extends AbstractDatabase {
    ...
}""")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "com.example.MyDatabase"
      java = """package com.example;

import org.jooq.meta.AbstractDatabase;

public class MyDatabase extends AbstractDatabase {
    ...
}"""
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "com.example.MyDatabase"
      java = """package com.example;

import org.jooq.meta.AbstractDatabase;

public class MyDatabase extends AbstractDatabase {
    ...
}"""
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> Make sure your custom database's dependencies are available to the code generator as a [code generator dependency](#codegen-dependencies)

<a id="codegen-database-regex-flags"></a>
##### 5.2.5.3. RegexFlags

A lot of configuration elements rely on regular expressions. The most prominent examples are the useful [includes and excludes](#codegen-database-includes-excludes) elements. All of these regular expressions use the Java [`java.util.regex.Pattern`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/regex/Pattern.html) API, with all of its features. The `Pattern` API allows for specifying flags and for your configuration convenience, the applied flags are, by default:

- `COMMENTS`: This allows for embedding comments (and, as a side-effect: meaningless whitespace) in regular expressions, which makes them much more readable.
- `CASE_INSENSITIVE`: Most schemas are case insensitive, so case-sensitive regular expressions are a bit of a pain, especially in multi-vendor setups, where databases like PostgreSQL (mostly lower case) and Oracle (mostly UPPER CASE) need to be supported simultaneously.

But of course, this default setting may get in your way, for instance if you rely on case sensitive identifiers and whitespace in identifiers a lot, it might be better for you to turn off the above defaults:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <regexFlags>COMMENTS DOTALL</regexFlags>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withRegexFlags(List.COMMENTS DOTALL)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      regexFlags = List.COMMENTS DOTALL
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      regexFlags = "COMMENTS DOTALL"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

All the flags available from [`java.util.regex.Pattern`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/regex/Pattern.html) are available as a whitespace-separated list in standalone XML, or a comma separated list in Maven.

<a id="codegen-database-includes-excludes"></a>
##### 5.2.5.4. Includes and Excludes

Perhaps the most important elements of the code generation configuration are used for the inclusion and exclusion of content as reported by your [database meta data configuration](#codegen-config-database)

These expressions match any of the following object types, either by their fully qualified names (`catalog.schema.object_name`), or by their names only (`object_name`):

- Array types
- Domains
- Enums
- Links
- Packages
- Queues
- Routines
- Sequences
- Tables
- UDTs

Excludes match *before* includes, meaning that something that has been excluded cannot be included again. For example:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <includes>.*</includes>
      <excludes>
           UNUSED_TABLE                # This table (unqualified name) should not be generated
         | PREFIX_.*                   # Objects with a given prefix should not be generated
         | SECRET_SCHEMA\.SECRET_TABLE # This table (qualified name) should not be generated
         | SECRET_ROUTINE              # This routine (unqualified name) ...
      </excludes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withIncludes(".*")
      .withExcludes("""
           UNUSED_TABLE                # This table (unqualified name) should not be generated
         | PREFIX_.*                   # Objects with a given prefix should not be generated
         | SECRET_SCHEMA\.SECRET_TABLE # This table (qualified name) should not be generated
         | SECRET_ROUTINE              # This routine (unqualified name) ...
      """)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      includes = ".*"
      excludes = """
           UNUSED_TABLE                # This table (unqualified name) should not be generated
         | PREFIX_.*                   # Objects with a given prefix should not be generated
         | SECRET_SCHEMA\.SECRET_TABLE # This table (qualified name) should not be generated
         | SECRET_ROUTINE              # This routine (unqualified name) ...
      """
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      includes = ".*"
      excludes = """
           UNUSED_TABLE                # This table (unqualified name) should not be generated
         | PREFIX_.*                   # Objects with a given prefix should not be generated
         | SECRET_SCHEMA\.SECRET_TABLE # This table (qualified name) should not be generated
         | SECRET_ROUTINE              # This routine (unqualified name) ...
      """
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

###### Identifier scope

A special, additional set of options allows for specifying whether the above two regular expressions should also match nested objects such as table columns or package routines. The following example will hide an `INVISIBLE_COL` in any table (and also tables and other objects called this way, of course), as well as `INVISIBLE_ROUTINE`:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <includes>.*</includes>
      <excludes>INVISIBLE_COL|INVISIBLE_ROUTINE</excludes>
      <includeExcludeColumns>true</includeExcludeColumns>
      <includeExcludePackageRoutines>true</includeExcludePackageRoutines>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withIncludes(".*")
      .withExcludes("INVISIBLE_COL|INVISIBLE_ROUTINE")
      .withIncludeExcludeColumns(true)
      .withIncludeExcludePackageRoutines(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      includes = ".*"
      excludes = "INVISIBLE_COL|INVISIBLE_ROUTINE"
      isIncludeExcludeColumns = true
      isIncludeExcludePackageRoutines = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      includes = ".*"
      excludes = "INVISIBLE_COL|INVISIBLE_ROUTINE"
      includeExcludeColumns = true
      includeExcludePackageRoutines = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

If these flags are enabled, make sure to understand that they will match on *all* the relevant levels of identifier hierarchy. E.g. for `includeExcludeColumns`, a regular expression will now match *both* the table *and* the column. E.g. use this kind of expression then:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <includes>
      # Table part of the expression
      (
        TABLE1
      | TABLE2
      )

      # Column part of the expression (optional for tables)
      (\..*)?
      </includes>
      <excludes>INVISIBLE_COL</excludes>
      <includeExcludeColumns>true</includeExcludeColumns>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withIncludes("""
      # Table part of the expression
      (
        TABLE1
      | TABLE2
      )

      # Column part of the expression (optional for tables)
      (\..*)?
      """)
      .withExcludes("INVISIBLE_COL")
      .withIncludeExcludeColumns(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      includes = """
      # Table part of the expression
      (
        TABLE1
      | TABLE2
      )

      # Column part of the expression (optional for tables)
      (\..*)?
      """
      excludes = "INVISIBLE_COL"
      isIncludeExcludeColumns = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      includes = """
      # Table part of the expression
      (
        TABLE1
      | TABLE2
      )

      # Column part of the expression (optional for tables)
      (\..*)?
      """
      excludes = "INVISIBLE_COL"
      includeExcludeColumns = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

###### Dynamic regular expression

Sometimes, you will like to dynamically generate the regular expression(s) based on more complex meta data than just the identifier of an object. For example, you might want to exclude all views from being generated. This can be done by appending `<includeSql/<` and `<excludeSql/<` elements, whose generated expressions are combined with `<includes/<` and `<excludes/<`. For example, if you're excluding views in PostgreSQL:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <includes>.*</includes>
      <excludes>STATIC_OBJECTS</excludes>
      <excludeSql>
        select table_schema || '\.' || table_name
        from information_schema.tables
        where table_type != 'VIEW'
      </excludeSql>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withIncludes(".*")
      .withExcludes("STATIC_OBJECTS")
      .withExcludeSql("""
        select table_schema || '\.' || table_name
        from information_schema.tables
        where table_type != 'VIEW'
      """)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      includes = ".*"
      excludes = "STATIC_OBJECTS"
      excludeSql = """
        select table_schema || '\.' || table_name
        from information_schema.tables
        where table_type != 'VIEW'
      """
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      includes = ".*"
      excludes = "STATIC_OBJECTS"
      excludeSql = """
        select table_schema || '\.' || table_name
        from information_schema.tables
        where table_type != 'VIEW'
      """
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-include-object-types"></a>
##### 5.2.5.5. Include object types

Sometimes, you want to generate only tables. Or only routines. Or you want to exclude them from being generated. Whatever the use-case, there's a way to do this with the following, additional includes flags:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <includeCheckConstraints>false</includeCheckConstraints>
      <includeDomains>true</includeDomains>
      <includeEmbeddables>true</includeEmbeddables>
      <includeForeignKeys>false</includeForeignKeys>
      <includeIndexes>false</includeIndexes>
      <includeInvisibleColumns>true</includeInvisibleColumns>
      <includePackageConstants>true</includePackageConstants>
      <includePackageRoutines>true</includePackageRoutines>
      <includePackageUDTs>true</includePackageUDTs>
      <includePackages>true</includePackages>
      <includePrimaryKeys>false</includePrimaryKeys>
      <includeRoutines>true</includeRoutines>
      <includeSequences>false</includeSequences>
      <includeSynonyms>false</includeSynonyms>
      <includeSystemCheckConstraints>false</includeSystemCheckConstraints>
      <includeSystemIndexes>false</includeSystemIndexes>
      <includeSystemSequences>false</includeSystemSequences>
      <includeSystemTables>false</includeSystemTables>
      <includeSystemUDTs>false</includeSystemUDTs>
      <includeTables>true</includeTables>
      <includeTriggerRoutines>false</includeTriggerRoutines>
      <includeTriggers>true</includeTriggers>
      <includeUDTs>true</includeUDTs>
      <includeUniqueKeys>false</includeUniqueKeys>
      <includeXMLSchemaCollections>false</includeXMLSchemaCollections>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withIncludeCheckConstraints(false)
      .withIncludeDomains(true)
      .withIncludeEmbeddables(true)
      .withIncludeForeignKeys(false)
      .withIncludeIndexes(false)
      .withIncludeInvisibleColumns(true)
      .withIncludePackageConstants(true)
      .withIncludePackageRoutines(true)
      .withIncludePackageUDTs(true)
      .withIncludePackages(true)
      .withIncludePrimaryKeys(false)
      .withIncludeRoutines(true)
      .withIncludeSequences(false)
      .withIncludeSynonyms(false)
      .withIncludeSystemCheckConstraints(false)
      .withIncludeSystemIndexes(false)
      .withIncludeSystemSequences(false)
      .withIncludeSystemTables(false)
      .withIncludeSystemUDTs(false)
      .withIncludeTables(true)
      .withIncludeTriggerRoutines(false)
      .withIncludeTriggers(true)
      .withIncludeUDTs(true)
      .withIncludeUniqueKeys(false)
      .withIncludeXMLSchemaCollections(false)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      isIncludeCheckConstraints = false
      isIncludeDomains = true
      isIncludeEmbeddables = true
      isIncludeForeignKeys = false
      isIncludeIndexes = false
      isIncludeInvisibleColumns = true
      isIncludePackageConstants = true
      isIncludePackageRoutines = true
      isIncludePackageUDTs = true
      isIncludePackages = true
      isIncludePrimaryKeys = false
      isIncludeRoutines = true
      isIncludeSequences = false
      isIncludeSynonyms = false
      isIncludeSystemCheckConstraints = false
      isIncludeSystemIndexes = false
      isIncludeSystemSequences = false
      isIncludeSystemTables = false
      isIncludeSystemUDTs = false
      isIncludeTables = true
      isIncludeTriggerRoutines = false
      isIncludeTriggers = true
      isIncludeUDTs = true
      isIncludeUniqueKeys = false
      isIncludeXMLSchemaCollections = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      includeCheckConstraints = false
      includeDomains = true
      includeEmbeddables = true
      includeForeignKeys = false
      includeIndexes = false
      includeInvisibleColumns = true
      includePackageConstants = true
      includePackageRoutines = true
      includePackageUDTs = true
      includePackages = true
      includePrimaryKeys = false
      includeRoutines = true
      includeSequences = false
      includeSynonyms = false
      includeSystemCheckConstraints = false
      includeSystemIndexes = false
      includeSystemSequences = false
      includeSystemTables = false
      includeSystemUDTs = false
      includeTables = true
      includeTriggerRoutines = false
      includeTriggers = true
      includeUDTs = true
      includeUniqueKeys = false
      includeXMLSchemaCollections = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

By default, most of these flags are set to true, with the exception of:

- `includeTriggerRoutines`: Some databases store triggers as special `ROUTINE` types in the schema. These routines are not meant to be called directly, by clients, which is why their inclusion in code generation is undesirable.
- `includeSystemCheckConstraints`: Some databases produce auxiliary `CHECK` constraints for other constraints like `NOT NULL` constraints. The redundant information is usually undesirable, which is why these are turned off by default.
- `includeSystemIndexes`: Some databases produce auxiliary `INDEX` objects for other constraints like `FOREIGN KEY` constraints. These indexes are not independent from the key, and the redundant information is usually undesirable, which is why these are turned off by default.
- `includeSystemSequences`: Some database produce auxiliary `SEQUENCE` objects to implement identities of tables. These sequences are usually not interesting to client code, which is why they are excluded by default.
- `includeSystemTables`: Some databases produce auxiliary `TABLE` objects to implement other types of tables, such as "virtual tables" (e.g. in SQLite). These implementation tables are usually not interesting for client code, which is why these are excluded by default.
- `includeSystemUDTs`: Some databases produce auxiliary `UDT` objects to implement other types of UDTs, such as "anonymous array types" (e.g. in Oracle for the `COLLECT()` aggregate functions). These implementation UDTs are usually not interesting for client code, which is why these are excluded by default.

<a id="codegen-database-record-version-timestamp-fields"></a>
##### 5.2.5.6. Record Version and Timestamp Fields

jOOQ's [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) supports an [optimistic locking feature](#optimistic-locking), which can be enabled in the code generator by specifying a regular expression that defines such a record's version and/or timestamp fields. These regular expressions should match at most one column per table, again either by their fully qualified names (catalog.schema.table.column_name) or by their names only (column_name):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <recordVersionFields>REC_VERSION</recordVersionFields>
      <recordTimestampFields>REC_TIMESTAMP</recordTimestampFields>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withRecordVersionFields("REC_VERSION")
      .withRecordTimestampFields("REC_TIMESTAMP")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      recordVersionFields = "REC_VERSION"
      recordTimestampFields = "REC_TIMESTAMP"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      recordVersionFields = "REC_VERSION"
      recordTimestampFields = "REC_TIMESTAMP"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-comments"></a>
##### 5.2.5.7. Comments

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator will pick up comments on schema objects created with [the COMMENT statement](#comment-statement) and generate Javadocs accordingly.

If your dialect does not support the `COMMENT` statement, or your schema doesn't have comments, or you want to amend / replace the schema comments in the code generator, this section will show you how to add "synthetic" comments to your schema objects.

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <comments>
        <comment>

          <!-- Regular expression matching all objects that have this comment. -->
          <expression>CONFIGURED_COMMENT_TABLE</expression>

          <!-- Whether the comment is a deprecation notice. Defaults to false. -->
          <deprecated>true</deprecated>

          <!-- Whether the original schema comment should be included. Defaults to true. -->
          <includeSchemaComment>false</includeSchemaComment>

          <!-- The actual comment text. Defaults to no message. -->
          <message>Do not use this table.</message>
        </comment>
      </comments>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withComments(
        new CommentType()

          // Regular expression matching all objects that have this comment.
          .withExpression("CONFIGURED_COMMENT_TABLE")

          // Whether the comment is a deprecation notice. Defaults to false.
          .withDeprecated(true)

          // Whether the original schema comment should be included. Defaults to true.
          .withIncludeSchemaComment(false)

          // The actual comment text. Defaults to no message.
          .withMessage("Do not use this table.")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      comments {
        comment {

          // Regular expression matching all objects that have this comment.
          expression = "CONFIGURED_COMMENT_TABLE"

          // Whether the comment is a deprecation notice. Defaults to false.
          isDeprecated = true

          // Whether the original schema comment should be included. Defaults to true.
          isIncludeSchemaComment = false

          // The actual comment text. Defaults to no message.
          message = "Do not use this table."
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      comments {
        comment {

          // Regular expression matching all objects that have this comment.
          expression = "CONFIGURED_COMMENT_TABLE"

          // Whether the comment is a deprecation notice. Defaults to false.
          deprecated = true

          // Whether the original schema comment should be included. Defaults to true.
          includeSchemaComment = false

          // The actual comment text. Defaults to no message.
          message = "Do not use this table."
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-objects"></a>
##### 5.2.5.8. Synthetic objects

Some legacy schemas may be lacking meta data such as foreign keys, but applications would still like to use them. Alternatively, updatable views may reflect underlying tables, but the code generator cannot access the meta data through the database's dictionary views. In those cases, "synthetic objects" can be configured, i.e. meta data that is generated purely by the code generator without being there in the meta data source.

<a id="codegen-database-synthetic-columns"></a>
###### 5.2.5.8.1. Synthetic columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

There exist use cases where you want jOOQ's code generator to produce more columns than your meta data source suggests there are, per table. For example:

- Your code generation user doesn't have access to some columns, but your runtime user will have access.
- Your code generation database does not yet / anymore have those columns, but your production system does.
- You're generating [client side computed columns](#codegen-database-forced-types-computed), and you want them to have `VIRTUAL` semantics (computation on read), so the columns don't really exist in the schema.

In those cases, you can add synthetic columns to your schema like this:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <columns>
          <column>

            <!-- Optional regular expression matching all tables that have this identity. -->
            <tables>SCHEMA\.TABLE</tables>

            <!-- The name of the column -->
            <name>COLUMN</name>

            <!-- The type of the column -->
            <type>INTEGER</type>
          </column>
        </columns>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withColumns(
          new SyntheticColumnType()

            // Optional regular expression matching all tables that have this identity.
            .withTables("SCHEMA\\.TABLE")

            // The name of the column
            .withName("COLUMN")

            // The type of the column
            .withType("INTEGER")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        columns {
          column {

            // Optional regular expression matching all tables that have this identity.
            tables = "SCHEMA\\.TABLE"

            // The name of the column
            name = "COLUMN"

            // The type of the column
            type = "INTEGER"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        columns {
          column {

            // Optional regular expression matching all tables that have this identity.
            tables = "SCHEMA\\.TABLE"

            // The name of the column
            name = "COLUMN"

            // The type of the column
            type = "INTEGER"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-readonly-columns"></a>
###### 5.2.5.8.2. Synthetic readonly columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator recognises [readonly columns](#codegen-database-readonly-columns) if it is configured to do so. Some databases do not support "real" readonly columns, but allow for emulating them, e.g. through triggers. If a column is a known "readonly column" without formally being one, users can specify regular expressions that match all tables and columns, which will be treated as if they were formal readonly columns. For example:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <readonlyColumns>
          <readonlyColumn>

            <!-- Optional regular expression matching all tables that have this identity. -->
            <tables>SCHEMA\.TABLE</tables>

            <!-- List all columns that are readonly -->
            <fields>ID</fields>
          </readonlyColumn>
        </readonlyColumns>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withReadonlyColumns(
          new SyntheticReadonlyColumnType()

            // Optional regular expression matching all tables that have this identity.
            .withTables("SCHEMA\\.TABLE")

            // List all columns that are readonly
            .withFields("ID")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        readonlyColumns {
          readonlyColumn {

            // Optional regular expression matching all tables that have this identity.
            tables = "SCHEMA\\.TABLE"

            // List all columns that are readonly
            fields = "ID"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        readonlyColumns {
          readonlyColumn {

            // Optional regular expression matching all tables that have this identity.
            tables = "SCHEMA\\.TABLE"

            // List all columns that are readonly
            fields = "ID"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-readonly-rowids"></a>
###### 5.2.5.8.3. Synthetic readonly ROWIDs

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A few database products support a `ROWID` type, which models a physical location of a row on the disk. A `ROWID` can act like a primary key, e.g. in the absence of a formal primary key, although being a physical address, rather than a logical one, there is usually no guarantee of a `ROWID` to never change. For short-lived record access, this may be irrelevant (e.g. within a single query, for faster self-joins).

jOOQ's code generator allows for specifying a synthetic ROWID configuration that produces such `ROWID` columns on all tables that it matches. Combine this with the [synthetic primary key feature](#codegen-database-synthetic-pks), and you can replace a potentially existing primary key for all interactions with the row, including e.g. [CRUD with UpdatableRecords](#crud-with-updatablerecords) (some vendor specific limitations may apply).

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <readonlyRowids>
          <readonlyRowid>

            <!-- Optional name of the column in generated code. -->
            <name>ROWID</name>

            <!-- Regular expression matching all tables that have this synthetic ROWID. -->
            <tables>SCHEMA\.TABLE</tables>
          </readonlyRowid>
        </readonlyRowids>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withReadonlyRowids(
          new SyntheticReadonlyRowidType()

            // Optional name of the column in generated code.
            .withName("ROWID")

            // Regular expression matching all tables that have this synthetic ROWID.
            .withTables("SCHEMA\\.TABLE")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        readonlyRowids {
          readonlyRowid {

            // Optional name of the column in generated code.
            name = "ROWID"

            // Regular expression matching all tables that have this synthetic ROWID.
            tables = "SCHEMA\\.TABLE"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        readonlyRowids {
          readonlyRowid {

            // Optional name of the column in generated code.
            name = "ROWID"

            // Regular expression matching all tables that have this synthetic ROWID.
            tables = "SCHEMA\\.TABLE"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-ids"></a>
###### 5.2.5.8.4. Synthetic identities

jOOQ's code generator recognises identity columns if they are reported as such by the database. Some databases do not support "real" identity columns, but allow for emulating them, e.g. through triggers and sequences (e.g. Oracle prior to 12c). If a column is a known "identity" without formally being one, users can specify regular expressions that match all tables and columns, which will be treated as if they were formal identities. For example:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <identities>
          <identity>

            <!-- Optional regular expression matching all tables that have this identity. -->
            <tables>SCHEMA\.TABLE</tables>

            <!-- List all columns that are identities -->
            <fields>ID</fields>
            
            <!-- Optionally specify BY DEFAULT or ALWAYS as a GenerationMode -->
            <generationMode>BY DEFAULT</generationMode>
          </identity>
        </identities>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withIdentities(
          new SyntheticIdentityType()

            // Optional regular expression matching all tables that have this identity.
            .withTables("SCHEMA\\.TABLE")

            // List all columns that are identities
            .withFields("ID")

            // Optionally specify BY DEFAULT or ALWAYS as a GenerationMode
            .withGenerationMode(SyntheticIdentityGenerationMode.BY DEFAULT)
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        identities {
          identity {

            // Optional regular expression matching all tables that have this identity.
            tables = "SCHEMA\\.TABLE"

            // List all columns that are identities
            fields = "ID"

            // Optionally specify BY DEFAULT or ALWAYS as a GenerationMode
            generationMode = SyntheticIdentityGenerationMode.BY DEFAULT
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        identities {
          identity {

            // Optional regular expression matching all tables that have this identity.
            tables = "SCHEMA\\.TABLE"

            // List all columns that are identities
            fields = "ID"

            // Optionally specify BY DEFAULT or ALWAYS as a GenerationMode
            generationMode = "BY DEFAULT"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-defaults"></a>
###### 5.2.5.8.5. Synthetic defaults

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator recognises default expressions on columns if they are reported as such by the database. Some databases do not support "real" defaulted columns, or do not propagate column defaults from underlying tables to views. If a column is a known "defaulted" column without formally being one, users can specify regular expressions that match all tables and columns, and provide a default expression for those. For example:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <defaults>
          <default>

            <!-- Optional regular expression matching all tables that have this identity. -->
            <tables>SCHEMA\.TABLE</tables>

            <!-- List all columns that are identities -->
            <fields>CREATION_DATE</fields>

            <!-- A valid SQL expression to apply as a default (e.g. 'string value', not string value) -->
            <expression>CURRENT_TIMESTAMP</expression>
          </default>
        </defaults>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withDefaults(
          new SyntheticDefaultType()

            // Optional regular expression matching all tables that have this identity.
            .withTables("SCHEMA\\.TABLE")

            // List all columns that are identities
            .withFields("CREATION_DATE")

            // A valid SQL expression to apply as a default (e.g. 'string value', not string value)
            .withExpression("CURRENT_TIMESTAMP")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        defaults {
          default_ {

            // Optional regular expression matching all tables that have this identity.
            tables = "SCHEMA\\.TABLE"

            // List all columns that are identities
            fields = "CREATION_DATE"

            // A valid SQL expression to apply as a default (e.g. 'string value', not string value)
            expression = "CURRENT_TIMESTAMP"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        defaults {
          default_ {

            // Optional regular expression matching all tables that have this identity.
            tables = "SCHEMA\\.TABLE"

            // List all columns that are identities
            fields = "CREATION_DATE"

            // A valid SQL expression to apply as a default (e.g. 'string value', not string value)
            expression = "CURRENT_TIMESTAMP"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-enums"></a>
###### 5.2.5.8.6. Synthetic enums

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator supports generating synthetic enums from a variety of enumeration literal sources, including:

- Explicit listing of literals
- The results of an arbitrary 1-column projecting SQL query
- A simple `CHECK` constraint of the form `CHECK (col IN ('a', 'b'))` or any other non-canonical form that can be reduced to an [IN predicate](#in-predicate) using [pattern-based transformation](#transform-patterns).

In particular, the `CHECK` constraint based configuration is very powerful!

```java
enum TStatus implements EnumType {
  A, B, C;

  // [...]
}
```

```sql
CREATE TABLE t (
  status VARCHAR(10),

  CHECK (status IN ('A', 'B', 'C'))
)
```

A configuration example:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <enums>
          <enum>

            <!-- Optional name of the enum type in the schema. If left empty, the generated name
                 is concatenated as TABLE_COLUMN -->
            <name>EnumName</name>

            <!-- Optional regular expression matching all tables that have this enum type. -->
            <tables>SCHEMA\.TABLE</tables>

            <!-- Regular expression matching all fields that have this enum type. -->
            <fields>STATUS</fields>

            <!-- An optional, defining comment of the enum -->
            <comment>An enumeration for the TABLE.STATUS column.</comment>

            <!-- The following are mutually exclusive settings. If none are provided, and the
                 synthetic enum is named, then it will just reference a previously defined
                 synthetic or actual enum type by name.
              -->

            <!-- Specify enum literals explicitly -->
            <literals>
              <literal>A</literal>
              <literal>B</literal>
            </literals>

            <!-- Specify a query that returns the distinct enum literals -->
            <literalSql>SELECT DISTINCT status FROM schema.table</literalSql>

            <!-- Fetch distinct enum literals from the column's content.
                 This is the same as specifying literalSql to be

                 SELECT DISTINCT matched_column FROM matched_table
              -->
            <literalsFromColumnContent>true</literalsFromColumnContent>

            <!-- The list of literals is parsed from the applicable CHECK constraints
                 for the matched column, if possible. -->
            <literalsFromCheckConstraints>true</literalsFromCheckConstraints>
          </enum>
        </enums>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withEnums(
          new SyntheticEnumType()

            // Optional name of the enum type in the schema. If left empty, the generated name
            // is concatenated as TABLE_COLUMN
            .withName("EnumName")

            // Optional regular expression matching all tables that have this enum type.
            .withTables("SCHEMA\\.TABLE")

            // Regular expression matching all fields that have this enum type.
            .withFields("STATUS")

            // An optional, defining comment of the enum
            .withComment("An enumeration for the TABLE.STATUS column.")

            // The following are mutually exclusive settings. If none are provided, and the
            // synthetic enum is named, then it will just reference a previously defined
            // synthetic or actual enum type by name.
            .withLiterals(
              "A",
              "B"
            )

            // Specify a query that returns the distinct enum literals
            .withLiteralSql("SELECT DISTINCT status FROM schema.table")

            // Fetch distinct enum literals from the column's content.
            // This is the same as specifying literalSql to be
            // 
            // SELECT DISTINCT matched_column FROM matched_table
            .withLiteralsFromColumnContent(true)

            // The list of literals is parsed from the applicable CHECK constraints
            // for the matched column, if possible.
            .withLiteralsFromCheckConstraints(true)
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        enums {
          enum_ {

            // Optional name of the enum type in the schema. If left empty, the generated name
            // is concatenated as TABLE_COLUMN
            name = "EnumName"

            // Optional regular expression matching all tables that have this enum type.
            tables = "SCHEMA\\.TABLE"

            // Regular expression matching all fields that have this enum type.
            fields = "STATUS"

            // An optional, defining comment of the enum
            comment = "An enumeration for the TABLE.STATUS column."

            // The following are mutually exclusive settings. If none are provided, and the
            // synthetic enum is named, then it will just reference a previously defined
            // synthetic or actual enum type by name.
            literals {
              literal = "A"
              literal = "B"
            }

            // Specify a query that returns the distinct enum literals
            literalSql = "SELECT DISTINCT status FROM schema.table"

            // Fetch distinct enum literals from the column's content.
            // This is the same as specifying literalSql to be
            // 
            // SELECT DISTINCT matched_column FROM matched_table
            isLiteralsFromColumnContent = true

            // The list of literals is parsed from the applicable CHECK constraints
            // for the matched column, if possible.
            isLiteralsFromCheckConstraints = true
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        enums {
          enum_ {

            // Optional name of the enum type in the schema. If left empty, the generated name
            // is concatenated as TABLE_COLUMN
            name = "EnumName"

            // Optional regular expression matching all tables that have this enum type.
            tables = "SCHEMA\\.TABLE"

            // Regular expression matching all fields that have this enum type.
            fields = "STATUS"

            // An optional, defining comment of the enum
            comment = "An enumeration for the TABLE.STATUS column."

            // The following are mutually exclusive settings. If none are provided, and the
            // synthetic enum is named, then it will just reference a previously defined
            // synthetic or actual enum type by name.
            literals {
              literal = "A"
              literal = "B"
            }

            // Specify a query that returns the distinct enum literals
            literalSql = "SELECT DISTINCT status FROM schema.table"

            // Fetch distinct enum literals from the column's content.
            // This is the same as specifying literalSql to be
            // 
            // SELECT DISTINCT matched_column FROM matched_table
            literalsFromColumnContent = true

            // The list of literals is parsed from the applicable CHECK constraints
            // for the matched column, if possible.
            literalsFromCheckConstraints = true
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-pks"></a>
###### 5.2.5.8.7. Synthetic primary keys

jOOQ's code generator recognises primary keys that are declared and reported as such by the database. But some databases don't report all keys, or some tables don't have them enabled, or sometimes, a view is a 1:1 representation of an underlying table, but it doesn't expose the key information. In these cases, this regular expression can match all columns that users wish to "pretend" are part of such a primary key. If a composite synthetic primary key is desired, the regular expression should match all columns of that table that are part of the primary key. For example, a composite synthetic primary key consists of `(COLUMN1, COLUMN2)` in table `SCHEMA.TABLE`:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <primaryKeys>
          <primaryKey>

            <!-- Optional name of the primary key, if tables matches only a single table. -->
            <name>PK_TABLE</name>

            <!-- Optional regular expression matching all tables that have this primary key. -->
            <tables>SCHEMA\.TABLE</tables>

            <!-- List multiple fields in the key order -->
            <fields>
              <field>COLUMN1</field>
              <field>COLUMN2</field>
            </fields>

            <!-- Alternatively, instead of listing columns above, promote a unique key to a primary key, by name. -->
            <key>UK_TABLE</key>
          </primaryKey>
        </primaryKeys>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withPrimaryKeys(
          new SyntheticPrimaryKeyType()

            // Optional name of the primary key, if tables matches only a single table.
            .withName("PK_TABLE")

            // Optional regular expression matching all tables that have this primary key.
            .withTables("SCHEMA\\.TABLE")

            // List multiple fields in the key order
            .withFields(
              "COLUMN1",
              "COLUMN2"
            )

            // Alternatively, instead of listing columns above, promote a unique key to a primary key, by name.
            .withKey("UK_TABLE")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        primaryKeys {
          primaryKey {

            // Optional name of the primary key, if tables matches only a single table.
            name = "PK_TABLE"

            // Optional regular expression matching all tables that have this primary key.
            tables = "SCHEMA\\.TABLE"

            // List multiple fields in the key order
            fields {
              field = "COLUMN1"
              field = "COLUMN2"
            }

            // Alternatively, instead of listing columns above, promote a unique key to a primary key, by name.
            key = "UK_TABLE"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        primaryKeys {
          primaryKey {

            // Optional name of the primary key, if tables matches only a single table.
            name = "PK_TABLE"

            // Optional regular expression matching all tables that have this primary key.
            tables = "SCHEMA\\.TABLE"

            // List multiple fields in the key order
            fields {
              field = "COLUMN1"
              field = "COLUMN2"
            }

            // Alternatively, instead of listing columns above, promote a unique key to a primary key, by name.
            key = "UK_TABLE"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

If the regular expression matches column in a table that already has an existing primary key, that existing primary key will be replaced by the synthetic one. It will still be reported as a unique key, though.

<a id="codegen-database-synthetic-uks"></a>
###### 5.2.5.8.8. Synthetic unique keys

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator recognises unique keys that are declared and reported as such by the database. But some databases don't report all keys, or some tables don't have them enabled, or sometimes, a view is a 1:1 representation of an underlying table, but it doesn't expose the key information. In these cases, this regular expression can match all columns that users wish to "pretend" are part of such a unique key. If a composite synthetic unique key is desired, the regular expression should match all columns of that table that are part of the unique key. For example, a composite synthetic unique key consists of `(COLUMN1, COLUMN2)` in table `SCHEMA.TABLE`:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <uniqueKeys>
          <uniqueKey>

            <!-- Optional name of the unique key, if tables matches only a single table. -->
            <name>UK_TABLE</name>

            <!-- Optional regular expression matching all tables that have this unique key. -->
            <tables>SCHEMA\.TABLE</tables>

            <!-- List multiple fields in the key order -->
            <fields>
              <field>COLUMN1</field>
              <field>COLUMN2</field>
            </fields>
          </uniqueKey>
        </uniqueKeys>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withUniqueKeys(
          new SyntheticUniqueKeyType()

            // Optional name of the unique key, if tables matches only a single table.
            .withName("UK_TABLE")

            // Optional regular expression matching all tables that have this unique key.
            .withTables("SCHEMA\\.TABLE")

            // List multiple fields in the key order
            .withFields(
              "COLUMN1",
              "COLUMN2"
            )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        uniqueKeys {
          uniqueKey {

            // Optional name of the unique key, if tables matches only a single table.
            name = "UK_TABLE"

            // Optional regular expression matching all tables that have this unique key.
            tables = "SCHEMA\\.TABLE"

            // List multiple fields in the key order
            fields {
              field = "COLUMN1"
              field = "COLUMN2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        uniqueKeys {
          uniqueKey {

            // Optional name of the unique key, if tables matches only a single table.
            name = "UK_TABLE"

            // Optional regular expression matching all tables that have this unique key.
            tables = "SCHEMA\\.TABLE"

            // List multiple fields in the key order
            fields {
              field = "COLUMN1"
              field = "COLUMN2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-fks"></a>
###### 5.2.5.8.9. Synthetic foreign keys

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator recognises foreign keys that are declared and reported as such by the database. But some databases don't report all keys, or some tables don't have them enabled, or sometimes, a view is a 1:1 representation of an underlying table, but it doesn't expose the key information. In these cases, this regular expression can match all columns that users wish to "pretend" are part of such a foreign key. If a composite synthetic foreign key is desired, the regular expression should match all columns of that table that are part of the foreign key. For example, a composite synthetic foreign key consists of `(COLUMN1, COLUMN2)` in table `SCHEMA.TABLE`:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <foreignKeys>
          <foreignKey>

            <!-- Optional name of the foreign key, if tables matches only a single table. -->
            <!-- This is useful to disambiguate navigational methods and implicit join methods! -->
            <name>FK_TABLE</name>

            <!-- Optional regular expression matching all tables that have this foreign key. -->
            <tables>SCHEMA\.TABLE</tables>

            <!-- List multiple fields in the key order -->
            <fields>
              <field>COLUMN1</field>
              <field>COLUMN2</field>
            </fields>

            <!-- Specify the table that is being referenced by this foreign key -->
            <referencedTable>SCHEMA\.OTHER_TABLE</referencedTable>

            <!-- Optional: The primary or unique key columns that are being referenced -->
            <referencedFields>
              <field>COLUMN1</field>
              <field>COLUMN2</field>
            </referencedFields>

            <!-- Optional: reference a primary or unique key by name -->
            <!-- If the referenced fields or key are not specified, the referencedTable's primary key is used -->
            <referencedKey>UK_TABLE</referencedKey>
          </foreignKey>
        </foreignKeys>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withForeignKeys(
          new SyntheticForeignKeyType()

            // Optional name of the foreign key, if tables matches only a single table.
            .withName("FK_TABLE")

            // Optional regular expression matching all tables that have this foreign key.
            .withTables("SCHEMA\\.TABLE")

            // List multiple fields in the key order
            .withFields(
              "COLUMN1",
              "COLUMN2"
            )

            // Specify the table that is being referenced by this foreign key
            .withReferencedTable("SCHEMA\\.OTHER_TABLE")

            // Optional: The primary or unique key columns that are being referenced
            .withReferencedFields(new ()
              .withField("COLUMN1")
              .withField("COLUMN2")
            )

            // Optional: reference a primary or unique key by name
            .withReferencedKey("UK_TABLE")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        foreignKeys {
          foreignKey {

            // Optional name of the foreign key, if tables matches only a single table.
            name = "FK_TABLE"

            // Optional regular expression matching all tables that have this foreign key.
            tables = "SCHEMA\\.TABLE"

            // List multiple fields in the key order
            fields {
              field = "COLUMN1"
              field = "COLUMN2"
            }

            // Specify the table that is being referenced by this foreign key
            referencedTable = "SCHEMA\\.OTHER_TABLE"

            // Optional: The primary or unique key columns that are being referenced
            referencedFields {
              field = "COLUMN1"
              field = "COLUMN2"
            }

            // Optional: reference a primary or unique key by name
            referencedKey = "UK_TABLE"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        foreignKeys {
          foreignKey {

            // Optional name of the foreign key, if tables matches only a single table.
            name = "FK_TABLE"

            // Optional regular expression matching all tables that have this foreign key.
            tables = "SCHEMA\\.TABLE"

            // List multiple fields in the key order
            fields {
              field = "COLUMN1"
              field = "COLUMN2"
            }

            // Specify the table that is being referenced by this foreign key
            referencedTable = "SCHEMA\\.OTHER_TABLE"

            // Optional: The primary or unique key columns that are being referenced
            referencedFields {
              field = "COLUMN1"
              field = "COLUMN2"
            }

            // Optional: reference a primary or unique key by name
            referencedKey = "UK_TABLE"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-synthetic-synonyms"></a>
###### 5.2.5.8.10. Synthetic synonyms

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

jOOQ's code generator recognises synonyms that are declared and reported as such by the database. But some databases don't report all synonyms. In those cases, a synthetic synonym can be declared for a table:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <syntheticObjects>
        <synonyms>
          <synonym>

            <!-- Optional catalog of the synonym (if omitted, this is the same as the table's). -->
            <catalog>CATALOG</catalog>

            <!-- Optional schema of the synonym (if omitted, this is the same as the table's). -->
            <schema>SCHEMA</schema>

            <!-- Mandatory name of the synonym. -->
            <name>SYNONYM</name>

            <!-- Mandatory regular expression matching a tables that have this synonym. -->
            <table>SCHEMA\.TABLE</table>
          </synonym>
        </synonyms>
      </syntheticObjects>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSyntheticObjects(new SyntheticObjectsType()
        .withSynonyms(
          new SyntheticSynonymType()

            // Optional catalog of the synonym (if omitted, this is the same as the table's).
            .withCatalog("CATALOG")

            // Optional schema of the synonym (if omitted, this is the same as the table's).
            .withSchema("SCHEMA")

            // Mandatory name of the synonym.
            .withName("SYNONYM")

            // Mandatory regular expression matching a tables that have this synonym.
            .withTable("SCHEMA\\.TABLE")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      syntheticObjects {
        synonyms {
          synonym {

            // Optional catalog of the synonym (if omitted, this is the same as the table's).
            catalog = "CATALOG"

            // Optional schema of the synonym (if omitted, this is the same as the table's).
            schema = "SCHEMA"

            // Mandatory name of the synonym.
            name = "SYNONYM"

            // Mandatory regular expression matching a tables that have this synonym.
            table = "SCHEMA\\.TABLE"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      syntheticObjects {
        synonyms {
          synonym {

            // Optional catalog of the synonym (if omitted, this is the same as the table's).
            catalog = "CATALOG"

            // Optional schema of the synonym (if omitted, this is the same as the table's).
            schema = "SCHEMA"

            // Mandatory name of the synonym.
            name = "SYNONYM"

            // Mandatory regular expression matching a tables that have this synonym.
            table = "SCHEMA\\.TABLE"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-database-date-as-timestamp"></a>
##### 5.2.5.9. Date as timestamp

The Oracle database doesn't know a SQL standard `DATE` type (`YYYY-MM-DD`). It's vendor-specific `DATE` type is really a `TIMESTAMP(0)`, i.e. a `TIMESTAMP` with zero fractional seconds precision (`YYYY-MM-DD HH24:MI:SS`). For historic reasons, many legacy Oracle databases do not use the `TIMESTAMP` data type, but the `DATE` data type for timestamps, in case of which client applications also need to treat these columns as timestamps.

If upgrading the schema to proper `TIMESTAMP` usage isn't an option, and neither is using [data type rewrites](#codegen-database-forced-types-rewrite) on a per-column basis, then this flag is the right one to activate. It will remove the `DATE` type from the Oracle type system (at least as far as the jOOQ code generator is concerned), and pretend all such columns are really `TIMESTAMP` typed. This is how to activate the flag:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <dateAsTimestamp>true</dateAsTimestamp>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withDateAsTimestamp(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      isDateAsTimestamp = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      dateAsTimestamp = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

This flag will apply before any other data type related flags are applied, including [forced types](#codegen-database-forced-types).

<a id="codegen-database-ignore-procedure-return-values"></a>
##### 5.2.5.10. Ignore procedure return values (deprecated)

In jOOQ 3.6.0, [#4106](https://github.com/jOOQ/jOOQ/issues/4106) was implemented to support Transact-SQL's optional return values from stored procedures. This turns all procedures into `Routine<Integer>` (instead of `Routine<Void>`). For backwards-compatibility reasons, users can suppress this change in jOOQ 3.x

This feature is deprecated as of jOOQ 3.6.0 and will be removed again in jOOQ 4.0.

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <ignoreProcedureReturnValues>true</ignoreProcedureReturnValues>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withIgnoreProcedureReturnValues(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      isIgnoreProcedureReturnValues = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      ignoreProcedureReturnValues = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-database-hidden-columns"></a>
##### 5.2.5.11. Hidden columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

There are various reasons why a column could be hidden, including:

- The column is formally marked as `HIDDEN` or `INVISIBLE`, if the database product supports this.
- A [forced type](#codegen-database-forced-types-hidden) marks the column as hidden.

jOOQ's code generator can detect some of these, and mark columns as hidden for you, meaning that the column will not be taken into consideration in default projections. For details about the runtime behaviour of such hidden columns, please see the relevant [section about hidden columns](#hidden-columns).

###### Useful feature interactions

One of the primary use-cases of hidden columns is schema evolution, where deprecated columns and their data are kept around for historic purposes, but shouldn't be used ordinarily. In this case, the feature works very well together with our [column deprecation support](#codegen-database-comments).

###### Limitations

> [!TIP]
> The `hidden` flag is a property of the generated [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html). As such, the property can only be enforced on expressions which make this flag available to jOOQ. For example, if you're using [plain SQL templates](#plain-sql-templating-language) without passing along a `DataType` with the `hidden` flag enabled to table meta data, then it cannot be enforced. See also [features requiring code generation](#codegen-feature-dependencies) for more details.

<a id="codegen-database-redacted-columns"></a>
##### 5.2.5.12. Redacted columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

When working with sensitive information, it can be useful to redact columns such that their contents won't leak to debug log outputs or other formatted content by accident. A [forced type](#codegen-database-forced-types-redacted) flag marks the column as redacted. More details about the functionality can be seen in the [section about redacted columns](#redacted-columns).

###### Limitations

> [!TIP]
> The `redacted` flag is a property of the generated [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html). As such, the property can only be enforced on expressions which make this flag available to jOOQ. For example, if you're using [plain SQL templates](#plain-sql-templating-language) without passing along a `DataType` with the `redacted` flag enabled to table meta data, then it cannot be enforced. See also [features requiring code generation](#codegen-feature-dependencies) for more details.

<a id="codegen-database-readonly-columns"></a>
##### 5.2.5.13. Readonly columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

There are various reasons why a column could be readonly, including:

- The column is formally marked as `READONLY`, if the database product supports this.
- The column is from a view, and either the entire view, or just that particular column is not updatable.
- The user lacks `INSERT` and/or `UPDATE` grants to the column.
- The column is computed using `[ GENERATED ALWAYS ] AS <expression>` (`DEFAULT` columns aren't readonly)
- There is a trigger preventing writing to the column.

jOOQ's code generator can detect some of these, and mark columns as readonly for you, meaning that the column will not be taken into consideration in DML statements, such as [INSERT](#insert-statement) or [UPDATE](#update-statement), or [UpdatableRecord CRUD calls](#crud-with-updatablerecords). To configure the runtime behaviour of such readonly columns, please see the relevant [section about readonly columns](#readonly-columns).

It's also possible to manually mark columns as readonly using the [synthetic readonly columns configuration](#codegen-database-synthetic-readonly-columns).

There are some flags that automatically turn certain column types into readonly columns:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <!-- Turn all identity columns into readonly columns -->
      <readonlyIdentities>true</readonlyIdentities>
      
      <!-- Turn only GENERATED BY DEFAULT AS IDENTITY columns into readonly columns -->
      <readonlyGeneratedByDefaultIdentities>true</readonlyGeneratedByDefaultIdentities>
      
      <!-- Turn only GENERATED BY ALWAYS IDENTITY columns into readonly columns (active by default) -->
      <readonlyGeneratedAlwaysIdentities>true</readonlyGeneratedAlwaysIdentities>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // Turn all identity columns into readonly columns
      .withReadonlyIdentities(true)

      // Turn only GENERATED BY DEFAULT AS IDENTITY columns into readonly columns
      .withReadonlyGeneratedByDefaultIdentities(true)

      // Turn only GENERATED BY ALWAYS IDENTITY columns into readonly columns (active by default)
      .withReadonlyGeneratedAlwaysIdentities(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {

      // Turn all identity columns into readonly columns
      isReadonlyIdentities = true

      // Turn only GENERATED BY DEFAULT AS IDENTITY columns into readonly columns
      isReadonlyGeneratedByDefaultIdentities = true

      // Turn only GENERATED BY ALWAYS IDENTITY columns into readonly columns (active by default)
      isReadonlyGeneratedAlwaysIdentities = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {

      // Turn all identity columns into readonly columns
      readonlyIdentities = true

      // Turn only GENERATED BY DEFAULT AS IDENTITY columns into readonly columns
      readonlyGeneratedByDefaultIdentities = true

      // Turn only GENERATED BY ALWAYS IDENTITY columns into readonly columns (active by default)
      readonlyGeneratedAlwaysIdentities = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

###### Limitations

> [!TIP]
> The `readonly` flag is a property of the generated [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html). As such, the property can only be enforced on expressions which make this flag available to jOOQ. For example, if you're using [plain SQL templates](#plain-sql-templating-language) without passing along a `DataType` with the `readonly` flag enabled, then it cannot be enforced. See also [features requiring code generation](#codegen-feature-dependencies) for more details.

<a id="codegen-database-unsigned-types"></a>
##### 5.2.5.14. Unsigned types

The JDBC and Java type system don't know any unsigned integer data types, but some databases do, most importantly MySQL. This flag allows for overriding the default mapping from unsigned to signed integers and generates jOOU types instead:

- [`org.jooq.types.UByte`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/UByte.html)
- [`org.jooq.types.UShort`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/UShort.html)
- [`org.jooq.types.UInteger`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/UInteger.html)
- [`org.jooq.types.ULong`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/ULong.html)

Those types work just like ordinary [`java.lang.Number`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Number.html) wrapper types, except that there is no primitive version of them. The configuration looks like follows:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <unsignedTypes>true</unsignedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withUnsignedTypes(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      isUnsignedTypes = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      unsignedTypes = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-database-catalog-and-schema-mapping"></a>
##### 5.2.5.15. Catalog and schema mapping

In addition to what we've seen in the section about [input catalogs and schemas](#input-schema), these configuration elements combine two features in one:

1. They allow for specifying one or more catalogs (default: all catalogs) as well as one or more schemas (default: all schemas) for inclusion in the code generator. This works in a similar fashion as [the includes and excludes elements](#codegen-database-includes-excludes), but it is applied at an earlier stage of reading the schema meta data.
2. Once all "input" catalogs and schemas are specified, they can each be associated with a matching "output" catalog or schema, in case of which the "input" will be mapped to the "output" by the code generator.

Wherever you can place an `inputCatalog` or `inputSchema` element (top level or nested, see the [manual section about input schemas](#input-schema)), you can also put a matching mapping instruction, if you wish to profit from the catalog and schema mapping feature. The following configurations are possible:

###### Top level configurations

This mode is preferrable for small projects or quick tutorials, where only a single catalog and a/or a single schema need to be generated. In this case, the following "top level" configuration elements can be applied:

**Read only a single schema (from all catalogs, but in most databases, there is only one "default catalog")**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <inputSchema>input_schema</inputSchema>
      <outputSchema>output_schema</outputSchema>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withInputSchema("input_schema")
      .withOutputSchema("output_schema")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      inputSchema = "input_schema"
      outputSchema = "output_schema"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      inputSchema = "input_schema"
      outputSchema = "output_schema"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Read only a single catalog and all its schemas**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <inputCatalog>input_catalog</inputCatalog>
      <outputCatalog>output_catalog</outputCatalog>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withInputCatalog("input_catalog")
      .withOutputCatalog("output_catalog")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      inputCatalog = "input_catalog"
      outputCatalog = "output_catalog"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      inputCatalog = "input_catalog"
      outputCatalog = "output_catalog"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Read only a single catalog and only a single schema**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <inputCatalog>input_catalog</inputCatalog>
      <outputCatalog>output_catalog</outputCatalog>
      <inputSchema>input_schema</inputSchema>
      <outputSchema>output_schema</outputSchema>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withInputCatalog("input_catalog")
      .withOutputCatalog("output_catalog")
      .withInputSchema("input_schema")
      .withOutputSchema("output_schema")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      inputCatalog = "input_catalog"
      outputCatalog = "output_catalog"
      inputSchema = "input_schema"
      outputSchema = "output_schema"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      inputCatalog = "input_catalog"
      outputCatalog = "output_catalog"
      inputSchema = "input_schema"
      outputSchema = "output_schema"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

###### Nested configurations

This mode is preferrable for larger projects where several catalogs and/or schemas need to be included. The following examples show different possible configurations:

**Read two or more schemas (from all catalogs, but in most databases, there is only one "default catalog")**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <schemata>
        <schema>
          <inputSchema>input_schema1</inputSchema>
          <outputSchema>output_schema1</outputSchema>
        </schema>
        <schema>
          <inputSchema>input_schema2</inputSchema>
          <outputSchema>output_schema2</outputSchema>
        </schema>
      </schemata>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSchemata(
        new SchemaMappingType()
          .withInputSchema("input_schema1")
          .withOutputSchema("output_schema1"),
        new SchemaMappingType()
          .withInputSchema("input_schema2")
          .withOutputSchema("output_schema2")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      schemata {
        schema {
          inputSchema = "input_schema1"
          outputSchema = "output_schema1"
        }
        schema {
          inputSchema = "input_schema2"
          outputSchema = "output_schema2"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      schemata {
        schema {
          inputSchema = "input_schema1"
          outputSchema = "output_schema1"
        }
        schema {
          inputSchema = "input_schema2"
          outputSchema = "output_schema2"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Read two or more catalogs and all their schemas**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <catalogs>
        <catalog>
          <inputCatalog>input_catalog1</inputCatalog>
          <outputCatalog>output_catalog1</outputCatalog>
        </catalog>
        <catalog>
          <inputCatalog>input_catalog2</inputCatalog>
          <outputCatalog>output_catalog2</outputCatalog>
        </catalog>
      </catalogs>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withCatalogs(
        new CatalogMappingType()
          .withInputCatalog("input_catalog1")
          .withOutputCatalog("output_catalog1"),
        new CatalogMappingType()
          .withInputCatalog("input_catalog2")
          .withOutputCatalog("output_catalog2")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "input_catalog1"
          outputCatalog = "output_catalog1"
        }
        catalog {
          inputCatalog = "input_catalog2"
          outputCatalog = "output_catalog2"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "input_catalog1"
          outputCatalog = "output_catalog1"
        }
        catalog {
          inputCatalog = "input_catalog2"
          outputCatalog = "output_catalog2"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Read two or more schemas from one or more specific catalogs**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <catalogs>
        <catalog>
          <inputCatalog>input_catalog</inputCatalog>
          <outputCatalog>output_catalog</outputCatalog>
          <schemata>
            <schema>
              <inputSchema>input_schema1</inputSchema>
              <outputSchema>output_schema1</outputSchema>
            </schema>
            <schema>
              <inputSchema>input_schema2</inputSchema>
              <outputSchema>output_schema2</outputSchema>
            </schema>
          </schemata>
        </catalog>
      </catalogs>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withCatalogs(
        new CatalogMappingType()
          .withInputCatalog("input_catalog")
          .withOutputCatalog("output_catalog")
          .withSchemata(
            new SchemaMappingType()
              .withInputSchema("input_schema1")
              .withOutputSchema("output_schema1"),
            new SchemaMappingType()
              .withInputSchema("input_schema2")
              .withOutputSchema("output_schema2")
          )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "input_catalog"
          outputCatalog = "output_catalog"
          schemata {
            schema {
              inputSchema = "input_schema1"
              outputSchema = "output_schema1"
            }
            schema {
              inputSchema = "input_schema2"
              outputSchema = "output_schema2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "input_catalog"
          outputCatalog = "output_catalog"
          schemata {
            schema {
              inputSchema = "input_schema1"
              outputSchema = "output_schema1"
            }
            schema {
              inputSchema = "input_schema2"
              outputSchema = "output_schema2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

###### Default catalogs and schemas

Instead of specifying an `outputCatalog` or `outputSchema`, it is also possible to specify `outputCatalogToDefault` or `outputSchemaToDefault` in order to omit the qualifier entirely from generated code. This is possible both at the top level or in nested configurations:

**Top level**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <inputCatalog>my_input_catalog</inputCatalog>
      <outputCatalogToDefault>true</outputCatalogToDefault>
      <inputSchema>my_input_schema</inputSchema>
      <outputSchemaToDefault>true</outputSchemaToDefault>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withInputCatalog("my_input_catalog")
      .withOutputCatalogToDefault(true)
      .withInputSchema("my_input_schema")
      .withOutputSchemaToDefault(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      inputCatalog = "my_input_catalog"
      isOutputCatalogToDefault = true
      inputSchema = "my_input_schema"
      isOutputSchemaToDefault = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      inputCatalog = "my_input_catalog"
      outputCatalogToDefault = true
      inputSchema = "my_input_schema"
      outputSchemaToDefault = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Nested**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <catalogs>
        <catalog>
          <inputCatalog>input_catalog</inputCatalog>
          <outputCatalogToDefault>true</outputCatalogToDefault>
          <schemata>
            <schema>
              <inputSchema>input_schema1</inputSchema>
              <outputSchemaToDefault>true</outputSchemaToDefault>
            </schema>
            <schema>
              <inputSchema>input_schema2</inputSchema>
              <outputSchema>output_schema2</outputSchema>
            </schema>
          </schemata>
        </catalog>
      </catalogs>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withCatalogs(
        new CatalogMappingType()
          .withInputCatalog("input_catalog")
          .withOutputCatalogToDefault(true)
          .withSchemata(
            new SchemaMappingType()
              .withInputSchema("input_schema1")
              .withOutputSchemaToDefault(true),
            new SchemaMappingType()
              .withInputSchema("input_schema2")
              .withOutputSchema("output_schema2")
          )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "input_catalog"
          isOutputCatalogToDefault = true
          schemata {
            schema {
              inputSchema = "input_schema1"
              isOutputSchemaToDefault = true
            }
            schema {
              inputSchema = "input_schema2"
              outputSchema = "output_schema2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "input_catalog"
          outputCatalogToDefault = true
          schemata {
            schema {
              inputSchema = "input_schema1"
              outputSchemaToDefault = true
            }
            schema {
              inputSchema = "input_schema2"
              outputSchema = "output_schema2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-database-version-providers"></a>
##### 5.2.5.16. Catalog and schema version providers

For continuous integration reasons, users often like to version their database schemas, e.g. with tools like [Flyway](#jooq-with-flyway). In these cases, it is usually beneficial if the catalog and/or schema version can be placed with generated jOOQ code for documentation purposes and to prevent unnecessary re-generation of a catalog and/or schema.

For this reason, jOOQ allows for implementing a simple code generation SPI which tells jOOQ what the user-defined version of any given catalog or schema is.

There are three possible ways to implement this SPI:

- By providing a fully qualified class name that implements any of `org.jooq.meta.CatalogVersionProvider` or `org.jooq.meta.SchemaVersionProvider` respectively for programmatic version providing.
- By providing a `SELECT` statement returning one row with one column containing the version string. The `SELECT` statement may contain a named variable called `:catalog_name` or `:schema_name` respectively.
- By providing a constant, such as a Maven property, for instance.

These schema versions will be generated into the `javax.annotation.Generated` annotation on generated artefacts.

###### Example: fully qualified class name

This example is assuming that you have version provider classes on your code generation classpath available:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <catalogVersionProvider>com.example.MyCatalogVersionProvider</catalogVersionProvider>
      <schemaVersionProvider>com.example.MySchemaVersionProvider</schemaVersionProvider>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withCatalogVersionProvider("com.example.MyCatalogVersionProvider")
      .withSchemaVersionProvider("com.example.MySchemaVersionProvider")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      catalogVersionProvider = "com.example.MyCatalogVersionProvider"
      schemaVersionProvider = "com.example.MySchemaVersionProvider"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      catalogVersionProvider = "com.example.MyCatalogVersionProvider"
      schemaVersionProvider = "com.example.MySchemaVersionProvider"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> Make sure your custom version providers are available to the code generator as a [code generator dependency](#codegen-dependencies)

###### Example: SQL SELECT statement

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <catalogVersionProvider>SELECT :catalog_name || '_' || MAX("version") FROM "schema_version"</catalogVersionProvider>
      <schemaVersionProvider>SELECT :schema_name || '_' || MAX("version") FROM "schema_version"</schemaVersionProvider>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withCatalogVersionProvider("SELECT :catalog_name || '_' || MAX(\"version\") FROM \"schema_version\"")
      .withSchemaVersionProvider("SELECT :schema_name || '_' || MAX(\"version\") FROM \"schema_version\"")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      catalogVersionProvider = "SELECT :catalog_name || '_' || MAX(\"version\") FROM \"schema_version\""
      schemaVersionProvider = "SELECT :schema_name || '_' || MAX(\"version\") FROM \"schema_version\""
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      catalogVersionProvider = "SELECT :catalog_name || '_' || MAX(\"version\") FROM \"schema_version\""
      schemaVersionProvider = "SELECT :schema_name || '_' || MAX(\"version\") FROM \"schema_version\""
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

###### Example: A constant

Instead of supplying the constant directly in your configuration, you can also use your build system's property expression, or some other mechanism to produce this constant.

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <catalogVersionProvider>1</catalogVersionProvider>
      <schemaVersionProvider>2</schemaVersionProvider>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withCatalogVersionProvider(1)
      .withSchemaVersionProvider(2)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      catalogVersionProvider = 1
      schemaVersionProvider = 2
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      catalogVersionProvider = 1
      schemaVersionProvider = 2
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

###### Re-generating up-to-date schemas

By default, these version providers ensure that up-to-date schemas do not get re-generated. In cases where this is undesired (even if only for single generation runs), there's an additional flag that allows for turning off the skipping of re-generating up-to-date schemas:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <!-- Defaults to true -->
      <skipRegenerationOnUpToDateVersion>false</skipRegenerationOnUpToDateVersion>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // Defaults to true
      .withSkipRegenerationOnUpToDateVersion(false)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {

      // Defaults to true
      isSkipRegenerationOnUpToDateVersion = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {

      // Defaults to true
      skipRegenerationOnUpToDateVersion = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-database-order-provider"></a>
##### 5.2.5.17. Custom ordering of generated code

By default, the jOOQ code generator maintains the following ordering of objects:

- Catalogs, schemas, tables, user-defined types, packages, routines, sequences, constraints are ordered alphabetically
- Table columns, user-defined type attributes, routine parameters are ordered in their order of definition

Sometimes, it may be desireable to override this default ordering to a custom ordering. In particular, the default ordering may be case-sensitive, when case-insensitive ordering is really more desireable at times. Users may define an order provider by specifying a fully qualified class on the code generator's class path, which must implement [`java.util.Comparator<org.jooq.meta.Definition>`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Comparator.html) as follows:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <orderProvider>com.example.CaseInsensitiveOrderProvider</orderProvider>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withOrderProvider("com.example.CaseInsensitiveOrderProvider")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      orderProvider = "com.example.CaseInsensitiveOrderProvider"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      orderProvider = "com.example.CaseInsensitiveOrderProvider"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> Make sure your custom order provider is available to the code generator as a [code generator dependency](#codegen-dependencies)

This order provider may then look as follows:

```java
package com.example;

import java.util.Comparator;

import org.jooq.meta.Definition;

public class CaseInsensitiveOrderProvider implements Comparator<Definition> {
    @Override
    public int compare(Definition o1, Definition o2) {
        return o1.getQualifiedInputName().compareToIgnoreCase(o2.getQualifiedInputName());
    }
}
```

While changing the order of "top level types" (like tables) is irrelevant to the jOOQ runtime, there may be some side-effects to changing the order of table columns, user-defined type attributes, routine parameters, as the database might expect the exact same order as is defined in the database. In order to only change the ordering for tables, the following order provider can be implemented instead:

```java
package com.example;

import java.util.Comparator;

import org.jooq.meta.Definition;
import org.jooq.meta.TableDefinition;

public class CaseInsensitiveOrderProvider implements Comparator<Definition> {
    @Override
    public int compare(Definition o1, Definition o2) {
        if (o1 instanceof TableDefinition && o2 instanceof TableDefinition)
            return o1.getQualifiedInputName().compareToIgnoreCase(o2.getQualifiedInputName());
        else
            return 0; // Retain input ordering
    }
}
```

<a id="codegen-database-forced-types"></a>
##### 5.2.5.18. Forced types

The code generator allows users to override column, attribute, and parameter data types, as well as other attributes in three different ways:

- By rewriting them to some other data type using the [data type rewriting feature](#codegen-database-forced-types-rewrite).
- By mapping them to some user type using the [data type converter feature](#codegen-database-forced-types-converter) and a custom [`org.jooq.Converter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html).
- By mapping them to some user type using the [data type binding feature](#codegen-database-forced-types-binding) and a custom [`org.jooq.Binding`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Binding.html).

All of this, and more, can be done using forced types.

<a id="codegen-database-forced-types-matching"></a>
###### 5.2.5.18.1. Matching of forced types

The `<database>` configuration's `<forcedTypes>` element can contain many `<forcedType>` elements and the generator will always pick the first of these definitions (orderered by `<priority/>` and then bylexical appearance in the configuration), where *all* given match predicates match a given database attribute, column, array element, parameter, or sequence.

These are the available match predicates, all are optional:

1. `<priority>`: Any number (default `0`) indicating the priority of the forced type. Higher numbers have higher priority.

Matching predicates:

1. `<objectType>`: Must be one of `ATTRIBUTE`, `COLUMN`, `ELEMENT`, `PARAMETER`, `SEQUENCE`, or `ALL` and specifies what type of database objects this forced type is applicable to
2. `<nullability>`: Must be one of `NULL`, `NOT_NULL`, or `ALL` and specifies if this forced type is applicable to `NULL`, `NOT NULL`, or all definitions
3. `<excludeExpression>`: This *exclude* predicate is a regular expression which is matched against the definition's fully qualified, partially qualified, or unqualified name; any definition's name matching the regular expression will be considered *not matching* this forced type. If left empty, then nothing is excluded.
4. `<includeExpression>`: This predicate is a regular expression which is matched against the definition's fully qualified, partially qualified, or unqualified name. If left empty, then everything is included.
5. `<excludeTypes>`: This *exclude* predicate is a regular expression which is matched against the name of the definition's type (provided that it has one); any definition's type name matching the regular expression will be considered *not matching* this forced type. If left empty, then nothing is excluded.
6. `<includeTypes>`: This predicate is a regular expression which is matched against the name of the definition's type (provided that it has one). If left empty, then everything is included.
7. `<sql>`: An SQL query returning all (qualified or unqualified) object names which should be considered to match this forced type; an example is given at the end of this section.

###### An example using various attributes

The following example is a forced type that applies a [data type rewrite](#codegen-database-forced-types-rewrite) of all matched objects to the type `BOOLEAN`:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>

      <!-- The first matching forcedType will be applied to the data type definition. -->
      <forcedTypes>
        <forcedType>

          <!-- Specify any data type that is supported in your database, or if unsupported,
               a type from org.jooq.impl.SQLDataType -->
          <name>BOOLEAN</name>

          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.IS_VALID</includeExpression>

          <!-- A Java regex matching data types to be forced to have this type.

               Data types may be reported by your database as:
               - NUMBER              regexp suggestion: NUMBER
               - NUMBER(5)           regexp suggestion: NUMBER\(5\)
               - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
               - any other form.

               It is thus recommended to use defensive regexes for types. -->
          <includeTypes>.*</includeTypes>

          <!-- Force a type depending on data type nullability. Default is ALL.

                - ALL - Force a type regardless of whether data type is nullable or not (default)
                - NULL - Force a type only when data type is nullable
                - NOT_NULL - Force a type only when data type is not null -->
          <nullability>ALL</nullability>

          <!-- Force a type on ALL or specific object types. Default is ALL. Options include:
               ATTRIBUTE, COLUMN, ELEMENT, PARAMETER, SEQUENCE -->
          <objectType>ALL</objectType>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // The first matching forcedType will be applied to the data type definition.
      .withForcedTypes(
        new ForcedType()

          // Specify any data type that is supported in your database, or if unsupported,
          // a type from org.jooq.impl.SQLDataType
          .withName("BOOLEAN")

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.IS_VALID")

          // A Java regex matching data types to be forced to have this type.
          // 
          // Data types may be reported by your database as:
          // - NUMBER              regexp suggestion: NUMBER
          // - NUMBER(5)           regexp suggestion: NUMBER\(5\)
          // - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
          // - any other form.
          // 
          // It is thus recommended to use defensive regexes for types.
          .withIncludeTypes(".*")

          // Force a type depending on data type nullability. Default is ALL.
          // 
          // - ALL - Force a type regardless of whether data type is nullable or not (default)
          // - NULL - Force a type only when data type is nullable
          // - NOT_NULL - Force a type only when data type is not null
          .withNullability(Nullability.ALL)

          // Force a type on ALL or specific object types. Default is ALL. Options include:
          // ATTRIBUTE, COLUMN, ELEMENT, PARAMETER, SEQUENCE
          .withObjectType(ForcedTypeObjectType.ALL)
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {

      // The first matching forcedType will be applied to the data type definition.
      forcedTypes {
        forcedType {

          // Specify any data type that is supported in your database, or if unsupported,
          // a type from org.jooq.impl.SQLDataType
          name = "BOOLEAN"

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.IS_VALID"

          // A Java regex matching data types to be forced to have this type.
          // 
          // Data types may be reported by your database as:
          // - NUMBER              regexp suggestion: NUMBER
          // - NUMBER(5)           regexp suggestion: NUMBER\(5\)
          // - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
          // - any other form.
          // 
          // It is thus recommended to use defensive regexes for types.
          includeTypes = ".*"

          // Force a type depending on data type nullability. Default is ALL.
          // 
          // - ALL - Force a type regardless of whether data type is nullable or not (default)
          // - NULL - Force a type only when data type is nullable
          // - NOT_NULL - Force a type only when data type is not null
          nullability = Nullability.ALL

          // Force a type on ALL or specific object types. Default is ALL. Options include:
          // ATTRIBUTE, COLUMN, ELEMENT, PARAMETER, SEQUENCE
          objectType = ForcedTypeObjectType.ALL
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {

      // The first matching forcedType will be applied to the data type definition.
      forcedTypes {
        forcedType {

          // Specify any data type that is supported in your database, or if unsupported,
          // a type from org.jooq.impl.SQLDataType
          name = "BOOLEAN"

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.IS_VALID"

          // A Java regex matching data types to be forced to have this type.
          // 
          // Data types may be reported by your database as:
          // - NUMBER              regexp suggestion: NUMBER
          // - NUMBER(5)           regexp suggestion: NUMBER\(5\)
          // - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
          // - any other form.
          // 
          // It is thus recommended to use defensive regexes for types.
          includeTypes = ".*"

          // Force a type depending on data type nullability. Default is ALL.
          // 
          // - ALL - Force a type regardless of whether data type is nullable or not (default)
          // - NULL - Force a type only when data type is nullable
          // - NOT_NULL - Force a type only when data type is not null
          nullability = "ALL"

          // Force a type on ALL or specific object types. Default is ALL. Options include:
          // ATTRIBUTE, COLUMN, ELEMENT, PARAMETER, SEQUENCE
          objectType = "ALL"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

###### Using SQL to match column names

If you want to match your column names based on more complex criteria not supported by jOOQ yet, you can supply the matching column names using a SQL query that runs against your dictionary views. The following example uses a SQL query to find all columns that are "probably boolean", and applies a [data type converter](#codegen-database-forced-types-converter) to them:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Rewrite types to BOOLEAN -->
          <userType>java.lang.Boolean</userType>
          <converter>com.example.YNBooleanConverter</converter>

          <!-- All Oracle columns that have a default of 'Y' or 'N' are probably boolean -->
          <sql>
            SELECT owner || '.' || table_name || '.' || column_name
            FROM all_tab_cols
            WHERE data_default IN ('Y', 'N')
          </sql>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Rewrite types to BOOLEAN
          .withUserType("java.lang.Boolean")
          .withConverter("com.example.YNBooleanConverter")

          // All Oracle columns that have a default of 'Y' or 'N' are probably boolean
          .withSql("""
            SELECT owner || '.' || table_name || '.' || column_name
            FROM all_tab_cols
            WHERE data_default IN ('Y', 'N')
          """)
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Rewrite types to BOOLEAN
          userType = "java.lang.Boolean"
          converter = "com.example.YNBooleanConverter"

          // All Oracle columns that have a default of 'Y' or 'N' are probably boolean
          sql = """
            SELECT owner || '.' || table_name || '.' || column_name
            FROM all_tab_cols
            WHERE data_default IN ('Y', 'N')
          """
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Rewrite types to BOOLEAN
          userType = "java.lang.Boolean"
          converter = "com.example.YNBooleanConverter"

          // All Oracle columns that have a default of 'Y' or 'N' are probably boolean
          sql = """
            SELECT owner || '.' || table_name || '.' || column_name
            FROM all_tab_cols
            WHERE data_default IN ('Y', 'N')
          """
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

Please see the relevant sections of the manual to get more information about using [converters](#codegen-database-forced-types-converter) or [bindings](#codegen-database-forced-types-binding).

<a id="codegen-database-forced-types-rewrite"></a>
###### 5.2.5.18.2. Data type rewriting

Sometimes, the actual database data type does not match the SQL data type that you would like to use in Java. This is often the case for ill-supported SQL data types, such as `BOOLEAN`, `UUID`, or `INSTANT`. jOOQ's code generator allows you to apply simple data type rewriting. The following configuration will rewrite `IS_VALID` columns in all tables to be of type `BOOLEAN`.

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify any data type that is supported in your database, or if unsupported,
               a type from org.jooq.impl.SQLDataType -->
          <name>BOOLEAN</name>

          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.IS_VALID</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify any data type that is supported in your database, or if unsupported,
          // a type from org.jooq.impl.SQLDataType
          .withName("BOOLEAN")

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.IS_VALID")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify any data type that is supported in your database, or if unsupported,
          // a type from org.jooq.impl.SQLDataType
          name = "BOOLEAN"

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.IS_VALID"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify any data type that is supported in your database, or if unsupported,
          // a type from org.jooq.impl.SQLDataType
          name = "BOOLEAN"

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.IS_VALID"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

After such a data type rewrite, neither jOOQ's code generator, nor the runtime have any information about the original data type that your column may have had. Hence, this approach works best when the original data type (e.g. `INTEGER`), and the configured data type (e.g. `BIGINT`) are reasonably compatible. If you wish to "rewrite" your user type, but keeping the backing type information available, an actual `Converter`, including an [AutoConverter](#codegen-database-forced-types-auto-converter) might be a better choice.

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

<a id="codegen-database-forced-types-converter"></a>
###### 5.2.5.18.3. Qualified converters

When using a custom type in jOOQ, you need to let jOOQ know about its associated [`org.jooq.Converter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html). Ad-hoc usages of such converters has been discussed in the chapter about [data type conversion](#data-type-conversion)or [ad-hoc converters](#ad-hoc-converter). However, when mapping a custom type onto a standard JDBC type, a more common use-case is to let jOOQ know about custom types at code generation time.

Assuming you have a converter like this:

```java
public class IntegerToYearConverter extends AbstractConverter<Integer, Year> {
    public IntegerToYearConverter() {
        super(Integer.class, Year.class);
    }

    @Override
    public Year from(Integer i) {
        return i == null ? null : Year.of(i);
    }

    @Override
    public Integer to(Year y) {
        return y == null ? null : y.getValue();
    }
}
```

The following example shows how to reference a custom `Converter` from your `<forcedType>` configuration:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>java.time.Year</userType>

          <!-- Associate that custom type with your converter. -->
          <converter>com.example.IntegerToYearConverter</converter>

          <!-- Optionally specify whether the converter receives <T, U> type variables
               and Class<T>, Class<U> constructor arguments. Default is false. -->
          <genericConverter>false</genericConverter>
          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.YEAR.*</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          .withUserType("java.time.Year")

          // Associate that custom type with your converter.
          .withConverter("com.example.IntegerToYearConverter")

          // Optionally specify whether the converter receives <T, U> type variables
          // and Class<T>, Class<U> constructor arguments. Default is false.
          .withGenericConverter(false)

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.YEAR.*")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "java.time.Year"

          // Associate that custom type with your converter.
          converter = "com.example.IntegerToYearConverter"

          // Optionally specify whether the converter receives <T, U> type variables
          // and Class<T>, Class<U> constructor arguments. Default is false.
          isGenericConverter = false

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.YEAR.*"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "java.time.Year"

          // Associate that custom type with your converter.
          converter = "com.example.IntegerToYearConverter"

          // Optionally specify whether the converter receives <T, U> type variables
          // and Class<T>, Class<U> constructor arguments. Default is false.
          genericConverter = false

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.YEAR.*"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

The above configuration will lead e.g. to `AUTHOR.YEAR_OF_BIRTH` being generated like this:

```java
public class TAuthor extends TableImpl<TAuthorRecord> {

    // [...]
    public final TableField<TAuthorRecord, Year> YEAR_OF_BIRTH =    // [...]
    // [...]

}
```

This means that the bound type of `<T>` will be `Year`, wherever you reference `YEAR_OF_BIRTH`. jOOQ will use your custom converter when binding variables and when fetching data from [`java.sql.ResultSet`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/ResultSet.html):

```java
// Get all date of births of authors born after 1980
List<Year> result =
create.selectFrom(AUTHOR)
      .where(AUTHOR.YEAR_OF_BIRTH.gt(Year.of(1980))
      .fetch(AUTHOR.YEAR_OF_BIRTH);
```

<a id="codegen-database-forced-types-inline-converter"></a>
###### 5.2.5.18.4. Inline converters

For convenience, you can inline your converter code directly into the configuration instead of providing a class reference, as [shown previously](#codegen-database-forced-types-converter).

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>java.time.Year</userType>

          <!-- Associate that custom type with your inline converter. -->
          <converter>org.jooq.Converter.ofNullable(
            Integer.class, Year.class,
            Year::of, Year::getValue
          )</converter>

          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.YEAR.*</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          .withUserType("java.time.Year")

          // Associate that custom type with your inline converter.
          .withConverter("""org.jooq.Converter.ofNullable(
            Integer.class, Year.class,
            Year::of, Year::getValue
          )""")

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.YEAR.*")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "java.time.Year"

          // Associate that custom type with your inline converter.
          converter = """org.jooq.Converter.ofNullable(
            Integer.class, Year.class,
            Year::of, Year::getValue
          )"""

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.YEAR.*"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "java.time.Year"

          // Associate that custom type with your inline converter.
          converter = """org.jooq.Converter.ofNullable(
            Integer.class, Year.class,
            Year::of, Year::getValue
          )"""

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.YEAR.*"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

The effect on your query user code will be the same as with [explicit converters](#codegen-database-forced-types-converter).

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

<a id="codegen-database-forced-types-lambda-converter"></a>
###### 5.2.5.18.5. Lambda converters

In addition to [inlining your complete converter definition](#codegen-database-forced-types-inline-converter), you can simplify usage of [`Converter.of()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html#of(java.lang.Class,java.lang.Class,java.util.function.Function,java.util.function.Function)) and [`Converter.ofNullable()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html#ofNullable(java.lang.Class,java.lang.Class,java.util.function.Function,java.util.function.Function)) using a `lambdaConverter`, specifying only the two lambda expressions, where `from` translates "from the database type" and `to` translates "to the database type".

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>java.time.Year</userType>

          <!-- Associate that custom type with your inline converter. -->
          <lambdaConverter>
            <from>Year::of</from>
            <to>Year::getValue</to>
          </lambdaConverter>

          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.YEAR.*</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          .withUserType("java.time.Year")

          // Associate that custom type with your inline converter.
          .withLambdaConverter(new LambdaConverter()
            .withFrom("Year::of")
            .withTo("Year::getValue")
          )

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.YEAR.*")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "java.time.Year"

          // Associate that custom type with your inline converter.
          lambdaConverter {
            from = "Year::of"
            to = "Year::getValue"
          }

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.YEAR.*"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "java.time.Year"

          // Associate that custom type with your inline converter.
          lambdaConverter {
            from = "Year::of"
            to = "Year::getValue"
          }

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.YEAR.*"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

The effect on your query user code will be the same as with [explicit converters](#codegen-database-forced-types-converter).

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

<a id="codegen-database-forced-types-auto-converter"></a>
###### 5.2.5.18.6. Auto converters

If your user type is a type that can be converted from/to using your configured [ConverterProvider](#converter-provider) (custom, or default), you can use the `<autoConverter/>` convenience flag instead of an explicit converter per type combination. This will apply the built-in [`org.jooq.impl.AutoConverter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/AutoConverter.html).

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>java.lang.String</userType>

          <!-- Apply the built in org.jooq.impl.AutoConverter. This flag can also be omitted -->
          <autoConverter>true</autoConverter>

          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.ID</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          .withUserType("java.lang.String")

          // Apply the built in org.jooq.impl.AutoConverter. This flag can also be omitted
          .withAutoConverter(true)

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.ID")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "java.lang.String"

          // Apply the built in org.jooq.impl.AutoConverter. This flag can also be omitted
          isAutoConverter = true

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.ID"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "java.lang.String"

          // Apply the built in org.jooq.impl.AutoConverter. This flag can also be omitted
          autoConverter = true

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.ID"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

Unlike when you [rewrite your data type](#codegen-database-forced-types-rewrite), which overrides the `T` type of your `Field<T>` this configuration applies a [`org.jooq.Converter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html), such that the SQL type information (`T`) is still available.

The effect on your query user code will be the same as with [explicit converters](#codegen-database-forced-types-converter).

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

<a id="codegen-database-forced-types-enum-converter"></a>
###### 5.2.5.18.7. Enum converters

If your user type is a Java enum, you can use the `<enumConverter/>` convenience flag instead of an explicit converter per enum type. This will apply the built-in [`org.jooq.impl.EnumConverter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/EnumConverter.html).

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>com.example.MyEnum</userType>

          <!-- Apply the built in org.jooq.impl.EnumConverter. -->
          <enumConverter>true</enumConverter>

          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.MY_STATUS</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          .withUserType("com.example.MyEnum")

          // Apply the built in org.jooq.impl.EnumConverter.
          .withEnumConverter(true)

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.MY_STATUS")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "com.example.MyEnum"

          // Apply the built in org.jooq.impl.EnumConverter.
          isEnumConverter = true

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.MY_STATUS"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "com.example.MyEnum"

          // Apply the built in org.jooq.impl.EnumConverter.
          enumConverter = true

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.MY_STATUS"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

The effect on your query user code will be the same as with [explicit converters](#codegen-database-forced-types-converter).

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

<a id="codegen-database-forced-types-jackson-converter"></a>
###### 5.2.5.18.8. Jackson converters

In case your database column is of type [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) or [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html), you may want to attach a custom data type binding that is backed by the popular [Jackson library](https://github.com/FasterXML/jackson). It is easy to achieve manually using a hand-written [Converter](#codegen-database-forced-types-converter), but you can also use the following convenience configuration:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>com.example.MyType</userType>

          <!-- Apply the built in converter of type

               - org.jooq.jackson.extensions.converters.JSONtoJacksonConverter,
               - org.jooq.jackson.extensions.converters.JSONBtoJacksonConverter,
               - org.jooq.jackson3.extensions.converters.JSONtoJacksonConverter,
               - org.jooq.jackson3.extensions.converters.JSONBtoJacksonConverter. -->
          <jsonConverter>true</jsonConverter>
          
          <!-- Choose an explicit Jackson version to implement the jsonConverter
               By default, the version found on the classpath is preferred, or Jackson 3 by default. -->
          <jsonConverterImplementation>JACKSON_3</jsonConverterImplementation>

          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.JSON_COLUMN</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          .withUserType("com.example.MyType")

          // Apply the built in converter of type
          // 
          // - org.jooq.jackson.extensions.converters.JSONtoJacksonConverter,
          // - org.jooq.jackson.extensions.converters.JSONBtoJacksonConverter,
          // - org.jooq.jackson3.extensions.converters.JSONtoJacksonConverter,
          // - org.jooq.jackson3.extensions.converters.JSONBtoJacksonConverter.
          .withJsonConverter(true)

          // Choose an explicit Jackson version to implement the jsonConverter
          // By default, the version found on the classpath is preferred, or Jackson 3 by default.
          .withJsonConverterImplementation(JSONConverterImplementation.JACKSON_3)

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.JSON_COLUMN")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "com.example.MyType"

          // Apply the built in converter of type
          // 
          // - org.jooq.jackson.extensions.converters.JSONtoJacksonConverter,
          // - org.jooq.jackson.extensions.converters.JSONBtoJacksonConverter,
          // - org.jooq.jackson3.extensions.converters.JSONtoJacksonConverter,
          // - org.jooq.jackson3.extensions.converters.JSONBtoJacksonConverter.
          isJsonConverter = true

          // Choose an explicit Jackson version to implement the jsonConverter
          // By default, the version found on the classpath is preferred, or Jackson 3 by default.
          jsonConverterImplementation = JSONConverterImplementation.JACKSON_3

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.JSON_COLUMN"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "com.example.MyType"

          // Apply the built in converter of type
          // 
          // - org.jooq.jackson.extensions.converters.JSONtoJacksonConverter,
          // - org.jooq.jackson.extensions.converters.JSONBtoJacksonConverter,
          // - org.jooq.jackson3.extensions.converters.JSONtoJacksonConverter,
          // - org.jooq.jackson3.extensions.converters.JSONBtoJacksonConverter.
          jsonConverter = true

          // Choose an explicit Jackson version to implement the jsonConverter
          // By default, the version found on the classpath is preferred, or Jackson 3 by default.
          jsonConverterImplementation = "JACKSON_3"

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.JSON_COLUMN"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

In order to access these converters, just add the following dependency to your project:

**Maven:**

```xml
<!-- For Jackson 2.x support -->
<dependency>
                <!-- Use org.jooq                for the Open Source Edition
                         org.jooq.pro            for commercial editions with Java 25 support,
                         org.jooq.pro-java-21    for commercial editions with Java 21 support,
                         org.jooq.pro-java-17    for commercial editions with Java 17 support,
                         org.jooq.pro-java-11    for commercial editions with Java 11 support,
                         org.jooq.pro-java-8     for commercial editions with Java 8 support,
                         org.jooq.trial          for the free trial edition with Java 25 support,
                         org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                         org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                         org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                         org.jooq.trial-java-8   for the free trial edition with Java 8 support
    
                 Note: Only the Open Source Edition is hosted on Maven Central.
                       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

    <groupId>org.jooq</groupId>
    <artifactId>jooq-jackson-extensions</artifactId>
    <version>3.22.0-SNAPSHOT</version>
</dependency>

<!-- For Jackson 3.x support -->
<dependency>
                <!-- Use org.jooq                for the Open Source Edition
                         org.jooq.pro            for commercial editions with Java 25 support,
                         org.jooq.pro-java-21    for commercial editions with Java 21 support,
                         org.jooq.pro-java-17    for commercial editions with Java 17 support,
                         org.jooq.pro-java-11    for commercial editions with Java 11 support,
                         org.jooq.pro-java-8     for commercial editions with Java 8 support,
                         org.jooq.trial          for the free trial edition with Java 25 support,
                         org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                         org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                         org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                         org.jooq.trial-java-8   for the free trial edition with Java 8 support
    
                 Note: Only the Open Source Edition is hosted on Maven Central.
                       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

    <groupId>org.jooq</groupId>
    <artifactId>jooq-jackson3-extensions</artifactId>
    <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    
    // For Jackson 2.x support
    implementation("org.jooq:jooq-jackson-extensions:3.22.0-SNAPSHOT")
    
    // For Jackson 3.x support
    implementation("org.jooq:jooq-jackson3-extensions:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    
    // For Jackson 2.x support
    implementation "org.jooq:jooq-jackson-extensions:3.22.0-SNAPSHOT"
    
    // For Jackson 3.x support
    implementation "org.jooq:jooq-jackson3-extensions:3.22.0-SNAPSHOT"
}
```

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

<a id="codegen-database-forced-types-jaxb-converter"></a>
###### 5.2.5.18.9. JAXB converters

In case your database column is of type [`org.jooq.XML`](https://www.jooq.org/javadoc/3.22.x/org/jooq/XML.html), you may want to attach a custom data type binding that is backed by JAXB. It is easy to achieve manually using a hand-written [Converter](#codegen-database-forced-types-converter), but you can also use the following convenience configuration:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
          <userType>com.example.MyType</userType>

          <!-- Apply the built in converter of type org.jooq.impl.XMLtoJAXBConverter. -->
          <xmlConverter>true</xmlConverter>

          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*\.XML_COLUMN</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          .withUserType("com.example.MyType")

          // Apply the built in converter of type org.jooq.impl.XMLtoJAXBConverter.
          .withXmlConverter(true)

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*\\.XML_COLUMN")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "com.example.MyType"

          // Apply the built in converter of type org.jooq.impl.XMLtoJAXBConverter.
          isXmlConverter = true

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.XML_COLUMN"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Converter's <U> type.
          userType = "com.example.MyType"

          // Apply the built in converter of type org.jooq.impl.XMLtoJAXBConverter.
          xmlConverter = true

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*\\.XML_COLUMN"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

<a id="codegen-database-forced-types-binding"></a>
###### 5.2.5.18.10. Data type bindings

The previous sections discussed the case where your custom data type is mapped onto a standard JDBC type as contained in [`org.jooq.impl.SQLDataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/SQLDataType.html). In some cases, however, you want to map your own type onto a type that is not explicitly supported by JDBC, such as for instance, PostgreSQL's various advanced data types (though do check out the `jooq-postgres-extensions` module to see what we're already offering in this area). For this, you can register an [`org.jooq.Binding`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Binding.html) for relevant columns in your code generator. Consider the following trivial implementation of a binding for PostgreSQL's JSON data type, which binds the JSON string in PostgreSQL to a Google GSON object:

```java
import java.sql.*;
import java.util.*;

import org.jooq.*;
import org.jooq.conf.*;
import org.jooq.impl.DSL;
import com.google.gson.*;

// We're binding <T> = JSON (or JSONB), and <U> = JsonElement (user type)
// Alternatively, extend org.jooq.impl.AbstractBinding to implement fewer methods.
public class PostgresJSONGsonBinding implements Binding<JSON, JsonElement> {

    private final Gson gson = new Gson();

    // The converter does all the work
    @Override
    public Converter<JSON, JsonElement> converter() {
        return new Converter<JSON, JsonElement>() {
            @Override
            public JsonElement from(JSON t) {
                return t == null ? JsonNull.INSTANCE : gson.fromJson(t.data(), JsonElement.class);
            }

            @Override
            public JSON to(JsonElement u) {
                return u == null || u == JsonNull.INSTANCE ? null : JSON.json(gson.toJson(u));
            }

            @Override
            public Class<JSON> fromType() {
                return JSON.class;
            }

            @Override
            public Class<JsonElement> toType() {
                return JsonElement.class;
            }
        };
    }

    // Rending a bind variable for the binding context's value and casting it to the json type
    @Override
    public void sql(BindingSQLContext<JsonElement> ctx) throws SQLException {
        // Depending on how you generate your SQL, you may need to explicitly distinguish
        // between jOOQ generating bind variables or inlined literals.
        if (ctx.render().paramType() == ParamType.INLINED)
            ctx.render().visit(DSL.inline(ctx.convert(converter()).value())).sql("::json");
        else
            ctx.render().sql(ctx.variable()).sql("::json");
    }

    // Registering VARCHAR types for JDBC CallableStatement OUT parameters
    @Override
    public void register(BindingRegisterContext<JsonElement> ctx) throws SQLException {
        ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR);
    }

    // Converting the JsonElement to a String value and setting that on a JDBC PreparedStatement
    @Override
    public void set(BindingSetStatementContext<JsonElement> ctx) throws SQLException {
        JSON json = ctx.convert(converter()).value();
        ctx.statement().setString(ctx.index(), json == null ? null : json.data());
    }

    // Getting a String value from a JDBC ResultSet and converting that to a JsonElement
    @Override
    public void get(BindingGetResultSetContext<JsonElement> ctx) throws SQLException {
        ctx.convert(converter()).value(JSON.json(ctx.resultSet().getString(ctx.index())));
    }

    // Getting a String value from a JDBC CallableStatement and converting that to a JsonElement
    @Override
    public void get(BindingGetStatementContext<JsonElement> ctx) throws SQLException {
        ctx.convert(converter()).value(JSON.json(ctx.statement().getString(ctx.index())));
    }

    // Setting a value on a JDBC SQLOutput (useful for Oracle OBJECT types)
    @Override
    public void set(BindingSetSQLOutputContext<JsonElement> ctx) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    // Getting a value from a JDBC SQLInput (useful for Oracle OBJECT types)
    @Override
    public void get(BindingGetSQLInputContext<JsonElement> ctx) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }
}
```

###### Registering bindings to the code generator

The above [`org.jooq.Binding`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Binding.html) implementation intercepts all the interaction on a JDBC level, such that jOOQ will never need to know how to correctly serialise / deserialise your custom data type. Similar to what we've seen in the previous section about [how to register Converters to the code generator](#codegen-database-forced-types-converter), we can now register such a binding to the code generator. Note that you will reuse the same types of XML elements (`<forcedType/>`):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Specify the Java type of your custom type. This corresponds to the Binding's <U> type. -->
          <userType>com.google.gson.JsonElement</userType>

          <!-- Associate that custom type with your binding. -->
          <binding>com.example.PostgresJSONGsonBinding</binding>

          <!-- Optionally specify whether the binding receives <T, U> type variables
               and Class<T>, Class<U> constructor arguments. Default is false. -->
          <genericBinding>true</genericBinding>
          <!-- A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions. -->
          <includeExpression>.*JSON.*</includeExpression>

          <!-- A Java regex matching data types to be forced to
               have this type.

               Data types may be reported by your database as:
               - NUMBER              regexp suggestion: NUMBER
               - NUMBER(5)           regexp suggestion: NUMBER\(5\)
               - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
               - any other form

               It is thus recommended to use defensive regexes for types.

               If provided, both "includeExpressions" and "includeTypes" must match. -->
          <includeTypes>(?i:JSON)</includeTypes>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Specify the Java type of your custom type. This corresponds to the Binding's <U> type.
          .withUserType("com.google.gson.JsonElement")

          // Associate that custom type with your binding.
          .withBinding("com.example.PostgresJSONGsonBinding")

          // Optionally specify whether the binding receives <T, U> type variables
          // and Class<T>, Class<U> constructor arguments. Default is false.
          .withGenericBinding(true)

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          .withIncludeExpression(".*JSON.*")

          // A Java regex matching data types to be forced to
          // have this type.
          // 
          // Data types may be reported by your database as:
          // - NUMBER              regexp suggestion: NUMBER
          // - NUMBER(5)           regexp suggestion: NUMBER\(5\)
          // - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
          // - any other form
          // 
          // It is thus recommended to use defensive regexes for types.
          // 
          // If provided, both "includeExpressions" and "includeTypes" must match.
          .withIncludeTypes("(?i:JSON)")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Binding's <U> type.
          userType = "com.google.gson.JsonElement"

          // Associate that custom type with your binding.
          binding = "com.example.PostgresJSONGsonBinding"

          // Optionally specify whether the binding receives <T, U> type variables
          // and Class<T>, Class<U> constructor arguments. Default is false.
          isGenericBinding = true

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*JSON.*"

          // A Java regex matching data types to be forced to
          // have this type.
          // 
          // Data types may be reported by your database as:
          // - NUMBER              regexp suggestion: NUMBER
          // - NUMBER(5)           regexp suggestion: NUMBER\(5\)
          // - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
          // - any other form
          // 
          // It is thus recommended to use defensive regexes for types.
          // 
          // If provided, both "includeExpressions" and "includeTypes" must match.
          includeTypes = "(?i:JSON)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Specify the Java type of your custom type. This corresponds to the Binding's <U> type.
          userType = "com.google.gson.JsonElement"

          // Associate that custom type with your binding.
          binding = "com.example.PostgresJSONGsonBinding"

          // Optionally specify whether the binding receives <T, U> type variables
          // and Class<T>, Class<U> constructor arguments. Default is false.
          genericBinding = true

          // A Java regex matching fully-qualified columns, attributes, parameters. Use the pipe to separate several expressions.
          includeExpression = ".*JSON.*"

          // A Java regex matching data types to be forced to
          // have this type.
          // 
          // Data types may be reported by your database as:
          // - NUMBER              regexp suggestion: NUMBER
          // - NUMBER(5)           regexp suggestion: NUMBER\(5\)
          // - NUMBER(5, 2)        regexp suggestion: NUMBER\(5,\s*2\)
          // - any other form
          // 
          // It is thus recommended to use defensive regexes for types.
          // 
          // If provided, both "includeExpressions" and "includeTypes" must match.
          includeTypes = "(?i:JSON)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

For more details about how to match columns, please refer to [the section about matching columns for forced types](#codegen-database-forced-types-matching).

The above configuration will lead to `AUTHOR.CUSTOM_DATA_JSON` being generated like this:

```java
public class TAuthor extends TableImpl<TAuthorRecord> {

    // [...]
    public final TableField<TAuthorRecord, JsonElement> CUSTOM_DATA_JSON =    // [...]
    // [...]

}
```

<a id="codegen-database-forced-types-computed"></a>
###### 5.2.5.18.11. Client side computed columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

[Computed columns](#computed-columns) are a powerful feature on the server side, where a column can be guaranteed to always contain a value according to an expression based on the other columns of a table. Many dialects support them in at least one of two flavours:

- `STORED`: The computed value is calculated on write, and stored in the table
- `VIRTUAL`: The computed value is calculated on read (although it may still be stored in indexes)

There are various reasons why you may wish to compute columns, but not on the server side, i.e. not in the database directly, but let jOOQ do that for you on the client side. The [forced type configuration](#codegen-database-forced-types) can be used again to match columns, and apply an [`org.jooq.Generator`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Generator.html):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>

          <!-- Provide an expression of type org.jooq.Generator, or a class reference
               com.example.X for a class of type org.jooq.Generator, which can be
               instantiated using new com.example.X() -->
          <generator>ctx -&gt; org.jooq.impl.DSL.val(1)</generator>
          <includeExpression>(?i:ALWAYS_ONE)</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Provide an expression of type org.jooq.Generator, or a class reference
          // com.example.X for a class of type org.jooq.Generator, which can be
          // instantiated using new com.example.X()
          .withGenerator("ctx -> org.jooq.impl.DSL.val(1)")
          .withIncludeExpression("(?i:ALWAYS_ONE)")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Provide an expression of type org.jooq.Generator, or a class reference
          // com.example.X for a class of type org.jooq.Generator, which can be
          // instantiated using new com.example.X()
          generator = "ctx -> org.jooq.impl.DSL.val(1)"
          includeExpression = "(?i:ALWAYS_ONE)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Provide an expression of type org.jooq.Generator, or a class reference
          // com.example.X for a class of type org.jooq.Generator, which can be
          // instantiated using new com.example.X()
          generator = "ctx -> org.jooq.impl.DSL.val(1)"
          includeExpression = "(?i:ALWAYS_ONE)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

The behaviour is as follows:

- If the forced type matches an actual column from your database, then the semantics is that of `STORED` computed columns, i.e. all of your DML statements will be transformed by jOOQ to ensure the correct computation of the value, which will be written to your schema. Other database clients, including non-jOOQ based ones, can then see those computed values.
- If the forced type matches a [synthetic column](#codegen-database-synthetic-columns), then the semantics is that of `VIRTUAL` computed columns, i.e. the column does not exist in your schema, but the computation will be added to all of your [SELECT statements](#select-statement), if you include the column in your projections and other clauses.

Unlike [server side computed columns](#computed-columns), these computational expressions can include any type of [column expression](#column-expressions), including [scalar subqueries](#scalar-subqueries) (even correlated ones), or [implicit joins](#implicit-join), making client side computed columns an extremely powerful jOOQ feature!

The exact time a computation takes place is not specified for both `VIRTUAL` and `STORED` client side computed columns. While it may seem reasonable to expect the computation to take place when the column is rendered to SQL, future implementations may defer or even cache the computation. As such, a computation is recommended to be pure and side effect free. While side effects, such as producing a "current timestamp" are not forbidden, it is important to take into account the non-determinism of when the computation takes place. For example, caching a pre-computed transaction timestamp may be more reliable than computing the timestamp from within the `Generator`.

###### Limitations

> [!TIP]
> The computed column expression is a property of the generated [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html). As such, the property can only be enforced on expressions which make this flag available to jOOQ. For example, if you're using [plain SQL templates](#plain-sql-templating-language) without passing along a `DataType` with the computed expression enabled, then the feature cannot be enforced. See also [features requiring code generation](#codegen-feature-dependencies) for more details.

###### Settings

It is possible to turn off this feature, e.g. for the scope of individual statements. For more information, please refer to the section of the manual related to [computed column activation](#settings-computed-column-activation).

<a id="codegen-database-forced-types-audit"></a>
###### 5.2.5.18.12. Audit columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A common use-case for [(STORED) client side computed columns](#codegen-database-forced-types-computed) are audit columns. There exist many ways to implement auditing, including:

- Journalling all changes using a trigger that stores the complete change into a separate table
- [SQL:2011 temporal tables](#temporal-tables), which are more powerful than mere auditing
- Using a trigger to fill in a few technical columns, such as `CREATED_AT`, `MODIFIED_AT`, etc.

While jOOQ recommends you use a trigger or other out-of-the-box, standard SQL features, in order to implement auditing directly inside of your database (to make sure no one can bypass it), there are valid use-cases where you may not want to do this in the database itself, e.g. because you cannot create triggers for some privilege or other technical reasons. For those cases, jOOQ offers basic support for audit columns.

For example, you can set up your code generation configuration like this:

**XML (standalone and maven):**

```xml
<configuration>
    <generator>
        <database>
            <forcedTypes>
                <forcedType>
                    <auditInsertTimestamp>true</auditInsertTimestamp>
                    <includeExpression>CREATED_AT</includeExpression>
                </forcedType>
                <forcedType>
                    <auditInsertUser>true</auditInsertUser>
                    <includeExpression>CREATED_BY</includeExpression>
                </forcedType>
                <forcedType>
                    <auditUpdateTimestamp>true</auditUpdateTimestamp>
                    <includeExpression>MODIFIED_AT</includeExpression>
                </forcedType>
                <forcedType>
                    <auditUpdateUser>true</auditUpdateUser>
                    <includeExpression>MODIFIED_BY</includeExpression>
                </forcedType>
                <forcedType>
                    <auditInsertTimestamp>true</auditInsertTimestamp>
                    <auditUpdateTimestamp>true</auditUpdateTimestamp>
                    <includeExpression>CREATED_OR_MODIFIED_AT</includeExpression>
                </forcedType>
                <forcedType>
                    <auditInsertUser>true</auditInsertUser>
                    <auditUpdateUser>true</auditUpdateUser>
                    <includeExpression>CREATED_OR_MODIFIED_BY</includeExpression>
                </forcedType>
            </forcedTypes>
        </database>
    </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()
          .withAuditInsertTimestamp(true)
          .withIncludeExpression("CREATED_AT"),
        new ForcedType()
          .withAuditInsertUser(true)
          .withIncludeExpression("CREATED_BY"),
        new ForcedType()
          .withAuditUpdateTimestamp(true)
          .withIncludeExpression("MODIFIED_AT"),
        new ForcedType()
          .withAuditUpdateUser(true)
          .withIncludeExpression("MODIFIED_BY"),
        new ForcedType()
          .withAuditInsertTimestamp(true)
          .withAuditUpdateTimestamp(true)
          .withIncludeExpression("CREATED_OR_MODIFIED_AT"),
        new ForcedType()
          .withAuditInsertUser(true)
          .withAuditUpdateUser(true)
          .withIncludeExpression("CREATED_OR_MODIFIED_BY")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {
          isAuditInsertTimestamp = true
          includeExpression = "CREATED_AT"
        }
        forcedType {
          isAuditInsertUser = true
          includeExpression = "CREATED_BY"
        }
        forcedType {
          isAuditUpdateTimestamp = true
          includeExpression = "MODIFIED_AT"
        }
        forcedType {
          isAuditUpdateUser = true
          includeExpression = "MODIFIED_BY"
        }
        forcedType {
          isAuditInsertTimestamp = true
          isAuditUpdateTimestamp = true
          includeExpression = "CREATED_OR_MODIFIED_AT"
        }
        forcedType {
          isAuditInsertUser = true
          isAuditUpdateUser = true
          includeExpression = "CREATED_OR_MODIFIED_BY"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {
          auditInsertTimestamp = true
          includeExpression = "CREATED_AT"
        }
        forcedType {
          auditInsertUser = true
          includeExpression = "CREATED_BY"
        }
        forcedType {
          auditUpdateTimestamp = true
          includeExpression = "MODIFIED_AT"
        }
        forcedType {
          auditUpdateUser = true
          includeExpression = "MODIFIED_BY"
        }
        forcedType {
          auditInsertTimestamp = true
          auditUpdateTimestamp = true
          includeExpression = "CREATED_OR_MODIFIED_AT"
        }
        forcedType {
          auditInsertUser = true
          auditUpdateUser = true
          includeExpression = "CREATED_OR_MODIFIED_BY"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Using the above flags, you can specify an [`org.jooq.impl.AuditGenerator`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/AuditGenerator.html) to be applied to your columns, which is just convenience for a hand-rolled [(STORED) client side computed columns](#codegen-database-forced-types-computed). All such audit columns compute their actual value from [`Configuration.auditProvider()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Configuration.html#auditProvider()), which allows for overriding the [`org.jooq.impl.DefaultAuditProvider`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultAuditProvider.html) behaviour, which is:

- Using [CURRENT_TIMESTAMP](#current-timestamp-function), [CURRENT_TIME](#current-time-function), [CURRENT_DATE](#current-date-function), or a similar function, if the data type is temporal, and we're auditing timestamps.
- Using [CURRENT_USER](#current-user-function) if the data type is a `String`, and we're auditing users.

The two types of [`org.jooq.AuditType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/AuditType.html) flags (`USER`, `TIMESTAMP`) are mutually exclusive, but the two types of [`org.jooq.GeneratorStatementType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/GeneratorStatementType.html) (`INSERT`, `UPDATE`) can be combined in order to trigger writing to the column on either or both types of operations.

As any other [(STORED) client side computed columns](#codegen-database-forced-types-computed), this transforms any jOOQ generated [DML statement](#sql-statements), irrespective of whether it originates from within jOOQ (e.g. via the [UpdatableRecord API](#crud-with-updatablerecords) or [DAO API](#daos)), or whether you hand-roll it using the jOOQ DSL. For example, assuming a table like this, which will be generated using the above `<forcedTypes/>` configuration:

```sql
CREATE TABLE audit (
  id INTEGER NOT NULL,
  val INTEGER NOT NULL,
  created_at TIMESTAMP NOT NULL,
  created_by VARCHAR(100) NOT NULL,
  modified_at TIMESTAMP,
  modified_by VARCHAR(100),
  created_or_modified_at TIMESTAMP NOT NULL,
  created_or_modified_by VARCHAR(100),

  CONSTRAINT pk_t_audit PRIMARY KEY (id)
);
```

Now, the following jOOQ statement:

```java
create.insertInto(AUDIT)
      .columns(AUDIT.ID, AUDIT.VAL)
      .values(1, 1)
      .execute();
```

Might produce a SQL statement like this:

```sql
INSERT INTO public.audit (
  id,
  val,
  created_at,
  created_by,
  created_or_modified_at,
  created_or_modified_by
)
SELECT
  id,
  val,
  current_timestamp,
  current_user(),
  current_timestamp,
  current_user()
FROM (
  SELECT 1, 1
) AS t (id, val)
```

Combining this feature with [embeddable types](#codegen-embeddable-types) is particularly useful.

###### Limitations

> [!TIP]
> The computed column expression (and thus the audit expressions) is a property of the generated [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html). As such, the property can only be enforced on expressions which make this flag available to jOOQ. For example, if you're using [plain SQL templates](#plain-sql-templating-language) without passing along a `DataType` with the computed expression enabled, then the feature cannot be enforced. See also [features requiring code generation](#codegen-feature-dependencies) for more details.

###### Settings

As audit columns are just special types of [client side computed columns](#codegen-database-forced-types-computed), it is possible to turn off this feature, e.g. for the scope of individual statements. For more information, please refer to the section of the manual related to [computed column activation](#settings-computed-column-activation).

<a id="codegen-database-forced-types-hidden"></a>
###### 5.2.5.18.13. Hidden columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A column may be [hidden from queries](#hidden-columns) by marking it as such in a forced type:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>
          <hidden>true</hidden>
          <includeExpression>(?i:CREATED|MODIFIED)_(?i:AT|BY)</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()
          .withHidden(true)
          .withIncludeExpression("(?i:CREATED|MODIFIED)_(?i:AT|BY)")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {
          isHidden = true
          includeExpression = "(?i:CREATED|MODIFIED)_(?i:AT|BY)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {
          hidden = true
          includeExpression = "(?i:CREATED|MODIFIED)_(?i:AT|BY)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> It may be useful to also change the [generated visibility](#codegen-database-forced-types-visibility) of a hidden column.

<a id="codegen-database-forced-types-redacted"></a>
###### 5.2.5.18.14. Redacted columns

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A column may be [redacted from formatted output](#redacted-columns) by marking it as such in a forced type:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>
          <redacted>true</redacted>
          <includeExpression>(?i:CREDIT_CARD_NO)</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()
          .withRedacted(true)
          .withIncludeExpression("(?i:CREDIT_CARD_NO)")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {
          isRedacted = true
          includeExpression = "(?i:CREDIT_CARD_NO)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {
          redacted = true
          includeExpression = "(?i:CREDIT_CARD_NO)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-database-forced-types-visibility"></a>
###### 5.2.5.18.15. Visibility Modifier (per forced type)

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

There are a few cases where the visibility of individual columns should be reduced, e.g. to `private` in order to hide a technical column from user code. For those cases, the [forced type configuration](#codegen-database-forced-types) can be used again to match columns, and apply a visibility:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>
          <!-- Possible values for visibilityModifier
             - DEFAULT  : The default per language (Java: public, Kotlin, Scala: implicit public)
             - NONE     : Do not generate visibility modifiers
             - PUBLIC   : Generate explicit public modifiers (Java, Kotlin)
             - INTERNAL : Generate explicit internal modifiers (Kotlin)
             - PRIVATE  : Generate explicit private modifiers (Java, Kotlin, Scala) -->
          <visibilityModifier>PRIVATE</visibilityModifier>
          <includeExpression>(?i:CREATED|MODIFIED)_(?i:AT|BY)</includeExpression>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()

          // Possible values for visibilityModifier
          // - DEFAULT  : The default per language (Java: public, Kotlin, Scala: implicit public)
          // - NONE     : Do not generate visibility modifiers
          // - PUBLIC   : Generate explicit public modifiers (Java, Kotlin)
          // - INTERNAL : Generate explicit internal modifiers (Kotlin)
          // - PRIVATE  : Generate explicit private modifiers (Java, Kotlin, Scala)
          .withVisibilityModifier(VisibilityModifier.PRIVATE)
          .withIncludeExpression("(?i:CREATED|MODIFIED)_(?i:AT|BY)")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Possible values for visibilityModifier
          // - DEFAULT  : The default per language (Java: public, Kotlin, Scala: implicit public)
          // - NONE     : Do not generate visibility modifiers
          // - PUBLIC   : Generate explicit public modifiers (Java, Kotlin)
          // - INTERNAL : Generate explicit internal modifiers (Kotlin)
          // - PRIVATE  : Generate explicit private modifiers (Java, Kotlin, Scala)
          visibilityModifier = VisibilityModifier.PRIVATE
          includeExpression = "(?i:CREATED|MODIFIED)_(?i:AT|BY)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {

          // Possible values for visibilityModifier
          // - DEFAULT  : The default per language (Java: public, Kotlin, Scala: implicit public)
          // - NONE     : Do not generate visibility modifiers
          // - PUBLIC   : Generate explicit public modifiers (Java, Kotlin)
          // - INTERNAL : Generate explicit internal modifiers (Kotlin)
          // - PRIVATE  : Generate explicit private modifiers (Java, Kotlin, Scala)
          visibilityModifier = "PRIVATE"
          includeExpression = "(?i:CREATED|MODIFIED)_(?i:AT|BY)"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Such private columns can now no longer be referred by user queries explicitly, although they are still a part of the table, and can be projected when projecting all columns. [Custom code sections](#codegen-custom-code) in generated code can still access these columns, and so can inline [converters](#codegen-database-forced-types).

It may make sense to combine this feature with [client side computed columns](#codegen-database-forced-types-computed), e.g. to compute a column `A` based on a column `B`, and then hide `B` from user code to make sure users always use `A`, instead.

Not all values make sense for all languages.

See also [global visibility modifiers](#codegen-generate-visibility-modifier) for further options.

<a id="codegen-database-table-valued-functions"></a>
##### 5.2.5.19. Table valued functions

jOOQ supports table valued functions in many databases, including Oracle, PostgreSQL, SQL Server. By default, table valued functions are treated as:

- ordinary tables in most databases including PostgreSQL, SQL Server - because that's what they are. They're intended for use in [FROM clauses of SELECT statements](#from-clause), not as standalone routines.
- ordinary routines in some databases including Oracle - for historic reasons. While Oracle also allows for embedding (pipelined) table functions in [FROM clauses of SELECT statements](#from-clause), it is not uncommon to call these as standalone routines in Oracle.

The `<tableValuedFunctions/>` flag is thus set to `false` by default on Oracle, and `true` otherwise. Here's how to explicitly change this behaviour:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <tableValuedFunctions>true</tableValuedFunctions>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withTableValuedFunctions(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      isTableValuedFunctions = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      tableValuedFunctions = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-config-generate"></a>
#### 5.2.6. Generate

This element wraps all the configuration elements that are used for the jooq-codegen module, which generates Java or Scala code, or XML from your [database](#codegen-config-database).

Contained elements are:

<a id="codegen-generate-annotations"></a>
##### 5.2.6.1. Annotations

The code generator supports a set of annotations on generated code, which can be turned on using the following flags. These annotations include:

- **Generated annotations:** The JDK generated annotation can be added to all generated classes to include some useful meta information, like the jOOQ version, or the schema version, or the generation date. Depending on the configured `generatedAnnotationType`, the annotation is one of:
  - [`javax.annotation.processing.Generated`](https://docs.oracle.com/en/java/javase/25/docs/api/java.compiler/javax/annotation/processing/Generated.html) (JDK 9+)
  - [`javax.annotation.Generated`](https://javaee.github.io/javaee-spec/javadocs/javax/annotation/Generated.html) (JDK 8-)

- **Nullable annotations:** When using alternative JVM languages like Kotlin, it may be desireable to have some hints related to nullability on generated code. When jOOQ encounters a nullable column, for instance, a JSR-305 `@Nullable` annotation could warn Kotlin users about well-known nullable columns. `@Nonnull` columns are more treacherous, as there are numerous reasons why a jOOQ `Record` could contain a `null` value in such a column, e.g. when the record was initialised without any values, or when the record originates from a `UNION` or `OUTER JOIN`.  
    
  If a `NOT NULL` column has a `DEFAULT` expression, it is considered "nullable-on-write," i.e. the value may be `null` prior to a successful `INSERT` statement.  
    
  The `nullableAnnotationType` and `nonnullAnnotationType` configurations allow for specifying an alternative, qualified annotation name other than the JSR-305 types below.
  - [`javax.annotation.Nullable`](https://javaee.github.io/javaee-spec/javadocs/javax/annotation/Nullable.html) When a column is nullable
  - [`javax.annotation.Nonnull`](https://javaee.github.io/javaee-spec/javadocs/javax/annotation/Nonnull.html) When a column is non-nullable

  The additional `nullableAnnotationOnWriteOnlyNullableTypes` configuration allows for specifying whether write-only nullable columns (e.g. identities / defaulted or computed non-null columns) should be marked as nullable as well.

- **JPA annotations:** A minimal set of JPA annotations can be generated on POJOs and other artefacts to convey type and metadata information that is available to the code generator. These annotations include:
  - [`jakarta.persistence.Column`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/Column)
  - [`jakarta.persistence.Entity`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/Entity)
  - [`jakarta.persistence.GeneratedValue`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/GeneratedValue)
  - [`jakarta.persistence.GenerationType`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/GenerationType)
  - [`jakarta.persistence.Id`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/Id)
  - [`jakarta.persistence.Index`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/Index) (JPA 2.1 and later)
  - [`jakarta.persistence.Table`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/Table)
  - [`jakarta.persistence.UniqueConstraint`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/UniqueConstraint)

  While jOOQ generated code cannot really be used as full-fledged entities (use e.g. Hibernate or EclipseLink to generate such entities), this meta information can still be useful as documentation on your generated code. Some of the annotations (e.g. `@Column`) can be used by the [`org.jooq.impl.DefaultRecordMapper`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultRecordMapper.html) for mapping records to POJOs.

- **Validation annotations:** A set of Bean Validation API annotations can be added to the generated code to convey type information. They include:
  - [`javax.validation.constraints.NotNull`](https://javaee.github.io/javaee-spec/javadocs/javax/validation/constraints/NotNull.html)
  - [`javax.validation.constraints.Size`](https://javaee.github.io/javaee-spec/javadocs/javax/validation/constraints/Size.html)

  jOOQ does not implement the validation spec, nor does it validate your data, but you can use third-party tools to read the jOOQ-generated validation annotations.

- **Bean annotations:** A set of JavaBeans annotations can be added to the generated code to facilitate interoperability with the JavaBeans specification
  - [`java.beans.ConstructorProperties`](https://docs.oracle.com/en/java/javase/25/docs/api/java.desktop/java/beans/ConstructorProperties.html)

- **Spring annotations:** Some useful Spring annotations can be generated on [DAOs](#codegen-daos) for better Spring integration. These include:
  - `org.springframework.beans.factory.annotation.Autowired`
  - `org.springframework.stereotype.Repository`
  - `org.springframework.transaction.annotation.Transactional` (if `<springDao/>` is set)

- **Kotlin annotations:** Some kotlin specific annotations may be generated in some cases. These include:
  - `set:JvmName`

The flags governing the generation of these annotations are:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Possible values for generatedAnnotationType
         - DETECT_FROM_JDK
         - JAVAX_ANNOTATION_GENERATED
         - JAVAX_ANNOTATION_PROCESSING_GENERATED
         - ORG_JOOQ_GENERATED -->
      
      <generatedAnnotation>true</generatedAnnotation>
      <generatedAnnotationType>DETECT_FROM_JDK</generatedAnnotationType>
      <generatedAnnotationDate>true</generatedAnnotationDate>
      <generatedAnnotationJooqVersion>true</generatedAnnotationJooqVersion>
      <generatedAnnotationConfigurationHash>true</generatedAnnotationConfigurationHash>

      <nullableAnnotation>true</nullableAnnotation>
      <nullableAnnotationOnWriteOnlyNullableTypes>true</nullableAnnotationOnWriteOnlyNullableTypes>
      <nullableAnnotationType>javax.annotation.Nullable</nullableAnnotationType>
      <nonnullAnnotation>true</nonnullAnnotation>
      <nonnullAnnotationType>javax.annotation.Nonnull</nonnullAnnotationType>

      <jpaAnnotations>true</jpaAnnotations>
      <jpaVersion>2.2</jpaVersion>

      <validationAnnotations>true</validationAnnotations>

      <!-- The springDao flag enables the generation of @Transactional annotations on a
           generated, Spring-specific DAO -->
      <springAnnotations>true</springAnnotations>
      <springDao>true</springDao>

      <kotlinSetterJvmNameAnnotationsOnIsPrefix>true</kotlinSetterJvmNameAnnotationsOnIsPrefix>

      <constructorPropertiesAnnotation>true</constructorPropertiesAnnotation>
      <constructorPropertiesAnnotationOnPojos>true</constructorPropertiesAnnotationOnPojos>
      <constructorPropertiesAnnotationOnRecords>true</constructorPropertiesAnnotationOnRecords>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Possible values for generatedAnnotationType
      // - DETECT_FROM_JDK
      // - JAVAX_ANNOTATION_GENERATED
      // - JAVAX_ANNOTATION_PROCESSING_GENERATED
      // - ORG_JOOQ_GENERATED
      .withGeneratedAnnotation(true)
      .withGeneratedAnnotationType(GeneratedAnnotationType.DETECT_FROM_JDK)
      .withGeneratedAnnotationDate(true)
      .withGeneratedAnnotationJooqVersion(true)
      .withGeneratedAnnotationConfigurationHash(true)
      .withNullableAnnotation(true)
      .withNullableAnnotationOnWriteOnlyNullableTypes(true)
      .withNullableAnnotationType("javax.annotation.Nullable")
      .withNonnullAnnotation(true)
      .withNonnullAnnotationType("javax.annotation.Nonnull")
      .withJpaAnnotations(true)
      .withJpaVersion(2.2)
      .withValidationAnnotations(true)

      // The springDao flag enables the generation of @Transactional annotations on a
      // generated, Spring-specific DAO
      .withSpringAnnotations(true)
      .withSpringDao(true)
      .withKotlinSetterJvmNameAnnotationsOnIsPrefix(true)
      .withConstructorPropertiesAnnotation(true)
      .withConstructorPropertiesAnnotationOnPojos(true)
      .withConstructorPropertiesAnnotationOnRecords(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Possible values for generatedAnnotationType
      // - DETECT_FROM_JDK
      // - JAVAX_ANNOTATION_GENERATED
      // - JAVAX_ANNOTATION_PROCESSING_GENERATED
      // - ORG_JOOQ_GENERATED
      isGeneratedAnnotation = true
      generatedAnnotationType = GeneratedAnnotationType.DETECT_FROM_JDK
      isGeneratedAnnotationDate = true
      isGeneratedAnnotationJooqVersion = true
      isGeneratedAnnotationConfigurationHash = true
      isNullableAnnotation = true
      isNullableAnnotationOnWriteOnlyNullableTypes = true
      nullableAnnotationType = "javax.annotation.Nullable"
      isNonnullAnnotation = true
      nonnullAnnotationType = "javax.annotation.Nonnull"
      isJpaAnnotations = true
      jpaVersion = 2.2
      isValidationAnnotations = true

      // The springDao flag enables the generation of @Transactional annotations on a
      // generated, Spring-specific DAO
      isSpringAnnotations = true
      isSpringDao = true
      isKotlinSetterJvmNameAnnotationsOnIsPrefix = true
      isConstructorPropertiesAnnotation = true
      isConstructorPropertiesAnnotationOnPojos = true
      isConstructorPropertiesAnnotationOnRecords = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Possible values for generatedAnnotationType
      // - DETECT_FROM_JDK
      // - JAVAX_ANNOTATION_GENERATED
      // - JAVAX_ANNOTATION_PROCESSING_GENERATED
      // - ORG_JOOQ_GENERATED
      generatedAnnotation = true
      generatedAnnotationType = "DETECT_FROM_JDK"
      generatedAnnotationDate = true
      generatedAnnotationJooqVersion = true
      generatedAnnotationConfigurationHash = true
      nullableAnnotation = true
      nullableAnnotationOnWriteOnlyNullableTypes = true
      nullableAnnotationType = "javax.annotation.Nullable"
      nonnullAnnotation = true
      nonnullAnnotationType = "javax.annotation.Nonnull"
      jpaAnnotations = true
      jpaVersion = 2.2
      validationAnnotations = true

      // The springDao flag enables the generation of @Transactional annotations on a
      // generated, Spring-specific DAO
      springAnnotations = true
      springDao = true
      kotlinSetterJvmNameAnnotationsOnIsPrefix = true
      constructorPropertiesAnnotation = true
      constructorPropertiesAnnotationOnPojos = true
      constructorPropertiesAnnotationOnRecords = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-covariant-overrides"></a>
##### 5.2.6.2. Covariant overrides

Generated tables can extend the DSL in a way for a DSL method return type to return again the generated type. This leads to improved type safety in client code by allowing for type safe [dereferencing of table columns](#dereferenced-table-columns) also from certain [table expressions](#table-expressions), not just the tables themselves.

The following sections discuss options for such covariant overrides:

<a id="codegen-covariant-overrides-as"></a>
###### 5.2.6.2.1. Overriding as()

The most popular covariant override is the override of the [`Table.as(Name)`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html#as(org.jooq.Name)) method and its overloads, in order to offer type safe [column aliasing](#aliased-columns).

```java
// Overridden Book.as() returns Book, not Table<Book>:
Book b = BOOK.as("b");

// Type safe dereferencing of TableField:
Field<String> title = b.TITLE;
```

If generating these overrides is not a desireable default, it can be deactivated explicitly globally using the following flag:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <asMethodOverrides>false</asMethodOverrides>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withAsMethodOverrides(false)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      isAsMethodOverrides = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      asMethodOverrides = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-covariant-overrides-rename"></a>
###### 5.2.6.2.2. Overriding rename()

> [!TIP]
> As of jOOQ 3.22.0-SNAPSHOT, the `rename()` method is not declared in any super type yet, but it will be eventually, see [#13937](https://github.com/jOOQ/jOOQ/issues/13937).

Occasionally, users will want to rename a table for the scope of a single query, rather than globally as with the [runtime schema and table mapping](#settings-render-mapping) feature. This can be done with `Table.rename(Name)`:

```java
// Overridden Book.rename() returns Book, not Table<Book>:
Book b = BOOK.rename("b");

// Type safe dereferencing of TableField:
Field<String> title = b.TITLE;
```

Unlike [as()](#codegen-covariant-overrides-as), this does not affect generated SQL other than assuming a table `b` of the same structure as `BOOK` exists in the schema.

If generating these overrides is not a desireable default, it can be deactivated explicitly globally using the following flag:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <renameMethodOverrides>false</renameMethodOverrides>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withRenameMethodOverrides(false)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      isRenameMethodOverrides = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      renameMethodOverrides = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-covariant-overrides-where"></a>
###### 5.2.6.2.3. Overriding where()

[inline derived tables](#inline-derived-tables) can be a powerful feature for [dynamic SQL](#dynamic-sql), where client side views are created based on a [table expression](#table-expressions) and a [conditional expression](#conditional-expressions).

```java
// Overridden Book.where() returns Book, not Table<Book>:
Book b = BOOK.where(BOOK.TITLE.like("A%"));

// Type safe dereferencing of TableField:
Field<String> title = b.TITLE;
```

If generating these overrides is not a desireable default, it can be deactivated explicitly globally using the following flag:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <whereMethodOverrides>false</whereMethodOverrides>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withWhereMethodOverrides(false)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      isWhereMethodOverrides = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      whereMethodOverrides = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-default-catalog-and-schema"></a>
##### 5.2.6.3. Default catalog and schema

Generated catalog and schema objects have purposes other than qualifying their contents, such as tables, sequences, routines, etc. Some of these purposes include:

- [mapping of qualifiers](#codegen-database-catalog-and-schema-mapping)
- [declaring of version providers to prevent unnecessary re-generation](#codegen-database-version-providers)
- [declaring of qualifier based global artefacts](#codegen-globals)

This is why jOOQ generates a `DefaultCatalog` and `DefaultSchema` instance even when there are no catalogs or schemas in the database, or when the catalogs or schemas have been [mapped to the default](#codegen-database-catalog-and-schema-mapping).

If generating these defaults is not a desireable, it can be deactivated explicitly globally using the following flag:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <defaultCatalog>false</defaultCatalog>
      <defaultSchema>false</defaultSchema>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withDefaultCatalog(false)
      .withDefaultSchema(false)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      isDefaultCatalog = false
      isDefaultSchema = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      defaultCatalog = false
      defaultSchema = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-explicit-nullability"></a>
##### 5.2.6.4. Explicit nullability

By default, the jOOQ code generator only generates nullability information on the [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html) of a column, UDT attribute, routine parameter, etc. if it is declared [NOT NULL](#create-table-nullability), e.g. `SQLDataType.INTEGER.nullable(false)`. All other data types are left with implicit nullability ([`Nullability.DEFAULT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Nullability.html#DEFAULT)), which is how a data type behaves if its nullability was never specified.

If you prefer the generated meta model to state nullability explicitly on all data types, e.g. because you export DDL from it using [`Meta.ddl()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Meta.html#ddl()) or compare it to other meta data, where `Nullability.DEFAULT` and `Nullability.NULL` are not the same thing, you can turn on the following flag (default: `false`):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <explicitNullability>true</explicitNullability>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withExplicitNullability(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      isExplicitNullability = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      explicitNullability = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

With the flag turned on, nullable columns are generated with an explicit `.nullable(true)` call:

```java
// Without <explicitNullability/> (the default)
public final TableField<BookRecord, String> TITLE = createField(DSL.name("TITLE"), SQLDataType.VARCHAR(400), this, "");

// With <explicitNullability>true</explicitNullability>
public final TableField<BookRecord, String> TITLE = createField(DSL.name("TITLE"), SQLDataType.VARCHAR(400).nullable(true), this, "");
```

Columns that reference a `NOT NULL` domain type do not receive an explicit `.nullable(true)` call, even if the database reports the column itself as nullable (as e.g. PostgreSQL does), in order not to override the domain's own nullability.

<a id="codegen-generate-extended-types"></a>
##### 5.2.6.5. Extended types

In addition to all the data types specified by the JDBC specification such as `SMALLINT`, `INTEGER`, `BIGINT`, `VARCHAR`, and many more, jOOQ includes support for additional standard SQL data types, which JDBC ignores.

These data types are very convenient when they work out of the box, although you may prefer to roll your own, e.g. using [converters](#codegen-database-forced-types-converter) or [bindings](#codegen-database-forced-types-binding).

Specifically, in the case of [spatial](#data-type-geometry) types, which are available to the commercial editions only, you may want to opt out of jOOQ's code generation support when you're using the jOOQ Open Source Edition.

Support for these four data types can be configured in code generation:

- [interval types](#data-type-interval) (i.e. [`org.jooq.types.Interval`](https://www.jooq.org/javadoc/3.22.x/org/jooq/types/Interval.html) and subtypes)
- [json types](#data-type-json) (i.e. [`org.jooq.JSON`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSON.html) and [`org.jooq.JSONB`](https://www.jooq.org/javadoc/3.22.x/org/jooq/JSONB.html))
- [spatial types](#data-type-geometry) (i.e. [`org.jooq.Spatial`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Spatial.html) and subtypes)
- [xml types](#data-type-xml) (i.e. [`org.jooq.XML`](https://www.jooq.org/javadoc/3.22.x/org/jooq/XML.html))

By default, all of the above data types are supported, and support is enabled. To disable support, use:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <intervalTypes>false</intervalTypes>
      <jsonTypes>false</jsonTypes>
      <spatialTypes>false</spatialTypes>
      <xmlTypes>false</xmlTypes>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withIntervalTypes(false)
      .withJsonTypes(false)
      .withSpatialTypes(false)
      .withXmlTypes(false)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      isIntervalTypes = false
      isJsonTypes = false
      isSpatialTypes = false
      isXmlTypes = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      intervalTypes = false
      jsonTypes = false
      spatialTypes = false
      xmlTypes = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-fluent-setters"></a>
##### 5.2.6.6. Fluent setters

By default, jOOQ generated artefacts follow JavaBeans conventions, where setters return `void`. If that is not a hard requirement, fluent setters can be generated where the setter returns the record/interface/pojo itself. To activate this behaviour, use:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <fluentSetters>true</fluentSetters>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withFluentSetters(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      isFluentSetters = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      fluentSetters = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-fully-qualified-types"></a>
##### 5.2.6.7. Fully Qualified Types

By default, the jOOQ code generator references all types as unqualified types, generating the necessary import statement at the beginning of generated classes.

In rare cases, this can cause problems when two types conflict with each other, e.g. when there is both a `TABLE` and a `TABLE_RECORD` table (generating a `TableRecord` [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) type for `TABLE` as well as a `TableRecord` [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) type for `TABLE_RECORD`). In this case, users can specify a regular expression that matches all objects whose corresponding generated artefacts should never be imported, but always be fully qualified.

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <fullyQualifiedTypes>.*\.MY_TABLE</fullyQualifiedTypes>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withFullyQualifiedTypes(".*\\.MY_TABLE")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      fullyQualifiedTypes = ".*\\.MY_TABLE"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      fullyQualifiedTypes = ".*\\.MY_TABLE"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

<a id="codegen-generate-globals"></a>
##### 5.2.6.8. Global Artefacts

For convenience, jOOQ generates a set of [global artefacts](#codegen-globals), which group static constants of the same type in a well-known class. The following set of flags allows for turning off the generation of these artefacts, individually:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- This overrides all the other individual flags -->
      <globalObjectReferences>true</globalObjectReferences>

      <!-- Individual flags for each object type -->
      <globalCatalogReferences>true</globalCatalogReferences>
      <globalSchemaReferences>true</globalSchemaReferences>
      <globalTableReferences>true</globalTableReferences>
      <globalSequenceReferences>true</globalSequenceReferences>
      <globalSynonymReferences>true</globalSynonymReferences>
      <globalDomainReferences>true</globalDomainReferences>
      <globalUDTReferences>true</globalUDTReferences>
      <globalRoutineReferences>true</globalRoutineReferences>
      <globalQueueReferences>true</globalQueueReferences>
      <globalLinkReferences>true</globalLinkReferences>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // This overrides all the other individual flags
      .withGlobalObjectReferences(true)

      // Individual flags for each object type
      .withGlobalCatalogReferences(true)
      .withGlobalSchemaReferences(true)
      .withGlobalTableReferences(true)
      .withGlobalSequenceReferences(true)
      .withGlobalSynonymReferences(true)
      .withGlobalDomainReferences(true)
      .withGlobalUDTReferences(true)
      .withGlobalRoutineReferences(true)
      .withGlobalQueueReferences(true)
      .withGlobalLinkReferences(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // This overrides all the other individual flags
      isGlobalObjectReferences = true

      // Individual flags for each object type
      isGlobalCatalogReferences = true
      isGlobalSchemaReferences = true
      isGlobalTableReferences = true
      isGlobalSequenceReferences = true
      isGlobalSynonymReferences = true
      isGlobalDomainReferences = true
      isGlobalUDTReferences = true
      isGlobalRoutineReferences = true
      isGlobalQueueReferences = true
      isGlobalLinkReferences = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // This overrides all the other individual flags
      globalObjectReferences = true

      // Individual flags for each object type
      globalCatalogReferences = true
      globalSchemaReferences = true
      globalTableReferences = true
      globalSequenceReferences = true
      globalSynonymReferences = true
      globalDomainReferences = true
      globalUDTReferences = true
      globalRoutineReferences = true
      globalQueueReferences = true
      globalLinkReferences = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-global-object-names"></a>
##### 5.2.6.9. Global object names

While jOOQ's default code generation output contains all the interesting bits for constructing queries based on type safe meta data, its `String` constants for identifiers and names are not accessible to the compiler, and thus to annotation processing.

If your custom code wishes to use annotations referencing table names, column names, etc. as follows:

```java
@MyAnnotation(MY_TABLE_NAME)
class MyClass {
    @MyAnnotation(MY_COLUMN_NAME)
    String someMember;
}
```

... then you can turn on the generation of these global names with the following configuration:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <globalObjectNames>true</globalObjectNames>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withGlobalObjectNames(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      isGlobalObjectNames = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      globalObjectNames = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-implicit-join-paths"></a>
##### 5.2.6.10. Implicit JOIN paths

[Implicit JOINs](#implicit-join) are one of jOOQ's most powerful synthetic SQL features, which depends entirely on code generation. The code generator produces links between tables that follow:

- `to-one` relationships (i.e. from child table to parent table)
- `to-many` relationships (i.e. from parent table to child table)
- `many-to-many` relationships (i.e. from parent table 1 to relationship table to parent table 2)

This way, it is possible to greatly simplify your queries:

```java
// Get all books, their authors, and their respective language
create.select(
          BOOK.author().FIRST_NAME,
          BOOK.author().LAST_NAME,
          BOOK.TITLE,
          BOOK.language().CD.as("language"))
      .from(BOOK)
      .fetch();
```

The feature has a few feature toggles in the code generator, including:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Allowing to turn off the feature for to-one join paths (including many-to-many).
           The default is true. -->
      <implicitJoinPathsToOne>true</implicitJoinPathsToOne>

      <!-- Allowing to turn off the feature for to-many join paths (including many-to-many).
           The default is true. -->
      <implicitJoinPathsToMany>true</implicitJoinPathsToMany>

      <!-- Allowing to turn off the feature for many-to-many join paths.
           The default is true. -->
      <implicitJoinPathsManyToMany>true</implicitJoinPathsManyToMany>

      <!-- Whether implicit join path constructors should also be generated if there
           isn't any outgoing or incoming foreign key relationship.
           The default is false. -->
      <implicitJoinPathUnusedConstructors>false</implicitJoinPathUnusedConstructors>

      <!-- Influencing how the DefaultGeneratorStrategy generates identifiers.
           The default is true.

           When a child table has only one FK towards a parent table, then that path is "unambiguous."
           In that case, the DefaultGeneratorStrategy uses the parent table name instead of the FK name. -->
      <implicitJoinPathsUseTableNameForUnambiguousFKs>true</implicitJoinPathsUseTableNameForUnambiguousFKs>

      <!-- Tell the KotlinGenerator to generate properties in addition to methods for these paths.
           The default is true. -->
      <implicitJoinPathsAsKotlinProperties>true</implicitJoinPathsAsKotlinProperties>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Allowing to turn off the feature for to-one join paths (including many-to-many).
      // The default is true.
      .withImplicitJoinPathsToOne(true)

      // Allowing to turn off the feature for to-many join paths (including many-to-many).
      // The default is true.
      .withImplicitJoinPathsToMany(true)

      // Allowing to turn off the feature for many-to-many join paths.
      // The default is true.
      .withImplicitJoinPathsManyToMany(true)

      // Whether implicit join path constructors should also be generated if there
      // isn't any outgoing or incoming foreign key relationship.
      // The default is false.
      .withImplicitJoinPathUnusedConstructors(false)

      // Influencing how the DefaultGeneratorStrategy generates identifiers.
      // The default is true.
      // 
      // When a child table has only one FK towards a parent table, then that path is "unambiguous."
      // In that case, the DefaultGeneratorStrategy uses the parent table name instead of the FK name.
      .withImplicitJoinPathsUseTableNameForUnambiguousFKs(true)

      // Tell the KotlinGenerator to generate properties in addition to methods for these paths.
      // The default is true.
      .withImplicitJoinPathsAsKotlinProperties(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Allowing to turn off the feature for to-one join paths (including many-to-many).
      // The default is true.
      isImplicitJoinPathsToOne = true

      // Allowing to turn off the feature for to-many join paths (including many-to-many).
      // The default is true.
      isImplicitJoinPathsToMany = true

      // Allowing to turn off the feature for many-to-many join paths.
      // The default is true.
      isImplicitJoinPathsManyToMany = true

      // Whether implicit join path constructors should also be generated if there
      // isn't any outgoing or incoming foreign key relationship.
      // The default is false.
      isImplicitJoinPathUnusedConstructors = false

      // Influencing how the DefaultGeneratorStrategy generates identifiers.
      // The default is true.
      // 
      // When a child table has only one FK towards a parent table, then that path is "unambiguous."
      // In that case, the DefaultGeneratorStrategy uses the parent table name instead of the FK name.
      isImplicitJoinPathsUseTableNameForUnambiguousFKs = true

      // Tell the KotlinGenerator to generate properties in addition to methods for these paths.
      // The default is true.
      isImplicitJoinPathsAsKotlinProperties = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Allowing to turn off the feature for to-one join paths (including many-to-many).
      // The default is true.
      implicitJoinPathsToOne = true

      // Allowing to turn off the feature for to-many join paths (including many-to-many).
      // The default is true.
      implicitJoinPathsToMany = true

      // Allowing to turn off the feature for many-to-many join paths.
      // The default is true.
      implicitJoinPathsManyToMany = true

      // Whether implicit join path constructors should also be generated if there
      // isn't any outgoing or incoming foreign key relationship.
      // The default is false.
      implicitJoinPathUnusedConstructors = false

      // Influencing how the DefaultGeneratorStrategy generates identifiers.
      // The default is true.
      // 
      // When a child table has only one FK towards a parent table, then that path is "unambiguous."
      // In that case, the DefaultGeneratorStrategy uses the parent table name instead of the FK name.
      implicitJoinPathsUseTableNameForUnambiguousFKs = true

      // Tell the KotlinGenerator to generate properties in addition to methods for these paths.
      // The default is true.
      implicitJoinPathsAsKotlinProperties = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-java-time-types"></a>
##### 5.2.6.11. Java Time Types

With jOOQ 3.9, support for JSR-310 `java.time` types has been added to the jOOQ API and to the code generator. Users of Java 8 can now specify that the jOOQ code generator should prefer JSR 310 types over their equivalent JDBC types. This includes:

- [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html) instead of [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html)
- [`java.time.LocalTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalTime.html) instead of [`java.sql.Time`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Time.html)
- [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html) instead of [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html)

Semantically, the above types are exactly equivalent, although the new types do away with the many flaws of the JDBC types. If there is no JDBC type for an equivalent JSR 310 type, then the JSR 310 type is generated by default. This includes

- [`java.time.OffsetTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetTime.html) (for SQL `TIME WITH TIME ZONE`)
- [`java.time.OffsetDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/OffsetDateTime.html) (for SQL `TIMESTAMP WITH TIME ZONE`)

To get more fine-grained control of the above, you may wish to consider applying [data type rewriting](#codegen-database-forced-types-rewrite).

In order to activate the generation of these types, use:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <javaTimeTypes>true</javaTimeTypes>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withJavaTimeTypes(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      isJavaTimeTypes = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      javaTimeTypes = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-serial-version-uid"></a>
##### 5.2.6.12. Serial Version UID

All jOOQ `QueryPart` types, including the generated ones, are [are serializable](#serializability). It is thus a good practice to generate a `serialVersionUID` value in all generated classes, for example:

```java
private static final long serialVersionUID = -2074134614;
```

By default, this value is `1L` to prevent compilation warnings and to minimise noisy diffs should you choose to [check in generated sources to version control](#codegen-version-control).

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Possible values for generatedSerialVersionUID
         - CONSTANT (default): Always generate 1L
         - OFF               : Don't generate a serialVersionUID
         - HASH              : Calculate a unique-ish value based on the hash code of the content -->
      <generatedSerialVersionUID>CONSTANT</generatedSerialVersionUID>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Possible values for generatedSerialVersionUID
      // - CONSTANT (default): Always generate 1L
      // - OFF               : Don't generate a serialVersionUID
      // - HASH              : Calculate a unique-ish value based on the hash code of the content
      .withGeneratedSerialVersionUID(GeneratedSerialVersionUID.CONSTANT)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Possible values for generatedSerialVersionUID
      // - CONSTANT (default): Always generate 1L
      // - OFF               : Don't generate a serialVersionUID
      // - HASH              : Calculate a unique-ish value based on the hash code of the content
      generatedSerialVersionUID = GeneratedSerialVersionUID.CONSTANT
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Possible values for generatedSerialVersionUID
      // - CONSTANT (default): Always generate 1L
      // - OFF               : Don't generate a serialVersionUID
      // - HASH              : Calculate a unique-ish value based on the hash code of the content
      generatedSerialVersionUID = "CONSTANT"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-sources"></a>
##### 5.2.6.13. Sources

With jOOQ 3.13, source code for views is generated by the code generator if available. This feature can be turned off using:

- `sources`: The generation of all types of source code can be turned off globally
- `sourcesOnViews`: The generation of source code on views can be turned off

The flags governing the generation of these annotations are:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <sources>true</sources>
      <sourcesOnViews>true</sourcesOnViews>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withSources(true)
      .withSourcesOnViews(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      isSources = true
      isSourcesOnViews = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      sources = true
      sourcesOnViews = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-textblocks"></a>
##### 5.2.6.14. Text blocks

By default, jOOQ's code generator produces Java 15 text blocks for generated source code (e.g. views, check constraints, etc.) if your Java version is up to date. In some cases, it may be desirable to turn that off:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Options include:
           - DETECT_FROM_JDK (default, generate text blocks if Java version supports them)
           - ON
           - OFF
        -->
      <textBlocks>OFF</textBlocks>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Options include:
      // - DETECT_FROM_JDK (default, generate text blocks if Java version supports them)
      // - ON
      // - OFF
      .withTextBlocks(GeneratedTextBlocks.OFF)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Options include:
      // - DETECT_FROM_JDK (default, generate text blocks if Java version supports them)
      // - ON
      // - OFF
      textBlocks = GeneratedTextBlocks.OFF
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Options include:
      // - DETECT_FROM_JDK (default, generate text blocks if Java version supports them)
      // - ON
      // - OFF
      textBlocks = "OFF"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-visibility-modifier"></a>
##### 5.2.6.15. Visibility Modifier (global)

By default, most generated code that is intended for use by users is generated using the explicit (Java) or implicit (Kotlin, Scala) `public` modifier.

In Kotlin there are valid reasons to deviate from this default, including:

- `-Xexplicit-api=strict` is enabled, and it is a compilation error to omit the otherwise optional visibility modifier
- The generated code should be generated as `internal`, not `public`

In the above cases, a configuration flag can help:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Possible values for visibilityModifier
         - DEFAULT  : The default per language (Java: public, Kotlin, Scala: implicit public)
         - NONE     : Do not generate visibility modifiers
         - PUBLIC   : Generate explicit public modifiers (Java, Kotlin)
         - INTERNAL : Generate explicit internal modifiers (Kotlin) -->
      <visibilityModifier>INTERNAL</visibilityModifier>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Possible values for visibilityModifier
      // - DEFAULT  : The default per language (Java: public, Kotlin, Scala: implicit public)
      // - NONE     : Do not generate visibility modifiers
      // - PUBLIC   : Generate explicit public modifiers (Java, Kotlin)
      // - INTERNAL : Generate explicit internal modifiers (Kotlin)
      .withVisibilityModifier(VisibilityModifier.INTERNAL)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Possible values for visibilityModifier
      // - DEFAULT  : The default per language (Java: public, Kotlin, Scala: implicit public)
      // - NONE     : Do not generate visibility modifiers
      // - PUBLIC   : Generate explicit public modifiers (Java, Kotlin)
      // - INTERNAL : Generate explicit internal modifiers (Kotlin)
      visibilityModifier = VisibilityModifier.INTERNAL
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Possible values for visibilityModifier
      // - DEFAULT  : The default per language (Java: public, Kotlin, Scala: implicit public)
      // - NONE     : Do not generate visibility modifiers
      // - PUBLIC   : Generate explicit public modifiers (Java, Kotlin)
      // - INTERNAL : Generate explicit internal modifiers (Kotlin)
      visibilityModifier = "INTERNAL"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Not all values make sense for all languages.

See also [visibility modifiers per forced types](#codegen-database-forced-types-visibility) for further options.

<a id="codegen-whitespace"></a>
##### 5.2.6.16. Whitespace (newlines and indentation)

By default, jOOQ's code generator produces unix newline characters (\n) and 4 space indentation (Java) or 2 space indentation (Scala). This can be overridden by using the below configuration flags. Depending on how you're loading the configuration, whitespace characters may get lost, which is why you may need to escape the backslash \ to \\. Supported escape sequences include:

- Indentation: \t (tab) and \s (whitespace)
- Newline: \r (carriage return) and \n (newline)

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      
      <indentation>\s\t</indentation>
      <newline>\r\n</newline>

      <!-- The number of characters after which Javadoc is line-wrapped. 0 to turn off line wrapping. -->
      <printMarginForBlockComment>80</printMarginForBlockComment>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()
      .withIndentation("\\s\\t")
      .withNewline("\\r\\n")

      // The number of characters after which Javadoc is line-wrapped. 0 to turn off line wrapping.
      .withPrintMarginForBlockComment(80)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {
      indentation = "\\s\\t"
      newline = "\\r\\n"

      // The number of characters after which Javadoc is line-wrapped. 0 to turn off line wrapping.
      printMarginForBlockComment = 80
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {
      indentation = "\\s\\t"
      newline = "\\r\\n"

      // The number of characters after which Javadoc is line-wrapped. 0 to turn off line wrapping.
      printMarginForBlockComment = 80
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-generate-zero-scale-decimals"></a>
##### 5.2.6.17. Zero Scale Decimal Types

A zero-scale decimal, such as `DECIMAL(10)` or `NUMBER(10, 0)` is really an integer type with a decimal precision rather than a binary / bitwise precision. Some databases (e.g. Oracle) do not support actual integer types at all, only decimal types. Historically, jOOQ generates the most appropriate integer wrapper type instead of `BigDecimal` or `BigInteger`:

- `NUMBER(2, 0)` and less: [`java.lang.Byte`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Byte.html)
- `NUMBER(4, 0)` and less: [`java.lang.Short`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Short.html)
- `NUMBER(9, 0)` and less: [`java.lang.Integer`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Integer.html)
- `NUMBER(18, 0)` and less: [`java.lang.Long`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Long.html)

If this is not a desireable default, it can be deactivated either explicitly on a per-column basis using [forced types](#codegen-database-forced-types), or globally using the following flag:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forceIntegerTypesOnZeroScaleDecimals>true</forceIntegerTypesOnZeroScaleDecimals>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForceIntegerTypesOnZeroScaleDecimals(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      isForceIntegerTypesOnZeroScaleDecimals = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forceIntegerTypesOnZeroScaleDecimals = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-config-target"></a>
#### 5.2.7. Output target configuration

In the previous sections, we've seen the `<target/>` element which configures the location of your generated output. The following XML snippet illustrates some additional flags that can be specified in that section:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <target>
      <packageName>org.jooq.your.packagename</packageName>
      <directory>/path/to/your/dir</directory>
      <encoding>UTF-8</encoding>
      <locale>de</locale>
      <clean>true</clean>
    </target>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withTarget(new Target()
      .withPackageName("org.jooq.your.packagename")
      .withDirectory("/path/to/your/dir")
      .withEncoding("UTF-8")
      .withLocale("de")
      .withClean(true)
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    target {
      packageName = "org.jooq.your.packagename"
      directory = "/path/to/your/dir"
      encoding = "UTF-8"
      locale = "de"
      isClean = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    target {
      packageName = "org.jooq.your.packagename"
      directory = "/path/to/your/dir"
      encoding = "UTF-8"
      locale = "de"
      clean = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

- **packageName**: Specifies the root package name inside of which all generated code is located. This package is located inside of the `<directory/>`. The package name is part of the [generator strategy](#codegen-generatorstrategy) and can be modified by a custom implementation, if so desired.
- **directory**: Specifies the root directoy inside of which all generated code is located.
- **encoding**: The encoding that should be used for generated classes.
- **locale**: The locale that should be used for locale-specific operations, such as `String.toUpperCase()`, e.g. by the [default generator strategy](#codegen-generatorstrategy).
- **clean**: Whether the target package (`<packageName/>`) should be cleaned to contain only generated code after a generation run. Defaults to true.

<a id="codegen-object-types"></a>
### 5.3. Generated object types

RDBMS have a rich set of object types, each of which are represented by one or more specific jOOQ types, respectively. The following sections explain what types exist, and how each of them can be configured in jOOQ's code generator.

<a id="codegen-tables"></a>
#### 5.3.1. Generated tables

Every table and view in your database will generate a [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) implementation that looks like this:

```java
public class Book extends TableImpl<BookRecord> {

    // The singleton instance
    public static final Book BOOK = new Book();

    // Generated columns
    public final TableField<BookRecord, Integer> ID        = createField("ID",        INTEGER, this);
    public final TableField<BookRecord, Integer> AUTHOR_ID = createField("AUTHOR_ID", INTEGER, this);
    public final TableField<BookRecord, String>  TITLE     = createField("TITLE",     VARCHAR, this);

    // Covariant aliasing method, returning a table of the same type as BOOK
    @Override
    public Book as(java.lang.String alias) {
        return new Book(alias);
    }

    // [...]
}
```

##### Flags influencing generated tables

These flags from the [code generation configuration](#codegen-advanced) influence generated tables:

- **recordVersionFields**: Relevant methods from super classes are overridden to return the VERSION field
- **recordTimestampFields**: Relevant methods from super classes are overridden to return the TIMESTAMP field
- **syntheticPrimaryKeys**: This overrides existing primary key information to allow for "custom" primary key column sets
- **overridePrimaryKeys**: This overrides existing primary key information to allow for unique key to primary key promotion
- **dateAsTimestamp**: This influences all relevant columns
- **unsignedTypes**: This influences all relevant columns
- **relations**: Relevant methods from super classes are overridden to provide primary key, unique key, foreign key and identity information
- **instanceFields**: This flag controls the "static" keyword on table columns, as well as aliasing convenience
- **records**: The generated record type is referenced from tables allowing for type-safe single-table record fetching
- **explicitNullability**: Nullable columns are generated with explicit nullability on their data types ([details here](#codegen-generate-explicit-nullability))

##### Flags controlling table generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Allows for turning on tables generation: default true -->
      <tables>true</tables>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Allows for turning on tables generation: default true
      .withTables(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Allows for turning on tables generation: default true
      isTables = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Allows for turning on tables generation: default true
      tables = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-records"></a>
#### 5.3.2. Generated records

Every table and view in your database will generate a [`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html) (or [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) if there's a primary key) implementation that looks like this:

```java
// JPA annotations can be generated, optionally
@Entity
@Table(name = "BOOK", schema = "TEST")
public class BookRecord extends UpdatableRecordImpl<BookRecord>

// An interface common to records and pojos can be generated, optionally
implements IBook {

    // Every column generates a setter and a getter
    @Override
    public void setId(Integer value) {
        setValue(BOOK.ID, value);
    }

    @Id
    @Column(name = "ID", unique = true, nullable = false, precision = 7)
    @Override
    public Integer getId() {
        return getValue(BOOK.ID);
    }

    // More setters and getters
    public void setAuthorId(Integer value) {...}
    public Integer getAuthorId() {...}

    // Convenience methods for foreign key methods
    public void setAuthorId(AuthorRecord value) {
        if (value == null) {
            setValue(BOOK.AUTHOR_ID, null);
        }
        else {
            setValue(BOOK.AUTHOR_ID, value.getValue(AUTHOR.ID));
        }
    }

    // Navigation methods
    public AuthorRecord fetchAuthor() {
        return create.selectFrom(AUTHOR).where(AUTHOR.ID.eq(getValue(BOOK.AUTHOR_ID))).fetchOne();
    }

    // [...]
}
```

##### TableRecord vs UpdatableRecord

If primary key information is available to the code generator, an [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) will be generated. If no such information is available, a [`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html) will be generated. Primary key information can be absent because:

- The table is a view, which does not expose the underlying primary keys
- The table does not have a primary key
- The code generator configuration has turned off primary keys usage information usage through one of various flags (see below)
- The primary key information is not available to the code generator

##### Flags controlling record generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Allows for turning on records generation: default true -->
      <records>true</records>

      <!-- Optionally, limit records generation to only tables matching this regular expression. -->
      <recordsIncludes>.*</recordsIncludes>

      <!-- Optionally, limit records generation to only tables not matching this regular expression.
           Excludes match before includes. -->
      <recordsExcludes>SYSTEM_TABLE_.*</recordsExcludes>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Allows for turning on records generation: default true
      .withRecords(true)

      // Optionally, limit records generation to only tables matching this regular expression.
      .withRecordsIncludes(".*")

      // Optionally, limit records generation to only tables not matching this regular expression.
      // Excludes match before includes.
      .withRecordsExcludes("SYSTEM_TABLE_.*")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Allows for turning on records generation: default true
      isRecords = true

      // Optionally, limit records generation to only tables matching this regular expression.
      recordsIncludes = ".*"

      // Optionally, limit records generation to only tables not matching this regular expression.
      // Excludes match before includes.
      recordsExcludes = "SYSTEM_TABLE_.*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Allows for turning on records generation: default true
      records = true

      // Optionally, limit records generation to only tables matching this regular expression.
      recordsIncludes = ".*"

      // Optionally, limit records generation to only tables not matching this regular expression.
      // Excludes match before includes.
      recordsExcludes = "SYSTEM_TABLE_.*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Allows for turning off records generation: default true -->
      <records>true</records>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Allows for turning off records generation: default true
      .withRecords(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Allows for turning off records generation: default true
      isRecords = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Allows for turning off records generation: default true
      records = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

The `recordsIncludes` and `recordsExcludes` regular expressions work just like the [global includes and excludes regular expressions](#codegen-database-includes-excludes)

##### Flags influencing generated records

Additional flags from the [code generation configuration](#codegen-advanced) influence generated records:

- `syntheticPrimaryKeys`: This overrides existing primary key information to allow for "custom" primary key column sets, possibly promoting a TableRecord to an UpdatableRecord
- `overridePrimaryKeys`: This overrides existing primary key information to allow for unique key to primary key promotion, possibly promoting a TableRecord to an UpdatableRecord
- `includePrimaryKeys`: This includes or excludes all primary key information in the generator's database meta data
- `dateAsTimestamp`: This influences all relevant getters and setters
- `unsignedTypes`: This influences all relevant getters and setters
- `relations`: This is needed as a prerequisite for navigation methods
- `daos`: Records are a pre-requisite for DAOs. If DAOs are generated, records are generated as well
- `interfaces`: If interfaces are generated, records will implement them
- `jpaAnnotations`: JPA annotations are used on generated records ([details here](#codegen-generate-annotations))
- `jpaVersion`: Version of JPA specification is to be used to generate version-specific annotations. If it is omitted, the latest version is used by default. ([details here](#codegen-generate-annotations))
- `recordsImplementingRecordN`: Whether generated records should implement [Record[N]](#record-n) types. Please note that this may impact compilation speeds! Starting from jOOQ 3.19, the default for this flag is `false`, for this reason.

<a id="codegen-pojos"></a>
#### 5.3.3. Generated POJOs

Every table and view in your database will generate a POJO implementation that looks like this:

```java
// JPA annotations can be generated, optionally
@Entity
@Table(name = "BOOK", schema = "TEST")
public class Book implements java.io.Serializable

// An interface common to records and pojos can be generated, optionally
, IBook {

    // JSR-303 annotations can be generated, optionally
    @NotNull
    private Integer id;

    @NotNull
    private Integer authorId;

    @NotNull
    @Size(max = 400)
    private String title;

    // Every column generates a getter and a setter
    @Id
    @Column(name = "ID", unique = true, nullable = false, precision = 7)
    @Override
    public Integer getId() {
        return this.id;
    }

    @Override
    public void setId(Integer id) {
        this.id = id;
    }

    // [...]
}
```

##### Flags controlling POJO generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Allows for turning on POJOs generation: default false -->
      <pojos>true</pojos>

      <!-- Optionally, limit POJOs generation to only tables matching this regular expression. -->
      <pojosIncludes>.*</pojosIncludes>

      <!-- Optionally, limit POJOs generation to only tables not matching this regular expression.
           Excludes match before includes. -->
      <pojosExcludes>SYSTEM_TABLE_.*</pojosExcludes>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Allows for turning on POJOs generation: default false
      .withPojos(true)

      // Optionally, limit POJOs generation to only tables matching this regular expression.
      .withPojosIncludes(".*")

      // Optionally, limit POJOs generation to only tables not matching this regular expression.
      // Excludes match before includes.
      .withPojosExcludes("SYSTEM_TABLE_.*")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Allows for turning on POJOs generation: default false
      isPojos = true

      // Optionally, limit POJOs generation to only tables matching this regular expression.
      pojosIncludes = ".*"

      // Optionally, limit POJOs generation to only tables not matching this regular expression.
      // Excludes match before includes.
      pojosExcludes = "SYSTEM_TABLE_.*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Allows for turning on POJOs generation: default false
      pojos = true

      // Optionally, limit POJOs generation to only tables matching this regular expression.
      pojosIncludes = ".*"

      // Optionally, limit POJOs generation to only tables not matching this regular expression.
      // Excludes match before includes.
      pojosExcludes = "SYSTEM_TABLE_.*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
      <!-- Allows for turning on POJOs generation: default false -->
      <pojos>true</pojos>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Allows for turning on POJOs generation: default false
      .withPojos(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Allows for turning on POJOs generation: default false
      isPojos = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Allows for turning on POJOs generation: default false
      pojos = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### Flags influencing generated POJOs

Additional flags from the [code generation configuration](#codegen-advanced) influence generated POJOs:

- `daos`: POJOs are a pre-requisite for DAOs. If DAOs are generated, POJOs are generated as well
- `dateAsTimestamp`: This influences all relevant getters and setters
- `immutablePojos`: Immutable POJOs have final members and no setters. All members must be passed to the constructor
- `interfaces`: If interfaces are generated, POJOs will implement them
- `jpaAnnotations`: JPA annotations are used on generated records ([details here](#codegen-generate-annotations))
- `jpaVersion`: Version of JPA specification is to be used to generate version-specific annotations. If it is omitted, the latest version is used by default. ([details here](#codegen-generate-annotations))
- `pojosAsJavaRecordClasses`: If you're using the `JavaGenerator`, this will generate POJOs as (immutable) Java 16 record types
- `pojosAsScalaCaseClasses`: If you're using the `ScalaGenerator`(or `Scala3Generator`), this will generate POJOs as (mutable or immutable) Scala case classes
- `pojosAsKotlinDataClasses`: If you're using the `KotlinGenerator`, this will generate POJOs as (mutable or immutable) kotlin data classes
- `pojosToString`: Whether POJOs should have a generated `toString()` implementation.
- `pojosEqualsAndHashCode`: Whether POJOs should have generated `equals()` and `hashCode()` implementations. These implementations are purely value-based, just like with records, i.e. two POJOs are equal if all their attributes are equal.
- `pojosEqualsAndHashCodeIncludePrimaryKeyOnly`: Whether the generated `equals()` and `hashCode()` implementations should consider primary key columns *only* (beware that the implementation is still purely value-based, i.e. two uninitialised `null` primary key values are then considered equal).
- `pojosEqualsAndHashCodeColumnIncludeExpression`: A regular expression matching qualified or unqualified column names that should be included in generated `equals()` and `hashCode()` implementations.
- `pojosEqualsAndHashCodeColumnExcludeExpression`: A regular expression matching qualified or unqualified column names that should be excluded from generated `equals()` and `hashCode()` implementations.
- `pojosCopyConstructor`: Whether POJOs should have a copy constructor
- `unsignedTypes`: This influences all relevant getters and setters
- `validationAnnotations`: JSR-303 validation annotations are used on generated records ([details here](#codegen-generate-annotations))

<a id="codegen-interfaces"></a>
#### 5.3.4. Generated Interfaces

Every table, view, udt in your database will generate an interface that looks like this:

```java
public interface IBook extends java.io.Serializable {

    // Every column generates a getter and a setter
    public void setId(Integer value);
    public Integer getId();

    // [...]
}
```

The purpose of these interfaces is to be able to abstract over jOOQ generated records and POJOs.

##### Flags controlling interface generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Turn on the generation of interfaces -->
      <interfaces>true</interfaces>

      <!-- Generated interfaces will not expose mutable components of their implementations, such as setters -->
      <immutableInterfaces>true</immutableInterfaces>

      <!-- Whether generated interfaces are Serializable -->
      <serializableInterfaces>true</serializableInterfaces>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Turn on the generation of interfaces
      .withInterfaces(true)

      // Generated interfaces will not expose mutable components of their implementations, such as setters
      .withImmutableInterfaces(true)

      // Whether generated interfaces are Serializable
      .withSerializableInterfaces(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Turn on the generation of interfaces
      isInterfaces = true

      // Generated interfaces will not expose mutable components of their implementations, such as setters
      isImmutableInterfaces = true

      // Whether generated interfaces are Serializable
      isSerializableInterfaces = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Turn on the generation of interfaces
      interfaces = true

      // Generated interfaces will not expose mutable components of their implementations, such as setters
      immutableInterfaces = true

      // Whether generated interfaces are Serializable
      serializableInterfaces = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> Note, there are numerous problems related to generated interfaces as can be seen in [#10509](https://github.com/jOOQ/jOOQ/issues/10509).

<a id="codegen-daos"></a>
#### 5.3.5. Generated DAOs

Every table and view in your database will generate a [`org.jooq.DAO`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DAO.html) implementation that looks like this:

```java
public class BookDao extends DAOImpl<BookRecord, Book, Integer> {

    // Generated constructors
    public BookDao() {
        super(BOOK, Book.class);
    }

    public BookDao(Configuration configuration) {
        super(BOOK, Book.class, configuration);
    }

    // Every column generates at least one fetch method
    public List<Book> fetchById(Integer... values) {
        return fetch(BOOK.ID, values);
    }

    public Book fetchOneById(Integer value) {
        return fetchOne(BOOK.ID, value);
    }

    public List<Book> fetchByAuthorId(Integer... values) {
        return fetch(BOOK.AUTHOR_ID, values);
    }

    // [...]
}
```

##### Flags controlling DAO generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Generate the DAO classes -->
      <daos>true</daos>

      <!-- Annotate DAOs (and other types) with spring annotations, such as @Repository and @Autowired
           for auto-wiring the Configuration instance, e.g. from Spring Boot's jOOQ starter -->
      <springAnnotations>true</springAnnotations>

      <!-- Generate Spring-specific DAOs containing @Transactional annotations -->
      <springDao>true</springDao>

      <!-- Optionally, limit DAOs generation to only tables matching this regular expression. -->
      <pojosIncludes>.*</pojosIncludes>

      <!-- Optionally, limit DAOs generation to only tables not matching this regular expression.
           Excludes match before includes. -->
      <pojosExcludes>SYSTEM_TABLE_.*</pojosExcludes>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Generate the DAO classes
      .withDaos(true)

      // Annotate DAOs (and other types) with spring annotations, such as @Repository and @Autowired
      // for auto-wiring the Configuration instance, e.g. from Spring Boot's jOOQ starter
      .withSpringAnnotations(true)

      // Generate Spring-specific DAOs containing @Transactional annotations
      .withSpringDao(true)

      // Optionally, limit DAOs generation to only tables matching this regular expression.
      .withPojosIncludes(".*")

      // Optionally, limit DAOs generation to only tables not matching this regular expression.
      // Excludes match before includes.
      .withPojosExcludes("SYSTEM_TABLE_.*")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Generate the DAO classes
      isDaos = true

      // Annotate DAOs (and other types) with spring annotations, such as @Repository and @Autowired
      // for auto-wiring the Configuration instance, e.g. from Spring Boot's jOOQ starter
      isSpringAnnotations = true

      // Generate Spring-specific DAOs containing @Transactional annotations
      isSpringDao = true

      // Optionally, limit DAOs generation to only tables matching this regular expression.
      pojosIncludes = ".*"

      // Optionally, limit DAOs generation to only tables not matching this regular expression.
      // Excludes match before includes.
      pojosExcludes = "SYSTEM_TABLE_.*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Generate the DAO classes
      daos = true

      // Annotate DAOs (and other types) with spring annotations, such as @Repository and @Autowired
      // for auto-wiring the Configuration instance, e.g. from Spring Boot's jOOQ starter
      springAnnotations = true

      // Generate Spring-specific DAOs containing @Transactional annotations
      springDao = true

      // Optionally, limit DAOs generation to only tables matching this regular expression.
      pojosIncludes = ".*"

      // Optionally, limit DAOs generation to only tables not matching this regular expression.
      // Excludes match before includes.
      pojosExcludes = "SYSTEM_TABLE_.*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [generation annotations](#codegen-generate-annotations) for more information about the annotation specific flags, above.

<a id="codegen-sequences"></a>
#### 5.3.6. Generated sequences

Every sequence in your database will generate a [`org.jooq.Sequence`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Sequence.html) implementation that looks like this:

```java
public final class Sequences {

    // Every sequence generates a member
    public static final Sequence<Integer> S_AUTHOR_ID = new SequenceImpl<Integer>("S_AUTHOR_ID", TEST, INTEGER);
}
```

##### Flags controlling sequence generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Generate the Sequences class -->
      <sequences>true</sequences>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Generate the Sequences class
      .withSequences(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Generate the Sequences class
      isSequences = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Generate the Sequences class
      sequences = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-synonyms"></a>
#### 5.3.7. Generated synonyms

Every synonym in your database will generate a [`org.jooq.Synonym`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Synonym.html) implementation that looks like this:

```java
public final class Synonyms {

    // Every synonym generates a member
    public static final Synonym S_BOOK = Internal.createSynonym(Public.PUBLIC, DSL.name("S_BOOK"), Book.BOOK, DSL.comment(""));
}
```

##### Flags controlling synonym generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Generate the Synonyms class -->
      <synonyms>true</synonyms>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Generate the Synonyms class
      .withSynonyms(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Generate the Synonyms class
      isSynonyms = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Generate the Synonyms class
      synonyms = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-procedures"></a>
#### 5.3.8. Generated procedures

Every procedure or function (routine) in your database will generate a [`org.jooq.Routine`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Routine.html) implementation that looks like this:

```java
public class AuthorExists extends AbstractRoutine<java.lang.Void> {

    // All IN, IN OUT, OUT parameters and function return values generate a static member
    public static final Parameter<String>     AUTHOR_NAME = createParameter("AUTHOR_NAME", VARCHAR);
    public static final Parameter<BigDecimal> RESULT      = createParameter("RESULT",      NUMERIC);

    // A constructor for a new "empty" procedure call
    public AuthorExists() {
        super("AUTHOR_EXISTS", TEST);

        addInParameter(AUTHOR_NAME);
        addOutParameter(RESULT);
    }

    // Every IN and IN OUT parameter generates a setter
    public void setAuthorName(String value) {
        setValue(AUTHOR_NAME, value);
    }

    // Every IN OUT, OUT and RETURN_VALUE generates a getter
    public BigDecimal getResult() {
        return getValue(RESULT);
    }

    // [...]
}
```

##### Package and member procedures or functions

Procedures or functions contained in packages or UDTs are generated in a sub-package that corresponds to the package or UDT name.

##### Flags controlling routine generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Generate the Routines class and a class for each individual routine -->
      <routines>true</routines>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Generate the Routines class and a class for each individual routine
      .withRoutines(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Generate the Routines class and a class for each individual routine
      isRoutines = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Generate the Routines class and a class for each individual routine
      routines = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-domains"></a>
#### 5.3.9. Generated domains

Every DOMAIN type in your database will generate an [`org.jooq.Domain`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Domain.html) reference in a single `Domains` class that looks like this:

```java
public class Domains {

    /**
     * The domain <code>PUBLIC.EMAIL</code>.
     */
    public static final Domain<String> EMAIL = Internal.createDomain(
          schema()
        , DSL.name("EMAIL")
        , org.jooq.impl.CLOB.nullable(false)
        , Internal.createCheck(null, null, "(\"VALUE\" LIKE '%@%')")
    );

    /**
     * The domain <code>PUBLIC.YEAR</code>.
     */
    public static final Domain<Integer> YEAR = Internal.createDomain(
          schema()
        , DSL.name("YEAR")
        , org.jooq.impl.INTEGER.nullable(false)
        , Internal.createCheck(null, null, "((\"VALUE\" >= 1900) AND (\"VALUE\" <= 2050))")
    );
}
```

These domain specifications are referenced from all columns that use the respective domain type.

<a id="codegen-udts"></a>
#### 5.3.10. Generated UDTs

Every UDT in your database will generate a [`org.jooq.UDT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDT.html) implementation that looks like this:

```java
public class AddressType extends UDTImpl<AddressTypeRecord> {

    // The singleton UDT instance
    public static final UAddressType U_ADDRESS_TYPE = new UAddressType();

    // Every UDT attribute generates a static member
    public static final UDTField<AddressTypeRecord, String> ZIP     =
      createField("ZIP",     VARCHAR, U_ADDRESS_TYPE);
    public static final UDTField<AddressTypeRecord, String> CITY    =
      createField("CITY",    VARCHAR, U_ADDRESS_TYPE);
    public static final UDTField<AddressTypeRecord, String> COUNTRY =
      createField("COUNTRY", VARCHAR, U_ADDRESS_TYPE);

    // [...]
}
```

Besides the [`org.jooq.UDT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDT.html) implementation, a [`org.jooq.UDTRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDTRecord.html) implementation is also generated

```java
public class AddressTypeRecord extends UDTRecordImpl<AddressTypeRecord> {

    // Every attribute generates a getter and a setter

    public void setZip(String value) {...}
    public String getZip() {...}
    public void setCity(String value) {...}
    public String getCity() {...}
    public void setCountry(String value) {...}
    public String getCountry() {...}

    // [...]
}
```

##### Flags controlling UDT generation

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Generate the UDTs class, records and UDT literals for each UDT -->
      <udts>true</udts>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Generate the UDTs class, records and UDT literals for each UDT
      .withUdts(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Generate the UDTs class, records and UDT literals for each UDT
      isUdts = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Generate the UDTs class, records and UDT literals for each UDT
      udts = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-triggers"></a>
#### 5.3.11. Generated triggers

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

Every trigger in your database will generate an [`org.jooq.Trigger`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Trigger.html) reference in a single `Triggers` class that looks like this:

```java
public class Triggers {

    /**
     * The trigger <code>PUBLIC.LAST_UPDATED</code>.
     */
    public static final Trigger LAST_UPDATED = Internal.createTrigger(
        Public.PUBLIC,
        Author.AUTHOR,
        Arrays.asList(),
        DSL.name("last_updated"),
        DSL.comment(""),
        TriggerTime.BEFORE,
        EnumSet.of(TriggerEvent.UPDATE),
        TriggerExecution.FOR_EACH_ROW,
        null,
        1,
        DSL.statement("EXECUTE FUNCTION last_updated()")
    );
}
```

These trigger specifications are referenced from all tables that use the respective trigger. Trigger meta data can be used for features like [INSERT .. RETURNING](#insert-returning), where some RDBMS require extra steps to fetch trigger generated values. If jOOQ knows there isn't a trigger on a table, then these steps can often be omitted.

<a id="codegen-globals"></a>
#### 5.3.12. Generated global artefacts

For increased convenience at the use-site, jOOQ generates "global" artefacts at the code generation root location, referencing tables, routines, sequences, etc. In detail, these global artefacts include the following:

- **Keys.java**: This file contains all of the required primary key, unique key, foreign key and identity references in the form of static members of type [`org.jooq.Key`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Key.html).
- **Routines.java**: This file contains all standalone routines (not in packages) in the form of static factory methods for [`org.jooq.Routine`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Routine.html) types.
- **Sequences.java**: This file contains all sequence objects in the form of static members of type [`org.jooq.Sequence`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Sequence.html).
- **Tables.java**: This file contains all table objects in the form of static member references to the actual singleton [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) object
- **UDTs.java**: This file contains all UDT objects in the form of static member references to the actual singleton [`org.jooq.UDT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDT.html) object

##### Referencing global artefacts

When referencing global artefacts from your client application, you would typically static import them as such:

```java
// Static imports for all global artefacts (if they exist)
import static com.example.generated.Keys.*;
import static com.example.generated.Routines.*;
import static com.example.generated.Sequences.*;
import static com.example.generated.Tables.*;

// You could then reference your artefacts as follows:
create.insertInto(MY_TABLE)
      .values(MY_SEQUENCE.nextval(), myFunction())

// as a more concise form of this:
create.insertInto(com.example.generated.Tables.MY_TABLE)
      .values(com.example.generated.Sequences.MY_SEQUENCE.nextval(), com.example.generated.Routines.myFunction())
```

##### Configuring these artefacts

The generation of these artefacts can be turned off. For details, see the [relevant section in the manual](#codegen-generate-globals).

<a id="codegen-object-naming"></a>
### 5.4. Class names, method names, identifiers

By default, generated class names, method names, identifiers, etc. follow Java's typical naming conventions.

Assuming a table like this:

```sql
CREATE TABLE account_transactions (
  id INTEGER NOT NULL,
  created_at TIMESTAMP NOT NULL,
  created_by VARCHAR(100) NOT NULL,
  ...
);
```

As a rule of thumb, the following defaults can be assumed for named objects:

- Class names follow `PascalCase` naming, i.e. the [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) class name is `AccountTransactions`
- Records have a `Record` suffix, i.e. the [`org.jooq.UpdatableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UpdatableRecord.html) class name is `AccountTransactionsRecord`
- Daos have a `Dao` suffix, i.e. the [`org.jooq.DAO`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DAO.html) class name is `AccountTransactionsDao`
- Identifiers follow `SNAKE_CASE` naming, i.e. the [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) instance name is `ACCOUNT_TRANSACTIONS`
- Path methods follow a `camleCase` naming, i.e. the [`org.jooq.Path`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Path.html) method name is `accountTransactions()` (e.g. on a child table)

If these defaults do not convene, or if a workaround needs to be applied for a limitation of the default naming, generator strategies allow for overriding these defaults.

<a id="codegen-generatorstrategy"></a>
#### 5.4.1. Custom generator strategies

##### Using custom generator strategies to override naming schemes

jOOQ allows you to override default implementations of the code generator or the generator strategy. Specifically, the latter can be very useful if you want to inject custom behaviour into jOOQ's code generator with respect to naming classes, members, methods, and other Java objects.

**XML (standalone and maven):**

```xml
<configuration>
  <generator>

    <!-- A programmatic naming strategy implementation, referened by class name. -->
    <strategy>
      <name>com.example.AsInDatabaseStrategy</name>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()

    // A programmatic naming strategy implementation, referened by class name.
    .withStrategy(new Strategy()
      .withName("com.example.AsInDatabaseStrategy")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {

    // A programmatic naming strategy implementation, referened by class name.
    strategy {
      name = "com.example.AsInDatabaseStrategy"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {

    // A programmatic naming strategy implementation, referened by class name.
    strategy {
      name = "com.example.AsInDatabaseStrategy"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Optionally, instead of referencing a previously compiled `GeneratorStrategy`, the strategy code (written in Java) can also be inlined into the configuration, in case of which it will be compiled ad-hoc (see [in-memory compilation](#codegen-in-memory-compilation) for more details):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>

    <!-- A programmatic naming strategy implementation, referened by class name. -->
    <strategy>
      <name>com.example.AsInDatabaseStrategy</name>
      <java>package com.example;

import org.jooq.codegen.DefaultGeneratorStrategy;

public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
    ...
}</java>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()

    // A programmatic naming strategy implementation, referened by class name.
    .withStrategy(new Strategy()
      .withName("com.example.AsInDatabaseStrategy")
      .withJava("""package com.example;

import org.jooq.codegen.DefaultGeneratorStrategy;

public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
    ...
}""")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {

    // A programmatic naming strategy implementation, referened by class name.
    strategy {
      name = "com.example.AsInDatabaseStrategy"
      java = """package com.example;

import org.jooq.codegen.DefaultGeneratorStrategy;

public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
    ...
}"""
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {

    // A programmatic naming strategy implementation, referened by class name.
    strategy {
      name = "com.example.AsInDatabaseStrategy"
      java = """package com.example;

import org.jooq.codegen.DefaultGeneratorStrategy;

public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
    ...
}"""
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> Make sure your custom generator strategy and its dependencies are available to the code generator as a [code generator dependency](#codegen-dependencies)

The following example shows how you can override the DefaultGeneratorStrategy to render table and column names the way they are defined in the database, rather than switching them to camel case:

```java
/**
 * It is recommended that you extend the DefaultGeneratorStrategy. Most of the
 * GeneratorStrategy API is already declared final. You only need to override any
 * of the following methods, for whatever generation behaviour you'd like to achieve.
 *
 * Also, the DefaultGeneratorStrategy takes care of disambiguating quite a few object
 * names in case of conflict. For example, MySQL indexes do not really have a name, so
 * a synthetic, non-ambiguous name is generated based on the table name. If you
 * override the default behaviour, you must ensure that this disambiguation still takes
 * place for generated code to be compilable.
 *
 * Beware that most methods also receive a "Mode" object, to tell you whether a
 * TableDefinition is being rendered as a Table, Record, POJO, etc. Depending on
 * that information, you can add a suffix only for TableRecords, but not for Tables,
 * for example.
 *
 * This example will name objects in Java as they are named in the database, without
 * applying any camelCase, PascalCase transformations, etc.
 */
public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {

    /**
     * Override this to specify what identifiers, such as Catalog, Schema, Table, 
     * TableField identifiers will look like.
     *
     * This example will just generate the identifier as defined in the database,
     * e.g. MY_TABLE or MY_TABLE.MY_FIELD.
     */
    @Override
    public String getJavaIdentifier(Definition definition) {
        // The DefaultGeneratorStrategy disambiguates some synthetic object names,
        // such as the MySQL PRIMARY key names, which do not really have a name
        // Uncomment the below code if you want to reuse that logic.
        // if (definition instanceof IndexDefinition)
        //     return super.getJavaIdentifier(definition);
        return definition.getOutputName();
    }

    /**
     * Override these to specify what a setter in Java should look like. Setters
     * are used in TableRecords, UDTRecords, and POJOs, depending on Mode.
     *
     * This example will name setters "set[NAME_IN_DATABASE]"
     */
    @Override
    public String getJavaSetterName(Definition definition, Mode mode) {
        return "set" + definition.getOutputName();
    }

    /**
     * Override these to specify what a getter in Java should look like. Getters
     * are used in TableRecords, UDTRecords, and POJOs, depending on Mode. 
     *
     * This example will name getters "set[NAME_IN_DATABASE]"
     */
    @Override
    public String getJavaGetterName(Definition definition, Mode mode) {
        return "get" + definition.getOutputName();
    }

    /**
     * Override this method to define what a Java method generated from a database
     * Definition should look like. This is used e.g. for convenience methods
     * when calling stored procedures and functions, or for path methods.
     *
     * This example shows how to set a prefix to a CamelCase version of your
     * procedure.
     */
    @Override
    public String getJavaMethodName(Definition definition, Mode mode) {
        if (definition instanceof RoutineDefinition)
            return "call" + org.jooq.tools.StringUtils.toCamelCase(definition.getOutputName());
        else
            return super.getJavaMethodName(definition, mode);
    }

    /**
     * Override this method to define how your Java classes and Java files should
     * be named.
     * 
     * This example applies no custom setting and uses CamelCase versions instead.
     */
    @Override
    public String getJavaClassName(Definition definition, Mode mode) {
        return super.getJavaClassName(definition, mode);
    }

    /**
     * Override this method to re-define the package names of your generated
     * artefacts.
     */
    @Override
    public String getJavaPackageName(Definition definition, Mode mode) {
        return super.getJavaPackageName(definition, mode);
    }

    /**
     * Override this method to define how Java members should be named. This is
     * used for POJO members and method arguments, for example, or when using the
     * KotlinGenerator or ScalaGenerator also for record or interface properties.
     */
    @Override
    public String getJavaMemberName(Definition definition, Mode mode) {
        return definition.getOutputName();
    }

    /**
     * Override this method to define the base class for those artefacts that
     * allow for custom base classes. Your custom base class should extend the
     * internal default base class (e.g. TableImpl, UpdatableRecordImpl, etc.)
     * for best results.
     *
     * This example provides a custom extension of the org.jooq.TableImpl class.
     */
    @Override
    public String getJavaClassExtends(Definition definition, Mode mode) {
        if (definition instanceof TableDefinition && mode == Mode.DEFAULT)
            return MyBaseTableImpl.class.getName();
        else
            return super.getJavaClassExtends(definition, mode);
    }

    /**
     * Override this method to define the interfaces to be implemented by those
     * artefacts that allow for custom interface implementation.
     *
     * This example adds serialisability and cloneability to all generated classes.
     */
    @Override
    public List<String> getJavaClassImplements(Definition definition, Mode mode) {
        return Arrays.asList(Serializable.class.getName(), Cloneable.class.getName());
    }

    /**
     * Override this method to define the suffix to apply to routines when
     * they are overloaded.
     *
     * Use this to resolve compile-time conflicts in generated source code, in
     * case you make heavy use of procedure overloading
     */
    @Override
    public String getOverloadSuffix(Definition definition, Mode mode, String overloadIndex) {
        return "_OverloadIndex_" + overloadIndex;
    }
}
```

##### An org.jooq.Table example:

This is an example showing which generator strategy method will be called in what place when generating tables. For improved readability, full qualification is omitted:

```java
package com.example.tables;
//   1: ^^^^^^^^^^^^^^^^^^
public class Book extends TableImpl<com.example.tables.records.BookRecord> {
//        2: ^^^^                                           3: ^^^^^^^^^^
    public static final Book    BOOK = new Book();
//                   2: ^^^^ 4: ^^^^
    public final TableField<BookRecord, Integer> ID = /* ... */
//                       3: ^^^^^^^^^^        5: ^^
}

// 1: strategy.getJavaPackageName(table)
// 2: strategy.getJavaClassName(table)
// 3: strategy.getJavaClassName(table, Mode.RECORD)
// 4: strategy.getJavaIdentifier(table)
// 5: strategy.getJavaIdentifier(column)
```

##### An org.jooq.Record example:

This is an example showing which generator strategy method will be called in what place when generating records. For improved readability, full qualification is omitted:

```java
package com.example.tables.records;
//   1: ^^^^^^^^^^^^^^^^^^^^^^^^^^
public class BookRecord extends UpdatableRecordImpl<BookRecord> {
//        2: ^^^^^^^^^^                          2: ^^^^^^^^^^
    public void setId(Integer value) { /* ... */ }
//           3: ^^^^^
    public Integer getId() { /* ... */ }
//              4: ^^^^^
}

// 1: strategy.getJavaPackageName(table, Mode.RECORD)
// 2: strategy.getJavaClassName(table, Mode.RECORD)
// 3: strategy.getJavaSetterName(column, Mode.RECORD)
// 4: strategy.getJavaGetterName(column, Mode.RECORD)
```

##### A POJO example:

This is an example showing which generator strategy method will be called in what place when generating pojos. For improved readability, full qualification is omitted:

```java
package com.example.tables.pojos;
//   1: ^^^^^^^^^^^^^^^^^^^^^^^^
public class Book implements java.io.Serializable {
//        2: ^^^^
    private Integer id;
//               3: ^^
    public void setId(Integer value) { /* ... */ }
//           4: ^^^^^
    public Integer getId() { /* ... */ }
//              5: ^^^^^

}

// 1: strategy.getJavaPackageName(table, Mode.POJO)
// 2: strategy.getJavaClassName(table, Mode.POJO)
// 3: strategy.getJavaMemberName(column, Mode.POJO)
// 4: strategy.getJavaSetterName(column, Mode.POJO)
// 5: strategy.getJavaGetterName(column, Mode.POJO)
```

##### Out-of-the-box strategies

The `jooq-codegen` module provides the following out-of-the-box strategies, which can be used directly, or taken as inspiration:

- `org.jooq.codegen.KeepNamesGeneratorStrategy`: Keeps all names and identifiers exactly as they are in the database, including case and underscores. I.e. `snake_case` identifiers will produce `snake_case` classes and members, whereas `PascalCase` identifiers will produce `PascalCase` classes and members.
- `org.jooq.codegen.PascalCaseGeneratorStrategy`: Turns all `snake_case` (lower and upper case) identifiers into `PascalCase` while leaving the `PascalCase` identifiers untouched. This is ideal in T-SQL style schemas where identifiers are usually defined in `PascalCase`.

More examples can be found here:

- [org.jooq.codegen.example.JPrefixGeneratorStrategy](https://github.com/jOOQ/jOOQ/blob/master/jOOQ-codegen/src/main/java/org/jooq/codegen/example/JPrefixGeneratorStrategy.java)
- [org.jooq.codegen.example.JVMArgsGeneratorStrategy](https://github.com/jOOQ/jOOQ/blob/master/jOOQ-codegen/src/main/java/org/jooq/codegen/example/JVMArgsGeneratorStrategy.java)

<a id="codegen-matcherstrategy"></a>
#### 5.4.2. Matcher strategies

##### Using custom matcher strategies

In the [previous section](#codegen-generatorstrategy), we have seen how to override generator strategies programmatically. In this chapter, we'll see how such strategies can be configured in the XML or Maven [code generator configuration](#codegen-configuration). Instead of specifying a strategy name, you can also specify a `<matchers/>` element as explained in the following subsections.

The generic structure of such matchers looks as follows:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <tables>
          <table>

            <!-- Match unqualified or qualified table names. If left empty, this matcher applies to all tables. -->
            <expression>MY_TABLE</expression>

            <!-- These elements influence the naming of a generated org.jooq.Table object. -->
            <tableClass> a MatcherRule specification </tableClass>
            <tableIdentifier> a MatcherRule specification </tableIdentifier>
            <tableExtends>com.example.MyOptionalTableBaseType</tableExtends>
            <tableImplements>com.example.MyOptionalCustomInterface</tableImplements>
          </table>
        </tables>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()
        .withTables(
          new MatchersTableType()

            // Match unqualified or qualified table names. If left empty, this matcher applies to all tables.
            .withExpression("MY_TABLE")

            // These elements influence the naming of a generated org.jooq.Table object.
            .withTableClass(MatcherRule. a MatcherRule specification )
            .withTableIdentifier(MatcherRule. a MatcherRule specification )
            .withTableExtends("com.example.MyOptionalTableBaseType")
            .withTableImplements("com.example.MyOptionalCustomInterface")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {
        tables {
          table {

            // Match unqualified or qualified table names. If left empty, this matcher applies to all tables.
            expression = "MY_TABLE"

            // These elements influence the naming of a generated org.jooq.Table object.
            tableClass = MatcherRule. a MatcherRule specification 
            tableIdentifier = MatcherRule. a MatcherRule specification 
            tableExtends = "com.example.MyOptionalTableBaseType"
            tableImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {
        tables {
          table {

            // Match unqualified or qualified table names. If left empty, this matcher applies to all tables.
            expression = "MY_TABLE"

            // These elements influence the naming of a generated org.jooq.Table object.
            tableClass = " a MatcherRule specification "
            tableIdentifier = " a MatcherRule specification "
            tableExtends = "com.example.MyOptionalTableBaseType"
            tableImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

A matcher configuration element can be any of these things:

- A regular expression matching an identifier
- A `org.jooq.meta.jaxb.MatcherRule` specification (see [MatcherRule](#codegen-matcher-rule))
- A constant value

> [!TIP]
> All regular expressions that match object identifiers try to match identifiers first by unqualified name (`org.jooq.meta.Definition.getName()`), then by qualified name (`org.jooq.meta.Definition.getQualifiedName()`).

> [!TIP]
> When using any `recordExtends`, `tableExtends`, etc. setting, you must make sure to correctly implement the internal jOOQ APIs, which are not documented here for they are internal. In particular, if you're extending [`org.jooq.impl.TableImpl`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/TableImpl.html), for example, your custom base class may break between minor versions of jOOQ, as new constructors are added.

The following sections explain the above more in detail:

<a id="codegen-matcher-rule"></a>
##### 5.4.2.1. MatcherRule

Most matchers use references to `MatcherRule`, which is consists of two elements:

- The regex replacement experssion to replace the matched name with.
- The transformation directive, which allows for specifying how to transform the resulting name.

###### Transformation directives

The following transformation directives are supported:

- `AS_IS`: Leave the database name as it is, e.g. `MY_name` => `MY_name`
- `LOWER`: ransform the database name into lower case, e.g. `MY_name` => `my_name`
- `LOWER_FIRST_LETTER`: Transform the first letter into lower case, e.g. `MY_name` => `mY_name`
- `UPPER`: Transform the database name into upper case, e.g. `MY_name` => `MY_NAME`
- `UPPER_FIRST_LETTER`: Transform the first letter into upper case, e.g. `my_NAME` => `My_NAME`
- `CAMEL`: Transform the database name into camel case, e.g. `MY_name` => `myName`
- `PASCAL`: Transform the database name into pascal case, e.g. `MY_name` => `MyName`

###### Example: Adding a prefix / suffix to names

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <strategy>
      <matchers>
        <schemas>
          <schema>

            <!-- Without an input expression, this rule applies to all schemas -->
            <schemaClass>

              <!-- Optional transform directive -->
              <transform>CAMEL</transform>

              <!-- The mandatory expression element lets you specify a replacement expression to be used when
                   replacing the matcher's regular expression. You can use indexed variables $0, $1, $2. -->
              <expression>PREFIX_$0_SUFFIX</expression>
            </schemaClass>
          </schema>
        </schemas>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()
        .withSchemas(
          new MatchersSchemaType()

            // Without an input expression, this rule applies to all schemas
            .withSchemaClass(new MatcherRule()

              // Optional transform directive
              .withTransform(MatcherTransformType.CAMEL)

              // The mandatory expression element lets you specify a replacement expression to be used when
              // replacing the matcher's regular expression. You can use indexed variables $0, $1, $2.
              .withExpression("PREFIX_$0_SUFFIX")
            )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    strategy {
      matchers {
        schemas {
          schema {

            // Without an input expression, this rule applies to all schemas
            schemaClass {

              // Optional transform directive
              transform = MatcherTransformType.CAMEL

              // The mandatory expression element lets you specify a replacement expression to be used when
              // replacing the matcher's regular expression. You can use indexed variables $0, $1, $2.
              expression = "PREFIX_$0_SUFFIX"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    strategy {
      matchers {
        schemas {
          schema {

            // Without an input expression, this rule applies to all schemas
            schemaClass {

              // Optional transform directive
              transform = "CAMEL"

              // The mandatory expression element lets you specify a replacement expression to be used when
              // replacing the matcher's regular expression. You can use indexed variables $0, $1, $2.
              expression = "PREFIX_$0_SUFFIX"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

###### Example: Removing a prefix / suffix from names

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <strategy>
      <matchers>
        <tables>
          <table>

            <!-- Provide an optional input expression to apply this rule only to certain tables.
                 We can match groups with the regex (group expression) -->
            <expression>^T_(.*)$</expression>

            <tableClass>

              <!-- Optional transform directive -->
              <transform>CAMEL</transform>

              <!-- This ignores the prefix and replaces the name by the first matched group. -->
              <expression>$1</expression>
            </tableClass>
          </table>
        </tables>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()
        .withTables(
          new MatchersTableType()

            // Provide an optional input expression to apply this rule only to certain tables.
            // We can match groups with the regex (group expression)
            .withExpression("^T_(.*)$")
            .withTableClass(new MatcherRule()

              // Optional transform directive
              .withTransform(MatcherTransformType.CAMEL)

              // This ignores the prefix and replaces the name by the first matched group.
              .withExpression("$1")
            )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    strategy {
      matchers {
        tables {
          table {

            // Provide an optional input expression to apply this rule only to certain tables.
            // We can match groups with the regex (group expression)
            expression = "^T_(.*)$"
            tableClass {

              // Optional transform directive
              transform = MatcherTransformType.CAMEL

              // This ignores the prefix and replaces the name by the first matched group.
              expression = "$1"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    strategy {
      matchers {
        tables {
          table {

            // Provide an optional input expression to apply this rule only to certain tables.
            // We can match groups with the regex (group expression)
            expression = "^T_(.*)$"
            tableClass {

              // Optional transform directive
              transform = "CAMEL"

              // This ignores the prefix and replaces the name by the first matched group.
              expression = "$1"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

In other words, a `MatcherRule` describes how a specific object type name (e.g. a class name representing a generated [`org.jooq.Schema`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Schema.html)) should be declared and referenced based on the object's input name.

<a id="codegen-matcher-catalogs"></a>
##### 5.4.2.2. Matching catalogs

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.Catalog`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Catalog.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n catalog matchers to provide a strategy for naming objects created from catalogs. -->
        <catalogs>
          <catalog>

            <!-- Match unqualified or qualified catalog names. If left empty, this matcher applies to all catalogs. -->
            <expression>MY_CATALOG</expression>

            <!-- These elements influence the naming of a generated org.jooq.Catalog object. -->
            <catalogClass> a MatcherRule specification </catalogClass>
            <catalogIdentifier> a MatcherRule specification </catalogIdentifier>
            <catalogExtends>com.example.MyOptionalCatalogBaseType</catalogExtends>
            <catalogImplements>com.example.MyOptionalCustomInterface</catalogImplements>
          </catalog>
        </catalogs>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n catalog matchers to provide a strategy for naming objects created from catalogs.
        .withCatalogs(
          new MatchersCatalogType()

            // Match unqualified or qualified catalog names. If left empty, this matcher applies to all catalogs.
            .withExpression("MY_CATALOG")

            // These elements influence the naming of a generated org.jooq.Catalog object.
            .withCatalogClass(MatcherRule. a MatcherRule specification )
            .withCatalogIdentifier(MatcherRule. a MatcherRule specification )
            .withCatalogExtends("com.example.MyOptionalCatalogBaseType")
            .withCatalogImplements("com.example.MyOptionalCustomInterface")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n catalog matchers to provide a strategy for naming objects created from catalogs.
        catalogs {
          catalog {

            // Match unqualified or qualified catalog names. If left empty, this matcher applies to all catalogs.
            expression = "MY_CATALOG"

            // These elements influence the naming of a generated org.jooq.Catalog object.
            catalogClass = MatcherRule. a MatcherRule specification 
            catalogIdentifier = MatcherRule. a MatcherRule specification 
            catalogExtends = "com.example.MyOptionalCatalogBaseType"
            catalogImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n catalog matchers to provide a strategy for naming objects created from catalogs.
        catalogs {
          catalog {

            // Match unqualified or qualified catalog names. If left empty, this matcher applies to all catalogs.
            expression = "MY_CATALOG"

            // These elements influence the naming of a generated org.jooq.Catalog object.
            catalogClass = " a MatcherRule specification "
            catalogIdentifier = " a MatcherRule specification "
            catalogExtends = "com.example.MyOptionalCatalogBaseType"
            catalogImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

> [!TIP]
> When using any `catalogExtends`, etc. setting, you must make sure to correctly implement the internal jOOQ APIs, which are not documented here for they are internal. In particular, if you're extending [`org.jooq.impl.TableImpl`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/TableImpl.html), for example, your custom base class may break between minor versions of jOOQ, as new constructors are added.

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-schemas"></a>
##### 5.4.2.3. Matching schemas

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.Schema`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Schema.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n schema matchers to provide a strategy for naming objects created from schemas. -->
        <schemas>
          <schema>

            <!-- Match unqualified or qualified schema names. If left empty, this matcher applies to all schemas. -->
            <expression>MY_SCHEMA</expression>

            <!-- These elements influence the naming of a generated org.jooq.Schema object. -->
            <schemaClass> a MatcherRule specification </schemaClass>
            <schemaIdentifier> a MatcherRule specification </schemaIdentifier>
            <schemaExtends>com.example.MyOptionalSchemaBaseType</schemaExtends>
            <schemaImplements>com.example.MyOptionalCustomInterface</schemaImplements>
          </schema>
        </schemas>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n schema matchers to provide a strategy for naming objects created from schemas.
        .withSchemas(
          new MatchersSchemaType()

            // Match unqualified or qualified schema names. If left empty, this matcher applies to all schemas.
            .withExpression("MY_SCHEMA")

            // These elements influence the naming of a generated org.jooq.Schema object.
            .withSchemaClass(MatcherRule. a MatcherRule specification )
            .withSchemaIdentifier(MatcherRule. a MatcherRule specification )
            .withSchemaExtends("com.example.MyOptionalSchemaBaseType")
            .withSchemaImplements("com.example.MyOptionalCustomInterface")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n schema matchers to provide a strategy for naming objects created from schemas.
        schemas {
          schema {

            // Match unqualified or qualified schema names. If left empty, this matcher applies to all schemas.
            expression = "MY_SCHEMA"

            // These elements influence the naming of a generated org.jooq.Schema object.
            schemaClass = MatcherRule. a MatcherRule specification 
            schemaIdentifier = MatcherRule. a MatcherRule specification 
            schemaExtends = "com.example.MyOptionalSchemaBaseType"
            schemaImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n schema matchers to provide a strategy for naming objects created from schemas.
        schemas {
          schema {

            // Match unqualified or qualified schema names. If left empty, this matcher applies to all schemas.
            expression = "MY_SCHEMA"

            // These elements influence the naming of a generated org.jooq.Schema object.
            schemaClass = " a MatcherRule specification "
            schemaIdentifier = " a MatcherRule specification "
            schemaExtends = "com.example.MyOptionalSchemaBaseType"
            schemaImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

> [!TIP]
> When using any `schemaExtends`, etc. setting, you must make sure to correctly implement the internal jOOQ APIs, which are not documented here for they are internal. In particular, if you're extending [`org.jooq.impl.TableImpl`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/TableImpl.html), for example, your custom base class may break between minor versions of jOOQ, as new constructors are added.

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-tables"></a>
##### 5.4.2.4. Matching tables

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) and [`org.jooq.TableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/TableRecord.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n table matchers to provide a strategy for naming objects created from tables. -->
        <tables>
          <table>

            <!-- Match unqualified or qualified table names. If left empty, this matcher applies to all tables. -->
            <expression>MY_TABLE</expression>

            <!-- These elements influence the naming of a generated org.jooq.Table object. -->
            <tableClass> a MatcherRule specification </tableClass>
            <tableIdentifier> a MatcherRule specification </tableIdentifier>
            <tableExtends>com.example.MyOptionalTableBaseType</tableExtends>
            <tableImplements>com.example.MyOptionalCustomInterface</tableImplements>

            <!-- These elements influence the naming of a generated org.jooq.Table & org.jooq.Path object. -->
            <pathClass> a MatcherRule specification </pathClass>
            <pathExtends>com.example.MyOptionalTableBaseType</pathExtends>
            <pathImplements>com.example.MyOptionalCustomInterface</pathImplements>
            <!-- These elements influence the naming of a generated org.jooq.Record object. -->
            <recordClass> a MatcherRule specification </recordClass>
            <recordExtends>com.example.MyOptionalRecordBaseType</recordExtends>
            <recordImplements>com.example.MyOptionalCustomInterface</recordImplements>

            <!-- These elements influence the naming of a generated interface, implemented by
                 generated org.jooq.Record objects and by generated POJOs. -->
            <interfaceClass> a MatcherRule specification </interfaceClass>
            <interfaceImplements>com.example.MyOptionalCustomInterface</interfaceImplements>

            <!-- These elements influence the naming of a generated org.jooq.DAO object. -->
            <daoClass> a MatcherRule specification </daoClass>
            <daoExtends>com.example.MyOptionalDAOBaseType</daoExtends>
            <daoImplements>com.example.MyOptionalCustomInterface</daoImplements>

            <!-- These elements influence the naming of a generated POJO object.  -->
            <pojoClass> a MatcherRule specification </pojoClass>
            <pojoExtends>com.example.MyOptionalPojoBaseClass</pojoExtends>
            <pojoImplements>com.example.MyOptionalCustomInterface</pojoImplements>
          </table>
        </tables>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n table matchers to provide a strategy for naming objects created from tables.
        .withTables(
          new MatchersTableType()

            // Match unqualified or qualified table names. If left empty, this matcher applies to all tables.
            .withExpression("MY_TABLE")

            // These elements influence the naming of a generated org.jooq.Table object.
            .withTableClass(MatcherRule. a MatcherRule specification )
            .withTableIdentifier(MatcherRule. a MatcherRule specification )
            .withTableExtends("com.example.MyOptionalTableBaseType")
            .withTableImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated org.jooq.Table & org.jooq.Path object.
            .withPathClass(MatcherRule. a MatcherRule specification )
            .withPathExtends(MatcherRule.com.example.MyOptionalTableBaseType)
            .withPathImplements(MatcherRule.com.example.MyOptionalCustomInterface)

            // These elements influence the naming of a generated org.jooq.Record object.
            .withRecordClass(MatcherRule. a MatcherRule specification )
            .withRecordExtends("com.example.MyOptionalRecordBaseType")
            .withRecordImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.Record objects and by generated POJOs.
            .withInterfaceClass(MatcherRule. a MatcherRule specification )
            .withInterfaceImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated org.jooq.DAO object.
            .withDaoClass(MatcherRule. a MatcherRule specification )
            .withDaoExtends("com.example.MyOptionalDAOBaseType")
            .withDaoImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated POJO object.
            .withPojoClass(MatcherRule. a MatcherRule specification )
            .withPojoExtends("com.example.MyOptionalPojoBaseClass")
            .withPojoImplements("com.example.MyOptionalCustomInterface")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n table matchers to provide a strategy for naming objects created from tables.
        tables {
          table {

            // Match unqualified or qualified table names. If left empty, this matcher applies to all tables.
            expression = "MY_TABLE"

            // These elements influence the naming of a generated org.jooq.Table object.
            tableClass = MatcherRule. a MatcherRule specification 
            tableIdentifier = MatcherRule. a MatcherRule specification 
            tableExtends = "com.example.MyOptionalTableBaseType"
            tableImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.Table & org.jooq.Path object.
            pathClass = MatcherRule. a MatcherRule specification 
            pathExtends = MatcherRule.com.example.MyOptionalTableBaseType
            pathImplements = MatcherRule.com.example.MyOptionalCustomInterface

            // These elements influence the naming of a generated org.jooq.Record object.
            recordClass = MatcherRule. a MatcherRule specification 
            recordExtends = "com.example.MyOptionalRecordBaseType"
            recordImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.Record objects and by generated POJOs.
            interfaceClass = MatcherRule. a MatcherRule specification 
            interfaceImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.DAO object.
            daoClass = MatcherRule. a MatcherRule specification 
            daoExtends = "com.example.MyOptionalDAOBaseType"
            daoImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated POJO object.
            pojoClass = MatcherRule. a MatcherRule specification 
            pojoExtends = "com.example.MyOptionalPojoBaseClass"
            pojoImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n table matchers to provide a strategy for naming objects created from tables.
        tables {
          table {

            // Match unqualified or qualified table names. If left empty, this matcher applies to all tables.
            expression = "MY_TABLE"

            // These elements influence the naming of a generated org.jooq.Table object.
            tableClass = " a MatcherRule specification "
            tableIdentifier = " a MatcherRule specification "
            tableExtends = "com.example.MyOptionalTableBaseType"
            tableImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.Table & org.jooq.Path object.
            pathClass = " a MatcherRule specification "
            pathExtends = "com.example.MyOptionalTableBaseType"
            pathImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.Record object.
            recordClass = " a MatcherRule specification "
            recordExtends = "com.example.MyOptionalRecordBaseType"
            recordImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.Record objects and by generated POJOs.
            interfaceClass = " a MatcherRule specification "
            interfaceImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.DAO object.
            daoClass = " a MatcherRule specification "
            daoExtends = "com.example.MyOptionalDAOBaseType"
            daoImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated POJO object.
            pojoClass = " a MatcherRule specification "
            pojoExtends = "com.example.MyOptionalPojoBaseClass"
            pojoImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

> [!TIP]
> When using any `tableExtends`, `recordExtends`, etc. setting, you must make sure to correctly implement the internal jOOQ APIs, which are not documented here for they are internal. In particular, if you're extending [`org.jooq.impl.TableImpl`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/TableImpl.html), for example, your custom base class may break between minor versions of jOOQ, as new constructors are added.

> [!TIP]
> If your `TableRecord`, POJO classes, or interfaces extend or implement other types, you can specify `override` modifiers to the respective [fields](#codegen-matcher-fields).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-fields"></a>
##### 5.4.2.5. Matching fields

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.Field`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Field.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n field matchers to provide a strategy for naming objects created from fields. -->
        <fields>
          <field>

            <!-- Match unqualified or qualified field names. If left empty, this matcher applies to all fields. -->
            <expression>MY_FIELD</expression>

            <!-- These elements influence the naming of a generated org.jooq.Field object. -->
            <fieldIdentifier> a MatcherRule specification </fieldIdentifier>
            <fieldMember> a MatcherRule specification </fieldMember>
            <fieldSetter> a MatcherRule specification </fieldSetter>
            <fieldGetter> a MatcherRule specification </fieldGetter>

            <!-- These elements influence the naming of generated DAO methods. -->
            <daoMember> a MatcherRule specification </daoMember>

            <!-- Whether a method should have an override modifier, e.g. because of an implemented interface -->
            <recordSetterOverride>false</recordSetterOverride>
            <recordGetterOverride>false</recordGetterOverride>
            <recordMemberOverride>false</recordMemberOverride>
            <interfaceSetterOverride>false</interfaceSetterOverride>
            <interfaceGetterOverride>false</interfaceGetterOverride>
            <interfaceMemberOverride>false</interfaceMemberOverride>
            <pojoSetterOverride>false</pojoSetterOverride>
            <pojoGetterOverride>false</pojoGetterOverride>
            <pojoMemberOverride>false</pojoMemberOverride>
            
            <!-- Since 3.20.12 also: -->
            <tableMemberOverride>false</tableMemberOverride>
            <udtMemberOverride>false</udtMemberOverride>
          </field>
        </fields>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n field matchers to provide a strategy for naming objects created from fields.
        .withFields(
          new MatchersFieldType()

            // Match unqualified or qualified field names. If left empty, this matcher applies to all fields.
            .withExpression("MY_FIELD")

            // These elements influence the naming of a generated org.jooq.Field object.
            .withFieldIdentifier(MatcherRule. a MatcherRule specification )
            .withFieldMember(MatcherRule. a MatcherRule specification )
            .withFieldSetter(MatcherRule. a MatcherRule specification )
            .withFieldGetter(MatcherRule. a MatcherRule specification )

            // These elements influence the naming of generated DAO methods.
            .withDaoMember(MatcherRule. a MatcherRule specification )

            // Whether a method should have an override modifier, e.g. because of an implemented interface
            .withRecordSetterOverride(false)
            .withRecordGetterOverride(false)
            .withRecordMemberOverride(false)
            .withInterfaceSetterOverride(false)
            .withInterfaceGetterOverride(false)
            .withInterfaceMemberOverride(false)
            .withPojoSetterOverride(false)
            .withPojoGetterOverride(false)
            .withPojoMemberOverride(false)

            // Since 3.20.12 also:
            .withTableMemberOverride(false)
            .withUdtMemberOverride(false)
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n field matchers to provide a strategy for naming objects created from fields.
        fields {
          field {

            // Match unqualified or qualified field names. If left empty, this matcher applies to all fields.
            expression = "MY_FIELD"

            // These elements influence the naming of a generated org.jooq.Field object.
            fieldIdentifier = MatcherRule. a MatcherRule specification 
            fieldMember = MatcherRule. a MatcherRule specification 
            fieldSetter = MatcherRule. a MatcherRule specification 
            fieldGetter = MatcherRule. a MatcherRule specification 

            // These elements influence the naming of generated DAO methods.
            daoMember = MatcherRule. a MatcherRule specification 

            // Whether a method should have an override modifier, e.g. because of an implemented interface
            isRecordSetterOverride = false
            isRecordGetterOverride = false
            isRecordMemberOverride = false
            isInterfaceSetterOverride = false
            isInterfaceGetterOverride = false
            isInterfaceMemberOverride = false
            isPojoSetterOverride = false
            isPojoGetterOverride = false
            isPojoMemberOverride = false

            // Since 3.20.12 also:
            isTableMemberOverride = false
            isUdtMemberOverride = false
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n field matchers to provide a strategy for naming objects created from fields.
        fields {
          field {

            // Match unqualified or qualified field names. If left empty, this matcher applies to all fields.
            expression = "MY_FIELD"

            // These elements influence the naming of a generated org.jooq.Field object.
            fieldIdentifier = " a MatcherRule specification "
            fieldMember = " a MatcherRule specification "
            fieldSetter = " a MatcherRule specification "
            fieldGetter = " a MatcherRule specification "

            // These elements influence the naming of generated DAO methods.
            daoMember = " a MatcherRule specification "

            // Whether a method should have an override modifier, e.g. because of an implemented interface
            recordSetterOverride = false
            recordGetterOverride = false
            recordMemberOverride = false
            interfaceSetterOverride = false
            interfaceGetterOverride = false
            interfaceMemberOverride = false
            pojoSetterOverride = false
            pojoGetterOverride = false
            pojoMemberOverride = false

            // Since 3.20.12 also:
            tableMemberOverride = false
            udtMemberOverride = false
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-indexes"></a>
##### 5.4.2.6. Matching indexes

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.Index`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Index.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n index matchers to provide a strategy for naming objects created from indexes. -->
        <indexes>
          <index>

            <!-- Match unqualified or qualified index names. If left empty, this matcher applies to all indexes. -->
            <expression>MY_IDX_NAME</expression>

            <!-- This influences the identifier in the generated Indexes class -->
            <keyIdentifier> a MatcherRule specification </keyIdentifier>
          </index>
        </indexes>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n index matchers to provide a strategy for naming objects created from indexes.
        .withIndexes(
          new MatchersIndexType()

            // Match unqualified or qualified index names. If left empty, this matcher applies to all indexes.
            .withExpression("MY_IDX_NAME")

            // This influences the identifier in the generated Indexes class
            .withKeyIdentifier(MatcherRule. a MatcherRule specification )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n index matchers to provide a strategy for naming objects created from indexes.
        indexes {
          index {

            // Match unqualified or qualified index names. If left empty, this matcher applies to all indexes.
            expression = "MY_IDX_NAME"

            // This influences the identifier in the generated Indexes class
            keyIdentifier = MatcherRule. a MatcherRule specification 
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n index matchers to provide a strategy for naming objects created from indexes.
        indexes {
          index {

            // Match unqualified or qualified index names. If left empty, this matcher applies to all indexes.
            expression = "MY_IDX_NAME"

            // This influences the identifier in the generated Indexes class
            keyIdentifier = " a MatcherRule specification "
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-primary-keys"></a>
##### 5.4.2.7. Matching primary keys

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.UniqueKey`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UniqueKey.html) types, which are primary keys, and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n primary key matchers to provide a strategy for naming objects created from primary keys. -->
        <primaryKeys>
          <primaryKey>

            <!-- Match unqualified or qualified primary key names. If left empty, this matcher applies to all primary keys. -->
            <expression>MY_PK_NAME</expression>

            <!-- This influences the identifier in the generated Keys class -->
            <keyIdentifier> a MatcherRule specification </keyIdentifier>
          </primaryKey>
        </primaryKeys>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n primary key matchers to provide a strategy for naming objects created from primary keys.
        .withPrimaryKeys(
          new MatchersPrimaryKeyType()

            // Match unqualified or qualified primary key names. If left empty, this matcher applies to all primary keys.
            .withExpression("MY_PK_NAME")

            // This influences the identifier in the generated Keys class
            .withKeyIdentifier(MatcherRule. a MatcherRule specification )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n primary key matchers to provide a strategy for naming objects created from primary keys.
        primaryKeys {
          primaryKey {

            // Match unqualified or qualified primary key names. If left empty, this matcher applies to all primary keys.
            expression = "MY_PK_NAME"

            // This influences the identifier in the generated Keys class
            keyIdentifier = MatcherRule. a MatcherRule specification 
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n primary key matchers to provide a strategy for naming objects created from primary keys.
        primaryKeys {
          primaryKey {

            // Match unqualified or qualified primary key names. If left empty, this matcher applies to all primary keys.
            expression = "MY_PK_NAME"

            // This influences the identifier in the generated Keys class
            keyIdentifier = " a MatcherRule specification "
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-unique-keys"></a>
##### 5.4.2.8. Matching unique keys

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.UniqueKey`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UniqueKey.html) types, which are not primary keys, and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>


        <!-- Specify 0..n unique key matchers to provide a strategy for naming objects created from unique keys. -->
        <uniqueKeys>
          <uniqueKey>

            <!-- Match unqualified or qualified unique key names. If left empty, this matcher applies to all unique keys. -->
            <expression>MY_UK_NAME</expression>

            <!-- This influences the identifier in the generated Keys class -->
            <keyIdentifier> a MatcherRule specification </keyIdentifier>
          </uniqueKey>
        </uniqueKeys>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n unique key matchers to provide a strategy for naming objects created from unique keys.
        .withUniqueKeys(
          new MatchersUniqueKeyType()

            // Match unqualified or qualified unique key names. If left empty, this matcher applies to all unique keys.
            .withExpression("MY_UK_NAME")

            // This influences the identifier in the generated Keys class
            .withKeyIdentifier(MatcherRule. a MatcherRule specification )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n unique key matchers to provide a strategy for naming objects created from unique keys.
        uniqueKeys {
          uniqueKey {

            // Match unqualified or qualified unique key names. If left empty, this matcher applies to all unique keys.
            expression = "MY_UK_NAME"

            // This influences the identifier in the generated Keys class
            keyIdentifier = MatcherRule. a MatcherRule specification 
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n unique key matchers to provide a strategy for naming objects created from unique keys.
        uniqueKeys {
          uniqueKey {

            // Match unqualified or qualified unique key names. If left empty, this matcher applies to all unique keys.
            expression = "MY_UK_NAME"

            // This influences the identifier in the generated Keys class
            keyIdentifier = " a MatcherRule specification "
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-foreign-keys"></a>
##### 5.4.2.9. Matching foreign keys

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.ForeignKey`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ForeignKey.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n foreign key matchers to provide a strategy for naming objects created from foreign keys. -->
        <foreignKeys>
          <foreignKey>

            <!-- Match unqualified or qualified foreign key names. If left empty, this matcher applies to all foreign keys. -->
            <expression>MY_FK_NAME</expression>

            <!-- This influences the identifier in the generated Keys class -->
            <keyIdentifier> a MatcherRule specification </keyIdentifier>

            <!-- The method name generated for to-one path joins. -->
            <pathMethodName> a MatcherRule specification </pathMethodName>

            <!-- The method name generated for to-many path joins. -->
            <pathMethodNameInverse> a MatcherRule specification </pathMethodNameInverse>

            <!-- The method name generated for many-to-many path joins. -->
            <pathMethodNameManyToMany> a MatcherRule specification </pathMethodNameManyToMany>
          </foreignKey>
        </foreignKeys>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n foreign key matchers to provide a strategy for naming objects created from foreign keys.
        .withForeignKeys(
          new MatchersForeignKeyType()

            // Match unqualified or qualified foreign key names. If left empty, this matcher applies to all foreign keys.
            .withExpression("MY_FK_NAME")

            // This influences the identifier in the generated Keys class
            .withKeyIdentifier(MatcherRule. a MatcherRule specification )

            // The method name generated for to-one path joins.
            .withPathMethodName(MatcherRule. a MatcherRule specification )

            // The method name generated for to-many path joins.
            .withPathMethodNameInverse(MatcherRule. a MatcherRule specification )

            // The method name generated for many-to-many path joins.
            .withPathMethodNameManyToMany(MatcherRule. a MatcherRule specification )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n foreign key matchers to provide a strategy for naming objects created from foreign keys.
        foreignKeys {
          foreignKey {

            // Match unqualified or qualified foreign key names. If left empty, this matcher applies to all foreign keys.
            expression = "MY_FK_NAME"

            // This influences the identifier in the generated Keys class
            keyIdentifier = MatcherRule. a MatcherRule specification 

            // The method name generated for to-one path joins.
            pathMethodName = MatcherRule. a MatcherRule specification 

            // The method name generated for to-many path joins.
            pathMethodNameInverse = MatcherRule. a MatcherRule specification 

            // The method name generated for many-to-many path joins.
            pathMethodNameManyToMany = MatcherRule. a MatcherRule specification 
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n foreign key matchers to provide a strategy for naming objects created from foreign keys.
        foreignKeys {
          foreignKey {

            // Match unqualified or qualified foreign key names. If left empty, this matcher applies to all foreign keys.
            expression = "MY_FK_NAME"

            // This influences the identifier in the generated Keys class
            keyIdentifier = " a MatcherRule specification "

            // The method name generated for to-one path joins.
            pathMethodName = " a MatcherRule specification "

            // The method name generated for to-many path joins.
            pathMethodNameInverse = " a MatcherRule specification "

            // The method name generated for many-to-many path joins.
            pathMethodNameManyToMany = " a MatcherRule specification "
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-routines"></a>
##### 5.4.2.10. Matching routines

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.Routine`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Routine.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n routine matchers to provide a strategy for naming objects created from routines. -->
        <routines>
          <routine>

            <!-- Match unqualified or qualified routine names. If left empty, this matcher applies to all routines. -->
            <expression>MY_ROUTINE</expression>

            <!-- These elements influence the naming of a generated org.jooq.Routine object. -->
            <routineClass> a MatcherRule specification </routineClass>
            <routineMethod> a MatcherRule specification </routineMethod>
            <routineExtends>com.example.MyOptionalRoutineBaseType</routineExtends>
            <routineImplements>com.example.MyOptionalCustomInterface</routineImplements>
          </routine>
        </routines>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n routine matchers to provide a strategy for naming objects created from routines.
        .withRoutines(
          new MatchersRoutineType()

            // Match unqualified or qualified routine names. If left empty, this matcher applies to all routines.
            .withExpression("MY_ROUTINE")

            // These elements influence the naming of a generated org.jooq.Routine object.
            .withRoutineClass(MatcherRule. a MatcherRule specification )
            .withRoutineMethod(MatcherRule. a MatcherRule specification )
            .withRoutineExtends("com.example.MyOptionalRoutineBaseType")
            .withRoutineImplements("com.example.MyOptionalCustomInterface")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n routine matchers to provide a strategy for naming objects created from routines.
        routines {
          routine {

            // Match unqualified or qualified routine names. If left empty, this matcher applies to all routines.
            expression = "MY_ROUTINE"

            // These elements influence the naming of a generated org.jooq.Routine object.
            routineClass = MatcherRule. a MatcherRule specification 
            routineMethod = MatcherRule. a MatcherRule specification 
            routineExtends = "com.example.MyOptionalRoutineBaseType"
            routineImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n routine matchers to provide a strategy for naming objects created from routines.
        routines {
          routine {

            // Match unqualified or qualified routine names. If left empty, this matcher applies to all routines.
            expression = "MY_ROUTINE"

            // These elements influence the naming of a generated org.jooq.Routine object.
            routineClass = " a MatcherRule specification "
            routineMethod = " a MatcherRule specification "
            routineExtends = "com.example.MyOptionalRoutineBaseType"
            routineImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

> [!TIP]
> When using any `routineExtends`, etc. setting, you must make sure to correctly implement the internal jOOQ APIs, which are not documented here for they are internal. In particular, if you're extending [`org.jooq.impl.TableImpl`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/TableImpl.html), for example, your custom base class may break between minor versions of jOOQ, as new constructors are added.

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-sequences"></a>
##### 5.4.2.11. Matching sequences

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.Sequence`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Sequence.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n sequence matchers to provide a strategy for naming objects created from sequences. -->
        <sequences>
          <sequence>

            <!-- Match unqualified or qualified sequence names. If left empty, this matcher applies to all sequences. -->
            <expression>MY_SEQUENCE</expression>

            <!-- These elements influence the naming of the generated Sequences class. -->
            <sequenceIdentifier> a MatcherRule specification </sequenceIdentifier>
          </sequence>
        </sequences>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n sequence matchers to provide a strategy for naming objects created from sequences.
        .withSequences(
          new MatchersSequenceType()

            // Match unqualified or qualified sequence names. If left empty, this matcher applies to all sequences.
            .withExpression("MY_SEQUENCE")

            // These elements influence the naming of the generated Sequences class.
            .withSequenceIdentifier(MatcherRule. a MatcherRule specification )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n sequence matchers to provide a strategy for naming objects created from sequences.
        sequences {
          sequence {

            // Match unqualified or qualified sequence names. If left empty, this matcher applies to all sequences.
            expression = "MY_SEQUENCE"

            // These elements influence the naming of the generated Sequences class.
            sequenceIdentifier = MatcherRule. a MatcherRule specification 
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n sequence matchers to provide a strategy for naming objects created from sequences.
        sequences {
          sequence {

            // Match unqualified or qualified sequence names. If left empty, this matcher applies to all sequences.
            expression = "MY_SEQUENCE"

            // These elements influence the naming of the generated Sequences class.
            sequenceIdentifier = " a MatcherRule specification "
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-enums"></a>
##### 5.4.2.12. Matching enums

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.EnumType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EnumType.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n enum matchers to provide a strategy for naming objects created from enums. -->
        <enums>
          <enum>

            <!-- Match unqualified or qualified enum names. If left empty, this matcher applies to all enums. -->
            <expression>MY_ENUM</expression>

            <!-- These elements influence the naming of a generated org.jooq.EnumType object. -->
            <enumClass> a MatcherRule specification </enumClass>
            <enumImplements>com.example.MyOptionalCustomInterface</enumImplements>
            <enumLiteral> a MatcherRule specification </enumLiteral>
          </enum>
        </enums>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n enum matchers to provide a strategy for naming objects created from enums.
        .withEnums(
          new MatchersEnumType()

            // Match unqualified or qualified enum names. If left empty, this matcher applies to all enums.
            .withExpression("MY_ENUM")

            // These elements influence the naming of a generated org.jooq.EnumType object.
            .withEnumClass(MatcherRule. a MatcherRule specification )
            .withEnumImplements("com.example.MyOptionalCustomInterface")
            .withEnumLiteral(MatcherRule. a MatcherRule specification )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n enum matchers to provide a strategy for naming objects created from enums.
        enums {
          enum_ {

            // Match unqualified or qualified enum names. If left empty, this matcher applies to all enums.
            expression = "MY_ENUM"

            // These elements influence the naming of a generated org.jooq.EnumType object.
            enumClass = MatcherRule. a MatcherRule specification 
            enumImplements = "com.example.MyOptionalCustomInterface"
            enumLiteral = MatcherRule. a MatcherRule specification 
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n enum matchers to provide a strategy for naming objects created from enums.
        enums {
          enum_ {

            // Match unqualified or qualified enum names. If left empty, this matcher applies to all enums.
            expression = "MY_ENUM"

            // These elements influence the naming of a generated org.jooq.EnumType object.
            enumClass = " a MatcherRule specification "
            enumImplements = "com.example.MyOptionalCustomInterface"
            enumLiteral = " a MatcherRule specification "
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-embeddables"></a>
##### 5.4.2.13. Matching embeddables

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.EmbeddableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EmbeddableRecord.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n embeddable matchers to provide a strategy for naming objects created from embeddables. -->
        <embeddables>
          <embeddable>

            <!-- Match unqualified or qualified embeddable names. If left empty, this matcher applies to all embeddables. -->
            <expression>MY_EMBEDDABLE</expression>

            <!-- These elements influence the naming of a generated org.jooq.EmbeddableRecord object. -->
            <recordClass> a MatcherRule specification </recordClass>
            <recordExtends>com.example.MyOptionalRoutineBaseType</recordExtends>
            <recordImplements>com.example.MyOptionalCustomInterface</recordImplements>

            <!-- These elements influence the naming of a generated interface, implemented by
                 generated org.jooq.EmbeddableRecord objects and by generated POJOs. -->
            <interfaceClass> a MatcherRule specification </interfaceClass>
            <interfaceImplements>com.example.MyOptionalCustomInterface</interfaceImplements>

            <!-- These elements influence the naming of a generated POJO object.  -->
            <pojoClass> a MatcherRule specification </pojoClass>
            <pojoExtends>com.example.MyOptionalCustomBaseClass</pojoExtends>
            <pojoImplements>com.example.MyOptionalCustomInterface</pojoImplements>
            
            <!-- Since 3.22.0 also: -->
            <tableMemberOverride>false</tableMemberOverride>
            <udtMemberOverride>false</udtMemberOverride>
          </embeddable>
        </embeddables>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n embeddable matchers to provide a strategy for naming objects created from embeddables.
        .withEmbeddables(
          new MatchersEmbeddableType()

            // Match unqualified or qualified embeddable names. If left empty, this matcher applies to all embeddables.
            .withExpression("MY_EMBEDDABLE")

            // These elements influence the naming of a generated org.jooq.EmbeddableRecord object.
            .withRecordClass(MatcherRule. a MatcherRule specification )
            .withRecordExtends("com.example.MyOptionalRoutineBaseType")
            .withRecordImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.EmbeddableRecord objects and by generated POJOs.
            .withInterfaceClass(MatcherRule. a MatcherRule specification )
            .withInterfaceImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated POJO object.
            .withPojoClass(MatcherRule. a MatcherRule specification )
            .withPojoExtends("com.example.MyOptionalCustomBaseClass")
            .withPojoImplements("com.example.MyOptionalCustomInterface")

            // Since 3.22.0 also:
            .withTableMemberOverride(false)
            .withUdtMemberOverride(false)
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n embeddable matchers to provide a strategy for naming objects created from embeddables.
        embeddables {
          embeddable {

            // Match unqualified or qualified embeddable names. If left empty, this matcher applies to all embeddables.
            expression = "MY_EMBEDDABLE"

            // These elements influence the naming of a generated org.jooq.EmbeddableRecord object.
            recordClass = MatcherRule. a MatcherRule specification 
            recordExtends = "com.example.MyOptionalRoutineBaseType"
            recordImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.EmbeddableRecord objects and by generated POJOs.
            interfaceClass = MatcherRule. a MatcherRule specification 
            interfaceImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated POJO object.
            pojoClass = MatcherRule. a MatcherRule specification 
            pojoExtends = "com.example.MyOptionalCustomBaseClass"
            pojoImplements = "com.example.MyOptionalCustomInterface"

            // Since 3.22.0 also:
            isTableMemberOverride = false
            isUdtMemberOverride = false
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n embeddable matchers to provide a strategy for naming objects created from embeddables.
        embeddables {
          embeddable {

            // Match unqualified or qualified embeddable names. If left empty, this matcher applies to all embeddables.
            expression = "MY_EMBEDDABLE"

            // These elements influence the naming of a generated org.jooq.EmbeddableRecord object.
            recordClass = " a MatcherRule specification "
            recordExtends = "com.example.MyOptionalRoutineBaseType"
            recordImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.EmbeddableRecord objects and by generated POJOs.
            interfaceClass = " a MatcherRule specification "
            interfaceImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated POJO object.
            pojoClass = " a MatcherRule specification "
            pojoExtends = "com.example.MyOptionalCustomBaseClass"
            pojoImplements = "com.example.MyOptionalCustomInterface"

            // Since 3.22.0 also:
            tableMemberOverride = false
            udtMemberOverride = false
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

> [!TIP]
> When using any `recordExtends`, etc. setting, you must make sure to correctly implement the internal jOOQ APIs, which are not documented here for they are internal. In particular, if you're extending [`org.jooq.impl.TableImpl`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/TableImpl.html), for example, your custom base class may break between minor versions of jOOQ, as new constructors are added.

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-udts"></a>
##### 5.4.2.14. Matching UDTs

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.UDT`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDT.html) and [`org.jooq.UDTRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDTRecord.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n table matchers to provide a strategy for naming objects created from UDTs. -->
        <udts>
          <udt>

            <!-- Match unqualified or qualified UDT names. If left empty, this matcher applies to all UDTs. -->
            <expression>MY_UDT</expression>

            <!-- These elements influence the naming of a generated org.jooq.UDT object. -->
            <udtClass> a MatcherRule specification </udtClass>
            <udtIdentifier> a MatcherRule specification </udtIdentifier>
            <udtExtends>com.example.MyOptionalTableBaseType</udtExtends>
            <udtImplements>com.example.MyOptionalCustomInterface</udtImplements>

            <!-- These elements influence the naming of a generated org.jooq.UDTPathField object. -->
            <pathClass> a MatcherRule specification </pathClass>
            <pathExtends>com.example.MyOptionalTableBaseType</pathExtends>
            <pathImplements>com.example.MyOptionalCustomInterface</pathImplements>

            <!-- These elements influence the naming of a generated org.jooq.UDTRecord object. -->
            <recordClass> a MatcherRule specification </recordClass>
            <recordExtends>com.example.MyOptionalRecordBaseType</recordExtends>
            <recordImplements>com.example.MyOptionalCustomInterface</recordImplements>

            <!-- These elements influence the naming of a generated record types for hierarchical org.jooq.UDTRecord object. -->
            <recordTypeClass> a MatcherRule specification </recordTypeClass>
            <recordTypeImplements>com.example.MyOptionalCustomInterface</recordTypeImplements>

            <!-- These elements influence the naming of a generated interface, implemented by
                 generated org.jooq.UDTRecord objects and by generated POJOs. -->
            <interfaceClass> a MatcherRule specification </interfaceClass>
            <interfaceImplements>com.example.MyOptionalCustomInterface</interfaceImplements>

            <!-- These elements influence the naming of a generated POJO object.  -->
            <pojoClass> a MatcherRule specification </pojoClass>
            <pojoExtends>com.example.MyOptionalPojoBaseClass</pojoExtends>
            <pojoImplements>com.example.MyOptionalCustomInterface</pojoImplements>
          </udt>
        </udts>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n table matchers to provide a strategy for naming objects created from UDTs.
        .withUdts(
          new MatchersUDTType()

            // Match unqualified or qualified UDT names. If left empty, this matcher applies to all UDTs.
            .withExpression("MY_UDT")

            // These elements influence the naming of a generated org.jooq.UDT object.
            .withUdtClass(MatcherRule. a MatcherRule specification )
            .withUdtIdentifier(MatcherRule. a MatcherRule specification )
            .withUdtExtends("com.example.MyOptionalTableBaseType")
            .withUdtImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated org.jooq.UDTPathField object.
            .withPathClass(MatcherRule. a MatcherRule specification )
            .withPathExtends("com.example.MyOptionalTableBaseType")
            .withPathImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated org.jooq.UDTRecord object.
            .withRecordClass(MatcherRule. a MatcherRule specification )
            .withRecordExtends("com.example.MyOptionalRecordBaseType")
            .withRecordImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated record types for hierarchical org.jooq.UDTRecord object.
            .withRecordTypeClass(MatcherRule. a MatcherRule specification )
            .withRecordTypeImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.UDTRecord objects and by generated POJOs.
            .withInterfaceClass(MatcherRule. a MatcherRule specification )
            .withInterfaceImplements("com.example.MyOptionalCustomInterface")

            // These elements influence the naming of a generated POJO object.
            .withPojoClass(MatcherRule. a MatcherRule specification )
            .withPojoExtends("com.example.MyOptionalPojoBaseClass")
            .withPojoImplements("com.example.MyOptionalCustomInterface")
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n table matchers to provide a strategy for naming objects created from UDTs.
        udts {
          udt {

            // Match unqualified or qualified UDT names. If left empty, this matcher applies to all UDTs.
            expression = "MY_UDT"

            // These elements influence the naming of a generated org.jooq.UDT object.
            udtClass = MatcherRule. a MatcherRule specification 
            udtIdentifier = MatcherRule. a MatcherRule specification 
            udtExtends = "com.example.MyOptionalTableBaseType"
            udtImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.UDTPathField object.
            pathClass = MatcherRule. a MatcherRule specification 
            pathExtends = "com.example.MyOptionalTableBaseType"
            pathImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.UDTRecord object.
            recordClass = MatcherRule. a MatcherRule specification 
            recordExtends = "com.example.MyOptionalRecordBaseType"
            recordImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated record types for hierarchical org.jooq.UDTRecord object.
            recordTypeClass = MatcherRule. a MatcherRule specification 
            recordTypeImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.UDTRecord objects and by generated POJOs.
            interfaceClass = MatcherRule. a MatcherRule specification 
            interfaceImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated POJO object.
            pojoClass = MatcherRule. a MatcherRule specification 
            pojoExtends = "com.example.MyOptionalPojoBaseClass"
            pojoImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n table matchers to provide a strategy for naming objects created from UDTs.
        udts {
          udt {

            // Match unqualified or qualified UDT names. If left empty, this matcher applies to all UDTs.
            expression = "MY_UDT"

            // These elements influence the naming of a generated org.jooq.UDT object.
            udtClass = " a MatcherRule specification "
            udtIdentifier = " a MatcherRule specification "
            udtExtends = "com.example.MyOptionalTableBaseType"
            udtImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.UDTPathField object.
            pathClass = " a MatcherRule specification "
            pathExtends = "com.example.MyOptionalTableBaseType"
            pathImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated org.jooq.UDTRecord object.
            recordClass = " a MatcherRule specification "
            recordExtends = "com.example.MyOptionalRecordBaseType"
            recordImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated record types for hierarchical org.jooq.UDTRecord object.
            recordTypeClass = " a MatcherRule specification "
            recordTypeImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated interface, implemented by
            // generated org.jooq.UDTRecord objects and by generated POJOs.
            interfaceClass = " a MatcherRule specification "
            interfaceImplements = "com.example.MyOptionalCustomInterface"

            // These elements influence the naming of a generated POJO object.
            pojoClass = " a MatcherRule specification "
            pojoExtends = "com.example.MyOptionalPojoBaseClass"
            pojoImplements = "com.example.MyOptionalCustomInterface"
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

> [!TIP]
> When using any `udtEtends`, `recordExtends`, etc. setting, you must make sure to correctly implement the internal jOOQ APIs, which are not documented here for they are internal. In particular, if you're extending [`org.jooq.impl.TableImpl`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/TableImpl.html), for example, your custom base class may break between minor versions of jOOQ, as new constructors are added.

> [!TIP]
> If your `UDTRecord`, POJO classes, or interfaces extend or implement other types, you can specify `override` modifiers to the respective [attributes](#codegen-matcher-attributes).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-attributes"></a>
##### 5.4.2.15. Matching attributes

The following example shows how to define a [MatcherStrategy](#codegen-matcherstrategy) for generated [`org.jooq.UDTField`](https://www.jooq.org/javadoc/3.22.x/org/jooq/UDTField.html) types and related objects:

**XML (standalone and maven):**

```xml
<configuration>
  <!-- These properties can be added directly to the generator element: -->
  <generator>
    <strategy>
      <matchers>

        <!-- Specify 0..n UDT attribute matchers to provide a strategy for naming objects created from UDT attributes. -->
        <attributes>
          <attribute>

            <!-- Match unqualified or qualified UDT attribute names. If left empty, this matcher applies to all UDT attributes. -->
            <expression>MY_FIELD</expression>

            <!-- These elements influence the naming of a generated org.jooq.UDTField object. -->
            <fieldIdentifier> a MatcherRule specification </fieldIdentifier>
            <fieldMember> a MatcherRule specification </fieldMember>
            <fieldSetter> a MatcherRule specification </fieldSetter>
            <fieldGetter> a MatcherRule specification </fieldGetter>
            <!-- Whether a method should have an override modifier, e.g. because of an implemented interface -->
            <recordSetterOverride>false</recordSetterOverride>
            <recordGetterOverride>false</recordGetterOverride>
            <recordMemberOverride>false</recordMemberOverride>
            <recordTypeSetterOverride>false</recordTypeSetterOverride>
            <recordTypeGetterOverride>false</recordTypeGetterOverride>
            <recordTypeMemberOverride>false</recordTypeMemberOverride>
            <interfaceSetterOverride>false</interfaceSetterOverride>
            <interfaceGetterOverride>false</interfaceGetterOverride>
            <interfaceMemberOverride>false</interfaceMemberOverride>
            <pojoSetterOverride>false</pojoSetterOverride>
            <pojoGetterOverride>false</pojoGetterOverride>
            <pojoMemberOverride>false</pojoMemberOverride>
          </attribute>
        </attributes>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()

  // These properties can be added directly to the generator element:
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()

        // Specify 0..n UDT attribute matchers to provide a strategy for naming objects created from UDT attributes.
        .withAttributes(
          new MatchersAttributeType()

            // Match unqualified or qualified UDT attribute names. If left empty, this matcher applies to all UDT attributes.
            .withExpression("MY_FIELD")

            // These elements influence the naming of a generated org.jooq.UDTField object.
            .withFieldIdentifier(" a MatcherRule specification ")
            .withFieldMember(" a MatcherRule specification ")
            .withFieldSetter(" a MatcherRule specification ")
            .withFieldGetter(" a MatcherRule specification ")

            // Whether a method should have an override modifier, e.g. because of an implemented interface
            .withRecordSetterOverride(false)
            .withRecordGetterOverride(false)
            .withRecordMemberOverride(false)
            .withRecordTypeSetterOverride(false)
            .withRecordTypeGetterOverride(false)
            .withRecordTypeMemberOverride(false)
            .withInterfaceSetterOverride(false)
            .withInterfaceGetterOverride(false)
            .withInterfaceMemberOverride(false)
            .withPojoSetterOverride(false)
            .withPojoGetterOverride(false)
            .withPojoMemberOverride(false)
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n UDT attribute matchers to provide a strategy for naming objects created from UDT attributes.
        attributes {
          attribute {

            // Match unqualified or qualified UDT attribute names. If left empty, this matcher applies to all UDT attributes.
            expression = "MY_FIELD"

            // These elements influence the naming of a generated org.jooq.UDTField object.
            fieldIdentifier = " a MatcherRule specification "
            fieldMember = " a MatcherRule specification "
            fieldSetter = " a MatcherRule specification "
            fieldGetter = " a MatcherRule specification "

            // Whether a method should have an override modifier, e.g. because of an implemented interface
            isRecordSetterOverride = false
            isRecordGetterOverride = false
            isRecordMemberOverride = false
            isRecordTypeSetterOverride = false
            isRecordTypeGetterOverride = false
            isRecordTypeMemberOverride = false
            isInterfaceSetterOverride = false
            isInterfaceGetterOverride = false
            isInterfaceMemberOverride = false
            isPojoSetterOverride = false
            isPojoGetterOverride = false
            isPojoMemberOverride = false
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {

  // These properties can be added directly to the generator element:
  generator {
    strategy {
      matchers {

        // Specify 0..n UDT attribute matchers to provide a strategy for naming objects created from UDT attributes.
        attributes {
          attribute {

            // Match unqualified or qualified UDT attribute names. If left empty, this matcher applies to all UDT attributes.
            expression = "MY_FIELD"

            // These elements influence the naming of a generated org.jooq.UDTField object.
            fieldIdentifier = " a MatcherRule specification "
            fieldMember = " a MatcherRule specification "
            fieldSetter = " a MatcherRule specification "
            fieldGetter = " a MatcherRule specification "

            // Whether a method should have an override modifier, e.g. because of an implemented interface
            recordSetterOverride = false
            recordGetterOverride = false
            recordMemberOverride = false
            recordTypeSetterOverride = false
            recordTypeGetterOverride = false
            recordTypeMemberOverride = false
            interfaceSetterOverride = false
            interfaceGetterOverride = false
            interfaceMemberOverride = false
            pojoSetterOverride = false
            pojoGetterOverride = false
            pojoMemberOverride = false
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

See [MatcherRule](#codegen-matcher-rule) for more information about `MatcherRule` specifications.

<a id="codegen-matcher-examples"></a>
##### 5.4.2.16. Matcher examples

The following example shows a matcher strategy that adds a `"T_"` prefix to all table classes and to table identifiers:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <strategy>
      <matchers>
        <tables>
          <table>

            <!-- Expression is omitted. This will make this rule apply to all tables -->
            <tableIdentifier>
              <transform>UPPER</transform>
              <expression>T_$0</expression>
            </tableIdentifier>
            <tableClass>
              <transform>PASCAL</transform>
              <expression>T_$0</expression>
            </tableClass>
          </table>
        </tables>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()
        .withTables(
          new MatchersTableType()

            // Expression is omitted. This will make this rule apply to all tables
            .withTableIdentifier(new MatcherRule()
              .withTransform(MatcherTransformType.UPPER)
              .withExpression("T_$0")
            )
            .withTableClass(new MatcherRule()
              .withTransform(MatcherTransformType.PASCAL)
              .withExpression("T_$0")
            )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    strategy {
      matchers {
        tables {
          table {

            // Expression is omitted. This will make this rule apply to all tables
            tableIdentifier {
              transform = MatcherTransformType.UPPER
              expression = "T_$0"
            }
            tableClass {
              transform = MatcherTransformType.PASCAL
              expression = "T_$0"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    strategy {
      matchers {
        tables {
          table {

            // Expression is omitted. This will make this rule apply to all tables
            tableIdentifier {
              transform = "UPPER"
              expression = "T_$0"
            }
            tableClass {
              transform = "PASCAL"
              expression = "T_$0"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

The following example shows a matcher strategy that renames BOOK table identifiers (or table identifiers containing BOOK) into BROCHURE (or tables containing BROCHURE):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <strategy>
      <matchers>
        <tables>
          <table>
            <expression>^(.*?)_BOOK_(.*)$</expression>
            <tableIdentifier>
              <transform>UPPER</transform>
              <expression>$1_BROCHURE_$2</expression>
            </tableIdentifier>
          </table>
        </tables>
      </matchers>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withMatchers(new Matchers()
        .withTables(
          new MatchersTableType()
            .withExpression("^(.*?)_BOOK_(.*)$")
            .withTableIdentifier(new MatcherRule()
              .withTransform(MatcherTransformType.UPPER)
              .withExpression("$1_BROCHURE_$2")
            )
        )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    strategy {
      matchers {
        tables {
          table {
            expression = "^(.*?)_BOOK_(.*)$"
            tableIdentifier {
              transform = MatcherTransformType.UPPER
              expression = "$1_BROCHURE_$2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    strategy {
      matchers {
        tables {
          table {
            expression = "^(.*?)_BOOK_(.*)$"
            tableIdentifier {
              transform = "UPPER"
              expression = "$1_BROCHURE_$2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

For more information about each XML tag, please refer to the [https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) XSD file.

<a id="codegen-custom-code"></a>
### 5.5. Custom code sections

Power users might choose to re-implement large parts of the `org.jooq.codegen.JavaGenerator` class. If you only want to add some custom code sections, however, you can extend the `JavaGenerator` and override only parts of it.

#### An example for generating custom class footers

```java
public class MyGenerator1 extends JavaGenerator {

    @Override
    protected void generateRecordClassFooter(TableDefinition table, JavaWriter out) {
        out.println();
        out.tab(1).println("public String toString() {");
        out.tab(2).println("return \"MyRecord[\" + valuesRow() + \"]\";");
        out.tab(1).println("}");
    }
}
```

The above example simply adds a class footer to [generated records](#codegen-records), in this case, overriding the default `toString()` implementation.

#### An example for generating custom class Javadoc

```java
public class MyGenerator2 extends JavaGenerator {

    @Override
    protected void generateRecordClassJavadoc(TableDefinition table, JavaWriter out) {
        out.println("/**");
        out.println(" * This record belongs to table " + table.getOutputName() + ".");

        if (table.getComment() != null && !"".equals(table.getComment())) {
            out.println(" * <p>");
            out.println(" * Table comment: " + table.getComment());
        }

        out.println(" */");
    }
}
```

Any of the below methods can be overridden:

```java
generateArray(SchemaDefinition, ArrayDefinition)           // Generates an Oracle array class
generateArrayClassFooter(ArrayDefinition, JavaWriter)      // Callback for an Oracle array class footer
generateArrayClassJavadoc(ArrayDefinition, JavaWriter)     // Callback for an Oracle array class Javadoc

generateDao(TableDefinition)                               // Generates a DAO class
generateDaoClassFooter(TableDefinition, JavaWriter)        // Callback for a DAO class footer
generateDaoClassJavadoc(TableDefinition, JavaWriter)       // Callback for a DAO class Javadoc

generateEnum(EnumDefinition)                               // Generates an enum
generateEnumClassFooter(EnumDefinition, JavaWriter)        // Callback for an enum footer
generateEnumClassJavadoc(EnumDefinition, JavaWriter)       // Callback for an enum Javadoc

generateInterface(TableDefinition)                         // Generates an interface
generateInterfaceClassFooter(TableDefinition, JavaWriter)  // Callback for an interface footer
generateInterfaceClassJavadoc(TableDefinition, JavaWriter) // Callback for an interface Javadoc

generatePackage(SchemaDefinition, PackageDefinition)       // Generates an Oracle package class
generatePackageClassFooter(PackageDefinition, JavaWriter)  // Callback for an Oracle package class footer
generatePackageClassJavadoc(PackageDefinition, JavaWriter) // Callback for an Oracle package class Javadoc

generatePojo(TableDefinition)                              // Generates a POJO class
generatePojoClassFooter(TableDefinition, JavaWriter)       // Callback for a POJO class footer
generatePojoClassJavadoc(TableDefinition, JavaWriter)      // Callback for a POJO class Javadoc

generateRecord(TableDefinition)                            // Generates a Record class
generateRecordClassFooter(TableDefinition, JavaWriter)     // Callback for a Record class footer
generateRecordClassJavadoc(TableDefinition, JavaWriter)    // Callback for a Record class Javadoc

generateRoutine(SchemaDefinition, RoutineDefinition)       // Generates a Routine class
generateRoutineClassFooter(RoutineDefinition, JavaWriter)  // Callback for a Routine class footer
generateRoutineClassJavadoc(RoutineDefinition, JavaWriter) // Callback for a Routine class Javadoc

generateCatalog(CatalogDefinition)                         // Generates a Catalog class
generateCatalogClassFooter(CatalogDefinition, JavaWriter)  // Callback for a Catalog class footer
generateCatalogClassJavadoc(CatalogDefinition, JavaWriter) // Callback for a Catalog class Javadoc

generateSchema(SchemaDefinition)                           // Generates a Schema class
generateSchemaClassFooter(SchemaDefinition, JavaWriter)    // Callback for a Schema class footer
generateSchemaClassJavadoc(SchemaDefinition, JavaWriter)   // Callback for a Schema class Javadoc

generateTable(SchemaDefinition, TableDefinition)           // Generates a Table class
generateTableClassFooter(TableDefinition, JavaWriter)      // Callback for a Table class footer
generateTableClassJavadoc(TableDefinition, JavaWriter)     // Callback for a Table class Javadoc

generateUDT(SchemaDefinition, UDTDefinition)               // Generates a UDT class
generateUDTClassFooter(UDTDefinition, JavaWriter)          // Callback for a UDT class footer
generateUDTClassJavadoc(UDTDefinition, JavaWriter)         // Callback for a UDT class Javadoc

generateUDTRecord(UDTDefinition)                           // Generates a UDT Record class
generateUDTRecordClassFooter(UDTDefinition, JavaWriter)    // Callback for a UDT Record class footer
generateUDTRecordClassJavadoc(UDTDefinition, JavaWriter)   // Callback for a UDT Record class Javadoc
```

When you override any of the above, do note that according to [jOOQ's understanding of semantic versioning](#semantic-versioning), incompatible changes may be introduced between minor releases, even if this should be the exception.

> [!TIP]
> Make sure your custom generator and its dependencies are available to the code generator as a [code generator dependency](#codegen-dependencies)

<a id="codegen-extensions"></a>
### 5.6. Code generation extensions

jOOQ has SPIs to support custom data types via [converters](#codegen-database-forced-types-converter) or [bindings](#codegen-database-forced-types-binding), which can be hand-written and attached to generated code using code generation configuration.

For some dialects and some of their more popular data types, jOOQ also supports opt-in extensions. The following subsections document these extensions:

<a id="codegen-extension-postgres"></a>
#### 5.6.1. PostgreSQL extensions

The `jooq-postgres-extensions` module contains data types, converters, and bindings for the following data types:

- The [cidr](#extended-type-pg-cidr) type is for IPv4 and IPv6 networks.
- The [citext](#extended-type-pg-citext) type is "case insensitive text".
- The [daterange](#extended-type-pg-daterange) type is a date range type. Depending on the [javaTimeTypes](#codegen-generate-java-time-types) configuration, this translates to [`java.sql.Date`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Date.html) or [`java.time.LocalDate`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDate.html) ranges.
- The [hstore](#extended-type-pg-hstore) type is a key-value store (i.e. a `Map<String, String>`).
- The [inet](#extended-type-pg-inet) type is for IPv4 and IPv6 hosts and networks.
- The [int4range](#extended-type-pg-int4range) type is a 32 bit integer range type.
- The [int8range](#extended-type-pg-int8range) type is a 64 bit integer range type.
- The [ltree](#extended-type-pg-ltree) type is a label tree data structure.
- The [numrange](#extended-type-pg-numrange) type is a numeric range type.
- The [tsrange](#extended-type-pg-tsrange) type is a timestamp range type. Depending on the [javaTimeTypes](#codegen-generate-java-time-types) configuration, this translates to [`java.sql.Timestamp`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/Timestamp.html) or [`java.time.LocalDateTime`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/time/LocalDateTime.html) ranges.
- The [tstzrange](#extended-type-pg-tstzrange) type is a timestamptz range type.

In order to access these data types, just add the following dependency to your project:

**Maven:**

```xml
<dependency>
                <!-- Use org.jooq                for the Open Source Edition
                         org.jooq.pro            for commercial editions with Java 25 support,
                         org.jooq.pro-java-21    for commercial editions with Java 21 support,
                         org.jooq.pro-java-17    for commercial editions with Java 17 support,
                         org.jooq.pro-java-11    for commercial editions with Java 11 support,
                         org.jooq.pro-java-8     for commercial editions with Java 8 support,
                         org.jooq.trial          for the free trial edition with Java 25 support,
                         org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                         org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                         org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                         org.jooq.trial-java-8   for the free trial edition with Java 8 support
    
                 Note: Only the Open Source Edition is hosted on Maven Central.
                       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

    <groupId>org.jooq</groupId>
    <artifactId>jooq-postgres-extensions</artifactId>
    <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation("org.jooq:jooq-postgres-extensions:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    implementation "org.jooq:jooq-postgres-extensions:3.22.0-SNAPSHOT"
}
```

Starting with jOOQ 3.17, the code generator will auto-register the following [forced types](#codegen-database-forced-types), if it finds the `jooq-postgres-extensions` module on the classpath. These types are registered with lowest priority, such that custom forced types will take precedence:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.BigDecimalRange</userType>
          <binding>org.jooq.postgres.extensions.bindings.BigDecimalRangeBinding</binding>
          <includeTypes>numrange</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.BigDecimalRange[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.BigDecimalRangeArrayBinding</binding>
          <includeTypes>_numrange</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.Cidr</userType>
          <binding>org.jooq.postgres.extensions.bindings.CidrBinding</binding>
          <includeTypes>cidr</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.Cidr[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.CidrArrayBinding</binding>
          <includeTypes>_cidr</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>java.lang.String</userType>
          <binding>org.jooq.postgres.extensions.bindings.CitextBinding</binding>
          <includeTypes>citext</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>java.lang.String[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.CitextArrayBinding</binding>
          <includeTypes>_citext</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.Hstore</userType>
          <binding>org.jooq.postgres.extensions.bindings.HstoreBinding</binding>
          <includeTypes>hstore</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.Hstore[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.HstoreArrayBinding</binding>
          <includeTypes>_hstore</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.Inet</userType>
          <binding>org.jooq.postgres.extensions.bindings.InetBinding</binding>
          <includeTypes>inet</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.Inet[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.InetArrayBinding</binding>
          <includeTypes>_inet</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.IntegerRange</userType>
          <binding>org.jooq.postgres.extensions.bindings.IntegerRangeBinding</binding>
          <includeTypes>int4range</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.IntegerRange[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.IntegerRangeArrayBinding</binding>
          <includeTypes>_int4range</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>

        <!-- Depending on <javaTimeTypes/>, this may map to DateRange instead -->
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.LocalDateRange</userType>
          <binding>org.jooq.postgres.extensions.bindings.LocalDateRangeBinding</binding>
          <includeTypes>daterange</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>

        <!-- Depending on <javaTimeTypes/>, this may map to DateRange[] instead -->
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.LocalDateRange[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.LocalDateRangeArrayBinding</binding>
          <includeTypes>_daterange</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>

        <!-- Depending on <javaTimeTypes/>, this may map to TimestampRange instead -->
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.LocalDateTimeRange</userType>
          <binding>org.jooq.postgres.extensions.bindings.LocalDateTimeRangeBinding</binding>
          <includeTypes>tsrange</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>

        <!-- Depending on <javaTimeTypes/>, this may map to TimestampRange[] instead -->
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.LocalDateTimeRange[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.LocalDateTimeRangeArrayBinding</binding>
          <includeTypes>_tsrange</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.LongRange</userType>
          <binding>org.jooq.postgres.extensions.bindings.LongRangeBinding</binding>
          <includeTypes>int8range</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.LongRange[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.LongRangeArrayBinding</binding>
          <includeTypes>_int8range</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.Ltree</userType>
          <binding>org.jooq.postgres.extensions.bindings.LtreeBinding</binding>
          <includeTypes>ltree</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.Ltree[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.LtreeArrayBinding</binding>
          <includeTypes>_ltree</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.OffsetDateTimeRange</userType>
          <binding>org.jooq.postgres.extensions.bindings.OffsetDateTimeRangeBinding</binding>
          <includeTypes>tstzrange</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
        <forcedType>
          <userType>org.jooq.postgres.extensions.types.OffsetDateTimeRange[]</userType>
          <binding>org.jooq.postgres.extensions.bindings.OffsetDateTimeRangeArrayBinding</binding>
          <includeTypes>_tstzrange</includeTypes>
          <priority>-2147483648</priority>
        </forcedType>
      </forcedTypes>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withForcedTypes(
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.BigDecimalRange")
          .withBinding("org.jooq.postgres.extensions.bindings.BigDecimalRangeBinding")
          .withIncludeTypes("numrange")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.BigDecimalRange[]")
          .withBinding("org.jooq.postgres.extensions.bindings.BigDecimalRangeArrayBinding")
          .withIncludeTypes("_numrange")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.Cidr")
          .withBinding("org.jooq.postgres.extensions.bindings.CidrBinding")
          .withIncludeTypes("cidr")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.Cidr[]")
          .withBinding("org.jooq.postgres.extensions.bindings.CidrArrayBinding")
          .withIncludeTypes("_cidr")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("java.lang.String")
          .withBinding("org.jooq.postgres.extensions.bindings.CitextBinding")
          .withIncludeTypes("citext")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("java.lang.String[]")
          .withBinding("org.jooq.postgres.extensions.bindings.CitextArrayBinding")
          .withIncludeTypes("_citext")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.Hstore")
          .withBinding("org.jooq.postgres.extensions.bindings.HstoreBinding")
          .withIncludeTypes("hstore")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.Hstore[]")
          .withBinding("org.jooq.postgres.extensions.bindings.HstoreArrayBinding")
          .withIncludeTypes("_hstore")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.Inet")
          .withBinding("org.jooq.postgres.extensions.bindings.InetBinding")
          .withIncludeTypes("inet")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.Inet[]")
          .withBinding("org.jooq.postgres.extensions.bindings.InetArrayBinding")
          .withIncludeTypes("_inet")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.IntegerRange")
          .withBinding("org.jooq.postgres.extensions.bindings.IntegerRangeBinding")
          .withIncludeTypes("int4range")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.IntegerRange[]")
          .withBinding("org.jooq.postgres.extensions.bindings.IntegerRangeArrayBinding")
          .withIncludeTypes("_int4range")
          .withPriority("-2147483648"),

        // Depending on <javaTimeTypes/>, this may map to DateRange instead
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.LocalDateRange")
          .withBinding("org.jooq.postgres.extensions.bindings.LocalDateRangeBinding")
          .withIncludeTypes("daterange")
          .withPriority("-2147483648"),

        // Depending on <javaTimeTypes/>, this may map to DateRange[] instead
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.LocalDateRange[]")
          .withBinding("org.jooq.postgres.extensions.bindings.LocalDateRangeArrayBinding")
          .withIncludeTypes("_daterange")
          .withPriority("-2147483648"),

        // Depending on <javaTimeTypes/>, this may map to TimestampRange instead
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.LocalDateTimeRange")
          .withBinding("org.jooq.postgres.extensions.bindings.LocalDateTimeRangeBinding")
          .withIncludeTypes("tsrange")
          .withPriority("-2147483648"),

        // Depending on <javaTimeTypes/>, this may map to TimestampRange[] instead
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.LocalDateTimeRange[]")
          .withBinding("org.jooq.postgres.extensions.bindings.LocalDateTimeRangeArrayBinding")
          .withIncludeTypes("_tsrange")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.LongRange")
          .withBinding("org.jooq.postgres.extensions.bindings.LongRangeBinding")
          .withIncludeTypes("int8range")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.LongRange[]")
          .withBinding("org.jooq.postgres.extensions.bindings.LongRangeArrayBinding")
          .withIncludeTypes("_int8range")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.Ltree")
          .withBinding("org.jooq.postgres.extensions.bindings.LtreeBinding")
          .withIncludeTypes("ltree")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.Ltree[]")
          .withBinding("org.jooq.postgres.extensions.bindings.LtreeArrayBinding")
          .withIncludeTypes("_ltree")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.OffsetDateTimeRange")
          .withBinding("org.jooq.postgres.extensions.bindings.OffsetDateTimeRangeBinding")
          .withIncludeTypes("tstzrange")
          .withPriority("-2147483648"),
        new ForcedType()
          .withUserType("org.jooq.postgres.extensions.types.OffsetDateTimeRange[]")
          .withBinding("org.jooq.postgres.extensions.bindings.OffsetDateTimeRangeArrayBinding")
          .withIncludeTypes("_tstzrange")
          .withPriority("-2147483648")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      forcedTypes {
        forcedType {
          userType = "org.jooq.postgres.extensions.types.BigDecimalRange"
          binding = "org.jooq.postgres.extensions.bindings.BigDecimalRangeBinding"
          includeTypes = "numrange"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.BigDecimalRange[]"
          binding = "org.jooq.postgres.extensions.bindings.BigDecimalRangeArrayBinding"
          includeTypes = "_numrange"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Cidr"
          binding = "org.jooq.postgres.extensions.bindings.CidrBinding"
          includeTypes = "cidr"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Cidr[]"
          binding = "org.jooq.postgres.extensions.bindings.CidrArrayBinding"
          includeTypes = "_cidr"
          priority = "-2147483648"
        }
        forcedType {
          userType = "java.lang.String"
          binding = "org.jooq.postgres.extensions.bindings.CitextBinding"
          includeTypes = "citext"
          priority = "-2147483648"
        }
        forcedType {
          userType = "java.lang.String[]"
          binding = "org.jooq.postgres.extensions.bindings.CitextArrayBinding"
          includeTypes = "_citext"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Hstore"
          binding = "org.jooq.postgres.extensions.bindings.HstoreBinding"
          includeTypes = "hstore"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Hstore[]"
          binding = "org.jooq.postgres.extensions.bindings.HstoreArrayBinding"
          includeTypes = "_hstore"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Inet"
          binding = "org.jooq.postgres.extensions.bindings.InetBinding"
          includeTypes = "inet"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Inet[]"
          binding = "org.jooq.postgres.extensions.bindings.InetArrayBinding"
          includeTypes = "_inet"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.IntegerRange"
          binding = "org.jooq.postgres.extensions.bindings.IntegerRangeBinding"
          includeTypes = "int4range"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.IntegerRange[]"
          binding = "org.jooq.postgres.extensions.bindings.IntegerRangeArrayBinding"
          includeTypes = "_int4range"
          priority = "-2147483648"
        }

        // Depending on <javaTimeTypes/>, this may map to DateRange instead
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LocalDateRange"
          binding = "org.jooq.postgres.extensions.bindings.LocalDateRangeBinding"
          includeTypes = "daterange"
          priority = "-2147483648"
        }

        // Depending on <javaTimeTypes/>, this may map to DateRange[] instead
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LocalDateRange[]"
          binding = "org.jooq.postgres.extensions.bindings.LocalDateRangeArrayBinding"
          includeTypes = "_daterange"
          priority = "-2147483648"
        }

        // Depending on <javaTimeTypes/>, this may map to TimestampRange instead
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LocalDateTimeRange"
          binding = "org.jooq.postgres.extensions.bindings.LocalDateTimeRangeBinding"
          includeTypes = "tsrange"
          priority = "-2147483648"
        }

        // Depending on <javaTimeTypes/>, this may map to TimestampRange[] instead
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LocalDateTimeRange[]"
          binding = "org.jooq.postgres.extensions.bindings.LocalDateTimeRangeArrayBinding"
          includeTypes = "_tsrange"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LongRange"
          binding = "org.jooq.postgres.extensions.bindings.LongRangeBinding"
          includeTypes = "int8range"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LongRange[]"
          binding = "org.jooq.postgres.extensions.bindings.LongRangeArrayBinding"
          includeTypes = "_int8range"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Ltree"
          binding = "org.jooq.postgres.extensions.bindings.LtreeBinding"
          includeTypes = "ltree"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Ltree[]"
          binding = "org.jooq.postgres.extensions.bindings.LtreeArrayBinding"
          includeTypes = "_ltree"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.OffsetDateTimeRange"
          binding = "org.jooq.postgres.extensions.bindings.OffsetDateTimeRangeBinding"
          includeTypes = "tstzrange"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.OffsetDateTimeRange[]"
          binding = "org.jooq.postgres.extensions.bindings.OffsetDateTimeRangeArrayBinding"
          includeTypes = "_tstzrange"
          priority = "-2147483648"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      forcedTypes {
        forcedType {
          userType = "org.jooq.postgres.extensions.types.BigDecimalRange"
          binding = "org.jooq.postgres.extensions.bindings.BigDecimalRangeBinding"
          includeTypes = "numrange"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.BigDecimalRange[]"
          binding = "org.jooq.postgres.extensions.bindings.BigDecimalRangeArrayBinding"
          includeTypes = "_numrange"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Cidr"
          binding = "org.jooq.postgres.extensions.bindings.CidrBinding"
          includeTypes = "cidr"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Cidr[]"
          binding = "org.jooq.postgres.extensions.bindings.CidrArrayBinding"
          includeTypes = "_cidr"
          priority = "-2147483648"
        }
        forcedType {
          userType = "java.lang.String"
          binding = "org.jooq.postgres.extensions.bindings.CitextBinding"
          includeTypes = "citext"
          priority = "-2147483648"
        }
        forcedType {
          userType = "java.lang.String[]"
          binding = "org.jooq.postgres.extensions.bindings.CitextArrayBinding"
          includeTypes = "_citext"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Hstore"
          binding = "org.jooq.postgres.extensions.bindings.HstoreBinding"
          includeTypes = "hstore"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Hstore[]"
          binding = "org.jooq.postgres.extensions.bindings.HstoreArrayBinding"
          includeTypes = "_hstore"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Inet"
          binding = "org.jooq.postgres.extensions.bindings.InetBinding"
          includeTypes = "inet"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Inet[]"
          binding = "org.jooq.postgres.extensions.bindings.InetArrayBinding"
          includeTypes = "_inet"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.IntegerRange"
          binding = "org.jooq.postgres.extensions.bindings.IntegerRangeBinding"
          includeTypes = "int4range"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.IntegerRange[]"
          binding = "org.jooq.postgres.extensions.bindings.IntegerRangeArrayBinding"
          includeTypes = "_int4range"
          priority = "-2147483648"
        }

        // Depending on <javaTimeTypes/>, this may map to DateRange instead
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LocalDateRange"
          binding = "org.jooq.postgres.extensions.bindings.LocalDateRangeBinding"
          includeTypes = "daterange"
          priority = "-2147483648"
        }

        // Depending on <javaTimeTypes/>, this may map to DateRange[] instead
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LocalDateRange[]"
          binding = "org.jooq.postgres.extensions.bindings.LocalDateRangeArrayBinding"
          includeTypes = "_daterange"
          priority = "-2147483648"
        }

        // Depending on <javaTimeTypes/>, this may map to TimestampRange instead
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LocalDateTimeRange"
          binding = "org.jooq.postgres.extensions.bindings.LocalDateTimeRangeBinding"
          includeTypes = "tsrange"
          priority = "-2147483648"
        }

        // Depending on <javaTimeTypes/>, this may map to TimestampRange[] instead
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LocalDateTimeRange[]"
          binding = "org.jooq.postgres.extensions.bindings.LocalDateTimeRangeArrayBinding"
          includeTypes = "_tsrange"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LongRange"
          binding = "org.jooq.postgres.extensions.bindings.LongRangeBinding"
          includeTypes = "int8range"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.LongRange[]"
          binding = "org.jooq.postgres.extensions.bindings.LongRangeArrayBinding"
          includeTypes = "_int8range"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Ltree"
          binding = "org.jooq.postgres.extensions.bindings.LtreeBinding"
          includeTypes = "ltree"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.Ltree[]"
          binding = "org.jooq.postgres.extensions.bindings.LtreeArrayBinding"
          includeTypes = "_ltree"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.OffsetDateTimeRange"
          binding = "org.jooq.postgres.extensions.bindings.OffsetDateTimeRangeBinding"
          includeTypes = "tstzrange"
          priority = "-2147483648"
        }
        forcedType {
          userType = "org.jooq.postgres.extensions.types.OffsetDateTimeRange[]"
          binding = "org.jooq.postgres.extensions.bindings.OffsetDateTimeRangeArrayBinding"
          includeTypes = "_tstzrange"
          priority = "-2147483648"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-embeddable-types"></a>
### 5.7. Embeddable types

Only few SQL databases support ORDBMS extensions, such as [user-defined types](#codegen-udts) (UDTs). When working with strong domain semantics, it is often desired to wrap the primitive, technical database type (e.g. `VARCHAR`) in a more semantic type (e.g. `com.example.Email`).

Embeddable types are generated, synthetic data types that wrap one or more database columns in a generated [`org.jooq.EmbeddableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EmbeddableRecord.html), as if the column group were an actual UDT.

This is particularly useful for [embedded keys](#codegen-embedded-keys), to help with type safe comparison between `PRIMARY KEY` / `FOREIGN KEY` columns, specifically when the keys are composite keys.

Embeddable types are a very complex feature that has been added to jOOQ 3.14. A list of known issues for embeddable types is available here: [#10527](https://github.com/jOOQ/jOOQ/issues/10527).

<a id="codegen-embeddable-types-configuration"></a>
#### 5.7.1. Configuration

Embeddable types can be specified in the code generator configuration as follows:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>

      <!-- For each type, one embeddable entry is required -->
      <embeddables>
        <embeddable>

          <!-- The optional catalog of the embeddable type (the catalog of the first matched table if left empty) -->
          <catalog/>

          <!-- The optional schema of the embeddable type (the schema of the first matched table if left empty) -->
          <schema>PUBLIC</schema>

          <!-- The name of the embeddable type -->
          <name>AUDIT</name>

          <!-- An optional, defining comment of an embeddable -->
          <comment>An audit record containing common audit fields.</comment>

          <!-- The name of the reference to the embeddable type. Defaults to <name/> if left blank -->
          <referencingName>AUDIT_REFERENCE</referencingName>

          <!-- An optional, referencing comment of an embeddable. Defaults to <comment/> if left blank -->
          <referencingComment>An audit record containing common audit fields.</referencingComment>

          <!-- A regular expression matching qualified or unqualified table names to which to apply this embeddable specification
               If left blank, this will apply to all tables -->
          <tables>.*</tables>

          <!-- A list of fields to match to an embeddable's attributes. Each field must match exactly one column in each matched table.
               A mandatory regular expression matches field names, whereas an optional name can be provided to define the embeddable
               attribute name. If no name is provided, then the first matched field's name will be taken -->
          <fields>
            <field><expression>CREATED_AT</expression></field>
            <field><expression>CREATED_BY</expression></field>
            <field><name>MODIFIED_AT</name><expression>MODIFIED_AT|CHANGED_AT</expression></field>
            <field><name>MODIFIED_BY</name><expression>MODIFIED_BY|CHANGED_BY</expression></field>
          </fields>

          <!-- Set this flag to true if no warning should be logged if two references to this embeddable don't match
               exactly in their column types (e.g. length, precision, scale, user type, converter, binding). Defaults to false -->
          <ignoreTypeMismatch>false</ignoreTypeMismatch>
        </embeddable>

        <!-- A more minimal configuration might look like this -->
        <embeddable>
          <name>MONETARY_AMOUNT</name>
          <fields>
            <field><expression>AMOUNT</expression></field>
            <field><expression>CURRENCY</expression></field>
          </fields>
        </embeddable>
      </embeddables>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // For each type, one embeddable entry is required
      .withEmbeddables(
        new EmbeddableDefinitionType()

          // The optional catalog of the embeddable type (the catalog of the first matched table if left empty)
          .withCatalog("")

          // The optional schema of the embeddable type (the schema of the first matched table if left empty)
          .withSchema("PUBLIC")

          // The name of the embeddable type
          .withName("AUDIT")

          // An optional, defining comment of an embeddable
          .withComment("An audit record containing common audit fields.")

          // The name of the reference to the embeddable type. Defaults to <name/> if left blank
          .withReferencingName("AUDIT_REFERENCE")

          // An optional, referencing comment of an embeddable. Defaults to <comment/> if left blank
          .withReferencingComment("An audit record containing common audit fields.")

          // A regular expression matching qualified or unqualified table names to which to apply this embeddable specification
          // If left blank, this will apply to all tables
          .withTables(".*")

          // A list of fields to match to an embeddable's attributes. Each field must match exactly one column in each matched table.
          // A mandatory regular expression matches field names, whereas an optional name can be provided to define the embeddable
          // attribute name. If no name is provided, then the first matched field's name will be taken
          .withFields(
            new EmbeddableField()
              .withExpression("CREATED_AT"),
            new EmbeddableField()
              .withExpression("CREATED_BY"),
            new EmbeddableField()
              .withName("MODIFIED_AT")
              .withExpression("MODIFIED_AT|CHANGED_AT"),
            new EmbeddableField()
              .withName("MODIFIED_BY")
              .withExpression("MODIFIED_BY|CHANGED_BY")
          )

          // Set this flag to true if no warning should be logged if two references to this embeddable don't match
          // exactly in their column types (e.g. length, precision, scale, user type, converter, binding). Defaults to false
          .withIgnoreTypeMismatch(false),

        // A more minimal configuration might look like this
        new EmbeddableDefinitionType()
          .withName("MONETARY_AMOUNT")
          .withFields(
            new EmbeddableField()
              .withExpression("AMOUNT"),
            new EmbeddableField()
              .withExpression("CURRENCY")
          )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {

      // For each type, one embeddable entry is required
      embeddables {
        embeddable {

          // The optional catalog of the embeddable type (the catalog of the first matched table if left empty)
          catalog = ""

          // The optional schema of the embeddable type (the schema of the first matched table if left empty)
          schema = "PUBLIC"

          // The name of the embeddable type
          name = "AUDIT"

          // An optional, defining comment of an embeddable
          comment = "An audit record containing common audit fields."

          // The name of the reference to the embeddable type. Defaults to <name/> if left blank
          referencingName = "AUDIT_REFERENCE"

          // An optional, referencing comment of an embeddable. Defaults to <comment/> if left blank
          referencingComment = "An audit record containing common audit fields."

          // A regular expression matching qualified or unqualified table names to which to apply this embeddable specification
          // If left blank, this will apply to all tables
          tables = ".*"

          // A list of fields to match to an embeddable's attributes. Each field must match exactly one column in each matched table.
          // A mandatory regular expression matches field names, whereas an optional name can be provided to define the embeddable
          // attribute name. If no name is provided, then the first matched field's name will be taken
          fields {
            field {
              expression = "CREATED_AT"
            }
            field {
              expression = "CREATED_BY"
            }
            field {
              name = "MODIFIED_AT"
              expression = "MODIFIED_AT|CHANGED_AT"
            }
            field {
              name = "MODIFIED_BY"
              expression = "MODIFIED_BY|CHANGED_BY"
            }
          }

          // Set this flag to true if no warning should be logged if two references to this embeddable don't match
          // exactly in their column types (e.g. length, precision, scale, user type, converter, binding). Defaults to false
          isIgnoreTypeMismatch = false
        }

        // A more minimal configuration might look like this
        embeddable {
          name = "MONETARY_AMOUNT"
          fields {
            field {
              expression = "AMOUNT"
            }
            field {
              expression = "CURRENCY"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {

      // For each type, one embeddable entry is required
      embeddables {
        embeddable {

          // The optional catalog of the embeddable type (the catalog of the first matched table if left empty)
          catalog {}

          // The optional schema of the embeddable type (the schema of the first matched table if left empty)
          schema = "PUBLIC"

          // The name of the embeddable type
          name = "AUDIT"

          // An optional, defining comment of an embeddable
          comment = "An audit record containing common audit fields."

          // The name of the reference to the embeddable type. Defaults to <name/> if left blank
          referencingName = "AUDIT_REFERENCE"

          // An optional, referencing comment of an embeddable. Defaults to <comment/> if left blank
          referencingComment = "An audit record containing common audit fields."

          // A regular expression matching qualified or unqualified table names to which to apply this embeddable specification
          // If left blank, this will apply to all tables
          tables = ".*"

          // A list of fields to match to an embeddable's attributes. Each field must match exactly one column in each matched table.
          // A mandatory regular expression matches field names, whereas an optional name can be provided to define the embeddable
          // attribute name. If no name is provided, then the first matched field's name will be taken
          fields {
            field {
              expression = "CREATED_AT"
            }
            field {
              expression = "CREATED_BY"
            }
            field {
              name = "MODIFIED_AT"
              expression = "MODIFIED_AT|CHANGED_AT"
            }
            field {
              name = "MODIFIED_BY"
              expression = "MODIFIED_BY|CHANGED_BY"
            }
          }

          // Set this flag to true if no warning should be logged if two references to this embeddable don't match
          // exactly in their column types (e.g. length, precision, scale, user type, converter, binding). Defaults to false
          ignoreTypeMismatch = false
        }

        // A more minimal configuration might look like this
        embeddable {
          name = "MONETARY_AMOUNT"
          fields {
            field {
              expression = "AMOUNT"
            }
            field {
              expression = "CURRENCY"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

The previous configuration, if matched correctly against relevant tables, produces the following [`org.jooq.EmbeddableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EmbeddableRecord.html) implementations (abbreviated):

```java
public class AuditRecord extends EmbeddableRecordImpl<AuditRecord> {
    public AuditRecord(Timestamp createdAt, Timestamp modifiedAt, String createdBy, String modifiedBy) { /* ... */ }

    // Getters, setters
}
```

```java
public class MonetaryAmountRecord extends EmbeddableRecordImpl<MonetaryAmountRecord> {
    public MonetaryAmountRecord(BigDecimal amount, String currency) { /* ... */ }

    // Getters, setters
}
```

Assuming we have a `TRANSACTIONS` table like this:

```sql
CREATE TABLE transactions (
  id BIGINT NOT NULL PRIMARY KEY,
  created_at TIMESTAMP NOT NULL,
  modified_at TIMESTAMP,
  created_by VARCHAR(100) NOT NULL,
  modified_by VARCHAR(100) NOT NULL,

  -- Other columns here
  amount DECIMAL(18, 2) NOT NULL,
  currency VARCHAR(10) NOT NULL
);
```

With the previous embeddable type definitions, we would get a table that looks like this:

```java
public class Transactions extends TableImpl<TransactionsRecord> {
    // Field initialisations omitted for simplicity

    // The AUDIT embeddable and its physical fields that it represents
    public TableField<TransactionsRecord, Integer> ID;
    public TableField<TransactionsRecord, Timestamp> CREATED_AT;
    public TableField<TransactionsRecord, Timestamp> MODIFIED_AT;
    public TableField<TransactionsRecord, String> CREATED_BY;
    public TableField<TransactionsRecord, String> MODIFIED_BY;
    public TableField<TransactionsRecord, AuditRecord> AUDIT_REFERENCE;

    // The MONETARY_AMOUNT embeddable and its physical fields that it represents
    public TableField<TransactionsRecord, BigDecimal> AMOUNT;
    public TableField<DRecord, String> CURRENCY;
    public TableField<DRecord, MonetaryAmountRecord> MONETARY_AMOUNT;
```

Notice how the embeddable type is just an auxiliary column, which, by default, does not replace its underlying columns. In order to replace the underlying columns, use the [<replaceFields/> flag](#codegen-embeddable-types-replacing-fields)

You can now work with the underlying columns, as always, or use the embeddable types instead:

```java
create.insertInto(TRANSACTIONS)
      .columns(TRANSACTIONS.ID, TRANSACTIONS.AUDIT_REFERENCE, TRANSACTIONS.MONETARY_AMOUNT)
      .values(
            1,
            new AuditRecord(Timestamp.valueOf("2000-01-01 00:00:00"), null, "user", null),
            new MonetaryAmountRecord(new BigDecimal("20.00"), "EUR"))
      .execute();
```

These columns can be used in all types of statements, including e.g. `SELECT`, `INSERT`, `UPDATE`, `DELETE`

##### Type mismatches between references

When an embeddable type matches several tables, all of its references share the same generated [`org.jooq.EmbeddableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EmbeddableRecord.html). If the matched columns differ in their Java types (e.g. `String` in one table and `Integer` in another), the generated code won't compile. More subtle differences, such as a different length, precision, scale, user type, converter, binding, or generator, still produce compiling code, but the embeddable's attributes can only reflect one of the references. For example, if `TRANSACTIONS.AMOUNT` is a `DECIMAL(18, 2)` and `INVOICES.AMOUNT` is a `DECIMAL(10, 2)`, the code generator logs a warning about the `MONETARY_AMOUNT` embeddable's `AMOUNT` attribute.

Differences in nullability aren't reported, as the embeddable's attributes simply become nullable if any of the references is nullable. If a type mismatch is intentional, the warning can be turned off for an embeddable by specifying `<ignoreTypeMismatch>true</ignoreTypeMismatch>` on its configuration. References from configurations with this flag are excluded from the check.

<a id="codegen-overlapping-embeddable-types"></a>
#### 5.7.2. Overlapping embeddable types

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A [previous section](#codegen-embeddable-types-configuration) explained how embeddable types work in general. In some cases, there's a risk of overlapping embeddable types, which can mainly happen when using [embedded keys](#codegen-embedded-keys), but also in some other cases.

For example, when defining an embeddable for each one of these `UNIQUE` constraints:

```sql
CREATE TABLE order_item (
  order_id BIGINT NOT NULL REFERENCES order
  product_id BIGINT NOT NULL REFERENCES product,
  item_no INT NOT NULL,
  quantity INT NOT NULL,

  -- Each order_item has a unique-per-order item_no, which acts as a sequential number
  CONSTRAINT pk_order_item PRIMARY KEY (order_id, item_no),

  -- Each product can only have one order_item
  CONSTRAINT uk_order_item UNIQUE (order_id, product_id)
);
```

The two `UNIQUE` constraints overlap. If they are represented by an [`org.jooq.EmbeddableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EmbeddableRecord.html), each (e.g. because of using [the embedded keys feature](#codegen-embedded-keys)), then both of the embeddable types will reference the `ORDER_ID` column. jOOQ will make sure that the `ORDER_ID` column is not generated twice in SQL statements, where this is forbidden, e.g. in `INSERT` statements:

```sql
INSERT INTO order_item (
  order_id,
  product_id,
  item_no,
  quantity
)
VALUES (
  12,
  15,
  1,
  10
);
```

```java
create.insertInto(ORDER_ITEM)
      .columns(
        ORDER_ITEM.PK_ORDER_ITEM,
        ORDER_ITEM.UK_ORDER_ITEM,
        ORDER_ITEM.QUANTITY
      )
      .values(
        new PkOrderItemRecord(12L, 15L),
        new UkOrderItemRecord(15L, 1),
        1
      )
      .execute();
```

Despite the value `15L` having been provided twice, it is produced in the generated SQL query only once (the second copy of the value is ignored).

<a id="codegen-embeddable-types-replacing-fields"></a>
#### 5.7.3. Field replacement

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A [previous section](#codegen-embeddable-types-configuration) explained how embeddable types work in general. In most cases, in the presence of an embeddable type, the original fields are no longer interesting in most queries, so you will want to replace them by the embeddable.

Assuming we have again a `TRANSACTIONS` table like this:

```sql
CREATE TABLE transactions (
  id BIGINT NOT NULL PRIMARY KEY,
  create_date TIMESTAMP NOT NULL,
  modified_date TIMESTAMP,
  created_by VARCHAR(100) NOT NULL,
  modified_by VARCHAR(100) NOT NULL,

  -- Other columns here
  amount DECIMAL(18, 2) NOT NULL,
  currency VARCHAR(10) NOT NULL
);
```

With the [previous embeddable type definitions](#codegen-embeddable-types-configuration), and a `<replacesFields/>` flag like this:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <embeddables>
        <embeddable>
          <name>MONETARY_AMOUNT</name>
          <fields>
            <field><expression>AMOUNT</expression></field>
            <field><expression>CURRENCY</expression></field>
          </fields>
          <replacesFields>true</replacesFields>
        </embeddable>
      </embeddables>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withEmbeddables(
        new EmbeddableDefinitionType()
          .withName("MONETARY_AMOUNT")
          .withFields(
            new EmbeddableField()
              .withExpression("AMOUNT"),
            new EmbeddableField()
              .withExpression("CURRENCY")
          )
          .withReplacesFields(true)
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      embeddables {
        embeddable {
          name = "MONETARY_AMOUNT"
          fields {
            field {
              expression = "AMOUNT"
            }
            field {
              expression = "CURRENCY"
            }
          }
          isReplacesFields = true
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      embeddables {
        embeddable {
          name = "MONETARY_AMOUNT"
          fields {
            field {
              expression = "AMOUNT"
            }
            field {
              expression = "CURRENCY"
            }
          }
          replacesFields = true
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

... we would get a table that looks like this:

```java
public class Transactions extends TableImpl<TransactionsRecord> {
    // Field initialisations omitted for simplicity

    // The AUDIT embeddable and its physical fields that it represents, but the fields are not accessible
    private TableField<TransactionsRecord, Integer> ID;
    private TableField<TransactionsRecord, Timestamp> CREATED_AT;
    private TableField<TransactionsRecord, Timestamp> MODIFIED_AT;
    private TableField<TransactionsRecord, String> CREATED_BY;
    private TableField<TransactionsRecord, String> MODIFIED_BY;
    public TableField<TransactionsRecord, AuditRecord> AUDIT_REFERENCE;

    // The MONETARY_AMOUNT embeddable and its physical fields that it represents , but the fields are not accessible
    private TableField<TransactionsRecord, BigDecimal> AMOUNT;
    private TableField<DRecord, String> CURRENCY;
    public TableField<DRecord, MonetaryAmountRecord> MONETARY_AMOUNT;
```

Not only are the fields no longer accessible (which means we cannot use them directly, nor do they get in the way with auto completion, etc.), but we also don't get the fields anymore when using `SELECT *` queries.

This flag is turned on when using [embedded keys](#codegen-embedded-keys) or [embedded domains](#codegen-embedded-domains), where the original field reference is undesired.

<a id="codegen-embedded-keys"></a>
#### 5.7.4. Embedded keys

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A very useful application of [embeddable types](#codegen-embeddable-types-configuration) are `PRIMARY KEYS`, `UNIQUE` constraints, and `FOREIGN KEYS`. There is are only few good use-case of joining two tables by two columns that are not the `FOREIGN KEY` and its referenced `PRIMARY` / `UNIQUE` key. If two such columns are chosen, this is mostly because of a typo, or even because of misunderstanding the underlying schema.

You can turn on the feature like this:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>

      <!-- Use regular expressions to match the keys that should be replaced by embeddables. -->
      <embeddablePrimaryKeys>.*</embeddablePrimaryKeys>
      <embeddableUniqueKeys>.*</embeddableUniqueKeys>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // Use regular expressions to match the keys that should be replaced by embeddables.
      .withEmbeddablePrimaryKeys(".*")
      .withEmbeddableUniqueKeys(".*")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {

      // Use regular expressions to match the keys that should be replaced by embeddables.
      embeddablePrimaryKeys = ".*"
      embeddableUniqueKeys = ".*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {

      // Use regular expressions to match the keys that should be replaced by embeddables.
      embeddablePrimaryKeys = ".*"
      embeddableUniqueKeys = ".*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

This will automatically produce an [embeddable type configuration](#codegen-embeddable-types-configuration) for each `PRIMARY KEY` and/or `UNIQUE` key, as well as for each `FOREIGN KEY` referencing the `PRIMARY KEY` or `UNIQUE` key. The generated configuration could be written manually, but the configuration generation algorithm is not trivial when [keys overlap](#codegen-overlapping-embeddable-types), or when tables reference a "remote" primary key transitively, through a relationship table.

Applying this to our [sample database](#sample-database), along with either well-designed constraint names (generated embeddables use constraint names), or a [programmatic generator strategy](#codegen-generatorstrategy), or a [configurative matcher strategy](#codegen-matcherstrategy), we might be getting [`org.jooq.EmbeddableRecord`](https://www.jooq.org/javadoc/3.22.x/org/jooq/EmbeddableRecord.html) types like these:

```java
// Both primary and foreign key produce the respective primary key record
Result<Record5<PkBookRecord, String, PkAuthorRecord, String, String>> result =
create.select(
            BOOK.PK_BOOK,
            BOOK.TITLE,
            BOOK.FK_BOOK_AUTHOR,
            AUTHOR.FIRST_NAME,
            AUTHOR.LAST_NAME)
      .from(BOOK)
      .join(AUTHOR)
      // This join compiles
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      // This wrong join wouldn't compile
      // .on(BOOK.LANGUAGE_ID.eq(AUTHOR.ID))
      .fetch();

for (Record5<PkBookRecord, String, PkAuthorRecord, String, String> record : result) {
    System.out.println("ID        : " + record.value1().getId());
    System.out.println("TITLE     : " + record.value2());
    System.out.println("AUTHOR_ID : " + record.value3().getId());
    System.out.println("FIRST_NAME: " + record.value4());
    System.out.println("LAST_NAME : " + record.value5());
}
```

Notice how:

- Each primary key produces an embeddable record type.
- Both primary key and foreign key columns reference the primary key record type.
- This means that only matching primary / foreign key columns can be compared in joins. It is not sufficient for them to be both of type [`java.lang.Integer`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Integer.html)

##### Composite keys

This feature is even more powerful when keys are composite! You no longer have to list each pair of join columns in your join predicates, just join by primary / foreign key embeddable type. Advantages are:

- You'll never forget a column again when joining by composite keys
- You'll never forget to refactor all your queries, in case you add / remove a column from a key. Just re-generate the jOOQ code, and the queries are automatically updated

The second bullet can also be achieved using [implicit joins](#implicit-join), or the synthetic [ON KEY](#join-predicate-on-key) clause.

<a id="codegen-embedded-domains"></a>
#### 5.7.5. Embedded domains

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

A very useful application of [embeddable types](#codegen-embeddable-types-configuration) are DOMAIN types. A `DOMAIN` type is a combination of:

- A semantic type name
- A data type (or other domain type)
- A default value
- A `CHECK` constraint

The combination name/type is enough to describe a semantic type like `EMAIL` across your schema, much better than e.g. `VARCHAR(10)`. With embedded domains, you can generate a Java type for each domain type, and have that automatically attached to all your columns.

You can turn on the feature like this:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>

      <!-- Use regular expressions to match the domains that should be replaced by embeddables. -->
      <embeddableDomains>.*</embeddableDomains>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // Use regular expressions to match the domains that should be replaced by embeddables.
      .withEmbeddableDomains(".*")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {

      // Use regular expressions to match the domains that should be replaced by embeddables.
      embeddableDomains = ".*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {

      // Use regular expressions to match the domains that should be replaced by embeddables.
      embeddableDomains = ".*"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

This will automatically produce an [embeddable type configuration](#codegen-embeddable-types-configuration) for each `DOMAIN`. For example, this schema:

```sql
CREATE DOMAIN email AS varchar(100);
CREATE DOMAIN year AS int;

CREATE TABLE user (
  id bigint NOT NULL PRIMARY KEY,
  name varchar(100) NOT NULL,
  email email NOT NULL,
  created year NOT NULL
);
```

The above would generate the following set of classes (simplified):

```java
public class EmailRecord extends EmbeddableRecordImpl<EmailRecord> {
    public void setValue(String value) { ... }
    public String getValue() { ... }
    public EmailRecord() { ... }
    public EmailRecord(String value) { ... }
}

public class YearRecord extends EmbeddableRecordImpl<YearRecord> {
    public void setValue(Integer value) { ... }
    public Integer getValue() { ... }
    public YearRecord() { ... }
    public YearRecord(Integer value) { ... }
}
```

These classes are now referenced by embedded fields in the `User` table and `UserRecord` record (simplified):

```java
public class User extends TableImpl<UserRecord> {
    public final TableField<UserRecord, Integer> ID;
    public final TableField<UserRecord, String> NAME;
    public final TableField<UserRecord, EmailRecord> EMAIL;
    public final TableField<UserRecord, YearRecord> CREATED;
}
```

With these generated fields, you can create semantically type safe queries:

```java
create.insertInto(USER)
      .columns(USER.ID, USER.NAME, USER.EMAIL, USER.CREATED)
      .values(1, "domain_user", new EmailRecord("domain@user.com"), new YearRecord(2020))
      .execute();
```

<a id="codegen-embedded-columns"></a>
#### 5.7.6. Embedded columns (auto configuration)

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The [configuration](#codegen-embeddable-types-configuration) of embeddables can get quite verbose, especially if there's a 1:1 relationship between individual columns and generated embeddable types. A simple convenience configuration will allow for specifying all the columns for which an embeddable type of the form `TABLENAME_COLUMNNAME` should be auto-configured:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>

      <!-- Use regular expressions to match the qualified or unqualified column names that should be replaced by embeddables. -->
      <embeddableColumns>email|currency</embeddableColumns>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()

      // Use regular expressions to match the qualified or unqualified column names that should be replaced by embeddables.
      .withEmbeddableColumns("email|currency")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {

      // Use regular expressions to match the qualified or unqualified column names that should be replaced by embeddables.
      embeddableColumns = "email|currency"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {

      // Use regular expressions to match the qualified or unqualified column names that should be replaced by embeddables.
      embeddableColumns = "email|currency"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

As always, when regular expressions are used, they are [regular expressions with default flags](#codegen-database-regex-flags).

This will automatically produce an [embeddable type configuration](#codegen-embeddable-types-configuration) for each matched table/column, with [field replacement](#codegen-embeddable-types-replacing-fields) activated.

> [!TIP]
> In case a column is already part of a [embedded key](#codegen-embedded-keys) or [embedded domain](#codegen-embedded-domains), then those features will take precedence, and no additional embeddable type is generated.

<a id="input-schema"></a>
### 5.8. Input catalogs and schemas

By default, the code generator will access all catalogs and all schemas that are available to it via the system catalog / information schema / dictionary views, or whatever it's called in your target RDBMS. This may produce too many unwanted generated objects, including unwanted system objects. To reduce generation scope, it is possible to specify input catalogs and input schemas.

#### Top level configurations

This mode is preferrable for small projects or quick tutorials, where only a single catalog and a/or a single schema need to be generated. In this case, the following "top level" configuration elements can be applied:

**Read only a single schema (from all catalogs, but in most databases, there is only one "default catalog")**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <inputSchema>my_schema</inputSchema>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withInputSchema("my_schema")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      inputSchema = "my_schema"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      inputSchema = "my_schema"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Read only a single catalog and all its schemas**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <inputCatalog>my_catalog</inputCatalog>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withInputCatalog("my_catalog")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      inputCatalog = "my_catalog"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      inputCatalog = "my_catalog"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Read only a single catalog and only a single schema**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <inputCatalog>my_catalog</inputCatalog>
      <inputSchema>my_schema</inputSchema>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withInputCatalog("my_catalog")
      .withInputSchema("my_schema")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      inputCatalog = "my_catalog"
      inputSchema = "my_schema"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      inputCatalog = "my_catalog"
      inputSchema = "my_schema"
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

#### Nested configurations

This mode is preferrable for larger projects where several catalogs and/or schemas need to be included. The following examples show different possible configurations:

**Read two or more schemas (from all catalogs, but in most databases, there is only one "default catalog")**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <schemata>
        <schema>
          <inputSchema>schema1</inputSchema>
        </schema>
        <schema>
          <inputSchema>schema2</inputSchema>
        </schema>
      </schemata>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withSchemata(
        new SchemaMappingType()
          .withInputSchema("schema1"),
        new SchemaMappingType()
          .withInputSchema("schema2")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      schemata {
        schema {
          inputSchema = "schema1"
        }
        schema {
          inputSchema = "schema2"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      schemata {
        schema {
          inputSchema = "schema1"
        }
        schema {
          inputSchema = "schema2"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Read two or more catalogs and all their schemas**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <catalogs>
        <catalog>
          <inputCatalog>catalog1</inputCatalog>
        </catalog>
        <catalog>
          <inputCatalog>catalog2</inputCatalog>
        </catalog>
      </catalogs>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withCatalogs(
        new CatalogMappingType()
          .withInputCatalog("catalog1"),
        new CatalogMappingType()
          .withInputCatalog("catalog2")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "catalog1"
        }
        catalog {
          inputCatalog = "catalog2"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "catalog1"
        }
        catalog {
          inputCatalog = "catalog2"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

**Read two or more schemas from one or more specific catalogs**

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <catalogs>
        <catalog>
          <inputCatalog>catalog</inputCatalog>
          <schemata>
            <schema>
              <inputSchema>schema1</inputSchema>
            </schema>
            <schema>
              <inputSchema>schema2</inputSchema>
            </schema>
          </schemata>
        </catalog>
      </catalogs>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withCatalogs(
        new CatalogMappingType()
          .withInputCatalog("catalog")
          .withSchemata(
            new SchemaMappingType()
              .withInputSchema("schema1"),
            new SchemaMappingType()
              .withInputSchema("schema2")
          )
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "catalog"
          schemata {
            schema {
              inputSchema = "schema1"
            }
            schema {
              inputSchema = "schema2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      catalogs {
        catalog {
          inputCatalog = "catalog"
          schemata {
            schema {
              inputSchema = "schema1"
            }
            schema {
              inputSchema = "schema2"
            }
          }
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> All of these input schemas and catalogs can be mapped to alternative names, or to defaults. For more information about this, please refer to the section about [code generation catalog and schema mapping](#codegen-database-catalog-and-schema-mapping).

<a id="codegen-meta-sources"></a>
### 5.9. Alternative meta data sources

Most [code generation configurations](#codegen-configuration) will reference an actual RDBMS connection using a JDBC URL to connect to a real RDBMS instance for meta data reverse engineering. The main benefit is that an actual database product is used, similar to what is going to be used in production. As such, all vendor specific features are available and code generation isn't limited.

But there are valid reasons for using an alternative meta data source, or "source of truth" for meta data. For example, there may be a pre-existing migration using [DDL scripts](#codegen-ddl) (such as used by Flyway), or [Liquibase migration](#codegen-liquibase). Or, you may work with [JPA annotated entities](#codegen-jpa) and wish to use those as a source of truth.

The following sections illustrated your options in this area.

<a id="codegen-jpa"></a>
#### 5.9.1. JPADatabase: Code generation from entities

Many jOOQ users use jOOQ as a complementary SQL API in applications that mostly use JPA for their database interactions, e.g. to perform reporting, batch processing, analytics, etc.

In such a setup, you might have a pre-existing schema implemented using JPA-annotated entities. Your real database schema might not be accessible while developing, or it is not a first-class citizen in your application (i.e. you follow a Java-first approach). This section explains how you can generate jOOQ classes from such a JPA model. Consider this model:

```java
@Entity
@Table(name = "author")
public class Author {

    @Id
    int       id;

    @Column(name = "first_name")
    String    firstName;

    @Column(name = "last_name")
    String    lastName;

    @OneToMany(mappedBy = "author")
    Set<Book> books;

    // Getters and setters...
}

@Entity
@Table(name = "book")
public class Book {

    @Id
    public int    id;

    @Column(name = "title")
    public String title;

    @ManyToOne
    public Author author;

    // Getters and setters...
}
```

Now, instead of connecting the jOOQ code generator to a database that holds a representation of the above schema, you can use jOOQ's `JPADatabase` and feed that to the code generator. The `JPADatabase` uses Hibernate internally, to generate an in-memory H2 database from your entities, and reverse-engineers that again back to jOOQ classes.

The easiest way forward is to use Maven in order to include the `jooq-meta-extensions-hibernate` library (which then includes the H2 and Hibernate dependencies)

**Maven:**

```xml
<dependency>
                <!-- Use org.jooq                for the Open Source Edition
                         org.jooq.pro            for commercial editions with Java 25 support,
                         org.jooq.pro-java-21    for commercial editions with Java 21 support,
                         org.jooq.pro-java-17    for commercial editions with Java 17 support,
                         org.jooq.pro-java-11    for commercial editions with Java 11 support,
                         org.jooq.pro-java-8     for commercial editions with Java 8 support,
                         org.jooq.trial          for the free trial edition with Java 25 support,
                         org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                         org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                         org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                         org.jooq.trial-java-8   for the free trial edition with Java 8 support
    
                 Note: Only the Open Source Edition is hosted on Maven Central.
                       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

    <groupId>org.jooq</groupId>
    <artifactId>jooq-meta-extensions-hibernate</artifactId>
    <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    jooqCodegen("org.jooq:jooq-meta-extensions-hibernate:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    jooqCodegen "org.jooq:jooq-meta-extensions-hibernate:3.22.0-SNAPSHOT"
}
```

With that dependency in place, you can now specify the `JPADatabase` in your code generator configuration:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.extensions.jpa.JPADatabase</name>
      <properties>

        <!-- A comma separated list of Java packages, that contain your entities -->
        <property>
          <key>packages</key>
          <value>com.example.entities</value>
        </property>

        <!-- Whether JPA 2.1 AttributeConverters should be auto-mapped to jOOQ Converters.
             Custom <forcedType/> configurations will have a higher priority than these auto-mapped converters.
             This defaults to true. -->
        <property>
          <key>useAttributeConverters</key>
          <value>true</value>
        </property>
        <!-- The default schema for unqualified objects:

             - public: all unqualified objects are located in the PUBLIC (upper case) schema
             - none: all unqualified objects are located in the default schema (default)

             This configuration can be overridden with the schema mapping feature -->
        <property>
          <key>unqualifiedSchema</key>
          <value>none</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.extensions.jpa.JPADatabase")
      .withProperties(

        // A comma separated list of Java packages, that contain your entities
        new Property()
          .withKey("packages")
          .withValue("com.example.entities"),

        // Whether JPA 2.1 AttributeConverters should be auto-mapped to jOOQ Converters.
        // Custom <forcedType/> configurations will have a higher priority than these auto-mapped converters.
        // This defaults to true.
        new Property()
          .withKey("useAttributeConverters")
          .withValue(true),

        // The default schema for unqualified objects:
        // 
        // - public: all unqualified objects are located in the PUBLIC (upper case) schema
        // - none: all unqualified objects are located in the default schema (default)
        // 
        // This configuration can be overridden with the schema mapping feature
        new Property()
          .withKey("unqualifiedSchema")
          .withValue("none")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.jpa.JPADatabase"
      properties {

        // A comma separated list of Java packages, that contain your entities
        property {
          key = "packages"
          value = "com.example.entities"
        }

        // Whether JPA 2.1 AttributeConverters should be auto-mapped to jOOQ Converters.
        // Custom <forcedType/> configurations will have a higher priority than these auto-mapped converters.
        // This defaults to true.
        property {
          key = "useAttributeConverters"
          isValue = true
        }

        // The default schema for unqualified objects:
        // 
        // - public: all unqualified objects are located in the PUBLIC (upper case) schema
        // - none: all unqualified objects are located in the default schema (default)
        // 
        // This configuration can be overridden with the schema mapping feature
        property {
          key = "unqualifiedSchema"
          value = "none"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.jpa.JPADatabase"
      properties {

        // A comma separated list of Java packages, that contain your entities
        property {
          key = "packages"
          value = "com.example.entities"
        }

        // Whether JPA 2.1 AttributeConverters should be auto-mapped to jOOQ Converters.
        // Custom <forcedType/> configurations will have a higher priority than these auto-mapped converters.
        // This defaults to true.
        property {
          key = "useAttributeConverters"
          value = true
        }

        // The default schema for unqualified objects:
        // 
        // - public: all unqualified objects are located in the PUBLIC (upper case) schema
        // - none: all unqualified objects are located in the default schema (default)
        // 
        // This configuration can be overridden with the schema mapping feature
        property {
          key = "unqualifiedSchema"
          value = "none"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

The above will generate all jOOQ artefacts for your `AUTHOR` and `BOOK` tables.

##### Passing settings to Hibernate

The current versions of jOOQ use Hibernate behind the scenes to generate an in-memory H2 database from which to reverse engineer jOOQ code. In order to influence Hibernate's schema generation, Hibernate specific flags can be passed to `MetadataSources`. All properties that are prefixed with `hibernate.` or `jakarta.persistence.` will be passed along to Hibernate. For example, this is possible:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <properties>
        <property>
          <key>hibernate.physical_naming_strategy</key>
          <value>org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withProperties(
        new Property()
          .withKey("hibernate.physical_naming_strategy")
          .withValue("org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      properties {
        property {
          key = "hibernate.physical_naming_strategy"
          value = "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      properties {
        property {
          key = "hibernate.physical_naming_strategy"
          value = "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### How to organise your dependencies

The `JPADatabase` will use Spring to look up your annotated entities from the classpath. This means that you have to create several modules with a dependency graph that looks like this:

```text
                        +-------------------+
                        | Your JPA entities |
                        +-------------------+
                             ^         ^
                  depends on |         | depends on
                             |         |
          +---------------------+   +---------------------+
          | jOOQ codegen plugin |   | Your application    |
          +---------------------+   +---------------------+
                             |         |
                   generates |         | depends on
                             v         v
                     +-------------------------+
                     | jOOQ generated classes  |
                     +-------------------------+
```

You cannot put your JPA entities in the same module as the one that runs the jOOQ code generator. See also [code generator dependencies](#codegen-dependencies).

<a id="codegen-xml"></a>
#### 5.9.2. XMLDatabase: Code generation from XML files

By default, jOOQ's code generator takes live database connections as a database meta data source. In many project setups, this might not be optimal, as the live database is not always available.

One way to circumvent this issue is by providing jOOQ with a database meta definition file in XML format and by passing this XML file to jOOQ's `XMLDatabase`.

The `XMLDatabase` can read a standardised XML file that implements the [https://www.jooq.org/xsd/jooq-meta-3.22.0.xsd](https://www.jooq.org/xsd/jooq-meta-3.22.0.xsd) schema. Essentially, this schema is an XML representation of the SQL standard `INFORMATION_SCHEMA`, as implemented by databases like H2, HSQLDB, MySQL, PostgreSQL, or SQL Server.

An example schema definition containing simple schema, table, column definitions can be seen below:

```xml
<?xml version="1.0"?>
<information_schema xmlns="http://www.jooq.org/xsd/jooq-meta-3.22.0.xsd">
    <schemata>
        <schema>
            <schema_name>TEST</schema_name>
        </schema>
    </schemata>

    <tables>
        <table>
            <table_schema>TEST</table_schema>
            <table_name>AUTHOR</table_name>
        </table>
        <table>
            <table_schema>TEST</table_schema>
            <table_name>BOOK</table_name>
        </table>
    </tables>

    <columns>
        <column>
            <table_schema>PUBLIC</table_schema>
            <table_name>AUTHOR</table_name>
            <column_name>ID</column_name>
            <data_type>NUMBER</data_type>
            <numeric_precision>7</numeric_precision>
            <ordinal_position>1</ordinal_position>
            <is_nullable>false</is_nullable>
        </column>
        <!-- ... -->
    </columns>
</information_schema>
```

Constraints can be defined with the following elements:

```xml
<?xml version="1.0"?>
<information_schema xmlns="http://www.jooq.org/xsd/jooq-meta-3.22.0.xsd">
    <table_constraints>
        <table_constraint>
            <constraint_schema>TEST</constraint_schema>
            <constraint_name>PK_AUTHOR</constraint_name>
            <constraint_type>PRIMARY KEY</constraint_type>
            <table_schema>TEST</table_schema>
            <table_name>AUTHOR</table_name>
        </table_constraint>
        <!-- ... -->
    </table_constraints>

    <key_column_usages>
        <key_column_usage>
            <constraint_schema>TEST</constraint_schema>
            <constraint_name>PK_AUTHOR</constraint_name>
            <table_schema>TEST</table_schema>
            <table_name>AUTHOR</table_name>
            <column_name>ID</column_name>
            <ordinal_position>1</ordinal_position>
        </key_column_usage>
        <!-- ... -->
    </key_column_usages>

    <referential_constraints>
        <referential_constraint>
            <constraint_schema>TEST</constraint_schema>
            <constraint_name>FK_BOOK_AUTHOR_ID</constraint_name>
            <unique_constraint_schema>TEST</unique_constraint_schema>
            <unique_constraint_name>PK_AUTHOR</unique_constraint_name>
        </referential_constraint>
        <!-- ... -->
    </referential_constraints>
</information_schema>
```

The above file can be made available to the code generator configuration by using the `XMLDatabase` as follows:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.xml.XMLDatabase</name>
      <properties>

        <!-- Use any of the SQLDialect values here -->
        <property>
          <key>dialect</key>
          <value>ORACLE</value>
        </property>

        <!-- Specify the location of your database file -->
        <property>
          <key>xmlFile</key>
          <value>src/main/resources/database.xml</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.xml.XMLDatabase")
      .withProperties(

        // Use any of the SQLDialect values here
        new Property()
          .withKey("dialect")
          .withValue("ORACLE"),

        // Specify the location of your database file
        new Property()
          .withKey("xmlFile")
          .withValue("src/main/resources/database.xml")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.xml.XMLDatabase"
      properties {

        // Use any of the SQLDialect values here
        property {
          key = "dialect"
          value = "ORACLE"
        }

        // Specify the location of your database file
        property {
          key = "xmlFile"
          value = "src/main/resources/database.xml"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.xml.XMLDatabase"
      properties {

        // Use any of the SQLDialect values here
        property {
          key = "dialect"
          value = "ORACLE"
        }

        // Specify the location of your database file
        property {
          key = "xmlFile"
          value = "src/main/resources/database.xml"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

If you already have a different XML format for your database, you can either XSL transform your own format into the one above via an additional Maven plugin, or pass the location of an XSL file to the `XMLDatabase` by providing an additional property:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.xml.XMLDatabase</name>
      <properties>

        <!-- Specify the location of your xsl file -->
        <property>
          <key>xslFile</key>
          <value>src/main/resources/transform-to-jooq-format.xsl</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.xml.XMLDatabase")
      .withProperties(

        // Specify the location of your xsl file
        new Property()
          .withKey("xslFile")
          .withValue("src/main/resources/transform-to-jooq-format.xsl")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.xml.XMLDatabase"
      properties {

        // Specify the location of your xsl file
        property {
          key = "xslFile"
          value = "src/main/resources/transform-to-jooq-format.xsl"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.xml.XMLDatabase"
      properties {

        // Specify the location of your xsl file
        property {
          key = "xslFile"
          value = "src/main/resources/transform-to-jooq-format.xsl"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

This XML configuration can now be checked in and versioned, and modified independently from your live database schema.

<a id="codegen-ddl"></a>
#### 5.9.3. DDLDatabase: Code generation from SQL files

In many cases, the schema is defined in the form of a SQL script, which can be used with [Flyway](#jooq-with-flyway), or some other database migration tool.

If you have a complete schema definition in a single file, or perhaps a set of incremental files that can reproduce your schema in any SQL dialect, then the `DDLDatabase` might be the right choice for you. It uses the [SQL parser](#sql-parser) internally and applies all your DDL increments to an in-memory H2 database, in order to produce a replica of your schema prior to reverse engineering it again using ordinary code generation.

For example, the following `database.sql` script (the [sample database from this manual](#sample-database)) could be used:

```sql
CREATE TABLE language (
  id              NUMBER(7)     NOT NULL PRIMARY KEY,
  cd              CHAR(2)       NOT NULL,
  description     VARCHAR2(50)
);

CREATE TABLE author (
  id              NUMBER(7)     NOT NULL PRIMARY KEY,
  first_name      VARCHAR2(50),
  last_name       VARCHAR2(50)  NOT NULL,
  date_of_birth   DATE,
  year_of_birth   NUMBER(7),
  distinguished   NUMBER(1)
);

CREATE TABLE book (
  id              NUMBER(7)     NOT NULL PRIMARY KEY,
  author_id       NUMBER(7)     NOT NULL,
  title           VARCHAR2(400) NOT NULL,
  published_in    NUMBER(7)     NOT NULL,
  language_id     NUMBER(7)     NOT NULL,

  CONSTRAINT fk_book_author     FOREIGN KEY (author_id)   REFERENCES author(id),
  CONSTRAINT fk_book_language   FOREIGN KEY (language_id) REFERENCES language(id)
);

CREATE TABLE book_store (
  name            VARCHAR2(400) NOT NULL UNIQUE
);

CREATE TABLE book_to_book_store (
  name            VARCHAR2(400) NOT NULL,
  book_id         INTEGER       NOT NULL,
  stock           INTEGER,

  PRIMARY KEY(name, book_id),
  CONSTRAINT fk_b2bs_book_store FOREIGN KEY (name)        REFERENCES book_store (name) ON DELETE CASCADE,
  CONSTRAINT fk_b2bs_book       FOREIGN KEY (book_id)     REFERENCES book (id)         ON DELETE CASCADE
);
```

While the script uses pretty standard SQL constructs, you may well use some vendor-specific extensions, and even [DML statements](#sql-statements) in between to set up your schema - it doesn't matter. You will simply need to set up your code generation configuration as follows:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.extensions.ddl.DDLDatabase</name>
      <properties>

        <!-- Specify the location of your SQL script.
             You may use ant-style file matching, e.g. /path/**/to/*.sql

             Where:
             - ** matches any directory subtree
             - * matches any number of characters in a directory / file name
             - ? matches a single character in a directory / file name -->
        <property>
          <key>scripts</key>
          <value>src/main/resources/database.sql</value>
        </property>

        <!-- The sort order of the scripts within a directory, where:

             - semantic: sorts versions, e.g. v-3.10.0 is after v-3.9.0 (default)
             - alphanumeric: sorts strings, e.g. v-3.10.0 is before v-3.9.0
             - flyway: sorts files the same way as flyway does
             - none: doesn't sort directory contents after fetching them from the directory -->
        <property>
          <key>sort</key>
          <value>semantic</value>
        </property>
        <!-- The default schema for unqualified objects:

             - public: all unqualified objects are located in the PUBLIC (upper case) schema
             - none: all unqualified objects are located in the default schema (default)

             This configuration can be overridden with the schema mapping feature -->
        <property>
          <key>unqualifiedSchema</key>
          <value>none</value>
        </property>

        <!-- The default name case for unquoted objects:

             - as_is: unquoted object names are kept unquoted
             - upper: unquoted object names are turned into upper case (most databases)
             - lower: unquoted object names are turned into lower case (e.g. PostgreSQL) -->
        <property>
          <key>defaultNameCase</key>
          <value>as_is</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.extensions.ddl.DDLDatabase")
      .withProperties(

        // Specify the location of your SQL script.
        // You may use ant-style file matching, e.g. /path/**/to/*.sql
        // 
        // Where:
        // - ** matches any directory subtree
        // - * matches any number of characters in a directory / file name
        // - ? matches a single character in a directory / file name
        new Property()
          .withKey("scripts")
          .withValue("src/main/resources/database.sql"),

        // The sort order of the scripts within a directory, where:
        // 
        // - semantic: sorts versions, e.g. v-3.10.0 is after v-3.9.0 (default)
        // - alphanumeric: sorts strings, e.g. v-3.10.0 is before v-3.9.0
        // - flyway: sorts files the same way as flyway does
        // - none: doesn't sort directory contents after fetching them from the directory
        new Property()
          .withKey("sort")
          .withValue("semantic"),

        // The default schema for unqualified objects:
        // 
        // - public: all unqualified objects are located in the PUBLIC (upper case) schema
        // - none: all unqualified objects are located in the default schema (default)
        // 
        // This configuration can be overridden with the schema mapping feature
        new Property()
          .withKey("unqualifiedSchema")
          .withValue("none"),

        // The default name case for unquoted objects:
        // 
        // - as_is: unquoted object names are kept unquoted
        // - upper: unquoted object names are turned into upper case (most databases)
        // - lower: unquoted object names are turned into lower case (e.g. PostgreSQL)
        new Property()
          .withKey("defaultNameCase")
          .withValue("as_is")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.ddl.DDLDatabase"
      properties {

        // Specify the location of your SQL script.
        // You may use ant-style file matching, e.g. /path/**/to/*.sql
        // 
        // Where:
        // - ** matches any directory subtree
        // - * matches any number of characters in a directory / file name
        // - ? matches a single character in a directory / file name
        property {
          key = "scripts"
          value = "src/main/resources/database.sql"
        }

        // The sort order of the scripts within a directory, where:
        // 
        // - semantic: sorts versions, e.g. v-3.10.0 is after v-3.9.0 (default)
        // - alphanumeric: sorts strings, e.g. v-3.10.0 is before v-3.9.0
        // - flyway: sorts files the same way as flyway does
        // - none: doesn't sort directory contents after fetching them from the directory
        property {
          key = "sort"
          value = "semantic"
        }

        // The default schema for unqualified objects:
        // 
        // - public: all unqualified objects are located in the PUBLIC (upper case) schema
        // - none: all unqualified objects are located in the default schema (default)
        // 
        // This configuration can be overridden with the schema mapping feature
        property {
          key = "unqualifiedSchema"
          value = "none"
        }

        // The default name case for unquoted objects:
        // 
        // - as_is: unquoted object names are kept unquoted
        // - upper: unquoted object names are turned into upper case (most databases)
        // - lower: unquoted object names are turned into lower case (e.g. PostgreSQL)
        property {
          key = "defaultNameCase"
          value = "as_is"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.ddl.DDLDatabase"
      properties {

        // Specify the location of your SQL script.
        // You may use ant-style file matching, e.g. /path/**/to/*.sql
        // 
        // Where:
        // - ** matches any directory subtree
        // - * matches any number of characters in a directory / file name
        // - ? matches a single character in a directory / file name
        property {
          key = "scripts"
          value = "src/main/resources/database.sql"
        }

        // The sort order of the scripts within a directory, where:
        // 
        // - semantic: sorts versions, e.g. v-3.10.0 is after v-3.9.0 (default)
        // - alphanumeric: sorts strings, e.g. v-3.10.0 is before v-3.9.0
        // - flyway: sorts files the same way as flyway does
        // - none: doesn't sort directory contents after fetching them from the directory
        property {
          key = "sort"
          value = "semantic"
        }

        // The default schema for unqualified objects:
        // 
        // - public: all unqualified objects are located in the PUBLIC (upper case) schema
        // - none: all unqualified objects are located in the default schema (default)
        // 
        // This configuration can be overridden with the schema mapping feature
        property {
          key = "unqualifiedSchema"
          value = "none"
        }

        // The default name case for unquoted objects:
        // 
        // - as_is: unquoted object names are kept unquoted
        // - upper: unquoted object names are turned into upper case (most databases)
        // - lower: unquoted object names are turned into lower case (e.g. PostgreSQL)
        property {
          key = "defaultNameCase"
          value = "as_is"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### Additional properties

Additional properties include:

- `logExecutedQueries`: Whether queries that are executed by the DDLDatabase should be logged for debugging purposes and auditing purposes.
- `logExecutionResults`: Whether results that are obtained after executing queries by the DDLDatabase should be logged for debugging and auditing purposes.

##### Ignoring unsupported content

The [jOOQ parser](#sql-parser) supports parsing everything that is representable through the jOOQ API, as well as ignores some well known vendor specific syntax. But RDBMS have a lot more features and syntax that are not known to jOOQ. In this case, you can specify two comment tokens around the SQL syntax that jOOQ should ignore. The tokens are located in ordinary single line or multi line comments, so they do not affect your DDL scripts in any other way. For example:

```sql
-- [jooq ignore start]
-- Anything between these two tokens is ignored by the jOOQ parser
CREATE EXTENSION postgis;
-- [jooq ignore stop]

CREATE TABLE a (i INT);
CREATE TABLE b (i INT);

/* [jooq ignore start] */
-- This table will not be generated by jOOQ:
CREATE TABLE c (i INT);
/* [jooq ignore stop] */
```

The tokens can be overridden, or the feature can be turned off entirely using the following properties:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.extensions.ddl.DDLDatabase</name>
      <properties>

        <!-- Turn on/off ignoring contents between such tokens. Defaults to true -->
        <property>
          <key>parseIgnoreComments</key>
          <value>true</value>
        </property>

        <!-- Change the starting token -->
        <property>
          <key>parseIgnoreCommentStart</key>
          <value>[jooq ignore start]</value>
        </property>

        <!-- Change the stopping token -->
        <property>
          <key>parseIgnoreCommentStop</key>
          <value>[jooq ignore stop]</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.extensions.ddl.DDLDatabase")
      .withProperties(

        // Turn on/off ignoring contents between such tokens. Defaults to true
        new Property()
          .withKey("parseIgnoreComments")
          .withValue(true),

        // Change the starting token
        new Property()
          .withKey("parseIgnoreCommentStart")
          .withValue("[jooq ignore start]"),

        // Change the stopping token
        new Property()
          .withKey("parseIgnoreCommentStop")
          .withValue("[jooq ignore stop]")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.ddl.DDLDatabase"
      properties {

        // Turn on/off ignoring contents between such tokens. Defaults to true
        property {
          key = "parseIgnoreComments"
          isValue = true
        }

        // Change the starting token
        property {
          key = "parseIgnoreCommentStart"
          value = "[jooq ignore start]"
        }

        // Change the stopping token
        property {
          key = "parseIgnoreCommentStop"
          value = "[jooq ignore stop]"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.ddl.DDLDatabase"
      properties {

        // Turn on/off ignoring contents between such tokens. Defaults to true
        property {
          key = "parseIgnoreComments"
          value = true
        }

        // Change the starting token
        property {
          key = "parseIgnoreCommentStart"
          value = "[jooq ignore start]"
        }

        // Change the stopping token
        property {
          key = "parseIgnoreCommentStop"
          value = "[jooq ignore stop]"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### Ad-hoc SQL

You can provide additional SQL that is prepended to your scripts to initialise the DDLDatabase, in case it can interpret it. This can also be used *instead of* providing scripts for quick code generation testing use-cases:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.extensions.ddl.DDLDatabase</name>
      <properties>
        <!-- Add additional SQL that is interpreted *before* any scripts -->
        <property>
          <key>sql</key>
          <value>create table t (i int primary key);</value>
        </property>

        <!-- The usual scripts -->
        <property>
          <key>scripts</key>
          <value>src/main/resources/database.sql</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.extensions.ddl.DDLDatabase")
      .withProperties(

        // Add additional SQL that is interpreted *before* any scripts
        new Property()
          .withKey("sql")
          .withValue("create table t (i int primary key);"),

        // The usual scripts
        new Property()
          .withKey("scripts")
          .withValue("src/main/resources/database.sql")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.ddl.DDLDatabase"
      properties {

        // Add additional SQL that is interpreted *before* any scripts
        property {
          key = "sql"
          value = "create table t (i int primary key);"
        }

        // The usual scripts
        property {
          key = "scripts"
          value = "src/main/resources/database.sql"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.ddl.DDLDatabase"
      properties {

        // Add additional SQL that is interpreted *before* any scripts
        property {
          key = "sql"
          value = "create table t (i int primary key);"
        }

        // The usual scripts
        property {
          key = "scripts"
          value = "src/main/resources/database.sql"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### Dependencies

Note that the `org.jooq.meta.extensions.ddl.DDLDatabase` class is located in an external dependency, which needs to be placed on the classpath of the jOOQ code generator. E.g. using Maven:

**Maven:**

```xml
<dependency>
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>
  <artifactId>jooq-meta-extensions</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    jooqCodegen("org.jooq:jooq-meta-extensions:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    jooqCodegen "org.jooq:jooq-meta-extensions:3.22.0-SNAPSHOT"
}
```

<a id="codegen-liquibase"></a>
#### 5.9.4. LiquibaseDatabase: Code generation from Liquibase XML, YAML, JSON files

> [!TIP]
> As of jOOQ 3.21.0, this functionality has been deprecated, see [https://github.com/jOOQ/jOOQ/issues/19353](https://github.com/jOOQ/jOOQ/issues/19353) for details. The recommended replacement is to use testcontainers or similar to emulate a Liquibase migration, similar to what is being recommended for Flyway: [https://blog.jooq.org/using-testcontainers-to-generate-jooq-code/](https://blog.jooq.org/using-testcontainers-to-generate-jooq-code/).

If you are using Liquibase, you will have defined your database as a set of Liquibase change sets, in XML, YAML, or JSON. That database definition is complete and self contained, and can easily be used as a source of meta information by the jOOQ code generator.

For example, the following `database.xml` script could be used (please refer to the liquibase documentation for YAML or JSON formats):

```xml
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
                      http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">
    <changeSet author="authorName" id="changelog-1.0">
        <createTable tableName="MY_TABLE">
            <column name="MY_COLUMN" type="TEXT">
                <constraints nullable="true" primaryKey="false" unique="false" />
            </column>
        </createTable>
    </changeSet>
</databaseChangeLog>
```

In order to use the above as a source of jOOQ's code generator, you will simply need to set up your code generation configuration as follows:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.extensions.liquibase.LiquibaseDatabase</name>
      <properties>

        <!-- Specify the classpath location of your XML, YAML, or JSON script. -->
        <property>
          <key>scripts</key>
          <value>/database.xml</value>
        </property>

        <!-- Whether you want to include liquibase tables in generated output

             - false (default)
             - true: includes DATABASECHANGELOG and DATABASECHANGELOGLOCK tables -->
        <property>
          <key>includeLiquibaseTables</key>
          <value>false</value>
        </property>

        <!-- Whether you want to use jOOQ's translating ParsingConnection to translate
             between your dialect (e.g. Oracle), and jOOQ's in-memory H2 dialect

             - false (default)
             - true: translates e.g. from VARCHAR2(100) to VARCHAR(100) -->
        <property>
          <key>useParsingConnection</key>
          <value>false</value>
        </property>

        <!-- Properties prefixed "database." will be passed on to the liquibase.database.Database class
             if a matching setter is found -->
        <property>
          <key>database.liquibaseSchemaName</key>
          <value>lb</value>
        </property>

        <!-- The property "changeLogParameters.contexts" will be passed on to the
             liquibase.database.Database.update() call (jOOQ 3.13.2+).
             See https://www.liquibase.org/documentation/contexts.html -->
        <property>
          <key>changeLogParameters.contexts</key>
          <value>!test</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.extensions.liquibase.LiquibaseDatabase")
      .withProperties(

        // Specify the classpath location of your XML, YAML, or JSON script.
        new Property()
          .withKey("scripts")
          .withValue("/database.xml"),

        // Whether you want to include liquibase tables in generated output
        // 
        // - false (default)
        // - true: includes DATABASECHANGELOG and DATABASECHANGELOGLOCK tables
        new Property()
          .withKey("includeLiquibaseTables")
          .withValue(false),

        // Whether you want to use jOOQ's translating ParsingConnection to translate
        // between your dialect (e.g. Oracle), and jOOQ's in-memory H2 dialect
        // 
        // - false (default)
        // - true: translates e.g. from VARCHAR2(100) to VARCHAR(100)
        new Property()
          .withKey("useParsingConnection")
          .withValue(false),

        // Properties prefixed "database." will be passed on to the liquibase.database.Database class
        // if a matching setter is found
        new Property()
          .withKey("database.liquibaseSchemaName")
          .withValue("lb"),

        // The property "changeLogParameters.contexts" will be passed on to the
        // liquibase.database.Database.update() call (jOOQ 3.13.2+).
        // See https://www.liquibase.org/documentation/contexts.html
        new Property()
          .withKey("changeLogParameters.contexts")
          .withValue("!test")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.liquibase.LiquibaseDatabase"
      properties {

        // Specify the classpath location of your XML, YAML, or JSON script.
        property {
          key = "scripts"
          value = "/database.xml"
        }

        // Whether you want to include liquibase tables in generated output
        // 
        // - false (default)
        // - true: includes DATABASECHANGELOG and DATABASECHANGELOGLOCK tables
        property {
          key = "includeLiquibaseTables"
          isValue = false
        }

        // Whether you want to use jOOQ's translating ParsingConnection to translate
        // between your dialect (e.g. Oracle), and jOOQ's in-memory H2 dialect
        // 
        // - false (default)
        // - true: translates e.g. from VARCHAR2(100) to VARCHAR(100)
        property {
          key = "useParsingConnection"
          isValue = false
        }

        // Properties prefixed "database." will be passed on to the liquibase.database.Database class
        // if a matching setter is found
        property {
          key = "database.liquibaseSchemaName"
          value = "lb"
        }

        // The property "changeLogParameters.contexts" will be passed on to the
        // liquibase.database.Database.update() call (jOOQ 3.13.2+).
        // See https://www.liquibase.org/documentation/contexts.html
        property {
          key = "changeLogParameters.contexts"
          value = "!test"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.liquibase.LiquibaseDatabase"
      properties {

        // Specify the classpath location of your XML, YAML, or JSON script.
        property {
          key = "scripts"
          value = "/database.xml"
        }

        // Whether you want to include liquibase tables in generated output
        // 
        // - false (default)
        // - true: includes DATABASECHANGELOG and DATABASECHANGELOGLOCK tables
        property {
          key = "includeLiquibaseTables"
          value = false
        }

        // Whether you want to use jOOQ's translating ParsingConnection to translate
        // between your dialect (e.g. Oracle), and jOOQ's in-memory H2 dialect
        // 
        // - false (default)
        // - true: translates e.g. from VARCHAR2(100) to VARCHAR(100)
        property {
          key = "useParsingConnection"
          value = false
        }

        // Properties prefixed "database." will be passed on to the liquibase.database.Database class
        // if a matching setter is found
        property {
          key = "database.liquibaseSchemaName"
          value = "lb"
        }

        // The property "changeLogParameters.contexts" will be passed on to the
        // liquibase.database.Database.update() call (jOOQ 3.13.2+).
        // See https://www.liquibase.org/documentation/contexts.html
        property {
          key = "changeLogParameters.contexts"
          value = "!test"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

If you prefer not to work with the Liquibase `ClassLoaderResourceAccessor` and want to use the `FileSystemResourceAccessor` instead, you will need to provide a `rootPath`, starting from jOOQ 3.16, which depends on Liquibase 4 (or later).

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <database>
      <name>org.jooq.meta.extensions.liquibase.LiquibaseDatabase</name>
      <properties>

        <!-- Specify the root path, e.g. a path in your Maven directory layout -->
        <property>
          <key>rootPath</key>
          <value>${basedir}/src/main/resources</value>
        </property>

        <!-- Specify the relative path location of your XML, YAML, or JSON script. -->
        <property>
          <key>scripts</key>
          <value>database.xml</value>
        </property>
      </properties>
    </database>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withDatabase(new Database()
      .withName("org.jooq.meta.extensions.liquibase.LiquibaseDatabase")
      .withProperties(

        // Specify the root path, e.g. a path in your Maven directory layout
        new Property()
          .withKey("rootPath")
          .withValue("${basedir}/src/main/resources"),

        // Specify the relative path location of your XML, YAML, or JSON script.
        new Property()
          .withKey("scripts")
          .withValue("database.xml")
      )
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.liquibase.LiquibaseDatabase"
      properties {

        // Specify the root path, e.g. a path in your Maven directory layout
        property {
          key = "rootPath"
          value = "${basedir}/src/main/resources"
        }

        // Specify the relative path location of your XML, YAML, or JSON script.
        property {
          key = "scripts"
          value = "database.xml"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    database {
      name = "org.jooq.meta.extensions.liquibase.LiquibaseDatabase"
      properties {

        // Specify the root path, e.g. a path in your Maven directory layout
        property {
          key = "rootPath"
          value = "${basedir}/src/main/resources"
        }

        // Specify the relative path location of your XML, YAML, or JSON script.
        property {
          key = "scripts"
          value = "database.xml"
        }
      }
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

##### Dependencies

Note that the `org.jooq.meta.extensions.liquibase.LiquibaseDatabase` class is located in an external dependency, which needs to be placed on the classpath of the jOOQ code generator. E.g. using Maven:

**Maven:**

```xml
<dependency>
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>
  <artifactId>jooq-meta-extensions-liquibase</artifactId>
  <version>3.22.0-SNAPSHOT</version>
</dependency>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    jooqCodegen("org.jooq:jooq-meta-extensions-liquibase:3.22.0-SNAPSHOT")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    jooqCodegen "org.jooq:jooq-meta-extensions-liquibase:3.22.0-SNAPSHOT"
}
```

Additional dependencies may be required by liquibase, e.g. when using YAML. Please refer to the liquibase documentation about additional dependencies.

##### Vendor specific features

The `LiquibaseDatabase` simulates your migration in memory and may thus not support all vendor specific features of your target dialect. If you run into such limitations, know that it is just a "quick-and-dirty" approach to such a simulation. Running an actual migration on your actual target RDBMS (e.g. using testcontainers) will be more reliable. An example of this approach is given here: [https://blog.jooq.org/using-testcontainers-to-generate-jooq-code/](https://blog.jooq.org/using-testcontainers-to-generate-jooq-code/).

<a id="codegen-output-languages"></a>
### 5.10. Alternative output languages

The following sections describe alternative output languages that can be generated using the code generator, including XML, Kotlin, Scala.

<a id="xmlgenerator"></a>
#### 5.10.1. XMLGenerator: Generating XML

By default the code generator produces Java files for use with the jOOQ API as documented throughout this manual. In some cases, however, it may be desireable to generate other meta data formats, such as an XML document. This can be done with the `XMLGenerator`.

The format produced by the `XMLGenerator` is the same as the one consumed by the [XMLDatabase](#codegen-xml), which can read such XML content to produce Java code. It is specified in the [https://www.jooq.org/xsd/jooq-meta-3.22.0.xsd](https://www.jooq.org/xsd/jooq-meta-3.22.0.xsd) schema. Essentially, this schema is an XML representation of the SQL standard `INFORMATION_SCHEMA`, as implemented by databases like H2, HSQLDB, MySQL, PostgreSQL, or SQL Server.

In order to use the `XMLGenerator`, simply place the following class reference into your code generation configuration:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <name>org.jooq.codegen.XMLGenerator</name>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withName("org.jooq.codegen.XMLGenerator")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    name = "org.jooq.codegen.XMLGenerator"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    name = "org.jooq.codegen.XMLGenerator"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

This configuration does not interfere with most of the remaining code generation configuration, e.g. you can still specify the JDBC connection or the generation output target as usual.

<a id="kotlingenerator"></a>
#### 5.10.2. KotlinGenerator

jOOQ can generate Kotlin code instead of Java code, which allows for leveraging a few kotlin language features also in generated code.

In order to use the `KotlinGenerator`, simply place the following class reference into your code generation configuration:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <name>org.jooq.codegen.KotlinGenerator</name>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withName("org.jooq.codegen.KotlinGenerator")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    name = "org.jooq.codegen.KotlinGenerator"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    name = "org.jooq.codegen.KotlinGenerator"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Most of the code generation configuration remains the same for as long as it's independent of the generation language. But there are a few kotlin specific configuration flags, which are documented below:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Tell the KotlinGenerator to generate properties in addition to methods for these paths. Default is true. -->
      <implicitJoinPathsAsKotlinProperties>true</implicitJoinPathsAsKotlinProperties>
      <!--  Workaround for Kotlin generating setX() setters instead of setIsX() in byte code for mutable properties called
            <code>isX</code>. Default is true. -->
      <kotlinSetterJvmNameAnnotationsOnIsPrefix>true</kotlinSetterJvmNameAnnotationsOnIsPrefix>
      <!-- Generate POJOs as data classes, when using the KotlinGenerator. Default is true. -->
      <pojosAsKotlinDataClasses>true</pojosAsKotlinDataClasses>

      <!-- Generate non-nullable types on POJO attributes, where column is not null. Default is false. -->
      <kotlinNotNullPojoAttributes>false</kotlinNotNullPojoAttributes>

      <!-- Generate non-nullable types on Record attributes, where column is not null. Default is false. -->
      <kotlinNotNullRecordAttributes>false</kotlinNotNullRecordAttributes>

      <!-- Generate non-nullable types on interface attributes, where column is not null. Default is false. -->
      <kotlinNotNullInterfaceAttributes>false</kotlinNotNullInterfaceAttributes>
      <!-- Generate defaulted nullable POJO attributes. Default is true. -->
      <kotlinDefaultedNullablePojoAttributes>true</kotlinDefaultedNullablePojoAttributes>

      <!-- Generate defaulted nullable Record attributes. Default is true. -->
      <kotlinDefaultedNullableRecordAttributes>true</kotlinDefaultedNullableRecordAttributes>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Tell the KotlinGenerator to generate properties in addition to methods for these paths. Default is true.
      .withImplicitJoinPathsAsKotlinProperties(true)

      // Workaround for Kotlin generating setX() setters instead of setIsX() in byte code for mutable properties called
      // <code>isX</code>. Default is true.
      .withKotlinSetterJvmNameAnnotationsOnIsPrefix(true)

      // Generate POJOs as data classes, when using the KotlinGenerator. Default is true.
      .withPojosAsKotlinDataClasses(true)

      // Generate non-nullable types on POJO attributes, where column is not null. Default is false.
      .withKotlinNotNullPojoAttributes(false)

      // Generate non-nullable types on Record attributes, where column is not null. Default is false.
      .withKotlinNotNullRecordAttributes(false)

      // Generate non-nullable types on interface attributes, where column is not null. Default is false.
      .withKotlinNotNullInterfaceAttributes(false)

      // Generate defaulted nullable POJO attributes. Default is true.
      .withKotlinDefaultedNullablePojoAttributes(true)

      // Generate defaulted nullable Record attributes. Default is true.
      .withKotlinDefaultedNullableRecordAttributes(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Tell the KotlinGenerator to generate properties in addition to methods for these paths. Default is true.
      isImplicitJoinPathsAsKotlinProperties = true

      // Workaround for Kotlin generating setX() setters instead of setIsX() in byte code for mutable properties called
      // <code>isX</code>. Default is true.
      isKotlinSetterJvmNameAnnotationsOnIsPrefix = true

      // Generate POJOs as data classes, when using the KotlinGenerator. Default is true.
      isPojosAsKotlinDataClasses = true

      // Generate non-nullable types on POJO attributes, where column is not null. Default is false.
      isKotlinNotNullPojoAttributes = false

      // Generate non-nullable types on Record attributes, where column is not null. Default is false.
      isKotlinNotNullRecordAttributes = false

      // Generate non-nullable types on interface attributes, where column is not null. Default is false.
      isKotlinNotNullInterfaceAttributes = false

      // Generate defaulted nullable POJO attributes. Default is true.
      isKotlinDefaultedNullablePojoAttributes = true

      // Generate defaulted nullable Record attributes. Default is true.
      isKotlinDefaultedNullableRecordAttributes = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Tell the KotlinGenerator to generate properties in addition to methods for these paths. Default is true.
      implicitJoinPathsAsKotlinProperties = true

      // Workaround for Kotlin generating setX() setters instead of setIsX() in byte code for mutable properties called
      // <code>isX</code>. Default is true.
      kotlinSetterJvmNameAnnotationsOnIsPrefix = true

      // Generate POJOs as data classes, when using the KotlinGenerator. Default is true.
      pojosAsKotlinDataClasses = true

      // Generate non-nullable types on POJO attributes, where column is not null. Default is false.
      kotlinNotNullPojoAttributes = false

      // Generate non-nullable types on Record attributes, where column is not null. Default is false.
      kotlinNotNullRecordAttributes = false

      // Generate non-nullable types on interface attributes, where column is not null. Default is false.
      kotlinNotNullInterfaceAttributes = false

      // Generate defaulted nullable POJO attributes. Default is true.
      kotlinDefaultedNullablePojoAttributes = true

      // Generate defaulted nullable Record attributes. Default is true.
      kotlinDefaultedNullableRecordAttributes = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

> [!TIP]
> While it is tempting to use non-nullability guarantees that are derived from your table definitions in generated code, it is important to remember that in SQL, there are numerous reasons why an expression that is based on a column declared as SQL `NOT NULL` can become `NULL` through the use of SQL operators, such as `LEFT JOIN` or `UNION`, etc. In particular, a column with a `DEFAULT` or `IDENTITY` expression is "nullable-on-write", so jOOQ will generate it as nullable *despite* a `NOT NULL` constraint!

<a id="scalagenerator"></a>
#### 5.10.3. ScalaGenerator and Scala3Generator

jOOQ can generate Scala code instead of Java code, which allows for leveraging a few Scala language features also in generated code.

In order to use the `ScalaGenerator`(or `Scala3Generator`), simply place the following class reference into your code generation configuration:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <!-- For legacy Scala 2.x support, use org.jooq.codegen.ScalaGenerator -->
    <name>org.jooq.codegen.Scala3Generator</name>
  </generator>
  
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()

    // For legacy Scala 2.x support, use org.jooq.codegen.ScalaGenerator
    .withName("org.jooq.codegen.Scala3Generator")
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {

    // For legacy Scala 2.x support, use org.jooq.codegen.ScalaGenerator
    name = "org.jooq.codegen.Scala3Generator"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {

    // For legacy Scala 2.x support, use org.jooq.codegen.ScalaGenerator
    name = "org.jooq.codegen.Scala3Generator"
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Most of the code generation configuration remains the same for as long as it's independent of the generation language. But there are a few Scala specific configuration flags, which are documented below:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>

      <!-- Generate POJOs as case classes, when using the ScalaGenerator. Default is true. -->
      <pojosAsScalaCaseClasses>true</pojosAsScalaCaseClasses>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Generate POJOs as case classes, when using the ScalaGenerator. Default is true.
      .withPojosAsScalaCaseClasses(true)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Generate POJOs as case classes, when using the ScalaGenerator. Default is true.
      isPojosAsScalaCaseClasses = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Generate POJOs as case classes, when using the ScalaGenerator. Default is true.
      pojosAsScalaCaseClasses = true
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

<a id="codegen-execution"></a>
### 5.11. Code generation execution

There are various ways to execute the code generator, either as a standalone application or using third party build systems like Maven, Gradle, Ant, or others.

<a id="codegen-maven"></a>
#### 5.11.1. Running the code generator with Maven

There is no substantial difference between running the code generator with Maven or in standalone mode. Both modes use the exact same `<configuration/>` element. The Maven plugin configuration adds some additional boilerplate around that:

```xml
<plugin>
  <!-- Specify the maven code generator plugin -->
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>
  <artifactId>jooq-codegen-maven</artifactId>
  <version>3.22.0-SNAPSHOT</version>

  <executions>
    <execution>
      <id>my-id</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>generate</goal>
      </goals>
    </execution>
  </executions>

  <configuration>
    ...
  </configuration>
</plugin>
```

> [!TIP]
> Note that in Maven, you can place configurations both in the `plugin` as well as in the `execution` of the plugin. The latter is useful especially if you have multiple executions, see below. If you do, however, please keep in mind that you may have to supply the execution ID explicitly when running the code generator from the command line, e.g. using `mvn jooq-codegen:generate@my-id`

##### Additional Maven-specific flags

There are, however, some additional, Maven-specific flags that can be specified with the `jooq-codegen-maven` plugin only:

```xml
<plugin>
  <configuration>

    <!-- A boolean property (or constant) can be specified here to tell the plugin not to do anything -->
    <skip>${skip.jooq.generation}</skip>

    <!-- Instead of providing an inline configuration here, you can specify an external XML configuration file here -->
    <configurationFile>${externalfile}</configurationFile>

    <!-- By default, code generation output goes to the compile source root. Use these flags to override this default -->
    <addCompileSourceRoot>true</addCompileSourceRoot>
    <addTestCompileSourceRoot>false</addTestCompileSourceRoot>

    <!-- Alternatively, you can provide several external configuration files. These will be merged by using
         Maven's combine.children="append" policy -->
    <configurationFiles>
      <configurationFile>${file1}</configurationFile>
      <configurationFile>${file2}</configurationFile>
      <configurationFile>...</configurationFile>
    </configurationFiles>
  </configuration>
</plugin>
```

##### Maven plugin inheritance mechanism

As with any other Maven plugin configuration, you can profit from [Maven's powerful plugin inheritance mechanism](https://maven.apache.org/pom.html#Plugins). This is particularly useful when you configure several code generation runs for jOOQ, e.g.

- Different configurations for different tenants
- Different configurations for different schemas
- Different configurations for different environments

One approach would be to use a `<pluginManagement/>` configuration

```xml
<pluginManagement>
  <plugins>
    <plugin>
                  <!-- Use org.jooq                for the Open Source Edition
                           org.jooq.pro            for commercial editions with Java 25 support,
                           org.jooq.pro-java-21    for commercial editions with Java 21 support,
                           org.jooq.pro-java-17    for commercial editions with Java 17 support,
                           org.jooq.pro-java-11    for commercial editions with Java 11 support,
                           org.jooq.pro-java-8     for commercial editions with Java 8 support,
                           org.jooq.trial          for the free trial edition with Java 25 support,
                           org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                           org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                           org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                           org.jooq.trial-java-8   for the free trial edition with Java 8 support
      
                   Note: Only the Open Source Edition is hosted on Maven Central.
                         Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                         See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

      <groupId>org.jooq</groupId>
      <artifactId>jooq-codegen-maven</artifactId>
      <configuration>

        <!-- Log at WARN level by default -->
        <logging>WARN</logging>
        <generator>
          <generate>

            <!-- Never generate deprecated code -->
            <deprecated>false</deprecated>
          </generate>
          <database>
            <forcedTypes>

              <!-- Use BIGINT for all ID columns -->
              <forcedType>
                <name>BIGINT</name>
                <includeExpression>ID</includeExpression>
              </forcedType>
            </forcedTypes>
          </database>
        </generator>
      </configuration>
    </plugin>
  </plugins>
</pluginManagement>
```

The above now applies to all of your `jooq-codegen-maven` plugin configurations *by default*. Now, in some module or execution, you may want to enhance / override the above defaults:

```xml
<plugin>
  <groupId>org.jooq</groupId>
  <artifactId>jooq-codegen-maven</artifactId>
  <configuration>

    <!-- Log at INFO level by in this particular configuration -->
    <logging>INFO</logging>
    <generator>
      <database>
        <!-- Append additional forced type children to the default, rather
             than merging or replacing the default -->
        <forcedTypes combine.children="append">
          <forcedType>
            <name>BIGINT</name>
            <includeExpression>.*_ID</includeExpression>
          </forcedType>
        </forcedTypes>
      </database>
    </generator>
  </configuration>
</plugin>
```

Another approach is to use multiple executions:

##### Multiple executions

As with any Maven plugin, jOOQ's maven code generation plugin can be executed multiple times, inheriting the common configuration in each execution:

```xml
<plugin>
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>
  <artifactId>jooq-codegen-maven</artifactId>

  <!-- Common configuration inherited by all executions -->
  <configuration>

    <!-- Log at WARN level by default -->
    <logging>WARN</logging>
    <generator>
      <generate>

        <!-- Never generate deprecated code -->
        <deprecated>false</deprecated>
      </generate>
      <database>
        <forcedTypes>

          <!-- Use BIGINT for all ID columns -->
          <forcedType>
            <name>BIGINT</name>
            <includeExpression>ID</includeExpression>
          </forcedType>
        </forcedTypes>
      </database>
    </generator>
  </configuration>

  <!-- Multiple executions with their own, specific configurations -->
  <executions>
    <execution>
      <id>generate-tenant-1</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>generate</goal>
      </goals>
      <configuration>
        ...
      </configuration>
    <execution>

    <execution>
      <id>generate-tenant-2</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>generate</goal>
      </goals>
      <configuration>
        ...
      </configuration>
    <execution>
  </executions>
</plugin>
```

Please refer to the [Maven documentation](https://maven.apache.org/pom.html#Plugins) for more details.

<a id="codegen-ant"></a>
#### 5.11.2. Running the code generator with Ant

##### Run generation with Ant

When running code generation with ant's <java/> task, you may have to set fork="true":

```xml
<!-- Run the code generation task -->
<target name="generate-test-classes">
  <java fork="true"
        classname="org.jooq.codegen.GenerationTool">
    <arg value="/path/to/configuration.xml"/>
    <classpath>
      <pathelement location="/path/to/jooq-3.22.0-SNAPSHOT.jar"/>
      <pathelement location="/path/to/jooq-meta-3.22.0-SNAPSHOT.jar"/>
      <pathelement location="/path/to/jooq-codegen-3.22.0-SNAPSHOT.jar"/>
      <!-- Add JDBC drivers and other required artifacts -->
    </classpath>
  </java>
</target>
```

##### Using the Ant Maven plugin

Sometimes, ant can be useful to work around a limitation (misunderstanding?) of the Maven build. Just as with the above standalone ant usage example, the jOOQ code generator can be called from the `maven-antrun-plugin`:

```xml
<!-- Run the code generation task -->
<plugin>
  <artifactId>maven-antrun-plugin</artifactId>
  <version>1.8</version>
  <executions>
    <execution>
      <phase>generate-sources</phase>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>

  <configuration>
    <tasks>
      <java fork="true"
            classname="org.jooq.codegen.GenerationTool"
            classpathref="maven.compile.classpath">
          <arg value="/path/to/configuration.xml"/>
      </java>
    </tasks>
  </configuration>

  <dependencies>
    <dependency>
      <!-- JDBC driver -->
    </dependency>
    <dependency>
                  <!-- Use org.jooq                for the Open Source Edition
                           org.jooq.pro            for commercial editions with Java 25 support,
                           org.jooq.pro-java-21    for commercial editions with Java 21 support,
                           org.jooq.pro-java-17    for commercial editions with Java 17 support,
                           org.jooq.pro-java-11    for commercial editions with Java 11 support,
                           org.jooq.pro-java-8     for commercial editions with Java 8 support,
                           org.jooq.trial          for the free trial edition with Java 25 support,
                           org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                           org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                           org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                           org.jooq.trial-java-8   for the free trial edition with Java 8 support
      
                   Note: Only the Open Source Edition is hosted on Maven Central.
                         Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                         See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

      <groupId>org.jooq</groupId>
      <artifactId>jooq-codegen</artifactId>
      <version>3.22.0-SNAPSHOT</version>
    </dependency>
    <!-- Add JDBC drivers and other required artifacts -->
  </dependencies>
</plugin>
```

<a id="codegen-gradle"></a>
#### 5.11.3. Running the code generator with Gradle

Starting with jOOQ 3.19, there's out of the box gradle support for jOOQ's code generator, which is documented below.

There is no substantial difference between running the code generator with Gradle or in standalone mode. Both modes use the exact same `<configuration/>` element. The Gradle plugin configuration adds some additional boilerplate around that:

**Kotlin:**

```kotlin
plugins {

             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    id("org.jooq.jooq-codegen-gradle") version "3.22.0-SNAPSHOT"
}

dependencies {

    // Code generation specific dependencies, like JDBC drivers, codegen extensions, etc.
    jooqCodegen("...")
}

jooq {
    configuration {
        // ...
    }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) or the manual's various sections about code generation for more details.

**Groovy:**

```groovy
plugins {

             // Use org.jooq                for the Open Source Edition
             //     org.jooq.pro            for commercial editions with Java 25 support,
             //     org.jooq.pro-java-21    for commercial editions with Java 21 support,
             //     org.jooq.pro-java-17    for commercial editions with Java 17 support,
             //     org.jooq.pro-java-11    for commercial editions with Java 11 support,
             //     org.jooq.pro-java-8     for commercial editions with Java 8 support,
             //     org.jooq.trial          for the free trial edition with Java 25 support,
             //     org.jooq.trial-java-21  for the free trial edition with Java 21 support,
             //     org.jooq.trial-java-17  for the free trial edition with Java 17 support,
             //     org.jooq.trial-java-11  for the free trial edition with Java 11 support,
             //     org.jooq.trial-java-8   for the free trial edition with Java 8 support
             //
             // Note: Only the Open Source Edition is hosted on Maven Central.
             //       Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
             //       See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk

    id "org.jooq.jooq-codegen-gradle" version "3.22.0-SNAPSHOT"
}

dependencies {

    // Code generation specific dependencies, like JDBC drivers, codegen extensions, etc.
    jooqCodegen "..."
}

jooq {
    configuration {
        // ...
    }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) or the manual's various sections about code generation for more details.

With the above configuration, a single execution is implicit.

<a id="codegen-gradle-executions"></a>
##### 5.11.3.1. Multiple executions

To emulate Maven's useful plugin `<executions/>` semantics, where a plugin can be configured to be executed multiple times, `jOOQ-codegen-gradle` also offers an `executions {}` element, which generates gradle tasks. Such a setup can be configured like this:

**Kotlin:**

```kotlin
jooq {

    // Common configuration to be shared by all executions
    configuration {
        // ...
    }

    executions {
        create("main") {
            configuration {
                // ...
            }
        }

        create("other") {
            configuration {
                // ...
            }
        }
    }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) or the manual's various sections about code generation for more details.

**Groovy:**

```groovy
jooq {

    // Common configuration to be shared by all executions
    configuration {
        // ...
    }

    executions {
        main {
            configuration {
                // ...
            }
        }

        other {
            configuration {
                // ...
            }
        }
    }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) or the manual's various sections about code generation for more details.

As these `executions` simply translate to gradle `tasks`, you can now either run them all together, or individually.

```text
gradle tasks
```

Produces:

```text
JOOQ tasks
----------
jooqCodegen - jOOQ code generation for all executions
jooqCodegenMain - jOOQ code generation for main execution
jooqCodegenOther - jOOQ code generation for other execution
```

<a id="codegen-gradle-compiler-dependency"></a>
##### 5.11.3.2. Compiler dependency

The generation output goes to the `main` source set, if that source set is available. In order for the Java, Kotlin, or Scala compiler to be able to compile generation output, the dependency must be declared as follows:

**Kotlin:**

```kotlin
jooq {
    // ...
}

// When using Java
tasks.named("compileJava") {
    dependsOn(tasks.named("jooqCodegen"))
}

// When using Kotlin
tasks.named("compileKotlin") {
    dependsOn(tasks.named("jooqCodegen"))
}

// When using Scala
tasks.named("compileScala") {
    dependsOn(tasks.named("jooqCodegen"))
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) or the manual's various sections about code generation for more details.

**Groovy:**

```groovy
jooq {
    // ...
}

// When using Java
tasks.named("compileJava") {
    dependsOn(tasks.named("jooqCodegen"))
}

// When using Kotlin
tasks.named("compileKotlin") {
    dependsOn(tasks.named("jooqCodegen"))
}

// When using Scala
tasks.named("compileScala") {
    dependsOn(tasks.named("jooqCodegen"))
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) or the manual's various sections about code generation for more details.

<a id="codegen-gradle-data-change-management"></a>
##### 5.11.3.3. Data change management

Data change management libraries like Liquibase or Flyway are popular when working with RDBMS. In order to re-run code generation whenever a database migration has been done, consider the following configuration:

**Kotlin:**

```kotlin
jooq {
    // ...
}

tasks.named("jooqCodegen") {

    // Run code generation after Flyway migration
    dependsOn(tasks.named("flywayMigrate"))

    // Optional: Use Flyway migration scripts as input to code generation, to avoid
    // task execution when unnecessary
    inputs.files(fileTree("src/main/resources/db/migration"))
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) or the manual's various sections about code generation for more details.

**Groovy:**

```groovy
jooq {
    // ...
}

tasks.named("jooqCodegen") {

    // Run code generation after Flyway migration
    dependsOn(tasks.named("flywayMigrate"))

    // Optional: Use Flyway migration scripts as input to code generation, to avoid
    // task execution when unnecessary
    inputs.files(fileTree("src/main/resources/db/migration"))
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) or the manual's various sections about code generation for more details.

By default, the gradle plugin assumes that task inputs have changed and thus it cannot participate in incremental builds (e.g. when connecting to externally managed databases). But if you manage your data changes in the same build, then we can leverage Gradle's build cache and incremental build capabilities to re-run code generation only when Flyway or Liquibase migration scripts have changed!

<a id="codegen-programmatic"></a>
#### 5.11.4. Programmatic configuration and execution

##### Configuring your code generator with Java, Groovy, etc.

In the previous sections, we have covered how to set up jOOQ's code generator using XML, either by running a standalone Java application, or by using Maven. However, it is also possible to use jOOQ's `GenerationTool` programmatically. The XSD file used for the configuration ([https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd)) is processed using [XJC](https://docs.oracle.com/javase/6/docs/technotes/tools/share/xjc.html) to produce Java artefacts. The below example uses those artefacts to produce the equivalent configuration of the previous [PostgreSQL / Maven example](#codegen-configuration):

```java
// Use the fluent-style API to construct the code generator configuration
import org.jooq.meta.jaxb.*;
import org.jooq.meta.jaxb.Configuration;

// [...]

Configuration configuration = new Configuration()
    .withJdbc(new Jdbc()
        .withDriver("org.postgresql.Driver")
        .withUrl("jdbc:postgresql:postgres")
        .withUser("postgres")
        .withPassword("test"))
    .withGenerator(new Generator()
        .withDatabase(new Database()
            .withName("org.jooq.meta.postgres.PostgresDatabase")
            .withIncludes(".*")
            .withExcludes("")
            .withInputSchema("public"))
        .withTarget(new Target()
            .withPackageName("org.jooq.codegen.maven.example")
            .withDirectory("target/generated-sources/jooq")));

GenerationTool.generate(configuration);
```

For the above example, you will need all of jooq-3.22.0-SNAPSHOT.jar, jooq-meta-3.22.0-SNAPSHOT.jar, and jooq-codegen-3.22.0-SNAPSHOT.jar, on your classpath.

##### Manually loading the XML file

Alternatively, you can also load parts of the configuration from an XML file using JAXB and programmatically modify other parts using the code generation API:

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration>
    <jdbc>
        <driver>org.h2.Driver</driver>
        <!-- ... -->
    </jdbc>
</configuration>
```

Load the above using standard JAXB API:

```java
import java.io.File;
import jakarta.xml.bind.JAXB;
import org.jooq.meta.jaxb.Configuration;

// [...]
// and then

Configuration configuration = JAXB.unmarshal(new File("jooq.xml"), Configuration.class);
configuration.getJdbc()
             .withUser("username")
             .withPassword("password");

GenerationTool.generate(configuration);
```

... and then, modify parts of your configuration programmatically, for instance the JDBC user / password:

<a id="codegen-system-properties"></a>
### 5.12. System properties governing code generation

Regardless if you're using a standalone code generation configuration, or if you're generating code with [Maven](#codegen-maven), [ant](#codegen-ant), or [gradle](#codegen-gradle), you can always provide default values for certain configuration elements through the following system properties:

- `-Djooq.codegen.configurationFile` (path): Specify an external configuration file, rather than using the inline configuration, e.g. in Maven
- `-Djooq.codegen.jdbc.driver` (class name): The JDBC driver to use for JDBC connection based code generation
- `-Djooq.codegen.jdbc.url` (url): The JDBC URL to use for JDBC connection based code generation (the name of this property can be overridden with the `urlProperty value`)
- `-Djooq.codegen.jdbc.user` (string): The JDBC user name to use for JDBC connection based code generation
- `-Djooq.codegen.jdbc.username` (string, same as user): The JDBC user name to use for JDBC connection based code generation
- `-Djooq.codegen.jdbc.password` (string): The JDBC password to use for JDBC connection based code generation
- `-Djooq.codegen.jdbc.autoCommit` (boolean): Whether the JDBC connection should be put in autocommit mode
- `-Djooq.codegen.jdbc.initScript` (string): A script to run after creating the JDBC connection, and before running the code generator
- `-Djooq.codegen.jdbc.initSeparator` (string): The separator used to separate statements in the initScript, defaulting to ";"
- `-Djooq.codegen.jdbc.securityProvider` (string): A [`java.security.Provider`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/security/Provider.html) class to load prior to connecting to JDBC
- `-Djooq.codegen.logging` (TRACE, DEBUG, INFO, WARN, ERROR, FATAL): The log level to use
- `-Djooq.codegen.skip` (boolean): Allows for skipping the execution of jOOQ code generation. Useful for larger builds, e.g. with Maven
- `-Djooq.codegen.target.packageName` (string): The output package name for generated code
- `-Djooq.codegen.target.directory` (string): The output directory for generated code
- `-Djooq.codegen.target.encoding` (string): The output encoding for generated code
- `-Djooq.codegen.target.locale` (string): The output locale for generated code

In case of conflict between the above default value and a more concrete, local configuration, the latter prevails and the default is overridden.

An additional flag allows for overriding this default, such that the system property takes precedence over any explicit configuration:

- `-Djooq.codegen.propertyOverride` (boolean): System properties override explicit configuration

<a id="codegen-dependencies"></a>
### 5.13. Code generation dependencies

Various code generation features allow for providing the code generator with a custom implementation of something, like:

- [The generator](#codegen-config-generator): The logic generating your code
- [The database](#codegen-config-database): The source for database meta data source
- [The generator strategy](#codegen-generatorstrategy): The strategy defining generated object names and identifiers
- Much more

Other use-cases require a classpath dependency to look up things like [JPA entities](#codegen-jpa).

Many of these custom implementation hooks come in two flavours:

- Using Java in-memory compilation of the implementation.
- Using a named reference to a previously compiled implementation.

Depending on the above approach, the following section explains how to set up your code generation dependencies. In both cases, any dependencies to the code generator need to be declared in your build:

**Maven:**

```xml
<plugin>
  <!-- Specify the maven code generator plugin -->
              <!-- Use org.jooq                for the Open Source Edition
                       org.jooq.pro            for commercial editions with Java 25 support,
                       org.jooq.pro-java-21    for commercial editions with Java 21 support,
                       org.jooq.pro-java-17    for commercial editions with Java 17 support,
                       org.jooq.pro-java-11    for commercial editions with Java 11 support,
                       org.jooq.pro-java-8     for commercial editions with Java 8 support,
                       org.jooq.trial          for the free trial edition with Java 25 support,
                       org.jooq.trial-java-21  for the free trial edition with Java 21 support,
                       org.jooq.trial-java-17  for the free trial edition with Java 17 support,
                       org.jooq.trial-java-11  for the free trial edition with Java 11 support,
                       org.jooq.trial-java-8   for the free trial edition with Java 8 support
  
               Note: Only the Open Source Edition is hosted on Maven Central.
                     Install the others locally using the provided scripts, or access them from here: https://repo.jooq.org
                     See the JDK version support matrix here: https://www.jooq.org/download/support-matrix-jdk -->

  <groupId>org.jooq</groupId>
  <artifactId>jooq-codegen-maven</artifactId>
  <version>3.22.0-SNAPSHOT</version>

  <executions>...</executions>
  <configuration>...</configuration>

  <dependencies>
    <dependency>...</dependency>
  </dependencies>
</plugin>
```

**Gradle (Kotlin):**

```kotlin
dependencies {
    jooqCodegen("...")
}
```

**Gradle (Groovy):**

```groovy
dependencies {
    jooqCodegen "..."
}
```

#### Using in-memory compilation

Some code generation classes can be declared directly using source code [inside of your code generation configuration](#codegen-in-memory-compilation). If this is available, it's documented with an explicit example.

When using in-memory compilation, everything that is available to jOOQ's code generator is available to your in-memory compiled implementation of the extension point. You do not have to do anything else than declare those dependencies.

#### Using a named reference

A named reference of a custom implementation needs to be on the classpath of the code in a pre-compiled form (unlike the previously mentioned in-memory compiled form). In both Maven and Gradle, this is typically best done by setting up a multi modular project of this form:

```text
                +-----------------------------------+
                | Your custom code generation logic |
                +-----------------------------------+
                             ^         ^
                  depends on |         | may or may not depend on
                             |         |
          +---------------------+   +---------------------+
          | jOOQ codegen plugin |   | Your application    |
          +---------------------+   +---------------------+
                             |         |
                   generates |         | depends on
                             v         v
                     +-------------------------+
                     | jOOQ generated classes  |
                     +-------------------------+
```

It is important to understand that your custom code generation logic has to be compiled (and packaged, etc.) *before* you use it in your code generation logic. Think of your custom code generation logic like any library provided by a third party, available from Maven Central or elsewhere. It's a dependency like any other.

<a id="codegen-in-memory-compilation"></a>
### 5.14. In-memory compilation of programmatic configuration

Various code generation configuration elements allow for programmatic configuration via external classes. This allows for more fine-grained control over the code generation behaviour. Examples include:

- [Programmatic GeneratorStrategy implementations](#codegen-generatorstrategy)
- [The Database instance, which provides meta data](#codegen-config-database)
- [The Generator instance, which provides code generation logic](#codegen-config-generator)

The above examples all allow for specifying inline code for in-memory compilation of the relevant object. For example, when defining a [GeneratorStrategy](#codegen-generatorstrategy):

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <strategy>
      <name>com.example.AsInDatabaseStrategy</name>
      <java>package com.example;

import org.jooq.codegen.DefaultGeneratorStrategy;

public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
    ...
}</java>
    </strategy>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(new Generator()
    .withStrategy(new Strategy()
      .withName("com.example.AsInDatabaseStrategy")
      .withJava("""package com.example;

import org.jooq.codegen.DefaultGeneratorStrategy;

public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
    ...
}""")
    )
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    strategy {
      name = "com.example.AsInDatabaseStrategy"
      java = """package com.example;

import org.jooq.codegen.DefaultGeneratorStrategy;

public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
    ...
}"""
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    strategy {
      name = "com.example.AsInDatabaseStrategy"
      java = """package com.example;

import org.jooq.codegen.DefaultGeneratorStrategy;

public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
    ...
}"""
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

The `name` must match the fully qualified class name of a `GeneratorStrategy`.

> [!TIP]
> Make sure your custom implementation's dependencies are available to the code generator as a [code generator dependency](#codegen-dependencies)

> [!TIP]
> Not all custom implementations can be provided as an in-memory compilable piece of code. Please do check the relevant manual section if this is possible.

<a id="codegen-large-schemas"></a>
### 5.15. Code generation for large schemas

Databases can become very large in real-world applications. This is not a problem for jOOQ's code generator, but it can be for the Java compiler. jOOQ generates some classes for [global access](#codegen-globals). These classes can hit two sorts of limits of the compiler / JVM:

- Methods (including static / instance initialisers) are allowed to contain only 64kb of bytecode.
- Classes are allowed to contain at most 64k of constant literals

While there exist workarounds for the above two limitations (delegating initialisations to nested classes, inheriting constant literals from implemented interfaces), the preferred approach is either one of these:

- Distribute your database objects in several schemas. That is probably a good idea anyway for such large databases
- [Configure jOOQ's code generator](#codegen-configuration) to exclude excess database objects
- [Configure jOOQ's code generator](#codegen-configuration) to avoid generating [global objects](#codegen-globals) using `<globalObjectReferences/>`
- Remove uncompilable classes after code generation

Independently of these hard limits, large schemas can produce a lot of generated code, which slows down compilation and IDE indexing. See the section about [reducing the size of generated code](#codegen-reducing-generated-code-size) for code generation flags that help with this.

<a id="codegen-reducing-generated-code-size"></a>
### 5.16. Reducing the size of generated code

jOOQ's generated code contains a lot of convenience, much of which is optional. For most schemas, this is not a problem, but for very large schemas with thousands of tables, foreign keys, or routines, the sheer amount of generated code can become a burden:

- Compilation (`javac`, `kotlinc`,`scalac`) gets slow and may require a lot of memory, especially with complex generic types
- IDEs need more time and memory to index the generated sources
- The resulting artefacts get larger, and class loading at runtime takes longer

While the section about [code generation for large schemas](#codegen-large-schemas) deals with hard limits of the compiler and the JVM, this section summarises the code generation flags that can be used to reduce the overall size of generated code, and the functionality that you give up when doing so. Typically, you will want to turn off only those features that you don't need in your project.

#### Generate fewer objects

The most effective way of reducing the size of generated code is not to generate objects that you don't need at all:

- Use [<includes/> and <excludes/>](#codegen-database-includes-excludes) to restrict code generation to the tables, routines, etc. that your application actually uses. This includes excluding backup tables, staging tables, legacy objects, etc.
- Use the [include object types flags](#codegen-database-include-object-types) (e.g. `<includeRoutines/>`, `<includePackages/>`, `<includeUDTs/>`, `<includeSequences/>`, `<includeIndexes/>`, `<includeCheckConstraints/>`) to exclude entire object types. Indexes and check constraints, for example, are only needed if you use the generated meta data, e.g. to [generate DDL](#generating-ddl).
- Keep the `<includeSystemTables/>`,`<includeSystemIndexes/>`, `<includeSystemSequences/>`,etc. flags turned off (which is the default).
- Turn off [global object references](#codegen-generate-globals) such as `<globalObjectReferences/>`, if you always dereference objects from their schema or table classes, rather than from the generated `Tables`, `Keys`, `Indexes`, `Routines`, etc. classes.

#### Optional artefacts that are turned off by default

A few flags are turned off by default, but may have been enabled in your configuration (e.g. because they used to be turned on by default in older versions of jOOQ). Revisit these if code size is a concern:

- **`<recordsImplementingRecordN/>`**: Makes [generated records](#codegen-records) implement `Record1<T1>` to `Record22<T1, ..., T22>` and generates a lot of additional methods on records and tables, including `fieldsRow()`, `valuesRow()`, `value1()` to `value22()`, `values(...)`, and type safe `mapping()` methods. The many generic type parameters are particularly heavy for compilers. Without this, you can still use records in the same way, except that the degree and column types are not available to the compiler on the record type.
- **`<implicitJoinPathUnusedConstructors/>`**: Generates path constructors on tables that aren't involved in any foreign key relationship. This is rarely needed.
- **`<pojos/>`**, **`<interfaces/>`**, **`<daos/>`**: Each of these generates an additional class per table (and UDT).If you need them only for some tables, use `<pojosIncludes/>`, `<pojosExcludes/>`, `<daosIncludes/>`, and `<daosExcludes/>` to restrict their generation. Note that [DAOs](#codegen-daos) also require records to be generated.
- **`<fluentSetters/>`**, **`<varargSetters/>`**, **`<explicitNullability/>`** (see [explicit nullability](#codegen-generate-explicit-nullability)): These generate additional methods or code per column.
- **Annotations**, including `<generatedAnnotation/>`,`<jpaAnnotations/>`, `<validationAnnotations/>`, `<nonnullAnnotation/>`, `<nullableAnnotation/>`, `<constructorPropertiesAnnotation/>` (see the section about [annotations](#codegen-generate-annotations)).

#### Records

[Generated records](#codegen-records) (`<records/>`) are mainly needed for [CRUD with UpdatableRecords](#crud-with-updatablerecords), and to get a type safe `TableRecord` type when fetching from a single table. If records are turned off, generated tables reference [`org.jooq.Record`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html) as their record type, instead.

If you need records only for some tables, e.g. those that you use with CRUD or DAOs, use `<recordsIncludes/>` and `<recordsExcludes/>` to generate records only for those tables.

#### Implicit join paths

For every foreign key, the code generator produces [implicit join path](#codegen-implicit-join-paths) constructors (methods and possibly cached instances) on both the referencing and the referenced table. In schemas with many foreign keys, this can add up to a significant amount of code. The relevant flags are:

- **`<implicitJoinPathsToOne/>`**: Path constructors for outgoing foreign keys (to-one relationships), e.g. `BOOK.author()`
- **`<implicitJoinPathsToMany/>`**: Path constructors for incoming foreign keys (to-many relationships), e.g. `AUTHOR.book()`
- **`<implicitJoinPathsManyToMany/>`**: Path constructors for many-to-many relationships via relationship tables. These are turned off implicitly if either of the above is turned off.
- **`<implicitJoinPathTableSubtypes/>`**: A `Path` subtype per table (e.g. `AuthorPath`) that implements [`org.jooq.Path`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Path.html). Without these subtypes, path constructors return the ordinary generated table type, and features that depend on the `Path` type, such as path joins with an optional `ON` clause (e.g. `.join(BOOK.author())`), are unavailable.

All of these are mere convenience. When turned off, you can no longer use [implicit path joins](#implicit-join) or path correlation, but you can still write explicit joins, including joins using [ON KEY](#join-predicate-on-key), which only depend on the generated keys (`<relations/>`).

#### Covariant overrides

Each generated table overrides a set of methods from [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) to return the generated table type instead of the general `Table<R>` type (see [covariant overrides](#codegen-covariant-overrides)):

- **`<whereMethodOverrides/>`**: About 10 overloads of `where()`, `whereExists()` and `whereNotExists()`, to support inline derived tables. These can usually be turned off without much loss.
- **`<renameMethodOverrides/>`**: Overloads of `rename()`. These can usually be turned off without much loss.
- **`<asMethodOverrides/>`**: Overloads of `as()`. Turning these off has a significant impact on usability, as aliased tables can no longer dereference their columns in a type safe way (e.g. `a.FIRST_NAME`), but only via `a.field(AUTHOR.FIRST_NAME)`. It is usually better to leave these turned on.

#### Javadoc, comments, and sources

- **`<javadoc/>`** and **`<comments/>`** (and the more fine grained `<commentsOnXYZ/>` flags): Javadoc doesn't contribute to byte code, but it makes source files larger, which affects compilation, IDE indexing, and version control(see [comments](#codegen-database-comments)).
- **`<sources/>`** and **`<sourcesOnViews/>`**: The source code of views is generated as a string literal into the generated table class. For large views, these literals can be quite large (see [sources](#codegen-generate-sources)).

#### Other flags

- **`<deprecated/>`**: Turn off the generation of deprecated code that is only kept for backwards compatibility.
- **`<udtPaths/>`**and **`<embeddablePaths/>`**: Turn off the generation of path expressions for UDT attributes and embeddable fields on tables, if you don't dereference nested attributes or fields in your queries.
- **`<indexes/>`**and **`<sequenceFlags/>`**: Index and sequence flag meta data is only needed if you work with the generated meta data, e.g. to [export DDL](#generating-ddl).
- **`<relations/>`**: As a last resort, primary keys, unique keys, and foreign keys can be turned off. This is not recommended, as a lot of functionality depends on them, including [UpdatableRecord CRUD](#crud-with-updatablerecords), [ON KEY joins](#join-predicate-on-key), and all implicit join paths.

#### Example

The following configuration turns off all of the convenience features that can be turned off without losing too much essential functionality:

**XML (standalone and maven):**

```xml
<configuration>
  <generator>
    <generate>
<!-- Keep these turned off (the default) -->
      <recordsImplementingRecordN>false</recordsImplementingRecordN>
      <implicitJoinPathUnusedConstructors>false</implicitJoinPathUnusedConstructors><!-- Generate records only where CRUD is needed -->
      <records>true</records>
      <recordsIncludes>CUSTOMER|ORDER|ORDER_LINE</recordsIncludes>
      <!-- Turn off implicit join path convenience -->
      <implicitJoinPathsToOne>false</implicitJoinPathsToOne>
      <implicitJoinPathsToMany>false</implicitJoinPathsToMany>
      <implicitJoinPathsManyToMany>false</implicitJoinPathsManyToMany>
      <implicitJoinPathTableSubtypes>false</implicitJoinPathTableSubtypes>
<!-- Turn off rarely used covariant overrides -->
      <whereMethodOverrides>false</whereMethodOverrides>
      <renameMethodOverrides>false</renameMethodOverrides>
      <!-- Turn off additional documentation and sources -->
      <comments>false</comments>
      <sourcesOnViews>false</sourcesOnViews>
      <deprecated>false</deprecated>
    </generate>
  </generator>
</configuration>
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd), [standalone code generation](#codegen-programmatic), and [maven code generation](#codegen-maven) for more details.

**Programmatic:**

```java
new org.jooq.meta.jaxb.Configuration()
  .withGenerator(
    new Generate()

      // Keep these turned off (the default)
      .withRecordsImplementingRecordN(false)
      .withImplicitJoinPathUnusedConstructors(false)

      // Generate records only where CRUD is needed
      .withRecords(true)
      .withRecordsIncludes("CUSTOMER|ORDER|ORDER_LINE")

      // Turn off implicit join path convenience
      .withImplicitJoinPathsToOne(false)
      .withImplicitJoinPathsToMany(false)
      .withImplicitJoinPathsManyToMany(false)
      .withImplicitJoinPathTableSubtypes(false)

      // Turn off rarely used covariant overrides
      .withWhereMethodOverrides(false)
      .withRenameMethodOverrides(false)

      // Turn off additional documentation and sources
      .withComments(false)
      .withSourcesOnViews(false)
      .withDeprecated(false)
  )
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [programmatic code generation](#codegen-programmatic) for more details.

**Gradle (Kotlin):**

```kotlin
import org.jooq.meta.jaxb.*


configuration {
  generator {
    generate {

      // Keep these turned off (the default)
      isRecordsImplementingRecordN = false
      isImplicitJoinPathUnusedConstructors = false

      // Generate records only where CRUD is needed
      isRecords = true
      recordsIncludes = "CUSTOMER|ORDER|ORDER_LINE"

      // Turn off implicit join path convenience
      isImplicitJoinPathsToOne = false
      isImplicitJoinPathsToMany = false
      isImplicitJoinPathsManyToMany = false
      isImplicitJoinPathTableSubtypes = false

      // Turn off rarely used covariant overrides
      isWhereMethodOverrides = false
      isRenameMethodOverrides = false

      // Turn off additional documentation and sources
      isComments = false
      isSourcesOnViews = false
      isDeprecated = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (Groovy):**

```groovy
configuration {
  generator {
    generate {

      // Keep these turned off (the default)
      recordsImplementingRecordN = false
      implicitJoinPathUnusedConstructors = false

      // Generate records only where CRUD is needed
      records = true
      recordsIncludes = "CUSTOMER|ORDER|ORDER_LINE"

      // Turn off implicit join path convenience
      implicitJoinPathsToOne = false
      implicitJoinPathsToMany = false
      implicitJoinPathsManyToMany = false
      implicitJoinPathTableSubtypes = false

      // Turn off rarely used covariant overrides
      whereMethodOverrides = false
      renameMethodOverrides = false

      // Turn off additional documentation and sources
      comments = false
      sourcesOnViews = false
      deprecated = false
    }
  }
}
```

See the [configuration XSD](https://www.jooq.org/xsd/jooq-codegen-3.22.0.xsd) and [gradle code generation](#codegen-gradle) for more details.

**Gradle (third party):**

```java
// The jOOQ-codegen-gradle plugin has been introduced in version 3.19.
// Please use the official plugin instead of the third party plugin that was recommended before.
```

Whether turning off any of these flags helps depends on your schema and your build. It is advisable to measure compilation time and memory consumption of your build before and after such changes, and to turn off only those features that make a noticeable difference.

<a id="codegen-version-control"></a>
### 5.17. Code generation and version control

When using jOOQ's code generation capabilities, you will need to make a strategic decision about whether you consider your generated code as

- Part of your code base
- Derived artefacts

In this section we'll see that both approaches have their merits and that none of them is clearly better.

#### Part of your code base

When you consider generated code as part of your code base, you will want to:

- Check in generated sources in your version control system
- Use manual source code generation
- Possibly use even partial source code generation

This approach is particularly useful when your Java developers are not in full control of or do not have full access to your database schema, or if you have many developers that work simultaneously on the same database schema, which changes all the time. It is also useful to be able to track side-effects of database changes, as your checked-in database schema can be considered when you want to analyse the history of your schema.

With this approach, you can also keep track of the change of behaviour in the jOOQ code generator, e.g. when upgrading jOOQ, or when modifying the code generation configuration.

The drawback of this approach is that it is more error-prone as the actual schema may go out of sync with the generated schema.

#### Derived artefacts

When you consider generated code to be derived artefacts, you will want to:

- Check in only the actual DDL (e.g. controlled via [Flyway](#jooq-with-flyway))
- Regenerate jOOQ code every time the schema changes
- Regenerate jOOQ code on every machine - including continuous integration

This approach is particularly useful when you have a smaller database schema that is under full control by your Java developers, who want to profit from the increased quality of being able to regenerate all derived artefacts in every step of your build.

The drawback of this approach is that the build may break in perfectly acceptable situations, when parts of your database are temporarily unavailable.

#### Pragmatic combination

In some situations, you may want to choose a pragmatic combination, where you put only some parts of the generated code under version control. For example, you may want to version control your POJOs, but not your tables / records. This can be achieved in multiple ways:

- You could use a [generator strategy](#codegen-generatorstrategy) to relocate your POJOs to a different package, making excluding one or the other artifact using e.g. `.gitignore` much simpler
- You could run the code generator twice, once for POJOs only, and once for the rest.

<a id="codegen-feature-dependencies"></a>
### 5.18. Features requiring generated code

There are numerous features in jOOQ that require the use of generated code, which is [why we always recommend using generated code by default](https://blog.jooq.org/why-you-should-use-jooq-with-code-generation/). The main and only reason why you wouldn't use the code generator is because your schema is dynamic and known only at runtime.

However, even when you use the jOOQ code generator, there are occasions where you may need to bypass it by using [plain SQL](#plain-sql) or [Name based Field and Table types](#names). In those cases, you will not benefit from the following features either (the features are effectively bypassed). Such features include:

- Calling [stored procedures and functions](#codegen-procedures)
- Binding [user defined types](#codegen-udts)
- [CRUD with UpdatableRecords](#crud-with-updatablerecords)
- [Implicit JOIN paths](#codegen-implicit-join-paths)
- [UDT paths](#user-defined-type-attribute-paths)
- [INSERT RETURNING](#insert-returning), [UPDATE RETURNING](#update-returning), and [DELETE RETURNING](#delete-returning) emulations need access to constraint and [trigger](#codegen-triggers)meta data.
- [Hidden columns](#codegen-database-hidden-columns) are a code generation feature that is attached to a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html).
- [Redacted columns](#codegen-database-redacted-columns) are a code generation feature that is attached to a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html).
- [Readonly columns](#codegen-database-readonly-columns) are a code generation feature that is attached to a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html).
- [Computed columns](#codegen-database-forced-types-computed) are a code generation feature that is attached to a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html).
- [Audit columns](#codegen-database-forced-types-audit) are implemented via [computed columns](#codegen-database-forced-types-computed), and thus the same limitations apply.
- [Forced types](#codegen-database-forced-types) are a code generation feature that is attached to a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html).
- [Policies](#policies) are a runtime feature, depending on [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) equality.
- [Render mapping](#settings-render-mapping) is a runtime feature, depending on [`org.jooq.Catalog`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Catalog.html), [`org.jooq.Schema`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Schema.html), or [`org.jooq.Table`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Table.html) equality.
- [QueryPart traversal](#model-api-traversal) is a runtime feature that depends on a [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) being traversable by jOOQ's internals.
- [QueryPart replacement](#model-api-replacement) is a runtime feature that depends on a [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) being traversable by jOOQ's internals.

> [!TIP]
> Note that it is possible to use some of the above features even with plain SQL if you copy a [`org.jooq.DataType`](https://www.jooq.org/javadoc/3.22.x/org/jooq/DataType.html) from generated code to your template, although, you will have to remember this step every time you create such a template.

<a id="coming-from-jpa"></a>
## 6. Coming from JPA

If you've written most of your Java persistence logic using JPA, then the following sections are for you.

In the following sections, we'll explain the main conceptual differences between JPA and jOOQ, as well as show how individual JPA features are best mapped to jOOQ or SQL features.

<a id="from-jpa-set-based-thinking"></a>
### 6.1. Set based thinking

Many conceptual differences that you may encounter between using JPA and jOOQ are not technology specific, but a matter of how you think about your database interactions. Neither approach is "the best" one, both approaches are each better suited to certain use-cases. The approaches being discussed here are:

- Working with entity state transitions (where JPA shines)
- Working with data set transformations (where jOOQ / SQL shine)

A typical application will have both of the above problems, maybe one type of problem more than the other. It is important to recognise that if you do have both problems, using both types of technology next to each other is a perfectly fine option! Using jOOQ and using JPA aren't mutually exclusive.

Having said so, jOOQ is used most efficiently when following the SQL paradigm of set based thinking. I.e. [don't do this](#dont-do-this-n-plus-one):

```sql
FOR rec IN (SELECT id FROM book WHERE title LIKE 'A%') LOOP
  UPDATE book
  SET last_update = CURRENT_TIMESTAMP
  WHERE book.id = rec.id;
END LOOP;
```

But do this, instead:

```sql
UPDATE book
SET last_update = CURRENT_TIMESTAMP
WHERE title LIKE 'A%';
```

The example deliberately didn't use any Java or even JPA code to show the idea that set based thinking isn't strictly related to writing SQL. The first example exposes the [N+1 problem](#dont-do-this-n-plus-one) via PL/SQL code. It may be perfectly fine to implement entity state transitions on an individual per-row basis in some cases, but in a lot of cases, it's much better to treat your data as data sets and run bulk queries.

Getting a deep understanding of this distinction is out of scope for this reference manual. It takes a lot of practice to do both approaches. But it's important to be reminded of this distinction when you want to switch from JPA to jOOQ. jOOQ embraces the SQL paradigm of set based thinking, and so should you, when you want to use jOOQ most effectively.

<a id="from-jpa-database-first"></a>
### 6.2. Database first

In principle, JPA is agnostic of an entity model first or DDL first / database first approach. In principle, you can:

- Write DDL (e.g. migrate it with Flyway or Liquibase), then re-generate your entity code.
- Write entities, then re-generate your database or derive DDL increments from your git history, etc.
- Manually maintain both in parallel.

jOOQ is more opinionated here. It assumes your database already exists, outside of jOOQ. It does not assume your database follows any rules imposed by jOOQ regarding the design. For example, when using jOOQ, it's completely irrelevant:

- If you're using surrogate keys or natural keys
- If your keys have single columns or multiple columns
- If your tables even have keys, or if they're not in the first normal form
- If your tables are even tables, or if they're views, table valued functions, etc

Not just that jOOQ doesn't care about your database model, it also doesn't care about your client side data representation (e.g. the DTOs). I.e. it doesn't care:

- If your DTO classes and attributes are `public` or `private`
- If your DTOs are immutable or mutable
- If your DTOs implement `equals()` or `hashCode()` in any way
- If your DTOs have a meaningful identity, or are just value based classes (or soon even actual value types!)

There are no best practices from a jOOQ perspective. jOOQ has seen everything, and jOOQ won't judge you. jOOQ knows, that if your tables are not even in the first normal form, you'll have enough problems already, so you don't also need a problem with jOOQ.

#### But

But, again, jOOQ expects you to have a database that already exists. Yes, you can even use jOOQ for your [DDL](#ddl-statements), but the point here is that you write DDL first, *then* your jOOQ queries later, [ideally using source code generation](https://blog.jooq.org/why-you-should-use-jooq-with-code-generation/).

Client applications come and go. They used to be written in Delphi. Then PHP. Then Java. Now Kotlin. Soon TypeScript/Rust/Go/Whatever? But your database stays. It will survive your client application, and as such, jOOQ understands that your database must come first.

Obviously, there exist other ways to think about business logic and databases. But jOOQ was designed for the database first model.

<a id="from-jpa-eager-lazy"></a>
### 6.3. Eager or lazy loading

In jOOQ, you always load data explicitly, never automatically via eager or lazy loading, both of which seem useful at first, but come at a heavy price, or say, complexity tax.

- Eager loading prevents extra round trips when you *need* the data, but cannot be easily prevented when you *do not need* the data, so chances are, eager loading is generating too much unnecessary effort
- Lazy loading prevents unnecessary loading when you *don't need* the data, but generates delayed extra work ([the dreaded N+1 problem](#dont-do-this-n-plus-one)) when you do need the data

In the JPA ecosystem, a lot of folks advocate using queries to avoid both of the above problems. That's why in jOOQ, the above problems don't exist, because you will *always* spell out the exact query that you need to produce the data you want.

<a id="from-jpa-caches"></a>
### 6.4. First level cache and second level cache

In the jOOQ world, a first or second level cache is not needed, because it fundamentally opposes [the idea that you interact with your database only using queries](#from-jpa-eager-lazy), not using entity graph navigation.

In the JPA world, this idea exists as well when you use *(DTO) projections*, which cannot reasonably be cached using first and second level caches (at least not without moving the query execution partially into the client).

As these caches solve problems that jOOQ doesn't have, because jOOQ doesn't have [eager or lazy loading](#from-jpa-eager-lazy), nor does it operate on the entity graph, there is no need for such a cache, or even a [stateful session](#from-jpa-statelesssession).

Should you find the need for caching other types of data (e.g. your DTOs of some master data), then it should be quite trivial to use any off-the-shelf cache product and cache that data in the service layer directly. From a jOOQ perspective, the query layer is the wrong place to cache any data.

<a id="from-jpa-statelesssession"></a>
### 6.5. StatelessSession

JPA is mainly used for its stateful `EntityManager`, which offers access to [caches](#from-jpa-caches), but recent JPA specification versions as well as implementations have supported a `StatelessSession`, which allows for fetching entities that aren't being tracked.

Since jOOQ does not have any concept of a session, similar to not having [caches](#from-jpa-caches), this is not a useful concept in jOOQ as any interaction with the database is stateless, including the [UpdatableRecord](#crud-with-updatablerecords), which does track changes, but isn't itself being tracked by some global session.

<a id="from-jpa-embeddable"></a>
### 6.6. Embeddable

JPA knows the [`jakarta.persistence.Embeddable`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/Embeddable), which has an similar representation in jOOQ, also called embeddables. See also [the manual's section on how to attach embeddables to generated code](#codegen-embeddable-types).

<a id="from-jpa-converter"></a>
### 6.7. AttributeConverter

JPA knows the [`jakarta.persistence.AttributeConverter`](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/AttributeConverter), which is called [`org.jooq.Converter`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Converter.html) in jOOQ. They work exactly the same way. See also [the manual's section on how to attach a Converter to generated code](#codegen-database-forced-types-converter).

<a id="from-jpa-user-type"></a>
### 6.8. User types

Some JPA implementations offer user types, which are called [`org.jooq.Binding`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Binding.html) in jOOQ. They work exactly the same way. See also [the manual's section on how to attach a Binding to generated code](#codegen-database-forced-types-binding).

<a id="from-jpa-implicit-join"></a>
### 6.9. Implicit JOIN

One of HQL's greatest features is the implicit `JOIN` feature, which is generated from path expressions when you follow foreign key "paths" from child entities to parent entities. The same feature is available in jOOQ as well, if you're using [code generation](https://blog.jooq.org/why-you-should-use-jooq-with-code-generation/).

In HQL, you might write:

```sql
from Book as book
where book.language.cd = 'en'
```

And in jOOQ, this just translates to:

```java
create.selectFrom(BOOK)
      .where(BOOK.language().CD.eq("en"))
      .fetch();
```

Some of the jOOQ features used in this section are:

- [implicit joins](#implicit-join) (these are optional to the task of nesting, but greatly simplify it)

> [!TIP]
> In Hibernate, implicit joins always produce an `INNER JOIN`, which may be surprising on nullable foreign keys, or on `to-many` path navigations. jOOQ generates `LEFT JOIN` by default, though you can [override this behaviour with Settings](#settings-implicit-join-type).

<a id="from-jpa-manytoone"></a>
### 6.10. @OneToOne or @ManyToOne

In JPA, you may have a `@ManyToOne` mapping like this:

```java
@Entity
public class Book {

    @Id
    @GeneratedValue
    private Long id;

    @Column
    private String title;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "language_id")
    private Language language;

    // [...]
}
```

In JPA, you get to specify whether such associations should be fetched [eagerly or lazily](#from-jpa-eager-lazy). In jOOQ, this is irrelevant as you will always express your intent explicitly via a query. [Nothing is ever done automatically](#from-jpa-eager-lazy).

From a mapping perspective, it can be convenient to nest a parent object in the child object (irrespective of whether this is a `@OneToOne` or `@ManyToOne` relationship). In jOOQ, such a mapping is always ad-hoc, on a per query basis, so it does not need to reflect your actual database model. For example, you can easily "nest" a `Title` in a `Book`. With jOOQ, nesting is done directly in SQL using ORDBMS features (native or emulated).

So, instead of having entity classes, you might have DTOs like these (note, we might not need to project the `ID`):

```java
public record Language(String code, String description) {}
public record Book(String title, Language language) {}
```

The DTOs may be reusable or ad-hoc, per query, it's entirely up to you. And you map your query data into the above records as follows:

```java
create.select(
           BOOK.TITLE,

           // Nested record here:
           row(

               // Implicit join here
               BOOK.language().CD,
               BOOK.language().DESCRIPTION

           // Ad-hoc converter here:
           ).mapping(Language::new))
      .from(BOOK)

      // Ad-hoc converter here
      .fetch(Records.mapping(Book::new));
```

The above mapping is completely compile time type safe.

Some of the jOOQ features used in this section are:

- [ad-hoc conversion](#ad-hoc-converter)
- [nested records](#nested-records)
- [nested table expressions](#select-clause-table) (this can be convenient, but it is far more likely you project only what's strictly needed)
- [implicit joins](#implicit-join) (these are optional to the task of nesting, but greatly simplify it)

<a id="from-jpa-onetomany"></a>
### 6.11. @OneToMany or @ManyToMany

In JPA, you may have a `@OneToMany` mapping like this:

```java
@Entity
public class Author {

    @OneToMany(mappedBy = "author")
    private Set<Book> items;

    // [...]
}
```

In JPA, you get to specify whether such associations should be fetched [eagerly or lazily](#from-jpa-eager-lazy). In jOOQ, this is irrelevant as you will always express your intent explicitly via a query. [Nothing is ever done automatically](#from-jpa-eager-lazy).

From a mapping perspective, it can be convenient to nest a set (or list, whatever) of child objects in the parent object (irrespective of whether this is a `@OneToMany` or `@ManyToMany` relationship). In jOOQ, such a mapping is always ad-hoc, on a per query basis, so it does not need to reflect your actual database model. For example, you can easily "nest" a set of `Language` values in a `BookStore`, as we'll see later. With jOOQ, nesting is done directly in SQL using ORDBMS features (native or emulated).

So, instead of having entity classes, you might have DTOs like these (note, we might not need to project the `ID`):

```java
public record Book(String title) {}
public record Author(String firstName, String lastName, List<Book> books) {}
```

The DTOs may be reusable or ad-hoc, per query, it's entirely up to you. And you map your query data into the above records as follows:

```java
create.select(
           AUTHOR.FIRST_NAME,
           AUTHOR.LAST_NAME,

           // Nested collection using to-many path correlation here:
           multiset(
               select(AUTHOR.book().TITLE)
               .from(AUTHOR.book())

           // Ad-hoc converter here:
           ).convertFrom(r -> r.map(Records.mapping(Book::new))))
      .from(AUTHOR)

      // Ad-hoc converter here
      .fetch(Records.mapping(Author::new));
```

The above mapping is completely compile time type safe.

Some of the jOOQ features used in this section are:

- [ad-hoc conversion](#ad-hoc-converter)
- [MULTISET value constructor](#multiset-value-constructor)

<a id="whats-new"></a>
## 7. What's new in version 3.22.0

The below list of sections documents all the sections about new features in jOOQ version 3.22.0:

- SQL building
  - The DSLContext API
    - Custom Settings
      - [Meta SQL on error](#settings-meta-sql-on-error)

  - SQL Statements (DDL)
    - The CREATE statement
      - CREATE TABLE
        - [Constraint deferrability](#create-table-constraint-deferrability)

    - The SET statement
      - [SET CONSTRAINTS](#set-constraints-statement)

  - Column expressions
    - Window functions
      - [IS_FIRST](#window-is-first)

- SQL execution
  - Importing data
    - Import data sources
      - [Importing XML](#importing-source-xml)

- Code generation
  - Advanced generator configuration
    - Generate
      - [Explicit nullability](#codegen-generate-explicit-nullability)

<a id="reference"></a>
## 8. Reference

These chapters hold some general jOOQ reference information

<a id="modules"></a>
### 8.1. Modules

jOOQ's logic is distributed into different modules, which are listed here.

<a id="module-jooq"></a>
#### 8.1.1. jOOQ module

The jOOQ module contains the runtime library.

Its main features are:

- [SQL building](#sql-building)
- [SQL execution](#sql-execution)
- [SQL parsing](#sql-parser)

And much more. Most systems will only include this library as a dependency.

<a id="module-jooq-beans-extensions"></a>
#### 8.1.2. jOOQ-beans-extensions module

The `jOOQ-beans-extensions` module contains [`org.jooq.impl.DefaultRecordMapper`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultRecordMapper.html) logic depending on the `java.desktop` module's [`java.beans.ConstructorProperties`](https://docs.oracle.com/en/java/javase/25/docs/api/java.desktop/java/beans/ConstructorProperties.html) annotation.

This logic has been extracted from the [core library](#module-jooq) in jOOQ 3.20 to allow for omitting a dependency on `java.desktop`, which is a very big JDK module adding no value to most jOOQ users.

<a id="module-jooq-bom"></a>
#### 8.1.3. jOOQ-bom module

The `jOOQ-bom` module offers an automatically generated Maven BOM (Bill of Materials) file for all the [jOOQ modules](#modules).

<a id="module-jooq-checker"></a>
#### 8.1.4. jOOQ-checker module

The `jOOQ-checker` module contains the logic using the [Checker Framework or ErrorProne libraries](#checker-framework) for additional compile time checks of jOOQ API usage.

<a id="module-jooq-codegen"></a>
#### 8.1.5. jOOQ-codegen module

The `jOOQ-codegen` module contains the [code generation logic](#code-generation) used to generate table / column meta data, etc. from your database. It has its own dependencies and extensions that are listed in these sections.

<a id="module-jooq-codegen-gradle"></a>
#### 8.1.6. jOOQ-codegen-gradle module

The `jOOQ-codegen-gradle` module exposes the [jOOQ-codegen module](#module-jooq-codegen) and its code generation logic as a [Gradle plugin](#codegen-gradle).

<a id="module-jooq-codegen-maven"></a>
#### 8.1.7. jOOQ-codegen-maven module

The `jOOQ-codegen-maven` module exposes the [jOOQ-codegen module](#module-jooq-codegen) and its code generation logic as a [Maven plugin](#codegen-maven).

<a id="module-jooq-jackson-extensions"></a>
#### 8.1.8. jOOQ-jackson-extensions module

The `jOOQ-jackson-extensions` module offers a few Jackson-specific [Converter](#data-type-converter) implementations to convert between JSON formats and Jackson annotated classes.

> [!TIP]
> To work with Jackson 3, use the `jOOQ-jackson3-extensions` module instead.

<a id="module-jooq-jpa-extensions"></a>
#### 8.1.9. jOOQ-jpa-extensions module

The `jOOQ-jpa-extensions` module offers a JPA-specific [Converter](#data-type-converter) as well as JPA specific [`org.jooq.impl.DefaultRecordMapper`](https://www.jooq.org/javadoc/3.22.x/org/jooq/impl/DefaultRecordMapper.html) extension logic.

This logic has been extracted from the [core library](#module-jooq) in jOOQ 3.20 to allow for omitting a dependency on `jakarta.persistence`, which most jOOQ users do not need.

<a id="module-jooq-kotlin"></a>
#### 8.1.10. jOOQ-kotlin module

The `jOOQ-kotlin` module offers a few Kotlin extension functions to provide a more idiomatic jOOQ experience to Kotlin users.

> [!TIP]
> To work with Kotlin 2, use the `jOOQ-kotlin2` module instead.

<a id="module-jooq-kotlin-coroutines"></a>
#### 8.1.11. jOOQ-kotlin-coroutines module

The `jOOQ-kotlin-coroutines` module offers a few Kotlin extension functions to allow for bridging between R2DBC and Kotlin coroutines.

> [!TIP]
> To work with Kotlin 2, use the `jOOQ-kotlin2-coroutines` module instead.

<a id="module-jooq-meta"></a>
#### 8.1.12. jOOQ-meta module

The `jOOQ-meta` module offers the dialect specific meta data querying capabilities required by the [jOOQ-codegen module](#module-jooq-codegen) if the database schema should be reverse engineered from a live RDBMS.

<a id="module-jooq-meta-extensions"></a>
#### 8.1.13. jOOQ-meta-extensions module

The `jOOQ-meta-extensions` module implements optional [Meta data querying capabilities](#module-jooq-meta) e.g. to reverse engineer a [DDL script](#codegen-ddl) instead of a live database connection.

<a id="module-jooq-meta-extensions-hibernate"></a>
#### 8.1.14. jOOQ-meta-extensions-hibernate module

The `jOOQ-meta-extensions-hibernate` module implements optional [Meta data querying capabilities](#module-jooq-meta) to reverse engineer a [set of JPA annotated entities](#codegen-jpa) instead of a live database connection.

<a id="module-jooq-meta-extensions-liquibase"></a>
#### 8.1.15. jOOQ-meta-extensions-liquibase module

> [!TIP]
> As of jOOQ 3.21.0, this functionality has been deprecated, see [https://github.com/jOOQ/jOOQ/issues/19353](https://github.com/jOOQ/jOOQ/issues/19353) for details. The recommended replacement is to use testcontainers or similar to emulate a Liquibase migration, similar to what is being recommended for Flyway: [https://blog.jooq.org/using-testcontainers-to-generate-jooq-code/](https://blog.jooq.org/using-testcontainers-to-generate-jooq-code/).

The `jOOQ-meta-extensions-liquibase` module implements optional [Meta data querying capabilities](#module-jooq-meta) to reverse engineer a [Liquibase migration](#codegen-liquibase) instead of a live database connection.

<a id="module-jooq-meta-kotlin"></a>
#### 8.1.16. jOOQ-meta-kotlin module

The `jOOQ-meta-kotlin` module implements Kotlin extension functions for code generation configuration elements from [jOOQ-meta](#module-jooq-meta), in order to better use them from a Kotlin script, e.g. when working with Gradle, but not with the official [Gradle plugin](#module-jooq-codegen-gradle).

> [!TIP]
> To work with Kotlin 2, use the `jOOQ-meta-kotlin2` module instead.

<a id="module-jooq-postgres-extensions"></a>
#### 8.1.17. jOOQ-postgres-extensions module

The `jOOQ-postgres-extensions` module contains PostgreSQL specific [DataType bindings](#data-type-binding), i.e. the ones listed as [extended data types](#extended-data-types).

<a id="module-jooq-reactor-extensions"></a>
#### 8.1.18. jOOQ-reactor-extensions module

The `jOOQ-reactor-extensions` module contains logic bridging between jOOQ's R2DBC support and the popular Reactor library.

<a id="module-jooq-scala"></a>
#### 8.1.19. jOOQ-scala module

The `jOOQ-scala` module offers a few Scala implicit methods and classes to provide a more idiomatic jOOQ experience to Scala users.

> [!TIP]
> To work with a specific Scala version, use e.g. the `jOOQ-scala_2.13` or `jOOQ-scala_3.5` module.

<a id="module-jooq-xtend"></a>
#### 8.1.20. jOOQ-xtend module

The `jOOQ-xtend` module offers a few Xtend extension functions to provide a more idiomatic jOOQ experience to Xtend users.

<a id="supported-rdbms"></a>
### 8.2. Supported RDBMS

#### A list of supported databases

- Aurora MySQL Edition
- Aurora PostgreSQL Edition
- Azure SQL Data Warehouse (Azure Synapse Analytics)
- Azure SQL Database
- BigQuery
- CockroachDB
- Databricks
- DB2 LUW
- Derby
- DuckDB
- EXASOL
- Firebird
- H2
- HANA
- HSQLDB
- Informix
- MariaDB
- Microsoft Access
- MySQL
- Oracle
- PostgreSQL
- Redshift
- SQL Server
- SQLite
- SingleStore (MemSQL)
- Snowflake
- Spanner
- Sybase Adaptive Server Enterprise
- Sybase SQL Anywhere
- Teradata
- Trino
- Vertica
- YugabyteDB

For an up-to-date list of currently supported RDBMS and minimal versions, please refer to [https://www.jooq.org/legal/licensing/#databases](https://www.jooq.org/legal/licensing/#databases) and [https://www.jooq.org/download/support-matrix](https://www.jooq.org/download/support-matrix).

<a id="commercial-only-features"></a>
### 8.3. Commercial only features

Supported editions: Express, Professional, Enterprise (not available in the Open Source Edition)

The commercial jOOQ editions give access to drivers for certain commercial RDBMS as well as to commercial only features, which are not available in the jOOQ Open Source Edition. These features mostly involve:

- Advanced model API usage, traversal, and transformation
- Advanced SQL transformation features
- Procedural language support (procedures, functions, triggers, anonymous blocks)
- Spatial extension support
- Computed column support (server side and client side)
- Advanced SQL parser features
- Advanced diagnostics
- Code generation extensions, e.g. for synthetic objects
- Advanced embeddable types

The below list of sections documents all the sections about commercial only features in jOOQ:

- SQL building
  - The DSLContext API
    - Custom Settings
      - [Auto-inline bind values](#settings-auto-inline-bind-values)
      - [Computed column activation](#settings-computed-column-activation)
      - [Computed column emulation](#settings-computed-column-emulation)
      - [Dialect compatibility](#settings-dialect-compatibility)
      - [Execute Logging SQL Exceptions](#settings-execute-logging-sql-exceptions)
      - [Fetch server output](#settings-fetch-server-output)
      - [Readonly column behaviour](#settings-readonly-columns)
      - [Redacted column behaviour](#settings-redacted-columns)

  - The model API
    - [Traversal](#model-api-traversal)
    - [Replacement](#model-api-replacement)
      - [Pattern transformation Replacer](#replacement-transform-patterns)
      - [Table mapping Replacer](#replacement-table-mapping)
      - [Listening Replacer](#replacement-listening)
      - [Decomposing Replacer](#replacement-decomposing)

  - SQL Statements (DML)
    - The SELECT statement
      - [CONNECT BY clause](#connect-by-clause)
      - [FOR XML clause](#for-xml-clause)
        - [AUTO mode](#for-xml-auto-mode)
        - [PATH mode](#for-xml-path-mode)
        - [EXPLICIT mode](#for-xml-explicit-mode)
        - [RAW mode](#for-xml-raw-mode)
        - [ROOT directive](#for-xml-root-directive)
        - [ELEMENTS directive](#for-xml-elements-directive)

      - [FOR JSON clause](#for-json-clause)
        - [AUTO mode](#for-json-auto-mode)
        - [PATH mode](#for-json-path-mode)
        - [ROOT directive](#for-json-root-directive)
        - [INCLUDE_NULL_VALUES directive](#for-json-include-null-values-directive)
        - [WITHOUT_ARRAY_WRAPPER directive](#for-json-without-array-wrapper-directive)

  - SQL Statements (DDL)
    - The COMMENT statement
      - [COMMENT ON FUNCTION](#comment-on-function)
      - [COMMENT ON PROCEDURE](#comment-on-procedure)

    - The CREATE statement
      - [CREATE FUNCTION](#create-function-statement)
        - [Scalar functions](#create-scalar-function-statement)
        - [CREATE OR REPLACE FUNCTION](#create-or-replace-function)
        - [SQL data access characteristics](#create-function-characteristics-sql-data-access)
        - [DETERMINISTIC characteristic](#create-function-characteristics-deterministic)
        - [ON NULL INPUT characteristic](#create-function-characteristics-on-null-input)
        - [COMMENT characteristic](#create-function-characteristics-comment)

      - [CREATE PROCEDURE](#create-procedure-statement)
        - [CREATE OR REPLACE PROCEDURE](#create-or-replace-procedure)
        - [SQL data access characteristics](#create-procedure-characteristics-sql-data-access)
        - [COMMENT characteristic](#create-procedure-characteristics-comment)

      - CREATE TABLE
        - [Computed columns](#create-table-computed-columns)

      - [CREATE TRIGGER](#create-trigger-statement)
        - [Events](#create-trigger-statement-events)
        - [REFERENCING clause](#create-trigger-statement-referencing)
        - [STATEMENT vs ROW triggers](#create-trigger-statement-statement-vs-row)
        - [WHEN clause](#create-trigger-statement-when)

    - The DROP statement
      - [DROP FUNCTION](#drop-function-statement)
      - [DROP PROCEDURE](#drop-procedure-statement)
      - [DROP TRIGGER](#drop-trigger-statement)

  - [Procedural statements](#procedural-statements)
    - [CALL statement](#procedural-call)
    - [CONTINUE statement](#procedural-continue)
    - [EXECUTE statement](#procedural-execute)
    - [EXIT statement](#procedural-exit)
    - [FOR statement](#procedural-for)
    - [GOTO statement](#procedural-goto)
    - [IF statement](#procedural-if)
    - [Labels](#procedural-label)
    - [LOOP statement](#procedural-loop)
    - [REPEAT statement](#procedural-repeat)
    - [SIGNAL](#procedural-signal)
    - [Variables](#procedural-variables)
    - [WHILE statement](#procedural-while)

  - Table expressions
    - Joined tables
      - JOIN hints
        - [HASH JOIN](#join-hint-hash)
        - [LOOP JOIN](#join-hint-loop)
        - [MERGE JOIN](#join-hint-merge)

    - [Temporal tables](#temporal-tables)

  - Column expressions
    - [Hidden columns](#hidden-columns)
    - [Redacted columns](#redacted-columns)
    - [Readonly columns](#readonly-columns)
    - [Computed columns](#computed-columns)
    - [Spatial functions](#spatial-functions)
      - [ST_Area](#st-area-function)
      - [ST_AsText](#st-astext-function)
      - [ST_Boundary](#st-boundary-function)
      - [ST_Centroid](#st-centroid-function)
      - [ST_Difference](#st-difference-function)
      - [ST_Dimension](#st-dimension-function)
      - [ST_Distance](#st-distance-function)
      - [ST_EndPoint](#st-endpoint-function)
      - [ST_ExteriorRing](#st-exteriorring-function)
      - [ST_GeometryN](#st-geometryn-function)
      - [ST_GeometryType](#st-geometrytype-function)
      - [ST_GeomFromText](#st-geomfromtext-function)
      - [ST_InteriorRingN](#st-interiorringn-function)
      - [ST_Intersection](#st-intersection-function)
      - [ST_Length](#st-length-function)
      - [ST_NumGeometries](#st-numgeometries-function)
      - [ST_NumInteriorRings](#st-numinteriorrings-function)
      - [ST_NumPoints](#st-numpoints-function)
      - [ST_Perimeter](#st-perimeter-function)
      - [ST_PointN](#st-pointn-function)
      - [ST_SRID](#st-srid-function)
      - [ST_StartPoint](#st-startpoint-function)
      - [ST_Transform](#st-transform-function)
      - [ST_Union](#st-union-function)
      - [ST_X](#st-x-function)
      - [ST_XMax](#st-xmax-function)
      - [ST_XMin](#st-xmin-function)
      - [ST_Y](#st-y-function)
      - [ST_YMax](#st-ymax-function)
      - [ST_YMin](#st-ymin-function)
      - [ST_Z](#st-z-function)
      - [ST_ZMax](#st-zmax-function)
      - [ST_ZMin](#st-zmin-function)

    - Aggregate functions
      - [COLLECT](#collect-function)

  - Conditional expressions
    - [Spatial predicates](#spatial-predicates)
      - [ST_Contains](#st-contains-predicate)
      - [ST_Crosses](#st-crosses-predicate)
      - [ST_Disjoint](#st-disjoint-predicate)
      - [ST_Equals](#st-equals-predicate)
      - [ST_Intersects](#st-intersects-predicate)
      - [ST_IsClosed](#st-isclosed-predicate)
      - [ST_IsEmpty](#st-isempty-predicate)
      - [ST_IsRing](#st-isring-predicate)
      - [ST_IsSimple](#st-issimple-predicate)
      - [ST_IsValid](#st-isvalid-predicate)
      - [ST_Overlaps](#st-overlaps-predicate)
      - [ST_Touches](#st-touches-predicate)
      - [ST_Within](#st-within-predicate)

  - Data types
    - Built-in data types
      - [GEOGRAPHY (Geography)](#data-type-geography)
      - [GEOMETRY (Geometry)](#data-type-geometry)

  - SQL Parser
    - [SQL Parser Listener](#sql-parser-listener)

  - QueryParts
    - SQL transformation
      - [ANSI JOIN to table lists](#ansi-join-to-table-lists)
      - [Table lists to ANSI JOIN](#table-lists-to-ansi-join)
      - [ROWNUM to LIMIT](#transform-rownum)
      - [QUALIFY to derived table](#transform-qualify)
      - [IN condition subquery with LIMIT to derived table](#transform-in-with-limit-to-derived-table)
      - [GROUP BY <column index>](#transform-group-by-column-index)
      - [Inline CTE](#transform-inline-cte)
      - [Unnecessary arithmetic expressions](#transform-unnecessary-arithmetic)
      - [Pattern based transformation](#transform-patterns)

    - [Policies](#policies)
      - [Configuration](#policies-configuration)
      - [Implementation](#policies-implementation)
      - [Inheritance](#policies-inheritance)
      - [Security considerations](#policies-security)

- SQL execution
  - Diagnostics
    - [Consecutive aggregation](#diagnostics-consecutive-aggregation)
    - [Concatenation in predicates](#diagnostics-concatenation-in-predicates)
    - [Possibly wrong expressions](#diagnostics-possibly-wrong-expressions)
    - [Incomplete equi join](#diagnostics-incomplete-equi-join)
    - [Trivial condition](#diagnostics-trivial-condition)
    - [Transform patterns](#diagnostics-transform-patterns)

  - [Logging with SQLExceptionLoggerListener](#logging-sql-exceptions)

- Code generation
  - Advanced generator configuration
    - Database
      - [Comments](#codegen-database-comments)
      - Synthetic objects
        - [Synthetic columns](#codegen-database-synthetic-columns)
        - [Synthetic readonly columns](#codegen-database-synthetic-readonly-columns)
        - [Synthetic readonly ROWIDs](#codegen-database-synthetic-readonly-rowids)
        - [Synthetic defaults](#codegen-database-synthetic-defaults)
        - [Synthetic enums](#codegen-database-synthetic-enums)
        - [Synthetic unique keys](#codegen-database-synthetic-uks)
        - [Synthetic foreign keys](#codegen-database-synthetic-fks)
        - [Synthetic synonyms](#codegen-database-synthetic-synonyms)

      - [Hidden columns](#codegen-database-hidden-columns)
      - [Redacted columns](#codegen-database-redacted-columns)
      - [Readonly columns](#codegen-database-readonly-columns)
      - Forced types
        - [Client side computed columns](#codegen-database-forced-types-computed)
        - [Audit columns](#codegen-database-forced-types-audit)
        - [Hidden columns](#codegen-database-forced-types-hidden)
        - [Redacted columns](#codegen-database-forced-types-redacted)
        - [Visibility Modifier (per forced type)](#codegen-database-forced-types-visibility)

  - Generated object types
    - [Generated triggers](#codegen-triggers)

  - Embeddable types
    - [Overlapping embeddable types](#codegen-overlapping-embeddable-types)
    - [Field replacement](#codegen-embeddable-types-replacing-fields)
    - [Embedded keys](#codegen-embedded-keys)
    - [Embedded domains](#codegen-embedded-domains)
    - [Embedded columns (auto configuration)](#codegen-embedded-columns)

- Reference
  - [Commercial only features](#commercial-only-features)

See also the [Feature comparison for a high-level description](https://www.jooq.org/download/#feature-comparison).

<a id="experimental-features"></a>
### 8.4. Experimental features

To improve our development process and get more early adopter feedback, we've started publishing experimental functionality with our ordinary distribution. All such functionality is clearly documented as experimental either in the manual, and/or annotated with the `@Experimental` annotation in the API to make it clear that usage is done at the user's own risk as the API might still change in the future.

The below list of sections documents all the sections about experimental features in jOOQ:

- SQL building
  - The model API
    - [Design](#model-api-design)
    - [Traversal](#model-api-traversal)
    - [Replacement](#model-api-replacement)
      - [Pattern transformation Replacer](#replacement-transform-patterns)
      - [Table mapping Replacer](#replacement-table-mapping)
      - [Listening Replacer](#replacement-listening)
      - [Decomposing Replacer](#replacement-decomposing)

<a id="dsl-mapping-rules"></a>
### 8.5. SQL to DSL mapping rules

jOOQ takes SQL as an external domain-specific language and maps it onto Java, creating an internal domain-specific language. Internal DSLs cannot 100% implement their external language counter parts, as they have to adhere to the syntax rules of their host or target language (i.e. Java). This section explains the various problems and workarounds encountered and implemented in jOOQ.

#### SQL allows for "keywordless" syntax

SQL syntax does not always need keywords to form expressions. The [UPDATE .. SET](#update-statement) clause takes various argument assignments:

```sql
UPDATE t SET a = 1, b = 2
```

```java
update(t).set(a, 1).set(b, 2)
```

The above example also shows missing operator overloading capabilities, where `"="` is replaced by `","` in jOOQ. Another example are [row value expressions](#row-value-expressions), which can be formed with parentheses only in SQL:

```sql
(a, b) IN ((1, 2), (3, 4))
```

```java
row(a, b).in(row(1, 2), row(3, 4))
```

In this case, `ROW` is an actual (optional) SQL keyword, implemented by at least PostgreSQL.

#### SQL contains "composed" keywords

As most languages, SQL does not attribute any meaning to whitespace. However, whitespace is important when forming "composed" keywords, i.e. SQL clauses composed of several keywords. jOOQ follows standard Java method naming conventions to map SQL keywords (case-insensitive) to Java methods (case-sensitive, camel-cased). Some examples:

```sql
GROUP BY
ORDER BY
WHEN MATCHED THEN UPDATE
```

```java
groupBy()
orderBy()
whenMatchedThenUpdate()
```

Future versions of jOOQ may use all-uppercased method names in addition to the camel-cased ones (to prevent collisions with Java keywords):

```sql
GROUP BY
ORDER BY
WHEN MATCHED THEN UPDATE
```

```java
GROUP_BY()
ORDER_BY()
WHEN_MATCHED_THEN_UPDATE()
```

#### SQL contains "superfluous" keywords

Some SQL keywords aren't really necessary. They are just part of a keyword-rich language, the way Java developers aren't used to anymore. These keywords date from times when languages such as ADA, BASIC, COBOL, FORTRAN, PASCAL were more verbose:

- `BEGIN .. END`
- `REPEAT .. UNTIL`
- `IF .. THEN .. ELSE .. END IF`

jOOQ omits some of those keywords when it is too tedious to write them in Java.

```sql
CASE WHEN .. THEN .. END
```

```java
decode().when(.., ..)
```

The above example omits `THEN` and `END` keywords in Java. Future versions of jOOQ may comprise a more complete DSL, including such keywords again though, to provide a more 1:1 match for the SQL language.

#### SQL contains "superfluous" syntactic elements

Some SQL constructs are hard to map to Java, but they are also not really necessary. SQL often expects syntactic parentheses where they wouldn't really be needed, or where they feel slightly inconsistent with the rest of the SQL language.

```sql
LISTAGG(a, b) WITHIN GROUP (ORDER BY c)
              OVER (PARTITION BY d)
```

```java
listAgg(a, b).withinGroupOrderBy(c)
             .over().partitionBy(d)
```

The parentheses used for the `WITHIN GROUP (..)` and `OVER (..)` clauses are required in SQL but do not seem to add any immediate value. In some cases, jOOQ omits them, although the above might be optionally re-phrased in the future to form a more SQLesque experience:

```sql
LISTAGG(a, b) WITHIN GROUP (ORDER BY c)
              OVER (PARTITION BY d)
```

```java
listAgg(a, b).withinGroup(orderBy(c))
             .over(partitionBy(d))
```

#### SQL uses some of Java's reserved words

Some SQL keywords map onto [Java Language Keywords](https://download.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html) if they're mapped using camel-casing. These keywords currently include:

- `CASE`
- `ELSE`
- `FOR`

jOOQ uses a suffix on those keywords to prevent a collision:

```sql
CASE .. ELSE
PIVOT .. FOR .. IN ..
```

```java
case_() .. else_()
pivot(..).for_(..).in(..)
```

There is more future collision potential with, each resolved with a suffix:

- `BOOLEAN`
- `CHAR`
- `DEFAULT`
- `DOUBLE`
- `ENUM`
- `FLOAT`
- `IF`
- `INT`
- `LONG`
- `PACKAGE`

#### SQL operators cannot be overloaded in Java

Most SQL operators have to be mapped to descriptive method names in Java, as Java does not allow operator overloading:

```sql
=
<>, !=
||
SET a = b
```

```java
equal(), eq()
notEqual(), ne()
concat()
set(a, b)
```

For those users using [jOOQ with Scala or Groovy](#scala-sql-building), operator overloading and implicit conversion can be leveraged to enhance jOOQ:

```sql
=
<>, !=
||
```

```java
===
<>, !==
||
```

#### SQL's reference before declaration capability

This is less of a syntactic SQL feature than a semantic one. In SQL, objects can be referenced before (i.e. "lexicographically before") they are declared. This is particularly true for [aliasing](#aliased-tables)

```sql
SELECT t.a
FROM my_table t
```

```java
MyTable t = MY_TABLE.as("t");
select(t.a).from(t)
```

A more sophisticated example are [common table expressions](#common-table-expressions) (CTE), which are currently not supported by jOOQ:

```sql
WITH t(a, b) AS (
  SELECT 1, 2 FROM DUAL
)
SELECT t.a, t.b
FROM t
```

Common table expressions define a "derived column list", just like [table aliases](#aliased-tables) can do. The formal record type thus created cannot be typesafely verified by the Java compiler, i.e. it is not possible to formally dereference `t.a` from `t`.

<a id="quality-assurance"></a>
### 8.6. Quality Assurance

jOOQ is running some of your most mission-critical logic: the interface layer between your Java / Scala application and the database. You have probably chosen jOOQ for any of the following reasons:

- To evade JDBC's verbosity and error-proneness due to string concatenation and index-based variable binding
- To add lots of type-safety to your inline SQL
- To increase productivity when writing inline SQL using your favourite IDE's autocompletion capabilities

With jOOQ being in the core of your application, you want to be sure that you can trust jOOQ. That is why jOOQ is heavily unit and integration tested with a strong focus on integration tests:

#### Unit tests

Unit tests are performed against dummy JDBC interfaces using mocks, including our own [JDBC mocking abstraction](#mocking-connection). These tests verify that various [`org.jooq.QueryPart`](https://www.jooq.org/javadoc/3.22.x/org/jooq/QueryPart.html) implementations render correct SQL and bind variables correctly.

In addition to the above, numerous types of unit tests include

- SQL formatting tests
- JSON and XML data import / export tests
- Parser tests
- Mapper and converter tests
- SPI tests
- SQL transformation tests
- And much more

#### Integration tests

This is the most important part of the jOOQ test suites. 10k+ queries are currently run against a standard integration test database, for which we use testcontainers and other virtualisation utilities. Both the test database and the queries are translated into every one of the 30+ supported SQL dialects to ensure that regressions are unlikely to be introduced into the code base.

For libraries like jOOQ, integration tests are much more expressive than unit tests, as there are so many subtle differences in SQL dialects. Simple mocks just don't give as much feedback as an actual database instance.

jOOQ integration tests run the weirdest and most unrealistic queries. As a side-effect of these extensive integration test suites, many corner-case bugs for JDBC drivers and/or open source databases have been discovered, feature requests submitted through jOOQ and reported mainly to Derby, H2, HSQLDB.

#### Code generation tests

For every one of the 30+ supported integration test databases, source code is generated and the tiniest differences in generated source code can be discovered. In case of compilation errors in generated source code, new test tables/views/columns are added to avoid regressions in this field.

#### API Usability tests and proofs of concept

jOOQ is used in jOOQ-meta as a proof of concept. This includes complex queries such as the following Postgres query

```java
Routines r1 = ROUTINES.as("r1");
Routines r2 = ROUTINES.as("r2");

for (Record record : create.select(
        r1.ROUTINE_SCHEMA,
        r1.ROUTINE_NAME,
        r1.SPECIFIC_NAME,

        // Ignore the data type when there is at least one out parameter
        DSL.when(exists(
                selectOne()
                .from(PARAMETERS)
                .where(PARAMETERS.SPECIFIC_SCHEMA.eq(r1.SPECIFIC_SCHEMA))
                .and(PARAMETERS.SPECIFIC_NAME.eq(r1.SPECIFIC_NAME))
                .and(upper(PARAMETERS.PARAMETER_MODE).ne("IN"))),
                    val("void"))
           .else_(r1.DATA_TYPE).as("data_type"),
        r1.CHARACTER_MAXIMUM_LENGTH,
        r1.NUMERIC_PRECISION,
        r1.NUMERIC_SCALE,
        r1.TYPE_UDT_NAME,

        // Calculate overload index if applicable
        DSL.when(
            exists(
                selectOne()
                .from(r2)
                .where(r2.ROUTINE_SCHEMA.in(getInputSchemata()))
                .and(r2.ROUTINE_SCHEMA.eq(r1.ROUTINE_SCHEMA))
                .and(r2.ROUTINE_NAME.eq(r1.ROUTINE_NAME))
                .and(r2.SPECIFIC_NAME.ne(r1.SPECIFIC_NAME))),
            select(count())
                .from(r2)
                .where(r2.ROUTINE_SCHEMA.in(getInputSchemata()))
                .and(r2.ROUTINE_SCHEMA.eq(r1.ROUTINE_SCHEMA))
                .and(r2.ROUTINE_NAME.eq(r1.ROUTINE_NAME))
                .and(r2.SPECIFIC_NAME.le(r1.SPECIFIC_NAME)).asField())
        .as("overload"))
    .from(r1)
    .where(r1.ROUTINE_SCHEMA.in(getInputSchemata()))
    .orderBy(
        r1.ROUTINE_SCHEMA.asc(),
        r1.ROUTINE_NAME.asc())
    .fetch()) {

    result.add(new PostgresRoutineDefinition(this, record));
}
```

These rather complex queries show that the jOOQ API is fit for advanced SQL use-cases, compared to the rather simple, often unrealistic queries in the integration test suite.

#### Clean API and implementation. Code is kept DRY

As a general rule of thumb throughout the jOOQ code, everything is kept [DRY](https://en.wikipedia.org/wiki/DRY). Some examples:

- There is only one place in the entire code base, which consumes values from a JDBC ResultSet
- There is only one place in the entire code base, which transforms jOOQ Records into custom POJOs

Keeping things DRY leads to longer stack traces, but in turn, also increases the relevance of highly reusable code-blocks. Chances that some parts of the jOOQ code base slips by integration test coverage decrease significantly.

<a id="security"></a>
### 8.7. Security

This section talks about a few common security related topics in jOOQ, which developers should be aware of.

<a id="security-sql-injection"></a>
#### 8.7.1. SQL Injection

For most standard use-cases jOOQ is SQL injection safe because ordinary jOOQ usage does not involve concatenation of SQL strings. At the same time, every bit of user input is generated as a [bind value](#bind-values) in a [`java.sql.PreparedStatement`](https://docs.oracle.com/en/java/javase/25/docs/api/java.sql/java/sql/PreparedStatement.html), or escaped properly, if [inlined explicitly](#inlined-parameters) (For more information, please refer to the section about [SQL injection](#sql-injection)).

In order to completely forbid usage of API that could lead to SQL injection vulnerabilities in jOOQ (i.e. the [plain SQL templating API](#plain-sql-templating-language)), you can use a [compiler plugin](#checker-framework) that prevents using such API.

<a id="security-debug-logging"></a>
#### 8.7.2. Debug logging

For the convenience of the out-of-the-box jOOQ experience, jOOQ includes a lot of debug log information in its [execute logging](#settings-execute-logging). Due to the sheer amount of logged data, users will unlikely keep this log around in production environments.

Another important reason to turn off this feature in production is the fact that [Personally identifiable information (PII)](https://en.wikipedia.org/wiki/Personal_data) can be contained in logged queries and logged result sets, including e.g. usernames, credit card numbers, etc. Logs may be distributed to other servers for technical analysis in case of production incidents, and thus give away such PII to third parties which shouldn't have access. This is also important from a GDPR compliance perspective. Instead of turning off all logging, it is also possible to use [redacted columns](#redacted-columns).

<a id="security-redacted-columns"></a>
#### 8.7.3. Redacted columns

[Redacted columns](#redacted-columns) are a useful feature to mask out certain sensitive data from formatted output, mainly when debug logging query executions, and also when calling [`Result.toString()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Result.html#toString()) or [`Record.toString()`](https://www.jooq.org/javadoc/3.22.x/org/jooq/Record.html#toString()) - even by accident.

<a id="security-exception-message"></a>
#### 8.7.4. Exception message

The [`org.jooq.exception.DataAccessException`](https://www.jooq.org/javadoc/3.22.x/org/jooq/exception/DataAccessException.html) may contain the SQL string that has produced the exception for an improved debugging experience, including debugging in production. The assumption here is that the exception and its stack trace will never be disclosed to clients, including web browsers.

If the exception and SQL string is disclosed, then third parties may be able to deduce schema meta data information from the error (e.g. what tables and columns are available). While this may not be a significant problem by itself, if combined with another vulnerability (e.g. [SQL Injection](#security-sql-injection)), this could help facilitate an attack.

<a id="security-contact"></a>
#### 8.7.5. Contact

In case you think you found a security issue, please look at [https://github.com/jOOQ/jOOQ/security](https://github.com/jOOQ/jOOQ/security) for information about how to get in touch.

<a id="migrating-to-3.0"></a>
### 8.8. Migrating to jOOQ 3.0

This section is for all users of jOOQ 2.x who wish to upgrade to the next major release. In the next sub-sections, the most important changes are explained. Some code hints are also added to help you fix compilation errors.

#### Type-safe row value expressions

Support for [row value expressions](#row-value-expressions) has been added in jOOQ 2.6. In jOOQ 3.0, many API parts were thoroughly (but often incompatibly) changed, in order to provide you with even more type-safety.

Here are some affected API parts:

- [N] in Row[N] has been raised from 8 to 22. This means that existing row value expressions with degree >= 9 are now type-safe
- Subqueries returned from `DSL.select(...)` now implement `Select<Record[N]>, not Select<Record>`
- `IN` predicates and comparison predicates taking subselects changed incompatibly
- `INSERT` and `MERGE` statements now take typesafe `VALUES()` clauses

Some hints related to row value expressions:

```java
// SELECT statements are now more typesafe:
Record2<String, Integer> record         = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).where(ID.eq(1)).fetchOne();
Result<Record2<String, Integer>> result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch();

// But Record2 extends Record. You don't have to use the additional typesafety:
Record record    = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).where(ID.eq(1)).fetchOne();
Result<?> result = create.select(BOOK.TITLE, BOOK.ID).from(BOOK).fetch();
```

#### SelectQuery and SelectXXXStep are now generic

In order to support type-safe row value expressions and type-safe Record[N] types, SelectQuery is now generic: SelectQuery<R>

#### SimpleSelectQuery and SimpleSelectXXXStep API were removed

The duplication of the SELECT API is no longer useful, now that SelectQuery and SelectXXXStep are generic.

#### Factory was split into DSL (query building) and DSLContext (query execution)

The pre-existing Factory class has been split into two parts:

1. **The DSL**: This class contains only static factory methods. All QueryParts constructed from this class are "unattached", i.e. queries that are constructed through DSL cannot be executed immediately. This is useful for subqueries.  
   The DSL class corresponds to the static part of the jOOQ 2.x Factory type
2. **The DSLContext**: This type holds a reference to a Configuration and can construct executable ("attached") QueryParts.  
   The DSLContext type corresponds to the non-static part of the jOOQ 2.x Factory / FactoryOperations type.

The FactoryOperations interface has been renamed to DSLContext. An example:

```java
// jOOQ 2.6, check if there are any books
Factory create = new Factory(connection, dialect);
create.selectOne()
      .whereExists(
        create.selectFrom(BOOK) // Reuse the factory to create subselects
      ).fetch();                // Execute the "attached" query

// jOOQ 3.0
DSLContext create = DSL.using(connection, dialect);
create.selectOne()
      .whereExists(
        selectFrom(BOOK)        // Create a static subselect from the DSL
      ).fetch();                // Execute the "attached" query
```

#### Quantified comparison predicates

Field.equalAny(...) and similar methods have been removed in favour of Field.eq(any(...)). This greatly simplified the Field API. An example:

```java
// jOOQ 2.6
Condition condition = BOOK.ID.equalAny(create.select(BOOK.ID).from(BOOK));

// jOOQ 3.0 adds some typesafety to comparison predicates involving quantified selects
QuantifiedSelect<Record1<Integer>> subselect = any(select(BOOK.ID).from(BOOK));
Condition condition = BOOK.ID.eq(subselect);
```

#### FieldProvider

The FieldProvider marker interface was removed. Its methods still exist on FieldProvider subtypes. Note, they have changed names from `getField()` to `field()` and from `getIndex()` to `indexOf()`

#### GroupField

GroupField has been introduced as a DSL marker interface to denote fields that can be passed to `GROUP BY` clauses. This includes all org.jooq.Field types. However, fields obtained from `ROLLUP()`, `CUBE()`, and `GROUPING SETS()` functions no longer implement Field. Instead, they only implement GroupField. An example:

```java
// jOOQ 2.6
Field<?>   field1a = Factory.rollup(...); // OK
Field<?>   field2a = Factory.one();       // OK

// jOOQ 3.0
GroupField field1b = DSL.rollup(...); // OK
Field<?>   field1c = DSL.rollup(...); // Compilation error
GroupField field2b = DSL.one();       // OK
Field<?>   field2c = DSL.one();       // OK
```

#### NULL predicate

Beware! Previously, Field.eq(null) was translated internally to an IS NULL predicate. This is no longer the case. Binding Java "null" to a comparison predicate will result in a regular comparison predicate (which never returns true). This was changed for several reasons:

- To most users, this was a surprising "feature".
- Other predicates didn't behave in such a way, e.g. the IN predicate, the BETWEEN predicate, or the LIKE predicate.
- Variable binding behaved unpredictably, as IS NULL predicates don't bind any variables.
- The generated SQL depended on the possible combinations of bind values, which creates unnecessary hard-parses every time a new unique SQL statement is rendered.

Here is an example how to check if a field has a given value, without applying SQL's ternary NULL logic:

```java
String possiblyNull = null; // Or else...

// jOOQ 2.6
Condition condition1 = BOOK.TITLE.eq(possiblyNull);

// jOOQ 3.0
Condition condition2 = BOOK.TITLE.eq(possiblyNull).or(BOOK.TITLE.isNull().and(val(possiblyNull).isNull()));
Condition condition3 = BOOK.TITLE.isNotDistinctFrom(possiblyNull);
```

#### Configuration

`DSLContext`, `ExecuteContext`, `RenderContext`, `BindContext` no longer extend `Configuration` for "convenience". From jOOQ 3.0 onwards, composition is chosen over inheritance as these objects are not really configurations. Most importantly

- `DSLContext` is only a DSL entry point for constructing "attached" QueryParts
- `ExecuteContext` has a well-defined lifecycle, tied to that of a single query execution
- `RenderContext` has a well-defined lifecycle, tied to that of a single rendering operation
- `BindContext` has a well-defined lifecycle, tied to that of a single variable binding operation

In order to resolve confusion that used to arise because of different lifecycle durations, these types are now no longer formally connected through inheritance.

#### ConnectionProvider

In order to allow for simpler connection / data source management, jOOQ externalised connection handling in a new ConnectionProvider type. The previous two connection modes are maintained backwards-compatibly (JDBC standalone connection mode, pooled DataSource mode). Other connection modes can be injected using:

```java
public interface ConnectionProvider {

    // Provide jOOQ with a connection
    Connection acquire() throws DataAccessException;

    // Get a connection back from jOOQ
    void release(Connection connection) throws DataAccessException;
}
```

These are some side-effects of the above change

- Connection-related JDBC wrapper utility methods (commit, rollback, etc) have been moved to the new DefaultConnectionProvider. They're no longer available from the DSLContext. This had been confusing to some users who called upon these methods while operating in pool DataSource mode.

#### ExecuteListeners

ExecuteListeners can no longer be configured via Settings. Instead they have to be injected into the Configuration. This resolves many class loader issues that were encountered before. It also helps listener implementations control their lifecycles themselves.

#### Data type API

The data type API has been changed drastically in order to enable some new DataType-related features. These changes include:

- [SQLDialect]DataType and SQLDataType no longer implement DataType. They're mere constant containers
- Various minor API changes have been done.

#### Object renames

These objects have been moved / renamed:

- jOOU: a library used to represent unsigned integer types was moved from `org.jooq.util.unsigned` to `org.jooq.util.types` (which already contained INTERVAL data types)

#### Feature removals

Here are some minor features that have been removed in jOOQ 3.0

- The ant task for code generation was removed, as it was not up to date at all. Code generation through ant can be performed easily by calling jOOQ's GenerationTool through a <java> target.
- The navigation methods and "foreign key setters" are no longer generated in Record classes, as they are useful only to few users and the generated code is very collision-prone.
- The code generation configuration no longer accepts comma-separated regular expressions. Use the regex pipe | instead.
- The code generation configuration can no longer be loaded from .properties files. Only XML configurations are supported.
- The master data type feature is no longer supported. This feature was unlikely to behave exactly as users expected. It is better if users write their own code generators to generate master enum data types from their database tables. jOOQ's enum mapping and converter features sufficiently cover interacting with such user-defined types.
- The DSL subtypes are no longer instantiable. As DSL now only contains static methods, subclassing is no longer useful. There are still dialect-specific DSL types providing static methods for dialect-specific functions. But the code-generator no longer generates a schema-specific DSL
- The concept of a "main key" is no longer supported. The code generator produces UpdatableRecords only if the underlying table has a PRIMARY KEY. The reason for this removal is the fact that "main keys" are not reliable enough. They were chosen arbitrarily among UNIQUE KEYs.
- The UpdatableTable type has been removed. While adding significant complexity to the type hierarchy, this type adds not much value over a simple `Table.getPrimaryKey() != null` check.
- The `USE` statement support has been removed from jOOQ. Its behaviour was ill-defined, while it didn't work the same way (or didn't work at all) in some databases.

<a id="dont-do-this"></a>
### 8.9. Don't do this

Like any software, jOOQ has a few pitfalls, known issues, historic design flaws, etc., which the seasoned jOOQ developer should know to avoid. This section summarises both of jOOQ's and SQL's own pitfalls.

<a id="dont-do-this-jooq-implement-dsl"></a>
#### 8.9.1. jOOQ: Implementing the DSL types

Almost the entire jOOQ [DSL API](#dsl-api) as well as the [model API](#model-api) should be considered as `sealed` in the sense of Java 17. In fact, starting from jOOQ 3.16, we have started sealing types and will continue to do so in the near future.

This means, users should *never* attempt to extend jOOQ via inheritance, unless explicitly stated otherwise. Exceptions to this rule include:

- [CustomQueryPart](#custom-queryparts) and related types, which are designed to be subclassed.
- [Configuration SPIs](#dsl-context) which are designed to be implemented by users, following a strategy pattern style design.
- Public classes starting with `AbstractXYZ` (must be extended to be used) or `DefaultXYZ` (may be extended, but can be used out of the box, too).

<a id="dont-do-this-jooq-step-types"></a>
#### 8.9.2. jOOQ: Referencing the Step types

By convention, all of jOOQ's [DSL API](#dsl-api) consists of interfaces whose name ends in `Step`, such as [`org.jooq.SelectFromStep`](https://www.jooq.org/javadoc/3.22.x/org/jooq/SelectFromStep.html), which is *the step in the DSL API where users can append the [FROM clause](#from-clause)*.

When writing [dynamic SQL](#dynamic-sql) queries, users may be tempted to reference these types explicitly, such as

```java
SelectConditionStep<?> c =
create.select(T.A, T.B)
      .from(T)
      .where(T.C.eq(1));

if (something)
    c = c.and(T.D.eq(2));

Result<?> result = c.fetch();
```

With this user-code, it is possible to add predicates dynamically to a query. But there are caveats:

- In jOOQ 3.x, the DSL API is mostly mutable, but this may change in the future. Code that assumes mutability might break.
- The DSL API guarantees source compatibility *of methods* between minor versions, but not *of types*, [as set out in this section of the manual](#semantic-versioning). In order to evolve the DSL, it is sometimes necessary to replace the type hierarchy that implements the DSL. If you chain your method calls to look like actual SQL, you will not notice these changes (as the method calls remain compatible). But if you assign the `Step` types to local variables, or pass them around in your API, then that code might break.

It is much better to use one of the approaches mentioned in the section about [dynamic SQL](#dynamic-sql). Also, [this blog post elaborates more in detail on the topic of creating optional SQL clauses.](https://blog.jooq.org/create-empty-optional-sql-clauses-with-jooq/)

<a id="dont-do-this-null-columns"></a>
#### 8.9.3. Schema: NULL columns

In most RDBMS, the default nullability on any column is `NULL`, even if `NOT NULL` is mostly a more reasonable default. Whenever you know your data is not supposed to contain `NULL` values, then add an explicit `NOT NULL` constraint. This has the following benefits:

- Data integrity: One case of incorrect data less to worry about.
- Documentation: Even if your client application might make sure you'll never get `NULL` values in a column, it's still better to formally communicate this fact through a constraint.
- Performance: With `NULL` being an impossible value, quite a few optimisations can be applied that couldn't be, otherwise.

For example

```sql
CREATE TABLE customer (
  -- [...]
  phone   TEXT,          -- Here, the default of being nullable applies (in most RDBMS), but should it?
  address TEXT NULL,     -- The address might optional, you can mark it as such, explicitly, in many RDBMS
  email   TEXT NOT NULL  -- Every customer needs an email, this isn't an optional field
);
```

This rule obviously doesn't apply when a value is optional, in case of which `NULL` might be a desirable value.

<a id="dont-do-this-schema-unnamed-constraints"></a>
#### 8.9.4. Schema: Unnamed constraints

Most RDBMS are able to generate a constraint name if you're not specifying one explicitly:

```sql
CREATE TABLE actor (
  actor_id BIGINT PRIMARY KEY
);

CREATE TABLE film (
  film_id BIGINT PRIMARY KEY
);

CREATE TABLE film_actor (
  actor_id BIGINT NOT NULL REFERENCES actor,
  film_id BIGINT NOT NULL REFERENCES film,

  PRIMARY KEY (actor_id, film_id)
);
```

While this is correct, it makes evolving such a schema much harder. It is usually better to give an explicit name to each constraint, such that constraints can easily be dropped, deactivated temporarily, etc.:

<a id="dont-do-this-schema-surrogate-keys"></a>
#### 8.9.5. Schema: Unnecessary surrogate keys

The surrogate key vs natural key discussion is almost as old as SQL itself. Both approaches have their pros and cons, depending on the nature of the table you're designing. In short:

- A surrogate key (e.g. an `IDENTITY` or `UUID`) has no business value, and can thus be generated on any data, including not well normalised data.
- A natural key is a true placeholder for the data it represents (e.g. an ISO country code), which can help prevent joins to look up the useful information, as the useful information is already referenced in the foreign keys.

While there is a lot of debate whether a schema should be uniformly designed for consistency reasons (usually all pro surrogate key), or whether a few exceptions on a few tables are possible, there is one exception where a surrogate key is often the wrong choice: Relationship tables! In a relationship table like this:

```sql
CREATE TABLE actor (
  actor_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL
);

CREATE TABLE film (
  film_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  title TEXT NOT NULL
);

CREATE TABLE film_actor (
  actor_id BIGINT NOT NULL REFERENCES actor,
  film_id BIGINT NOT NULL REFERENCES film,

  PRIMARY KEY (actor_id, film_id)
);
```

Schema designers might be tempted to add a `FILM_ACTOR_ID` to the `FILM_ACTOR` table, but why? There is never any need to reference a many-to-many relationship entry by its surrogate key alone. We always use the foreign keys, which, if the schema is properly normalised, should have at least a `UNIQUE` constraint on them. Why not just make that the `PRIMARY KEY`?

This blog post discusses the topic of the [cost of useless surrogate keys in relationship tables](https://blog.jooq.org/the-cost-of-useless-surrogate-keys-in-relationship-tables/), from a performance perspective.

<a id="dont-do-this-wrong-datatypes"></a>
#### 8.9.6. Schema: Wrong data types

Most RDBMS don't have too many data types, with PostgreSQL being an exception via its powerful `EXTENSIONS` system. Even so, using the correct data type has at least these benefits:

- Data integrity: One case of incorrect data less to worry about.
- Documentation: Even if your client application might make sure you'll never get e.g. non-numeric values in a `VARCHAR` column, it's still better to formally communicate this fact through types.
- Performance: Without proper statistics, [the optimiser might make the wrong estimates simply because of wrong data types being used](https://blog.jooq.org/why-you-should-design-your-database-to-optimise-for-statistics/).

For example

```sql
CREATE TABLE transaction (
  -- [...]
  amount     TEXT NOT NULL, -- Amount is probably a DECIMAL or NUMERIC value, so why not use that?
  value_date TEXT NOT NULL  -- But it's a date, so why not use DATE or TIMESTAMP?
);
```

<a id="dont-do-this-count-instead-of-exists"></a>
#### 8.9.7. SQL: COUNT(*) instead of EXISTS()

Do you go to the supermarket to count all their apples just to see if they have any apples? You don't. Likewise, you shouldn't run a `COUNT(*)` query to check if the value is bigger than `0`. Use the [EXISTS predicate](#exists-predicate), instead.

> [!TIP]
> Our pattern transformation feature can auto detect bad queries for you, e.g. [COUNT(*) > 0 style queries](#transform-patterns-scalar-subquery-count-asterisk-gt-zero) or [COUNT(expr) > 0 style queries](#transform-patterns-scalar-subquery-count-expression-gt-zero).

[We've blogged about this and benchmarked the difference](https://blog.jooq.org/avoid-using-count-in-sql-when-you-could-use-exists/). It really does make a difference!

So, don't do this:

```java
if (create.fetchValue(selectCount().from(AUTHOR)) > 0) {
    // ...
}
```

But do this, instead:

```java
if (create.fetchValue(exists(selectOne().from(AUTHOR)))) {
    // ...
}
```

Of course, it's totally possible to embed this `EXISTS` predicate in a more complex query and possibly avoid the unnecessary secondary roundtrip...

<a id="dont-do-this-n-plus-one"></a>
#### 8.9.8. SQL: N+1

"Hooray, we're using jOOQ (i.e. SQL), so we got rid of our N+1 problems."

Well, there's a class of N+1 problems that jOOQ won't ever run into. It's those "accidental" N+1 queres that happen because of lazy loading. With jOOQ everything is always loaded "eagerly", exactly as you specify it in your queries. Unlike in ORMs, eager loading isn't automatic either. jOOQ doesn't just materialise large parts of your object graph on its own. Everything is done explicitly. But that means you can still run into *explicit* N+1 problems

> [!TIP]
> Our diagnostics module can auto detect repeated queries for you, which are usually caused by N+1 problems. See [repeated statements](#diagnostics-repeated-statements)

An example of an N+1 problem caused by jOOQ queries:

```java
// 1 query
for (Integer id : create
    .select(AUTHOR.ID)
    .from(AUTHOR)
    .fetch(AUTHOR.ID)
) {

    // N queries
    List<Integer> books =
    create.select(BOOK.ID)
          .from(BOOK)
          .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
          .fetch(BOOK.ID);
}
```

The N+1 problem (technically, it should have been named 1+N problem) can be seen easily above:

- `1` query is executed to fetch all `AUTHOR` records.
- `N` queries are executed to fetch all `BOOK` records *per* `AUTHOR`.

This particular query would much better be implemented with a simple SQL [JOIN](#join-clause):

```java
// 1 query
for (Record2<Integer, Integer> record : create
    .select(AUTHOR.ID)
    .from(AUTHOR)
    .join(BOOK)
    .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
) {

    // No additional queries needed...
}
```

You can use one of jOOQ's many mapping capabilities to nest your collections directly in your Java logic, or use [MULTISET](#multiset-value-constructor) or [MULTISET_AGG](#multiset-agg-function) to nest the collection directly in SQL, as long as you just don't run several roundtrips to the database.

N+1 isn't a problem that is strictly related to SQL. It just got popularised by ORMs that emphasise automatic population of object graphs via lazy loading, rather than emphasising querying. The underlying problem, however, is latency between a client (your Java code) and a server (your RDBMS), which is caused by too many round trips. See this blog post for an example that compares calling a stored procedure `1` time to fetch `N` items, vs. calling another stored procedure `N` times to fetch `1` item, each time: [https://blog.jooq.org/the-cost-of-jdbc-server-roundtrips/](https://blog.jooq.org/the-cost-of-jdbc-server-roundtrips/). The result is the same.

But with SQL, things get even worse. If you're pushing the entire declarative query into the database, the database has freedom to choose between various eligible algorithms to produce the result (e.g. hash join vs nested loop join, etc.). If you loop over your `N` parent rows yourself, you're enforcing a nested loop join, which can be worse *in addition to* the extra latency, in case a hash join or merge join would have been better.

<a id="dont-do-this-natural-join-or-using"></a>
#### 8.9.9. SQL: NATURAL JOIN or JOIN USING

[NATURAL JOIN](#join-predicate-natural) or [JOIN .. USING](#join-predicate-using) seem to be useful utilities at first when a normalised schema is very well designed in a way for `PRIMARY KEY` and `FOREIGN KEY` column names to always match (and in the case of `NATURAL JOIN`, all other column names to never match). The [Sakila database](https://www.jooq.org/sakila) is an example for the latter, with tables like these:

```sql
CREATE TABLE actor (
  actor_id BIGINT PRIMARY KEY,
  first_name TEXT,
  last_name TEXT,
  last_update TIMESTAMP
);

CREATE TABLE film (
  film_id BIGINT PRIMARY KEY,
  title TEXT,
  last_update TIMESTAMP
);

CREATE TABLE film_actor (
  actor_id BIGINT REFERENCES film,
  film_id BIGINT REFERENCES film,
  last_update TIMESTAMP
)
```

And indeed, the fact that e.g. `ACTOR_ID` is present in both `ACTOR` and `FILM_ACTOR` tables, and that it means the same thing in both tables is very convenient for queries like these:

```sql
SELECT *
FROM actor
JOIN film_actor USING (actor_id)
JOIN film USING (film_id);
```

But already this simple schema shows that we cannot use `NATURAL JOIN` due to the `LAST_UPDATE` columns, which shouldn't be part of the `JOIN` predicate.

```sql
SELECT *
FROM actor
NATURAL JOIN film_actor -- Wrong, because it joins on actor.last_update = film_actor.last_update
NATURAL JOIN film       -- Wrong, because it joins on film_actor.last_update = film.last_update
```

Even `USING` can suffer from such ambiguity, e.g. when we happen to add an `ACTOR_ID` column to the `FILM` table:

```sql
-- Where actor_id means the "main" actor ID
ALTER TABLE film ADD actor_id BIGINT REFERENCES actor;
```

This addition is debatable as:

- The naming seems to be insufficiently describing the fact that it is the "main" actor
- From a normalisation perspective, it seems to be redundant to repeat this information on the `FILM` table, as the `FILM_ACTOR` table could just have an additional flag about an actor being the "main" actor in a film.

As can be seen, queries containing `NATURAL JOIN` or `JOIN .. USING` are easy to get (often subtly) wrong, and even easier to break when the schema evolves. As such, it is best to just avoid the language feature entirely, except for the occasional ad-hoc query.

<a id="dont-do-this-sql-not-in"></a>
#### 8.9.10. SQL: NOT IN predicate

The `NOT IN` predicate seems to be just the inverse of the useful [IN predicate](#in-predicate), but in SQL, this isn't entirely true, thanks to SQL's [three valued logic](https://en.wikipedia.org/wiki/Three-valued_logic).

Look at the following transformations of equivalent predicates:

```sql
-- IN predicate is equivalent to:
A IN (B, C)
A = ANY (B, C)
A = B OR A = C

-- NOT IN predicate is equivalent to:
A NOT IN (B, C)
A <> ANY (B, C)
A <> B AND A <> C
```

Now, imagine if one of the values is `NULL`, then, informally:

```sql
-- IN predicate is equivalent to:
A IN (B, NULL)
A = ANY (B, NULL)
A = B OR A = NULL
A = B OR NULL
A = B

-- NOT IN predicate is equivalent to:
A NOT IN (B, NULL)
A <> ANY (B, NULL)
A <> B AND A <> NULL
A <> B AND NULL
NULL
```

Think of `NULL` as `UNKNOWN`:

- If one value of a disjunction (`OR`) is `UNKNOWN`, the result is either `TRUE` or `UNKNOWN`, the latter behaving like `FALSE` in a query. We're fine.
- If one value of a conjunction (`AND`) is `UNKNOWN`, the result is either `FALSE` or `UNKNOWN`, so the predicate always behaves as if it were `FALSE`. This is never what we want!

To make things worse, if you're using `NOT IN (subquery)`, this problem can happen occasionally only, when the subquery returns a single `NULL` value. It's logical, but never useful. So better just use the [NOT EXISTS predicate](#exists-predicate) instead.

See also [this blog post, which talks about compatibility across dialects](https://blog.jooq.org/sql-incompatibilities-not-in-and-null-values/).

<a id="dont-do-this-order-by-column-index"></a>
#### 8.9.11. SQL: ORDER BY [column index]

The SQL-92 standard and most implementations have always supported [ordering by column index](#order-by-field-index) (though the feature has been removed already from SQL-99!). It can be useful for quick and dirty queries like these:

```sql
SELECT ID, FIRST_NAME || ' ' || LAST_NAME
FROM AUTHOR
ORDER BY 2;
```

The above is equivalent to this:

```sql
SELECT ID, FIRST_NAME || ' ' || LAST_NAME
FROM AUTHOR
ORDER BY FIRST_NAME || ' ' || LAST_NAME;
```

But it is easy to see that this query may quickly break by introducing another column in the projection, anywhere before the sorted column with index `2`

```sql
-- Adding a column has broken the query
SELECT ID, LAST_UPDATE, FIRST_NAME || ' ' || LAST_NAME
FROM AUTHOR
ORDER BY 2;
```

Alternatively, these variants would not have broken:

```sql
-- The query is not affected by this change
SELECT ID, LAST_UPDATE, FIRST_NAME || ' ' || LAST_NAME
FROM AUTHOR
ORDER BY FIRST_NAME || ' ' || LAST_NAME;

-- Also, aliasing the expression (to avoid repetition) can work in many dialects
SELECT ID, LAST_UPDATE, FIRST_NAME || ' ' || LAST_NAME AS NAME
FROM AUTHOR
ORDER BY NAME;
```

While for quick ad-hoc queries, the `ORDER BY [column index]` feature can be occasionally useful, it's generally good to simply avoid the feature, especially when using jOOQ, [which makes reusing query parts very simple](#dynamic-sql).

<a id="dont-do-this-rely-on-implicit-ordering"></a>
#### 8.9.12. SQL: Rely on implicit ordering

A SQL query produces reliable ordering *only* if:

- An [ORDER BY clause](#order-by-clause) is provided, explicitly.
- That `ORDER BY` clause is deterministic.

For example:

```sql
SELECT *
FROM BOOK
ORDER BY title, id
```

In many of the above examples, it would be weird if the RDBMS didn't produce any implicit ordering. But since SQL is a [4GL](https://en.wikipedia.org/wiki/Fourth-generation_programming_language), and optimisers are free to produce *any* execution plan that implements the query's specifications (which don't specify any ordering explicitly), your assumptions may break at any time.

##### Implicit row insertion ordering

```sql
SELECT TITLE FROM BOOK;
```

You might think that rows are simple read out of a table, but what if this table is a view? What if it is partitioned? What if it is distributed? What if a covering index suddenly applies?

##### Implicit derived table ordering

```sql
SELECT TITLE FROM (
  SELECT TITLE FROM BOOK ORDER BY TITLE
) AS B;
```

The [derived table](#derived-tables) specifies an explicit ordering, but the outer query does not. Nothing prevents an optimiser from deciding that in this case, the explicit ordering is unnecessary, even if it might be unlikely to do so for arbitrary reasons.

##### Implicit union subquery ordering

```sql
(SELECT TITLE FROM BOOK ORDER BY TITLE) UNION (SELECT 'Not really a book')
```

The [UNION](#set-operation-union) subquery specifies an explicit ordering, but there's no requirement at all for the `UNION` operator to maintain this ordering. In fact, `UNION` might be implemented using hashing, so the ordering wouldn't be stable.

##### Implicit window ordering

```sql
SELECT TITLE, ROW_NUMBER () OVER (ORDER BY TITLE)
FROM BOOK;
```

A [window function](#window-functions) may be ordered, and that ordering may be stable within a query, such that *by accident*, the results are as one would expect. But there's no guarantee for this. The RDBMS may produce results in any other order than the one from the window function.

##### Implicit GROUP BY ordering

```sql
SELECT AUTHOR_ID, COUNT(*) FROM BOOK GROUP BY AUTHOR_ID;
```

The [GROUP BY](#group-by-clause) clause may be implemented using a sort operation, but it may as well be implemented using hashing. There's no guarantee of one algorithm being used rather than the other. With sorting, there might be an accidental order that remains stable, but there's no guarantee for that.

##### Implicit non-deterministic ordering

```sql
SELECT ID, TITLE FROM BOOK ORDER BY TITLE;
```

In our schema, `TITLE` is not a `UNIQUE` column, so multiple books could share the same title. There's no guarantee of any stable ordering among the resulting `ID` values, unless `ID` is included in the `ORDER BY` clause.

<a id="dont-do-this-sql-select-all"></a>
#### 8.9.13. SQL: SELECT *

The `SELECT *` syntax has been introduced mostly for convenience of ad-hoc SQL. It's very useful to be able to quickly check out data on a production system to see what's available. For those cases, we often don't care about supplying a meaningful [SELECT clause](#select-clause). We just want to project everything, e.g.

```sql
SELECT * FROM book
```

```java
create.select(asterisk()).from(BOOK).fetch();
```

In real world applications, however, we shouldn't do this practice, neither in SQL, nor with jOOQ. We should limit ourselves to project only those columns that we really need. The key here is to project only what we need, so this isn't about the `*` (the asterisk as a syntactic token), but it could equally be about listing all columns explicitly, e.g.

```sql
SELECT
  id,
  author_id,
  title,
  published_in,
  language_id,
  ...
FROM book
```

```java
create.select(
          BOOK.ID,
          BOOK.AUTHOR_ID,
          BOOK.TITLE,
          BOOK.PUBLISHED_IN,
          BOOK.LANGUAGE_ID,
          ...)
      .from(BOOK).fetch();
```

[This blog post explains in depth why `SELECT *` is bad practice](https://blog.jooq.org/many-sql-performance-problems-stem-from-unnecessary-mandatory-work/) (not the asterisk is at fault, but the blind projection of everything, including when you use jOOQ's `selectFrom(Table)`). The main problem is that you're creating unnecessary, mandatory work on the server:

- Unnecessary, because you're throwing away the data right after fetching it
- Mandatory, because the SQL optimiser doesn't know that, so it must provide the data

This has at least the following effects:

- Disk I/O: The server has to read all the data from disk, which may be offloaded to lob storages or whatever. If your tables are wide, then this can be significant!
- Memory consumption: Both on the server and on the client, you're wasting memory and the associated CPU cycles of transferring data from/to memory, just to discard it again. The server might even cache all this data in a "buffer cache", completely unnecessarily.
- Index usage: So called "covering indexes" cannot be used this way, e.g. when your relationship tables have additional columns other than the foreign keys, the projection of those columns will likely make the query *much* slower than if you could just have used a covering index.
- Join elimination: Some more advanced SQL transformations are impossible to do, such as the `JOIN` elimination transformation, where whole joins are removed from your query, as they're provably unnecessary. But they're only unnecessary if you're not projecting anything from a table. If you do, then the `JOIN` must be executed.

Seems obvious, no? Best not be lazy, design your queries carefully. Again, [this blog post explains the topic in depth](https://blog.jooq.org/many-sql-performance-problems-stem-from-unnecessary-mandatory-work/).

<a id="dont-do-this-sql-select-distinct"></a>
#### 8.9.14. SQL: SELECT DISTINCT

The `SELECT DISTINCT` syntax can occasionally be useful to remove duplicates in case your schema isn't normalised. For example, in a log table, you may want to query for distinct IP addresses:

```sql
SELECT DISTINCT ip FROM access_log
```

```java
create.selectDistinct(ACCESS_LOG.IP).from(ACCESS_LOG).fetch();
```

This is especially useful for ad-hoc querying.

A lot of times, when removing such duplicates in application queries, you'll want to add [aggregate functions](#aggregate-functions) (e.g. number of log entries per IP, number of distinct logins per IP, etc.), so you'll use [GROUP BY](#group-by-clause), instead of the [DISTINCT](#select-clause-distinct) clause.

However, be wary of using `DISTINCT` for removing duplicates that you're not entirely sure why they happen, i.e. typically in very large and complex queries, but also a lot of times when there are [(INNER) JOIN](#join-type-inner) expressions, when in fact there should be [SEMI JOIN](#join-type-semi) expressions. For example, the following query looks for all authors of books available in book stores starting with the letter `A`:

```sql
SELECT DISTINCT
  author.first_name,
  author.last_name
FROM author
JOIN book ON author.id = book.author_id
JOIN book_to_book_store
  ON book.id = book_to_book_store.book_id
WHERE book_to_book_store.name LIKE 'A%'
```

```java
create.selectDistinct(
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME)
      .from(AUTHOR)
      .join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
      .join(BOOK_TO_BOOK_STORE)
        .on(BOOK.ID.eq(BOOK_TO_BOOK_STORE.BOOK_ID))
      .where(BOOK_TO_BOOK_STORE.NAME.like("A%")).fetch();
```

Now, due to the nature of our schema:

- Authors have written many books
- Books are available from multiple book stores

Hence, it is very likely that the same author appears in the result multiple times, thus `DISTINCT`. From a database performance perspective, this may be very bad, because the authors are duplicated into some internal data structure before they're removed again from the result. Besides, depending on the optimiser, we might have to scan all the books and all the book stores even if we already found an author. Optimisers are very different, so this may or may not be a problem of equal severity in each RDBMS, but certainly something to keep an eye out for.

A much better solution here is to use a [SEMI JOIN](#join-type-semi), e.g. using the [IN predicate](#in-predicate) or [EXISTS predicate](#exists-predicate) (they're semantically equivalent):

```sql
SELECT
  author.first_name,
  author.last_name
FROM author
WHERE author.id IN (
  SELECT book.author_id
  FROM book
  JOIN book_to_book_store
    ON book.id = book_to_book_store.book_id
  WHERE book_to_book_store.name LIKE 'A%'
)
```

```java
create.select(
          AUTHOR.FIRST_NAME,
          AUTHOR.LAST_NAME)
      .from(AUTHOR)
      .where(AUTHOR.ID).in(
          select(BOOK.AUTHOR_ID)
          .from(BOOK)
          .join(BOOK_TO_BOOK_STORE)
            .on(BOOK.ID.eq(BOOK_TO_BOOK_STORE.BOOK_ID))
          .where(BOOK_TO_BOOK_STORE.NAME.like("A%")
      ).fetch();
```

Now, we'll never get any duplicate authors.

If in doubt, check your execution plan and execution metrics about what is the best query here, but in a lot of cases, `DISTINCT` is a hint that something unnecessary is being done, and then duplicates are removed again.

<a id="dont-do-this-unnecessary-union"></a>
#### 8.9.15. SQL: Unnecessary UNION instead of UNION ALL

The [UNION](#set-operation-union) operator removes duplicate rows, whereas `UNION ALL` retains them. It isn't always possible for an optimiser to prove that there are no duplicates possible. If you, as a developer, *know* that there can't be any duplicates, or if you don't care about the duplicates, or even want them, then it's always better to use `UNION ALL` instead of `UNION`, as that avoids a potentially costly sort or hash operation to remove the duplicates.

For example:

```sql
SELECT 'Book' AS OBJECT_TYPE, ID FROM BOOK
UNION ALL -- No removal of duplicates necessary in this case
SELECT 'Author' AS OBJECT_TYPE, ID FROM AUTHOR;
```

<a id="reference-types"></a>
### 8.10. The most important jOOQ types

For new users working with jOOQ for the first time, the number of types in the jOOQ API can be overwhelming. The SQL language doesn’t have many such “visible” types, although if you think about SQL the way jOOQ does, then they’re there just the same, but hidden from users via an English style syntax.

[This overview will list the most important jOOQ types in a cheat sheet form.](https://blog.jooq.org/a-brief-overview-over-the-most-common-jooq-types/)

<a id="reference-credits"></a>
### 8.11. Credits

jOOQ lives in a very challenging ecosystem. The Java to SQL interface is still one of the most important system interfaces. Yet there are still a lot of open questions, best practices and no "true" standard has been established. This situation gave way to a lot of tools, APIs, utilities which essentially tackle the same problem domain as jOOQ. jOOQ has gotten great inspiration from pre-existing tools and this section should give them some credit. Here is a list of inspirational tools in alphabetical order:

- [Hibernate](https://www.hibernate.org): The de-facto standard (JPA) with its useful table-to-POJO mapping features have influenced jOOQ's [`org.jooq.ResultQuery`](https://www.jooq.org/javadoc/3.22.x/org/jooq/ResultQuery.html#fetchInto(java.lang.Class)) facilities
- [JPA](https://jakarta.ee/specifications/persistence/3.0/): The de-facto standard in the jakarta.persistence packages, supplied by Oracle. Its annotations are useful to jOOQ as well.
- [QueryDSL](https://www.querydsl.com): A "LINQ-port" to Java. It has a similar fluent API, a similar code-generation facility, yet quite a different purpose. While jOOQ is all about SQL, QueryDSL (like LINQ) is mostly about querying.
- [SLICK](https://scala-slick.org): A "LINQ-like" database abstraction layer for Scala. Unlike LINQ, its API doesn't really remind of SQL. Instead, it makes SQL look like Scala.
- [Spring Data](https://spring.io/projects/spring-data): Spring's JdbcTemplate knows RowMappers, which are reflected by jOOQ's [RecordMapper](#recordmapper)

