postgresql函数的语法错误。语法不可能

时间:2013-01-30 16:31:40

标签: postgresql

我尝试纠正这个功能但是不可能! 我声明一个整数“var_id”,并在id_val中插入frist查询的值, if为null,标签名称插入表中,var_id = last insert id,否则执行最后一次插入...

CREATE OR REPLACE FUNCTION public."InsertVideoTag"
(
  IN  in_idvideo  integer,
  IN  in_tagname  VARCHAR(25)      
)
RETURNS bigint AS
$$

DECLARE var_id bigint DEFAULT NULL;


SELECT var_id := IDTag FROM Tag WHERE TagName = in_tagname;


IF var_id IS NULL
THEN

INSERT INTO tag (   TagName )
VALUES( in_tagname );

var_id := SELECT CURRVAL(pg_get_serial_sequence('public.tag','idtag'));

END IF;

INSERT INTO video_has_tag 
(                 
  IDVideo,      
  IDTag             
)
VALUES 
(
  in_idvideo,                
  var_id             
);

SELECT CURRVAL(pg_get_serial_sequence('public.video','idvideo'));
$$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER;

4 个答案:

答案 0 :(得分:1)

  • 不需要if语句,where子句就足够了:
  • 选择当前值不适合作为返回值(或输入到其他表FK中):它可能在第一次插入后被碰撞。

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE tag
        ( idtag SERIAL NOT NULL PRIMARY KEY
        , tagname varchar
        );
CREATE TABLE video_has_tag
        ( idvideo INTEGER NOT NULL
        , idtag INTEGER NOT NULL REFERENCES tag (idtag)
        );

CREATE OR REPLACE FUNCTION tmp.insertvideotag
            ( in_idvideo  integer , in_tagname  VARCHAR  )
RETURNS bigint AS
$$

DECLARE var_id bigint DEFAULT NULL;

BEGIN

INSERT INTO tag (tagname )
SELECT in_tagname
WHERE NOT EXISTS (
        SELECT * FROM tag
        WHERE tagname = in_tagname
        );

INSERT INTO video_has_tag (idvideo,idtag)
SELECT in_idvideo, tg.idtag
FROM tag tg
WHERE tg.tagname = in_tagname
RETURNING idtag          
INTO var_id
        ;

RETURN var_id;
END;
$$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER;
SELECT insertvideotag(11, 'Eleven');
SELECT insertvideotag(12, 'Eleven');
SELECT insertvideotag(13, 'Thirteen');

SELECT tv.idvideo
        ,tv.idtag, tg.tagname
FROM video_has_tag tv
JOIN tag tg ON tg.idtag = tv.idtag
        ;

结果:

NOTICE:  CREATE TABLE will create implicit sequence "tag_idtag_seq" for serial column "tag.idtag"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "tag_pkey" for table "tag"
CREATE TABLE
CREATE TABLE
CREATE FUNCTION
 insertvideotag 
----------------
              1
(1 row)

 insertvideotag 
----------------
              2
(1 row)

 idvideo | idtag | tagname  
---------+-------+----------
      11 |     1 | Eleven
      12 |     1 | Eleven
      13 |     2 | Thirteen
(2 rows)

答案 1 :(得分:1)

该函数可以转换为纯SQL函数,这将使其表现更好。我还注意到,如果使用相同的参数多次调用,当前功能将在video_has_tag表中创建重复条目。 我已经将函数更改为幂等。

我假设的第一个表结构:

CREATE TABLE tag (
  idTag   serial,
  tagName text);
CREATE TABLE video_has_tag (
  idVideo integer,
  idTag   integer);

然后是函数本身:

CREATE OR REPLACE FUNCTION insVideoTag(in_idvideo integer, in_tagname text)
RETURNS integer STRICT AS $insVideoTag$

WITH
new_tag AS (
    INSERT INTO tag (tagName)
    SELECT $2
     WHERE NOT EXISTS (SELECT 1 FROM tag WHERE tagName = $2)
    RETURNING idTag, tagName
), tag_data AS (
    SELECT * FROM new_tag
    UNION
    SELECT idTag, tagName FROM tag
     WHERE tagName = $2
), new_target AS (
    INSERT INTO video_has_tag(idVideo, idTag)
    SELECT $1, td.idTag
      FROM tag_data td
     WHERE NOT EXISTS (SELECT 1 FROM video_has_tag
                        WHERE idVideo=$1 AND idTag=td.idTag)
    RETURNING idVideo, idTag
)
SELECT idVideo FROM (
    SELECT * FROM new_target
    UNION
    SELECT * FROM video_has_tag
     WHERE idVideo=$1 AND idTag=(SELECT idTag FROM tag_data)
) s;

$insVideoTag$ LANGUAGE sql;

答案 2 :(得分:0)

CREATE OR REPLACE FUNCTION public."InsertVideoTag"
(
  IN  in_idvideo  integer,
  IN  in_tagname  VARCHAR(25)      
)
RETURNS bigint AS
$$
DECLARE var_id bigint DEFAULT NULL;
begin
var_id := (select IDTag FROM Tag WHERE TagName = in_tagname);
IF var_id IS NULL
THEN
    INSERT INTO tag (   TagName )
    VALUES( in_tagname );
    var_id := (SELECT CURRVAL(pg_get_serial_sequence('public.tag','idtag')));
END IF;
INSERT INTO video_has_tag 
(                 
  IDVideo,      
  IDTag             
)
VALUES 
(
  in_idvideo,                
  var_id             
);
return (SELECT CURRVAL(pg_get_serial_sequence('public.video','idvideo')));
end;
$$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER;

答案 3 :(得分:0)

我发现使用小写列和&使用postgres的表名等,所以我对您现有的代码做了一些更改:

CREATE OR REPLACE FUNCTION public."insertvideotag"
(
  IN  in_idvideo  integer,
  IN  in_tagname  VARCHAR(25)      
)
RETURNS bigint AS
$$

DECLARE var_id bigint DEFAULT NULL;

BEGIN
--SELECT var_id := IDTag FROM Tag WHERE TagName = in_tagname;
SELECT idtag into var_id FROM tag WHERE tagname = in_tagname;


IF var_id IS NULL
THEN

INSERT INTO tag (   TagName )
VALUES( in_tagname );

--var_id := SELECT CURRVAL(pg_get_serial_sequence('public.tag','idtag'));
SELECT CURRVAL(pg_get_serial_sequence('public.tag','idtag')) into var_id;

END IF;

INSERT INTO video_has_tag 
(                 
  idvideo,      
  idtag             
)
VALUES 
(
  in_idvideo,                
  var_id             
);

SELECT CURRVAL(pg_get_serial_sequence('public.video','idvideo'));
END
$$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER;

剩下的潜在问题是序列名称,也许是您想要返回的值。