【问题标题】:PostgreSQL date differencePostgreSQL 日期差异
【发布时间】:2012-12-13 20:15:21
【问题描述】:

我有一个计算日期差异的 PostgreSQL 函数:

CREATE OR REPLACE FUNCTION testDateDiff () RETURNS int AS $BODY$
DECLARE startDate TIMESTAMP;
DECLARE endDate TIMESTAMP;
DECLARE diffDatePart int ;
BEGIN
Select evt_start_date From events Where evt_id = 5 INTO startDate ;
Select evt_start_date From events Where evt_id = 6 INTO  endDate ;
SELECT EXTRACT(day FROM TIMESTAMP startDate - endDate) INTO diffDatePart;
RETURN diffDatePart;
END;
$BODY$
LANGUAGE plpgsql 
COST 100

如果直接减去日期,则计算差值。但在我的情况下,日期存在于变量中,如 startDateendDate,这会导致问题。

如何减去变量中包含的日期?

【问题讨论】:

  • 如果您提供了此函数定义不可避免的语法错误消息,那会更容易。即使它对你没有意义,它至少可以帮助我们排除其他嫌疑人。

标签: sql postgresql datetime plpgsql postgresql-9.1


【解决方案1】:

调试

你的函数正在做的事情可以简单得多。语法错误的实际原因在这里:

SELECT EXTRACT(day FROM TIMESTAMP startDate - endDate) INTO diffDatePart;

您似乎正在尝试将startDate 转换为timestamp,这首先是无稽之谈,因为您的参数startDate 已经声明为timestamp

它也不起作用。我引用the manual here

为避免语法歧义,类型'string'的语法只能是 用于指定简单文字常量的类型。

像这样工作:

SELECT EXTRACT(day FROM startDate - endDate)::int INTO diffDatePart;

但这仍然没有多大意义。您在谈论“日期”,但仍将您的参数定义为timestamp。你可以像这样对你拥有的东西进行消毒:

CREATE OR REPLACE FUNCTION f_date_diff()
  RETURNS int AS
$BODY$
DECLARE
    start_date date;
    end_date   date;
    date_diff  int;
BEGIN
SELECT evt_start_date FROM events WHERE evt_id = 5 INTO start_date;
SELECT evt_start_date FROM events WHERE evt_id = 6 INTO end_date;
date_diff := (endDate - startDate);
RETURN date_diff;
END
$BODY$ LANGUAGE plpgsql;
  • DECLARE 只需要一次。
  • date 列声明为正确类型 date
  • 请勿使用大小写混合的标识符,除非您确切知道自己在做什么。
  • end中减去start得到一个正数或应用absolute value operator @
  • 由于减去 日期(而不是减去 时间戳,得到 interval)已经得到 integer,简化为:

    SELECT (startDate - endDate) INTO diffDatePart;
    

    甚至更简单的 plpgsql 赋值:

    diffDatePart := (startDate - endDate);
    

简单查询

您可以通过简单的查询来解决简单的任务 - 使用子查询:

SELECT (SELECT evt_start_date
        FROM   events
        WHERE  evt_id = 6) 
      - evt_start_date AS date_diff
FROM   events
WHERE  evt_id = 5;

或者您可以 CROSS JOIN 将基表添加到自身(每个实例 1 行,这样没关系):

SELECT e.evt_start_date - s.evt_start_date AS date_diff
FROM   events e
      ,events s
WHERE  e.evt_id = 6
AND    s.evt_id = 5;

SQL 函数

如果你为了某个目的坚持一个函数,就用一个简单的sql函数:

CREATE OR REPLACE FUNCTION f_date_diff(_start_id int, _end_id int)
  RETURNS int LANGUAGE sql AS
$func$
SELECT e.evt_start_date - s.evt_start_date
FROM   events s, events e
WHERE  s.evt_id = $1
AND    e.evt_id = $2
$func$;

呼叫:

SELECT  f_date_diff(5, 6);

PL/pgSQL 函数

如果你坚持使用 plpgsql ...

CREATE OR REPLACE FUNCTION f_date_diff(_start_id int, _end_id int)
  RETURNS int LANGUAGE plpgsql AS
$func$
BEGIN

RETURN (SELECT evt_start_date 
             - (SELECT evt_start_date FROM events WHERE evt_id = _start_id)
        FROM   events WHERE evt_id = _end_id);
END
$func$;

同样的电话。

【讨论】:

    【解决方案2】:

    你真的需要一个函数吗?

    这个查询也可以:

    SELECT (SELECT evt_start_date::date FROM events WHERE evt_id = 5) 
            - evt_start_date::date 
            FROM events WHERE evt_id = 6;
    

    【讨论】:

      【解决方案3】:

      我会这样写查询:

      create function testDateDiff()
        returns integer as $$
        declare 
          startDate timestamp;
          endDate timestamp;
        begin
          startDate := (select evt_start_date From events Where evt_id = 5);
          endDate   := (select evt_start_date From events Where evt_id = 6);
          return (select extract(day from startDate - endDate));
        end;
        $$ language 'plpgsql';
      

      在上述上下文中使用:=into 之间的区别在于,使用:= 您的查询必须返回单个值。如果您使用into,您的查询可以返回单行(即多于一列)。

      有关使用selectinto 和plpgsql 的完整说明,您应该阅读http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html。具体来说,PostgreSQL 文档的第 39.5.3 节。

      【讨论】:

      • 我对事实不正确的答案投了反对票。 SELECT INTO 的分配工作正常。这里还有许多其他问题。
      • @ErwinBrandstetter,如果你有时间,我还有什么其他问题?所以我可以理解我在哪里错了,我将不胜感激。我现在明白为什么 OP 的 select into 语法没有错。
      • 对不起,我的最后一句话含糊不清。我的意思不是您的回答中有更多问题,而是 OP 的代码中存在更多问题。我已经在我的回答中广泛地处理了这个问题。另外,由于您删除了错误信息,因此现在删除了我的反对票。
      猜你喜欢
      • 2021-10-26
      • 1970-01-01
      • 2018-05-25
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      • 2014-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多