Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/sphinx/source/reference/sql_commands/DQL/Operators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Operators
Operators/Logical
Operators/Comparison
Operators/IS
Operators/IS_DISTINCT_FROM
Operators/BETWEEN
Operators/LIKE
Operators/IN

.. list-table::

Expand All @@ -19,3 +23,11 @@ Operators
- `<`, `>`, `<=`, `>=`, `=`, `!=`
* - :ref:`IS Operator <is-operators>`
- `IS`, `IS NOT`
* - :ref:`IS DISTINCT FROM Operator <is-distinct-from>`
- `IS DISTINCT FROM`, `IS NOT DISTINCT FROM`
* - :ref:`BETWEEN Operator <between>`
- `BETWEEN`, `NOT BETWEEN`
* - :ref:`LIKE Operator <like>`
- `LIKE`, `NOT LIKE`
* - :ref:`IN Operator <in>`
- `IN`, `NOT IN`
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Diagram(
NonTerminal('expression'),
Optional(Terminal('NOT'), 1),
Terminal('BETWEEN'),
NonTerminal('lower_bound'),
Terminal('AND'),
NonTerminal('upper_bound')
)
225 changes: 225 additions & 0 deletions docs/sphinx/source/reference/sql_commands/DQL/Operators/BETWEEN.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
=======
BETWEEN
=======

.. _between:

Tests whether a value falls within a specified range (inclusive).

Syntax
======

.. raw:: html
:file: BETWEEN.diagram.svg

The BETWEEN operator is used in WHERE clauses:

.. code-block:: sql

SELECT column1, column2
FROM table_name
WHERE column1 BETWEEN lower_value AND upper_value

Parameters
==========

``expression``
The value to test. Can be a column name, calculation, or any valid expression.

``lower_bound``
The lower bound of the range (inclusive).

``upper_bound``
The upper bound of the range (inclusive).

``NOT`` (optional)
Negates the result - returns true if the value is **outside** the range.

Returns
=======

Returns:
- ``TRUE`` if ``expression >= lower_bound AND expression <= upper_bound``
- ``FALSE`` otherwise
- ``NULL`` if any operand is NULL

With ``NOT BETWEEN``:
- ``TRUE`` if ``expression < lower_bound OR expression > upper_bound``
- ``FALSE`` otherwise
- ``NULL`` if any operand is NULL

**Important**: If ``lower_bound > upper_bound``, the range is empty and ``BETWEEN`` always returns ``FALSE``.

Examples
========

Setup
-----

For these examples, assume we have a ``products`` table:

.. code-block:: sql

CREATE TABLE products(
id BIGINT,
name STRING,
price BIGINT,
stock INTEGER,
PRIMARY KEY(id))

INSERT INTO products VALUES
(1, 'Widget A', 100, 50),
(2, 'Widget B', 150, 30),
(3, 'Gadget X', 200, 20),
(4, 'Tool A', 80, 100),
(5, 'Tool B', 120, 15)

BETWEEN with Numbers
--------------------

Find products with prices between 100 and 150 (inclusive):

.. code-block:: sql

SELECT name, price
FROM products
WHERE price BETWEEN 100 AND 150

.. list-table::
:header-rows: 1

* - :sql:`name`
- :sql:`price`
* - :json:`"Widget A"`
- :json:`100`
* - :json:`"Widget B"`
- :json:`150`
* - :json:`"Tool B"`
- :json:`120`

NOT BETWEEN
-----------

Find products with prices outside the range 100-150:

.. code-block:: sql

SELECT name, price
FROM products
WHERE price NOT BETWEEN 100 AND 150

.. list-table::
:header-rows: 1

* - :sql:`name`
- :sql:`price`
* - :json:`"Tool A"`
- :json:`80`
* - :json:`"Gadget X"`
- :json:`200`

BETWEEN with Equal Bounds
--------------------------

Test for exact value using BETWEEN:

.. code-block:: sql

SELECT name, price
FROM products
WHERE price BETWEEN 100 AND 100

.. list-table::
:header-rows: 1

