Разница дат 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 , что вызывает проблему.

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

8
nl ja de
Если вы предоставили сообщение о синтаксической ошибке , которое вы неизбежно получите для определения этой функции, было бы проще. Даже если это не имеет смысла для вас, это по крайней мере помогает нам исключить других подозреваемых.
добавлено автор Erwin Brandstetter, источник

3 ответы

Отлаживать

То, что делает ваша функция, можно сделать проще much . Действительная причина синтаксической ошибки:

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

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

Он также не работает. Я цитирую руководство здесь :

Чтобы избежать синтаксической двусмысленности, синтаксис типа «строка» может быть только   используется для указания типа простой константы литерала.

Это будет работать следующим образом:

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;

Простой запрос

You can solve the simple task with a Простой запрос - using a subquery:

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

If you insist on a function for the purpose, use a simple Функция 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/pgФункция SQL

Если вы настаиваете на 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$;

Тот же звонок.

11
добавлено

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

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';

Разница между использованием : = и в в приведенном выше контексте заключается в том, что с помощью : = ваш запрос должен вернуть одно значение. Если вы используете в , ваш запрос может вернуть одну строку (т. Е. Более одного столбца).

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

1
добавлено
Мой downvote для фактически неверного ответа. Назначение с помощью SELECT INTO отлично работает. Здесь есть и другие проблемы.
добавлено автор Erwin Brandstetter, источник
Извините, мое последнее замечание было неоднозначным. Я не имел в виду больше проблем в вашем ответе, но больше проблем в коде OP. Я подробно рассмотрел это в своем ответе. Кроме того, удалил мой downvote с тех пор, как вы удалили дезинформацию.
добавлено автор Erwin Brandstetter, источник
@ErwinBrandstetter, Если у вас есть время, какие у меня другие проблемы? Поэтому я могу понять, где еще я ошибаюсь, я был бы признателен. Теперь я вижу, почему синтаксис OP для select в был неправильным.
добавлено автор fbynite, источник

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

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

SELECT (SELECT evt_start_date::date FROM events WHERE evt_id = 5) 
        - evt_start_date::date 
        FROM events WHERE evt_id = 6;
1
добавлено
pgsql – PostgreSQL
pgsql – PostgreSQL
2 429 участник(ов)

Чат про PostgreSQL

DBA - русскоговорящее сообщество
DBA - русскоговорящее сообщество
1 345 участник(ов)

Общаемся и обсуждаем темы, посвященные DBA, PostgreSQL, Redis, MongoDB, MySQL, neo4j, riak и т.д. См. также: @devops_ru, @kubernetes_ru, @docker_ru, @nodejs_ru Рекомендуем сразу отключить уведомления, чтобы пребывание здесь было полезным и комфортным.

SqlCom.ru - Стиль жизни SQL
SqlCom.ru - Стиль жизни SQL
908 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только MS SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz). Предложения в @sql_ninja

SQL_Ninja
SQL_Ninja
340 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz)