简体   繁体   中英

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

I'm attempting to write a plpgsql function to insert a record into a table that expects some timestamps in certain columns. Here is the function:

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

This works fine when I am passing a literal string for the date format, but not for a parameter:

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

When I try to use @start_date or start_date instead of the literal string I get this error:

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

Can someone enlighten me as to the correct syntax to use? I've found plenty of posts online about using parameters but can't find anything that addresses why I can't pass through the function parameter to epoch from timestamp.

1.

Do not use a @ character to prepend variables. That's SQL-Server or MySQL syntax (and maybe others) and illegal in Postgres SQL or PL/pgSQL code.

PL/pgSQL variable names follow the same rules as SQL identifiers. The manual:

SQL identifiers and key words must begin with a letter ( az , 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 ( $ ).

So @start_date is a syntax error.

2.

In this expression:

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

timestamp is the data type of the immediately following string literal.

But this notation is not allowed for run-time type conversions. So this is a syntax error:

to_timestamp(extract(epoch from timestamp start_date))

You can use an explicit type cast instead:

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.


In your particular case it would be smarter / cleaner to define the function parameter as date or timestamp to begin with - depends on what kind of data you plan to pass to the function. Your parameter name indicates a date , but your example indicates a timestamp .

Either way, you don't need to cast that later. EXTRACT() also accepts date and casts it to timestamp automatically.

I would recomend you to use serial/bigserial for id :

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

Also is better to pass start_date as timestsamp.

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

For access to function's argument in postgresql you just use its name. Also you can call it via <function_name>.<variable name> . It might be useful when arguments of your function has the same name as column in tables (as is in your function). To avoid this you can add something (for example v_ ) to names. Also you do not need too complicate construction as to_timestamp(extract(epoch from timestamp '2017-3-19 10:30:00')) . Also you can use just sql function. Improved variant of function:

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;

For checking results:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM