PostgreSQL。日期间隔问题

Ale*_*ndr 1 postgresql sqldatatypes

我试图获得天数差异,将结果转换为小数:

SELECT
CAST( TO_DATE('2999-01-01','yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd') AS DECIMAL )
;
Run Code Online (Sandbox Code Playgroud)

现在,如果我在第二个日期上添加 1 个月:

SELECT
CAST( TO_DATE('2999-01-01','yyyy-mm-dd') - (TO_DATE('2909-01-01','yyyy-mm-dd') + INTERVAL '1 MONTH' * (1) ) AS DECIMAL )
;
Run Code Online (Sandbox Code Playgroud)

我收到错误: 错误:无法将类型间隔转换为数字

好的,我可以转换为 char 以获得结果:

SELECT
CAST( TO_CHAR( TO_DATE('2909-02-10','yyyy-mm-dd') - (TO_DATE('2909-01-01','yyyy-mm-dd') + INTERVAL '1 MONTH' * (1) ), 'DD') AS DECIMAL )
;
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,使用 TO_CHAR 转换修改的第一个查询停止工作:

SELECT
CAST( TO_CHAR(TO_DATE('2999-01-01','yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd'), 'DD') AS DECIMAL )
;
Run Code Online (Sandbox Code Playgroud)

我收到错误:多个小数点。

所以,我的问题是,如何使用相同的 sql 语句获得天数?对于这两个 sql 查询。

Ric*_*ton 9

再看看你的前两个例子。如果删除外部 CAST ... AS DECIMAL 你会得到

 ?column? 
----------
    32872

  ?column?  
------------
 32841 days
Run Code Online (Sandbox Code Playgroud)

显然,差异在于“天”。第二个是一个区间值而不是一个简单的数字。您只需要数字(因为您总是只需要天数),因此您需要提取该部分。然后你可以投射到你喜欢的任何精度:

SELECT extract(days FROM '32841 days'::interval)::numeric(9,2);
 date_part 
-----------
  32841.00
Run Code Online (Sandbox Code Playgroud)

编辑回应亚历山大的后续行动:

您的第一个示例因相当具体的错误而失败:

SELECT extract(days FROM (TO_DATE('2999-01-01','yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd'))::interval)::numeric(9,2);

ERROR:  cannot cast type integer to interval
LINE 1: ...yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd'))::interval...
Run Code Online (Sandbox Code Playgroud)

这里你有一个整数(这是你最初想要的)并尝试将其转换为一个区间(出于我不明白的原因)。它抱怨它不知道你想要什么单位。您想要 32872间隔内的什么内容- 秒、小时、周、世纪?

第二个例子是抱怨的,因为你试图从一个简单的整数中提取“日”部分,当然系统中没有 extract() 函数可以做到这一点。

我认为您可能需要退后一步,花点时间来理解各种表达式返回的值。

将一个日期与另一个日期相减,得到它们之间相隔的天数 - 作为整数。真的没有其他明智的措施。

在日期中添加(或减去)间隔会得到时间戳(不带时区),因为间隔可能包含整日、天数、小时、秒等。

从日期中减去时间戳将得到一个间隔,因为结果可能包含天、小时、秒等。

如果您有一个间隔并且只需要天数部分,那么您可以对其使用 extract() ,您将获得整数天数。

如果您想转换为数字,则需要整数(或浮点数)天数,而不是间隔,因为如果没有单位,将间隔转换为标量是没有意义的。

因此,要么坚持使用日期和日期算术(简单),要么意识到您正在使用时间戳(灵活)但了解它是什么。

要了解正在发生的情况,您可以执行以下操作(在 psql 中):

CREATE TEMP TABLE tt AS SELECT
  ('2909-01-02'::date - '2909-01-01'::date) AS a,
  ('2909-01-02'::date - '2909-01-02 00:00:00'::timestamp) AS b;
\x
SELECT * FROM tt;
\d tt
Run Code Online (Sandbox Code Playgroud)

这将向您显示您正在处理的值和类型。对您认为有用的尽可能多的列重复此操作。

华泰