0

我试图在几天内获得差异,将结果转换为十进制:

SELECT
CAST( TO_DATE('2999-01-01','yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd') AS DECIMAL )
;

现在,如果我将 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 )
;

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

好的,我可以转换为 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 )
;

但在这种情况下,使用 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 )
;

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

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

4

3 回答 3

4

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

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

  ?column?  
------------
 32841 days

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

SELECT extract(days FROM '32841 days'::interval)::numeric(9,2);
 date_part 
-----------
  32841.00

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

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

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...

在这里,您有一个整数(这是您最初想要的)并尝试将其转换为一个区间(出于我不明白的原因)。它抱怨它不知道你想要什么单位。您想要 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

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

高温高压

于 2012-12-11T09:44:02.047 回答
1

如果您使用日期进行区间算术,通常应该使用时间戳,如docs中所述。

# SELECT extract(days FROM TO_TIMESTAMP('2999-01-01','yyyy-mm-dd') - TO_TIMESTAMP('2909-01-01','yyyy-mm-dd'))

 date_part 
-----------
     32872

# SELECT extract(days FROM TO_TIMESTAMP('2999-01-01','yyyy-mm-dd') - (TO_TIMESTAMP('2909-01-01','yyyy-mm-dd') + '1 month'::interval) );
 date_part 
-----------
     32841
于 2012-12-11T12:25:24.650 回答
0

将间隔添加到日期的结果实际上是时间戳,而不是另一个日期(间隔可能包含时间部分),因此您必须首先将添加的结果转换回日期:

SELECT
CAST( TO_DATE('2999-01-01','yyyy-mm-dd')
       - CAST( (TO_DATE('2909-01-01','yyyy-mm-dd') + INTERVAL '1 MONTH' * (1) ) AS DATE)
      AS DECIMAL )
于 2012-12-11T11:53:42.930 回答