如何在函数内传递参数并强制转换为某种数据类型?

时间:2017-02-05 14:17:37

标签: postgresql plpgsql postgresql-9.3 identifier

我正在尝试编写一个plpgsql函数来将记录插入到某些列中需要某些时间戳的表中。这是功能:

create or replace function insert_slot(created_by varchar
                                     , version bigint
                                     , bsv_id bigint
                                     , start_date varchar) returns int as $$
declare
    last_id int := (select id from appointments order by id desc limit 1) + 1;

begin
    insert into appointments (
        id,
        created,
        created_by,
        version,
        bsv_id,
        usrn,
        start_date,
        end_date,
        status,
        request_priority_name,
        reservation_expiry,
        day_of_week
    )values (
        last_id,
        now(),
        created_by,
        version,
        bsv_id,
        'UN-' || last_id,
        to_timestamp(extract(epoch from timestamp @start_date)),
        to_timestamp(extract(epoch from timestamp '2017-2-12 10:30:00')),
        'OCCUPIED',
        'ROUTINE',
        to_timestamp(extract(epoch from timestamp '2017-3-19 10:30:00')),
        1
    );

    return last_id;
end;
$$ LANGUAGE plpgsql;

select * from insert_slot('Brad', 2, 70000, '2017-2-12 10:00:00');

当我传递日期格式的文字字符串时,这可以正常工作,但不适用于参数:

to_timestamp(extract(epoch from timestamp @start_date)),
to_timestamp(extract(epoch from timestamp '2017-2-12 10:30:00')),

当我尝试使用@start_datestart_date而不是文字字符串时,我收到此错误:

ERROR:  column "timestamp" does not exist
LINE 21:    to_timestamp(extract(epoch from timestamp @start_date)),

有人可以告诉我使用正确的语法吗?我在网上发现了很多关于使用参数的帖子,但找不到任何解决我无法通过时间戳将函数参数传递给epoch的内容。

2 个答案:

答案 0 :(得分:1)

1

不要使用@字符来添加变量。这种SQL-Server或MySQL语法(也许是其他语法)在Postgres SQL或PL / pgSQL代码中是非法的。

PL / pgSQL变量名遵循与SQL标识符相同的规则。 The manual:

  

SQL标识符和关键字必须以字母(a-z开头,但也必须以字母开头   带变音符号和非拉丁字母的字母)或下划线   (_)。标识符或关键字中的后续字符可以是   字母,下划线,数字(0 - 9)或美元符号($)。

所以 @start_date 是语法错误。

2

在这个表达式中:

to_timestamp(extract(epoch from timestamp '2017-2-12 10:30:00')),

timestamp是紧随其后的字符串文字的数据类型

但是运行时类型转换不允许使用此表示法。所以这是一个语法错误:

<击> to_timestamp(extract(epoch from timestamp start_date))

您可以使用显式类型转换:

to_timestamp(extract(epoch from start_date::timestamp))

The manual:

  

::CAST()和函数调用语法也可用于指定   任意表达式的运行时类型转换,如中所述   Section 4.2.9。为了避免语法歧义,type 'string'语法   只能用于指定简单文字常量的类型。

在您的特定情况下,将函数参数定义为datetimestamp以开始时更智能/更清晰 - 取决于您计划传递给函数的数据类型。您的参数名称表示date,但您的示例表示timestamp

无论哪种方式,你都不需要在以后投出。 EXTRACT()也接受date并自动将其投放到timestamp

答案 1 :(得分:0)

我建议您使用serial / bigserial作为id

CREATE TABLE appointments(id bigserial PRIMARY KEY, ...

最好将start_date作为timestsamp传递。

create or replace function insert_slot(created_by varchar, version bigint, bsv_id bigint, start_date timestsamp) returns int as $$

要在postgresql中访问函数的参数,只需使用其名称即可。您也可以通过<function_name>.<variable name>拨打电话。当函数的参数与表中的列具有相同的名称时(在函数中),它可能很有用。为避免这种情况,您可以在名称中添加一些内容(例如v_)。此外,您不需要太复杂的构造to_timestamp(extract(epoch from timestamp '2017-3-19 10:30:00'))。你也可以使用sql函数。 改进的功能变体:

create table appointments (
            id serial PRIMARY KEY,
            created timestamp,
            created_by text,
            version text,
            bsv_id int8,
            usrn text,
            start_date timestamp,
            end_date timestamp,
            status text,
            request_priority_name text,
            reservation_expiry timestamp,
            day_of_week int2);

CREATE OR REPLACE FUNCTION set_usrn() RETURNS TRIGGER AS $sql$
BEGIN
    NEW.usrn := 'UN' || NEW.id;
    RETURN NEW;
END;
$sql$ LANGUAGE plpgsql;

CREATE TRIGGER insert_usrn BEFORE INSERT ON appointments FOR EACH ROW EXECUTE PROCEDURE set_usrn();

create or replace function insert_slot(v_created_by varchar, v_version bigint, v_bsv_id bigint, v_start_date timestamp) returns int as $$
        insert into appointments (
            created,
            created_by,
            version,
            bsv_id,
            start_date,
            end_date,
            status,
            request_priority_name,
            reservation_expiry,
            day_of_week
        )values (
            now(),
            v_created_by,
            v_version,
            v_bsv_id,
            v_start_date,
            '2017-2-12 10:30:00',
            'OCCUPIED',
            'ROUTINE',
            '2017-3-19 10:30:00',
            1
        ) RETURNING id;
$$ LANGUAGE sql;

检查结果:

select * from insert_slot('Brad', 2, 70000, '2017-2-12 10:00:00');
SELECT * FROM appointments;



 id |          created           | created_by | version | bsv_id | usrn |     start_date      |      end_date       |  status  | request_priority_name | reservation_expiry  | day_of_week 
----+----------------------------+------------+---------+--------+------+---------------------+---------------------+----------+-----------------------+---------------------+-------------
  1 | 2017-02-05 17:30:59.800305 | Brad       | 2       |  70000 | UN1  | 2017-02-12 10:00:00 | 2017-02-12 10:30:00 | OCCUPIED | ROUTINE               | 2017-03-19 10:30:00 |           1