PostgreSQL数据库timestamp数据类型精度进位问题
- 1. PostgreSQL起源
- 2. PostgreSQL特点
- 3. PostgreSQL优缺点
- 4. PostgreSQL数据类型
- 5. PostgreSQL注意事项
1. PostgreSQL起源
PostgreSQL 起源于 1986 年加州大学伯克利分校开发的 POSTGRES 项目。它经过多年的发展和演进,成为了一个功能强大、开源的关系型数据库管理系统。
PostgreSQL 本身是开源的,通常不存在严格意义上的商业版和社区版之分。
官网地址:https://www.postgresql.org/
在官网上,您可以获取更详细和准确的信息,包括最新的特性、下载安装指南、文档教程等。
2. PostgreSQL特点
- 强大的功能:支持丰富的特性,如复杂查询、事务处理、存储过程、视图等。
- 开源和社区驱动:拥有活跃的开源社区,不断进行改进和更新。
- 可扩展性:易于扩展功能和数据类型。
- 标准符合性:高度符合 SQL 标准。
- 安全性:提供多种安全机制,包括用户认证、权限管理等。
3. PostgreSQL优缺点
优点:
- 稳定性高:经过长期的实践和优化,具有出色的稳定性和可靠性。
- 数据完整性:确保数据的一致性和完整性。
- 跨平台支持:可在多种操作系统上运行。
- 丰富的文档和支持:有详细的官方文档和活跃的社区支持。
缺点:
- 配置相对复杂:对于新手来说,初始配置可能具有一定的难度。
- 资源消耗:在处理大型数据集时,可能需要较多的系统资源。
4. PostgreSQL数据类型
包括数值类型(如整数、浮点数)、字符串类型(固定长度和可变长度)、日期和时间类型、布尔类型、数组类型、枚举类型、几何类型等。
数据类型 | 说明 | 精度 | 特点 | 案例 |
---|---|---|---|---|
smallint | 小范围整数 | 2 字节 | 占用存储空间小,适用于数据范围较小的整数 | smallint: 100 |
integer (或 int ) | 常规整数 | 4 字节 | 常见的整数类型,能满足大多数常规整数需求 | integer: 2000 |
bigint | 大范围整数 | 8 字节 | 用于存储非常大的整数数值 | bigint: 9000000000 |
decimal (或 numeric ) | 用户指定精度和小数位数的精确数值 | 取决于指定的精度和小数位数 | 精度和小数位数可自定义,适用于对精度要求高的数值计算 | decimal(5, 2): 123.45 |
real | 单精度浮点数 | 4 字节 | 大约 6 位十进制精度 | 存储精度要求不高的浮点数 |
double precision | 双精度浮点数 | 8 字节 | 大约 15 位十进制精度 | 适用于高精度的浮点数计算 |
char(n) | 固定长度的字符字符串,不足长度用空格填充 | n 个字符 | 长度固定,存储和读取效率较高 | char(10): 'hello ' |
varchar(n) | 可变长度的字符字符串,最大长度为 n | 最大 n 个字符 | 节省存储空间,适用于长度不固定的字符串 | varchar(20): 'hello world' |
text | 可变长度的字符字符串,无长度限制 | 无限制 | 可存储大量文本数据 | text: 'This is a long text.' |
date | 日期 | 格式为 YYYY-MM-DD | 只存储日期信息 | date: '2024-08-08' |
time | 时间,不包含日期 | 格式为 HH:MM:SS | 只存储时间信息 | time: '12:30:00' |
timestamp | 日期和时间 | 格式为 YYYY-MM-DD HH:MM:SS ,支持到微秒级别(6 位小数) | 同时包含日期和时间信息 | timestamp: '2024-08-08 12:30:00.123456' |
boolean | 布尔值 | 真或假 | 用于表示逻辑值 | boolean: true |
array | 数组 | 取决于元素类型和数组长度 | 可以存储相同数据类型的元素集合 | integer[]: '{1, 2, 3}' |
json | JSON 数据 | 无固定精度 | 方便存储和处理 JSON 格式的数据 | json: '{"key": "value"}' |
uuid | 通用唯一标识符 | 128 位 | 用于生成唯一标识符 | uuid: 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' |
5. PostgreSQL注意事项
timestamp数据类型精度进位问题,先说结论,在测试验证。
PostgreSQL只能存储最多6位的小数部分。因此,当尝试存储超过6位的分数秒时,会发生以下情况之一:
如果额外的数字导致整个分数秒部分超过 999999 微秒,则整个时间值会进位到下一秒,剩余的部分会被截断或者四舍五入到 6 位小数。
在这种情况下,2024-08-07 16:19:23.999999999 会被处理为 2024-08-07 16:19:24.000000。
如果你使用的是某种客户端或者编程语言接口来处理这个时间值,在插入之前它可能会自动进行四舍五入或截断。
比如,
截取前三位数据:小于 2024-08-07 16:19:23.999999500
进位数据:[2024-08-07 16:19:23.999999500 - 2024-08-07 16:19:23.999999999]
注意问题:
PostgreSQL 的 timestamp 类型默认只支持到微秒级别(6位小数),为什么select出来的数据中展示三位2024-08-07 16:19:23.999?
PostgreSQL 的 timestamp 类型确实支持到微秒级别(6位小数)。然而,默认情况下,当您从数据库中查询 timestamp 值时,PostgreSQL 会将结果显示为毫秒级别(3位小数)以提高可读性。这是默认的行为,但是您可以更改输出的精度。案例如下。
--PostgreSQL数据库timestamp数据类型精度进位问题
--# 1.PostgreSQL数据库数据类型
-- 数据库版本,PostgreSQL 15.3 on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
SELECT version();-- 创建数据库
-- crm.t_wx_user_1 definition-- Drop table-- DROP TABLE crm.t_wx_user_1;CREATE TABLE crm.t_wx_user_1 (user_id int8 NOT NULL,union_id varchar(50) NULL,open_id varchar(50) NULL,last_login_time timestamp NULL,privacy_agreement_version int8 NOT NULL DEFAULT 0,create_time timestamp NOT NULL,update_time timestamp NOT NULL DEFAULT '1970-01-01 00:00:00'::timestamp without time zone,delete_flag int2 NOT NULL DEFAULT 0,delete_time timestamp NOT NULL DEFAULT '1970-01-01 00:00:00'::timestamp without time zone,first_login_time timestamp NULL,created_by int8 NOT NULL DEFAULT '-1'::integer,updated_by int8 NOT NULL DEFAULT '-1'::integer,inst_id int8 NULL,CONSTRAINT t_wx_user_pkey_1 PRIMARY KEY (user_id)
);
CREATE INDEX idx_t_wx_user_open_id_1 ON crm.t_wx_user_1 USING btree (open_id);
CREATE INDEX idx_t_wx_user_union_id_1 ON crm.t_wx_user_1 USING btree (union_id);
CREATE UNIQUE INDEX uniq_wx_userid_unionid_openid_1 ON crm.t_wx_user_1 USING btree (user_id, union_id, open_id);-- 测试验证数据库
select * from crm.t_wx_user_1 order by user_id ;-- postgres数据库 timestamp类型,新增操作,支持类型 2024-08-07 16:19:23.142,正常插入数据库
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230000, '1', '1', '2024-08-07 16:19:23.142', 0, '2024-07-12 16:52:39.674', '2024-08-07 16:19:23.142', 0, '1970-01-01 00:00:00.000', '2024-07-12 16:52:39.674', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,6位数据类型 2024-08-07 16:19:23.123456,截断前三位插入数据库
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230001, '1', '1', '2024-08-07 16:19:23.123456', 0, '2024-07-12 16:52:39.123456', '2024-08-07 16:19:23.123456', 0, '1970-01-01 00:00:00.123456', '2024-07-12 16:52:39.123456', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,3个9验证 2024-08-07 16:19:23.999,正常插入数据库
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230002, '1', '1', '2024-08-07 16:19:23.999', 0, '2024-07-12 16:52:39.999', '2024-08-07 16:19:23.999', 0, '1970-01-01 00:00:00.999', '2024-07-12 16:52:39.999', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,4个9验证 2024-08-07 16:19:23.9999,截断前三位插入数据库
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230003, '1', '1', '2024-08-07 16:19:23.9999', 0, '2024-07-12 16:52:39.9999', '2024-08-07 16:19:23.9999', 0, '1970-01-01 00:00:00.9999', '2024-07-12 16:52:39.9999', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,6个9验证 2024-08-07 16:19:23.999999,截断前三位插入数据库
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230004, '1', '1', '2024-08-07 16:19:23.999999', 0, '2024-07-12 16:52:39.999999', '2024-08-07 16:19:23.999999', 0, '1970-01-01 00:00:00.999999', '2024-07-12 16:52:39.999999', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999999,会进位,存到数据库为:2024-08-07 16:19:24.000
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230005, '1', '1', '2024-08-07 16:19:23.999999999', 0, '2024-07-12 16:52:39.999999999', '2024-08-07 16:19:23.999999999', 0, '1970-01-01 00:00:00.999999999', '2024-07-12 16:52:39.999999999', -1, -1, 1);-- postgres数据库 timestamp类型,查询操作,9个9验证 2024-08-07 16:19:23.999999999,会进位,把2024-08-07 16:19:24.000的也查询出来。
select * from crm.t_wx_user_1 where last_login_time <= '2024-08-07 16:19:23.999999999';-- postgres数据库 timestamp类型,新增操作,9个值验证 2024-08-07 16:19:23.123456789,截断前三位插入数据库
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230006, '1', '1', '2024-08-07 16:19:23.123456789', 0, '2024-07-12 16:52:39.123456789', '2024-08-07 16:19:23.123456789', 0, '1970-01-01 00:00:00.123456789', '2024-07-12 16:52:39.123456789', -1, -1, 1);-- postgres数据库 timestamp类型,查询操作,9个9验证 2024-08-07 16:19:23.999999999,会进位,把2024-08-07 16:19:24.000的也查询出来。
select * from crm.t_wx_user_1 where last_login_time <= '2024-08-07 16:19:23.999999999';-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999998,会进位,存到数据库为:2024-08-07 16:19:24.000
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230007, '1', '1', '2024-08-07 16:19:23.999999998', 0, '2024-07-12 16:52:39.999999998', '2024-08-07 16:19:23.999999998', 0, '1970-01-01 00:00:00.999999998', '2024-07-12 16:52:39.999999998', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999001,截断前三位插入数据库
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230008, '1', '1', '2024-08-07 16:19:23.999999001', 0, '2024-07-12 16:52:39.999999001', '2024-08-07 16:19:23.999999001', 0, '1970-01-01 00:00:00.999999001', '2024-07-12 16:52:39.999999001', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999991,进位
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230009, '1', '1', '2024-08-07 16:19:23.999999991', 0, '2024-07-12 16:52:39.999999991', '2024-08-07 16:19:23.999999991', 0, '1970-01-01 00:00:00.999999991', '2024-07-12 16:52:39.999999991', -1, -1, 1);
-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999990,进位
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230010, '1', '1', '2024-08-07 16:19:23.999999990', 0, '2024-07-12 16:52:39.999999990', '2024-08-07 16:19:23.999999990', 0, '1970-01-01 00:00:00.999999990', '2024-07-12 16:52:39.999999990', -1, -1, 1);
-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999900,进位
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230011, '1', '1', '2024-08-07 16:19:23.999999900', 0, '2024-07-12 16:52:39.999999900', '2024-08-07 16:19:23.999999900', 0, '1970-01-01 00:00:00.999999900', '2024-07-12 16:52:39.999999900', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999800,进位
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230012, '1', '1', '2024-08-07 16:19:23.999999800', 0, '2024-07-12 16:52:39.999999800', '2024-08-07 16:19:23.999999800', 0, '1970-01-01 00:00:00.999999800', '2024-07-12 16:52:39.999999800', -1, -1, 1);-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999000,截取前三位
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230013, '1', '1', '2024-08-07 16:19:23.999999000', 0, '2024-07-12 16:52:39.999999000', '2024-08-07 16:19:23.999999000', 0, '1970-01-01 00:00:00.999999000', '2024-07-12 16:52:39.999999000', -1, -1, 1);
-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999500,进位
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230014, '1', '1', '2024-08-07 16:19:23.999999500', 0, '2024-07-12 16:52:39.999999500', '2024-08-07 16:19:23.999999500', 0, '1970-01-01 00:00:00.999999500', '2024-07-12 16:52:39.999999000', -1, -1, 1);
-- postgres数据库 timestamp类型,新增操作,9个9验证 2024-08-07 16:19:23.999999100,进位
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230015, '1', '1', '2024-08-07 16:19:23.999999100', 0, '2024-07-12 16:52:39.999999100', '2024-08-07 16:19:23.999999100', 0, '1970-01-01 00:00:00.999999100', '2024-07-12 16:52:39.999999100', -1, -1, 1);
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230016, '1', '1', '2024-08-07 16:19:23.999999200', 0, '2024-07-12 16:52:39.999999200', '2024-08-07 16:19:23.999999100', 0, '1970-01-01 00:00:00.999999100', '2024-07-12 16:52:39.999999100', -1, -1, 1);
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230017, '1', '1', '2024-08-07 16:19:23.999999300', 0, '2024-07-12 16:52:39.999999300', '2024-08-07 16:19:23.999999100', 0, '1970-01-01 00:00:00.999999100', '2024-07-12 16:52:39.999999100', -1, -1, 1);
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230018, '1', '1', '2024-08-07 16:19:23.999999400', 0, '2024-07-12 16:52:39.999999400', '2024-08-07 16:19:23.999999100', 0, '1970-01-01 00:00:00.999999100', '2024-07-12 16:52:39.999999100', -1, -1, 1);-- 再次验证 500 进位
INSERT INTO crm.t_wx_user_1
(user_id, union_id, open_id, last_login_time, privacy_agreement_version, create_time, update_time, delete_flag, delete_time, first_login_time, created_by, updated_by, inst_id)
VALUES(1230019, '1', '1', '2024-08-07 16:19:23.999999500', 0, '2024-07-12 16:52:39.999999500', '2024-08-07 16:19:23.999999100', 0, '1970-01-01 00:00:00.999999100', '2024-07-12 16:52:39.999999100', -1, -1, 1);-- postgres数据库 timestamp类型,查询操作,9个9验证 2024-08-07 16:19:23.999999999,会进位,把2024-08-07 16:19:24.000的也查询出来。
select * from crm.t_wx_user_1 ;
where last_login_time <= '2024-08-07 16:19:23.999999999';--截取前三位数据:小于 2024-08-07 16:19:23.999999500
--进位数据:[2024-08-07 16:19:23.999999500 - 2024-08-07 16:19:23.999999999]结论
PostgreSQL只能存储最多6位的小数部分。因此,当尝试存储超过6位的分数秒时,会发生以下情况之一:
如果额外的数字导致整个分数秒部分超过 999999 微秒,则整个时间值会进位到下一秒,剩余的部分会被截断或者四舍五入到 6 位小数。
在这种情况下,2024-08-07 16:19:23.999999999 会被处理为 2024-08-07 16:19:24.000000。
如果你使用的是某种客户端或者编程语言接口来处理这个时间值,在插入之前它可能会自动进行四舍五入或截断。比如:
截取前三位数据:小于 2024-08-07 16:19:23.999999500
进位数据:[2024-08-07 16:19:23.999999500 - 2024-08-07 16:19:23.999999999]-- 创建表
CREATE TABLE crm.wx_users (id SERIAL PRIMARY KEY,name VARCHAR(255) NOT NULL,created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL
);-- 插入数据
INSERT INTO crm.wx_users (name, created_at)
VALUES ('John Doe', '2024-08-07 16:19:23.999999');
INSERT INTO crm.wx_users (name, created_at)
VALUES ('Jerry', '2024-08-07 16:19:23.999996');-- 查询数据
SELECT * FROM crm.wx_users;PostgreSQL 的 timestamp 类型默认只支持到微秒级别(6位小数),为什么select出来的数据中展示三位2024-08-07 16:19:23.999PostgreSQL 的 timestamp 类型确实支持到微秒级别(6位小数)。然而,默认情况下,当您从数据库中查询 timestamp 值时,PostgreSQL 会将结果显示为毫秒级别(3位小数)以提高可读性。这是默认的行为,但是您可以更改输出的精度。-- 使用 to_char 函数来显示完整的微秒
SELECT id, name, to_char(created_at, 'YYYY-MM-DD HH24:MI:SS.US') AS created_at FROM crm.wx_users;