Using Between In Sql For Dates

5 min read

Filtering data by a specific timeframe is one of the most frequent tasks in database management. Whether you are generating a monthly sales report, analyzing user activity from last week, or archiving records older than a specific year, the ability to isolate rows based on a date column is fundamental. The BETWEEN operator provides a concise, readable syntax for defining these ranges, but its behavior with temporal data types requires a precise understanding to avoid common pitfalls like missing boundary records or suffering performance degradation And it works..

Understanding the Syntax and Inclusive Logic

At its core, the BETWEEN operator selects values within a given range. The syntax is straightforward:

SELECT column_name(s)
FROM table_name
WHERE date_column BETWEEN 'start_date' AND 'end_date';

The critical characteristic of this operator is that it is inclusive. This means the range includes both the start_date and the end_date values. If you query for dates between '2023-01-01' and '2023-01-31', any row with a timestamp exactly matching midnight on January 1st or January 31st will be returned That alone is useful..

This inclusivity is where many developers encounter their first logic error. While intuitive for discrete values like integers (where BETWEEN 1 AND 10 clearly includes 1 and 10), date and time data types often store precision down to milliseconds, microseconds, or nanoseconds. A column defined as DATETIME, TIMESTAMP, or DATETIME2 does not just store a date; it stores a specific moment in time.

The "Midnight Trap" with DateTime Data Types

Consider a table Orders with a CreatedAt column of type DATETIME. You want all orders placed on January 31st, 2023. A typical query might look like this:

SELECT * FROM Orders
WHERE CreatedAt BETWEEN '2023-01-31' AND '2023-01-31';

In many SQL dialects (like SQL Server, MySQL, PostgreSQL), a date string literal without a time component defaults to midnight (00:00:00.000). Because of this, the query above effectively translates to:

WHERE CreatedAt BETWEEN '2023-01-31 00:00:00.000' AND '2023-01-31 00:00:00.000'

This will only return orders placed exactly at midnight. Orders placed at 10:00 AM, 3:45 PM, or 11:59 PM on that same day are excluded because their timestamp values are greater than the upper bound.

The "End of Day" Workaround (And Why It Is Fragile)

A common historical workaround is to calculate the last millisecond of the day:

-- SQL Server Example
WHERE CreatedAt BETWEEN '2023-01-31 00:00:00.000' AND '2023-01-31 23:59:59.997'

This approach is dangerous and non-portable. Day to day, 2. 1. 003, .Practically speaking, DATETIME2(7) and TIMESTAMP in PostgreSQL/MySQL support nanosecond precision. 997or.That's why Precision Mismatch: In SQL Server, DATETIME has a precision of ~3. 999will miss records falling in the gaps. On the flip side, 007). 000, .Hardcoding.33 milliseconds (rounding to .Maintenance Burden: If the column data type changes from DATETIME to DATETIME2(7), the hardcoded logic silently breaks, excluding records in the final milliseconds of the day Most people skip this — try not to..

The Best Practice: Half-Open Intervals

The industry-standard, dependable solution for filtering date ranges—regardless of the underlying data type precision—is the half-open interval pattern. Instead of BETWEEN, you use a combination of >= (greater than or equal to) and < (strictly less than).

Logic: WHERE date_column >= 'start_date' AND date_column < 'next_day_after_end_date'

Why This Works Perfectly

  1. Precision Agnostic: It captures every possible granularity (seconds, milliseconds, nanoseconds) on the start date without needing to know the max precision.
  2. Index Friendly: It remains a "SARGable" (Search ARGument Able) predicate, allowing the query optimizer to perform an Index Seek.
  3. Clear Boundaries: The logic reads naturally: "On or after the start, but strictly before the beginning of the next period."

Practical Examples

Scenario A: Get all data for a specific day (e.g., Jan 31, 2023)

SELECT * FROM Orders
WHERE CreatedAt >= '2023-01-31' 
  AND CreatedAt < '2023-02-01'; -- The start of the *next* day

Scenario B: Get data for a full month (January 2023)

SELECT * FROM Orders
WHERE CreatedAt >= '2023-01-01' 
  AND CreatedAt < '2023-02-01'; -- First day of February

Scenario C: Rolling window (Last 30 days relative to today)

-- Syntax varies slightly by dialect (GETDATE(), NOW(), CURRENT_TIMESTAMP)
SELECT * FROM Orders
WHERE CreatedAt >= DATEADD(day, -30, CAST(GETDATE() AS DATE)) -- Midnight 30 days ago
  AND CreatedAt < CAST(GETDATE() AS DATE); -- Midnight today (excludes future timestamps today)

Note: Using functions like CAST(GETDATE() AS DATE) or CURRENT_DATE strips the time component, anchoring the boundary safely at midnight.

When Is BETWEEN Actually Safe for Dates?

Despite the risks with DATETIME/TIMESTAMP, there are two specific scenarios where BETWEEN is perfectly safe and semantically correct:

1. The Column is a Pure DATE Type

Modern databases (PostgreSQL, MySQL 5.6+, SQL Server 2008+, Oracle) support a DATE data type that stores only the calendar date (Year, Month, Day) with zero time component Which is the point..

CREATE TABLE Events (
    EventID INT PRIMARY KEY,
    EventDate DATE -- No time portion stored
);

In this case, WHERE EventDate BETWEEN '2023-01-01' AND '2023-01-31' works exactly as a human expects. There is no "midnight trap" because 23:59:59 cannot exist in the column Still holds up..

2. Filtering on Whole Months/Years with DATE Truncation

If you must query a DATETIME column but only care about the calendar date, you can cast the column first. On the flip side, this kills index performance (Non-SARGable) Worth keeping that in mind..

-- Works logically, but usually SCANS the index/table
WHERE CAST(CreatedAt AS DATE) BETWEEN '2023-01-01' AND '2023-01-31'

Recommendation: Avoid casting columns in the WHERE clause. Use the half-open interval method on the raw column to preserve Index Seeks And it works..

Performance Implications:

Latest Batch

Just Dropped

Others Liked

Explore the Neighborhood

Thank you for reading about Using Between In Sql For Dates. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home