* - :sql:`name`
- :sql:`price`
* - :json:`"Widget A"`
- :json:`100`

This is equivalent to ``WHERE price = 100``.

Empty Range
-----------

If lower bound > upper bound, no rows match:

.. code-block:: sql

SELECT name, price
FROM products
WHERE price BETWEEN 150 AND 100

Returns empty result set (no rows).

Combined with OR
----------------

Use multiple BETWEEN clauses with OR:

.. code-block:: sql

SELECT name, price
FROM products
WHERE price BETWEEN 80 AND 100 OR price BETWEEN 180 AND 220

.. list-table::
:header-rows: 1

* - :sql:`name`
- :sql:`price`
* - :json:`"Tool A"`
- :json:`80`
* - :json:`"Widget A"`
- :json:`100`
* - :json:`"Gadget X"`
- :json:`200`

Important Notes
===============

Inclusive Range
---------------

``BETWEEN`` uses **inclusive** bounds. Both ``lower_bound`` and ``upper_bound`` are included in the matching range.

NULL Handling
-------------

If any operand (expression, lower_bound, or upper_bound) is NULL, the result is NULL:

.. code-block:: sql

-- Returns NULL
WHERE NULL BETWEEN 1 AND 10

-- Returns NULL
WHERE price BETWEEN NULL AND 100

-- Returns NULL
WHERE price BETWEEN 100 AND NULL

Equivalence
-----------

``BETWEEN`` is shorthand for a range check:

.. code-block:: sql

-- These are equivalent:
WHERE x BETWEEN a AND b
WHERE x >= a AND x <= b

-- These are equivalent:
WHERE x NOT BETWEEN a AND b
WHERE x < a OR x > b

Type Compatibility
------------------

The expression, lower_bound, and upper_bound must be of compatible types. The comparison follows SQL type coercion rules.

See Also
========

* :ref:`Comparison Operators <comparison-operators>` - Other comparison operations
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,35 @@
Comparison Operators
====================


.. _comparison-operators:

TODO: flesh out doc
Standard Comparison Operators
==============================

We support standard comparison operators: ``>``, ``>=``, ``=``, ``<``, ``<=``, ``!=``, ``<>``

If either the left or right operand is NULL, the comparison result is NULL.

.. code-block:: sql

SELECT * FROM products WHERE price > 100
SELECT * FROM products WHERE price <= 50
SELECT * FROM products WHERE name = 'Widget'
SELECT * FROM products WHERE stock != 0

IS DISTINCT FROM
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that the IS DISTINCT FROM operator is currently placed under Comparison Operators as well as described in its own page. However, the latter is more elaborate. Is this intentional in the sense that there should be a small summary of the operator in the Comparison Operators page?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an earlier attempt at documenting IS DISTINCT FROM that I forgot about when writing a proper page. I think this can go away, or link to the page.
Thanks for catching that!

================

NULL-safe comparison operator that treats NULL values as comparable:

- ``expression1 IS DISTINCT FROM expression2`` - Returns ``TRUE`` if values are different (treating NULL as a value)
- ``expression1 IS NOT DISTINCT FROM expression2`` - Returns ``TRUE`` if values are the same (treating NULL as a value)

Unlike ``=`` and ``!=``, this operator never returns NULL.

For detailed documentation, examples, and use cases, see :ref:`IS DISTINCT FROM <is-distinct-from>`.

We support comparison operators: :sql:`>`, :sql:`>=`, :sql:`=`, :sql:`<`, :sql:`<=`, :sql:`!=`
See Also
========

If the left or right operand is :sql:`NULL`, the comparison result is :sql:`NULL`.
* :ref:`IS Operator <is-operators>` - IS NULL, IS TRUE, IS FALSE
11 changes: 11 additions & 0 deletions docs/sphinx/source/reference/sql_commands/DQL/Operators/IN.diagram
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Diagram(
NonTerminal('expression'),
Optional(Terminal('NOT'), 1),
Terminal('IN'),
Terminal('('),
OneOrMore(
NonTerminal('value'),
Terminal(',')
),
Terminal(')')
)
Loading
Loading