如何传递参数并转换为函数内的特定数据类型?

How to pass a parameter and cast to a certain data type inside a function?

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

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)),

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

我建议您将 serial/bigserial 用于 id:

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

最好将 start_date 作为时间戳传递。

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

1.

不要使用 @ 字符前置变量。这是 SQL-Server 或 MySQL 语法(可能还有其他语法),在 Postgres SQL 或 PL/pgSQL 代码中是非法的。

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

SQL identifiers and key words must begin with a letter (a-z, but also letters with diacritical marks and non-Latin letters) or an underscore (_). Subsequent characters in an identifier or key word can be letters, underscores, digits (0-9), or dollar signs ($).

所以@start_date是语法错误

2.

在此表达式中:

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

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

但是 run-time 类型转换不允许使用这种表示法。所以这是一个语法错误:

to_timestamp(extract(epoch from timestamp start_date))

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

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

The manual:

The ::, CAST(), and function-call syntaxes can also be used to specify run-time type conversions of arbitrary expressions, as discussed in Section 4.2.9. To avoid syntactic ambiguity, the type 'string' syntax can only be used to specify the type of a simple literal constant.


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

无论哪种方式,您都不需要稍后施放。 EXTRACT() 也接受 date 并自动将其转换为 timestamp