0

我试图纠正这个功能,但这是不可能的!我声明一个整数“var_id”,并在id_val中插入第一个查询的值,如果为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

4 回答 4

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;
于 2013-01-30T17:59:23.323 回答
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)
于 2013-01-30T17:15:26.610 回答
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;
于 2013-01-30T16:48:09.533 回答
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;

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

于 2013-01-30T16:55:28.333 回答