- 安装
- 文档
- 入门
- 连接
- 数据导入
- 客户端 API
- 概览
- ADBC
- C
- C++
- CLI
- Dart
- Go
- Java (JDBC)
- Julia
- Node.js (已弃用)
- Node.js (Neo)
- ODBC
- PHP
- Python
- R
- Rust
- Swift
- Wasm
- SQL
- 介绍
- 语句
- 概览
- ANALYZE
- ALTER TABLE
- ALTER VIEW
- ATTACH 和 DETACH
- CALL
- CHECKPOINT
- COMMENT ON
- COPY
- CREATE INDEX
- CREATE MACRO
- CREATE SCHEMA
- CREATE SECRET
- CREATE SEQUENCE
- CREATE TABLE
- CREATE VIEW
- CREATE TYPE
- DELETE
- DESCRIBE
- DROP
- EXPORT 和 IMPORT DATABASE
- INSERT
- LOAD / INSTALL
- PIVOT
- 性能分析
- SELECT
- SET / RESET
- SET VARIABLE
- SUMMARIZE
- 事务管理
- UNPIVOT
- UPDATE
- USE
- VACUUM
- 查询语法
- SELECT
- FROM 和 JOIN
- WHERE
- GROUP BY
- GROUPING SETS
- HAVING
- ORDER BY
- LIMIT 和 OFFSET
- SAMPLE
- 展开嵌套
- WITH
- WINDOW
- QUALIFY
- VALUES
- FILTER
- 集合操作
- 预处理语句
- 数据类型
- 表达式
- 函数
- 概览
- 聚合函数
- 数组函数
- 位字符串函数
- Blob 函数
- 日期格式化函数
- 日期函数
- 日期部分函数
- 枚举函数
- 间隔函数
- Lambda 函数
- 列表函数
- 映射函数
- 嵌套函数
- 数值函数
- 模式匹配
- 正则表达式
- 结构体函数
- 文本函数
- 时间函数
- 时间戳函数
- 带时区时间戳函数
- 联合函数
- 实用函数
- 窗口函数
- 约束
- 索引
- 元查询
- DuckDB 的 SQL 方言
- 示例
- 配置
- 扩展
- 核心扩展
- 概览
- 自动补全
- Avro
- AWS
- Azure
- Delta
- DuckLake
- 编码
- Excel
- 全文搜索
- httpfs (HTTP 和 S3)
- Iceberg
- ICU
- inet
- jemalloc
- MySQL
- PostgreSQL
- 空间
- SQLite
- TPC-DS
- TPC-H
- UI
- VSS
- 指南
- 概览
- 数据查看器
- 数据库集成
- 文件格式
- 概览
- CSV 导入
- CSV 导出
- 直接读取文件
- Excel 导入
- Excel 导出
- JSON 导入
- JSON 导出
- Parquet 导入
- Parquet 导出
- 查询 Parquet 文件
- 使用 file: 协议访问文件
- 网络和云存储
- 概览
- HTTP Parquet 导入
- S3 Parquet 导入
- S3 Parquet 导出
- S3 Iceberg 导入
- S3 Express One
- GCS 导入
- Cloudflare R2 导入
- 通过 HTTPS / S3 使用 DuckDB
- Fastly 对象存储导入
- 元查询
- ODBC
- 性能
- Python
- 安装
- 执行 SQL
- Jupyter Notebooks
- marimo Notebooks
- Pandas 上的 SQL
- 从 Pandas 导入
- 导出到 Pandas
- 从 Numpy 导入
- 导出到 Numpy
- Arrow 上的 SQL
- 从 Arrow 导入
- 导出到 Arrow
- Pandas 上的关系型 API
- 多个 Python 线程
- 与 Ibis 集成
- 与 Polars 集成
- 使用 fsspec 文件系统
- SQL 编辑器
- SQL 功能
- 代码片段
- 故障排除
- 术语表
- 离线浏览
- 操作手册
- 开发
- 内部结构
- 为什么选择 DuckDB
- 行为准则
- 发布日历
- 路线图
- 站点地图
- 在线演示
INTERVAL
表示可用于对 DATE
、TIMESTAMP
、TIMESTAMPTZ
或 TIME
值进行加减的时间段。
名称 | 描述 |
---|---|
INTERVAL |
时间段 |
可以通过提供数量和单位来构造一个 INTERVAL
。不是 月、天 或 微秒 的单位会被转换为这三个基本单位中下一个更小单位的等效数量。
SELECT
INTERVAL 1 YEAR, -- single unit using YEAR keyword; stored as 12 months
INTERVAL (random() * 10) YEAR, -- parentheses necessary for variable amounts;
-- stored as integer number of months
INTERVAL '1 month 1 day', -- string type necessary for multiple units; stored as (1 month, 1 day)
'16 months'::INTERVAL, -- string cast supported; stored as 16 months
'48:00:00'::INTERVAL, -- HH::MM::SS string supported; stored as (48 * 60 * 60 * 1e6 microseconds)
;
警告:当与单位关键字一起使用时,小数数值会被截断为整数(除非单位是
SECONDS
或MILLISECONDS
)。SELECT INTERVAL '1.5' YEARS; -- Returns 12 months; equivalent to `to_years(CAST(trunc(1.5) AS INTEGER))`
为了获得更高的精度,请在字符串中包含单位或使用更精细的单位;例如,
INTERVAL '1.5 years'
或INTERVAL 18 MONTHS
。
需要三个基本单位,因为一个月不对应固定的天数(二月比三月的天数少),一天也不对应固定的微秒数。这种组件划分使得 INTERVAL
类适用于对日期进行特定时间单位的加减运算。例如,我们可以使用以下 SQL 查询生成一个包含每月第一天的表:
SELECT DATE '2000-01-01' + INTERVAL (i) MONTH
FROM range(12) t(i);
当 INTERVAL
通过 datepart
函数分解时,月 组件会进一步拆分为年和月,而 微秒 组件会拆分为小时、分钟和微秒。天 组件不会拆分为额外的单位。为了证明这一点,以下查询通过对三个基本单位的随机量求和,生成了一个名为 period
的 INTERVAL
。然后它从 period
中提取上述六个部分,将它们加回,并确认结果总是等于原始的 period
。
SELECT
period = list_reduce(
[INTERVAL (datepart(part, period) || part) FOR part IN
['year', 'month', 'day', 'hour', 'minute', 'microsecond']
],
(i1, i2) -> i1 + i2
) -- always true
FROM (
VALUES (
INTERVAL (random() * 123_456_789_123) MICROSECONDS
+ INTERVAL (random() * 12_345) DAYS
+ INTERVAL (random() * 12_345) MONTHS
)
) _(period);
警告:微秒 组件只拆分为小时、分钟和微秒,而不是小时、分钟、秒 和微秒。
此外,INTERVAL
中的世纪、十年、季度、秒和毫秒(向下舍入到最接近的整数)的数量可以通过 datepart
函数提取。然而,这些组件并非重新组装原始 INTERVAL
所必需的。事实上,如果之前的查询还提取了十年或秒,那么提取部分的和通常会大于原始的 period
,因为这会分别重复计算月和微秒组件。
所有单位都使用 0-based 索引,除了季度使用 1-based 索引。
例如
SELECT
datepart('decade', INTERVAL 12 YEARS), -- returns 1
datepart('year', INTERVAL 12 YEARS), -- returns 12
datepart('second', INTERVAL 1_234 MILLISECONDS), -- returns 1
datepart('microsecond', INTERVAL 1_234 MILLISECONDS), -- returns 1_234_000
;
时间戳、日期和间隔的算术运算
可以使用 +
和 -
运算符将 INTERVAL
添加到 TIMESTAMP
、TIMESTAMPTZ
、DATE
和 TIME
值,或从中减去。
SELECT
DATE '2000-01-01' + INTERVAL 1 YEAR,
TIMESTAMP '2000-01-01 01:33:30' - INTERVAL '1 month 13 hours',
TIME '02:00:00' - INTERVAL '3 days 23 hours', -- wraps; equals TIME '03:00:00'
;
即使
INTERVAL
没有微秒组件,将INTERVAL
添加到DATE
也会返回TIMESTAMP
。结果与将DATE
转换为TIMESTAMP
(这会将时间组件设置为00:00:00
)后再添加INTERVAL
的结果相同。
相反,两个 TIMESTAMP
或两个 TIMESTAMPTZ
相减会创建一个 INTERVAL
,描述时间戳之间的差异,其中只包含 天和微秒 组件。例如:
SELECT
TIMESTAMP '2000-02-06 12:00:00' - TIMESTAMP '2000-01-01 11:00:00', -- 36 days 1 hour
TIMESTAMP '2000-02-01' + (TIMESTAMP '2000-02-01' - TIMESTAMP '2000-01-01'), -- '2000-03-03', NOT '2000-03-01'
;
两个 DATE
相减不会创建 INTERVAL
,而是返回给定日期之间的天数作为整数值。
警告:提取两个
TIMESTAMP
之间INTERVAL
差异的某个组件,不等同于使用datediff
函数计算的对应单位下两个TIMESTAMP
之间的分区边界数量。SELECT datediff('day', TIMESTAMP '2020-01-01 01:00:00', TIMESTAMP '2020-01-02 00:00:00'), -- 1 datepart('day', TIMESTAMP '2020-01-02 00:00:00' - TIMESTAMP '2020-01-01 01:00:00'), -- 0 ;
相等性和比较
仅用于相等和排序比较时,INTERVAL
中的总微秒数是这样计算的:将天基本单位转换为 24 * 60 * 60 * 1e6
微秒,将月基本单位转换为 30 天,即 30 * 24 * 60 * 60 * 1e6
微秒。
因此,即使 INTERVAL
在功能上不同,它们也可能比较相等;并且当 INTERVAL
被添加到日期或时间戳时,其顺序并不总是保留。
例如
INTERVAL 30 DAYS = INTERVAL 1 MONTH
- 但
DATE '2020-01-01' + INTERVAL 30 DAYS != DATE '2020-01-01' + INTERVAL 1 MONTH
。
且
INTERVAL '30 days 12 hours' > INTERVAL 1 MONTH
- 但
DATE '2020-01-01' + INTERVAL '30 days 12 hours' < DATE '2020-01-01' + INTERVAL 1 MONTH
。
函数
有关可与 INTERVAL
一起使用的日期部分的列表,请参阅日期部分函数页面。
有关对间隔进行操作的函数,请参阅间隔运算符页面。