Разница в дате PostgreSQL

у меня есть функция 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

Если даты вычитаются непосредственно, то рассчитывается разница. Но в моем случае даты присутствуют в переменных как startDate и endDate, который вызывает проблему.

как вычесть даты, содержащиеся в переменных?

3 ответов


Debug

что делает ваша функция может быть сделано много проще. Фактическая причина синтаксической ошибки здесь:

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

похоже, вы пытаетесь бросить startDate to timestamp, что является нонсенсом, потому что ваш параметр startDate объявлен timestamp уже.

он также не работает. Цитирую инструкция тут:

чтобы избежать синтаксической двусмысленности синтаксис типа' 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.
  • не используйте идентификаторы смешанных регистров, если вы точно не знаете, что делаете.
  • вычесть старт С конец чтобы получить положительное число или применить оператор абсолютного значения @.
  • после вычитания времени (в отличие от вычитая метки, которые дает 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 = 
AND    e.evt_id = 
$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$;

тот же вызов.


Я бы написал запрос следующим образом:

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 запрос может возвращать одну строку (т. е. более одного столбца).

для полного объяснения с помощью select С into и plpgsql вы должны прочитать http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html. В частности, раздел 39.5.3 документации PostgreSQL.


вам действительно нужна функция для этого?

этот запрос также будет работать:

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