回答

收藏

插入一个COALESCE(NULL,默认)

技术问答 技术问答 170 人阅读 | 0 人回复 | 2023-09-13

我有使用UUID的表。我希望能够插入有或没有UUID的新行,因为有时客户端有时会生成UUID。
/ K" t1 u$ Z& T. c' I! T( k+ a每个表的核心是这样的:( t  j; ~  r. b$ G, {3 x
CREATE TABLE IF NOT EXISTS person (
1 K  z4 b2 A) h! ?    id UUID PRIMARY KEY DEFAULT gen_random_uuid()8 C" H1 n, x' I8 Z! [: j. y
);
" |3 ^, }1 [$ s7 V. i我正在尝试使用一个函数来插入行。我希望能够提供一个NULL ID并获取默认值(生成的UUID)。我有这样的事情:
7 V5 n8 y: j. x% iCREATE OR REPLACE FUNCTION create_person(
- h2 X, ~" q  d; a! d    id UUID2 N# e& ?% Z9 i- m8 S6 X$ e
) RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$, c3 q& j" p% b9 N
BEGIN
! W; ^6 @. i0 K% t; c* _    INSERT INTO person( id ), {! p! I( h9 B& I2 r3 _
    VALUES (
+ H3 O8 A) F. f+ Y: |" M6 e        COALESCE(id,default)
3 b" E* [( Y! x: g. g5 [    );
- b  l3 H/ F8 h& p8 v* t# |  K    RETURN FOUND;! `4 C$ L- A7 E; ?
END;
7 P9 X1 u6 r2 a5 N5 |$$;0 g) N! f, q$ Z* P8 n
我已经试过了:
  t# I, O! l: T1 e" H. {6 TINSERT INTO person ( id ) VALUES (
0 f: M2 v; E! W5 ^" t( g    COALESCE(id, default),( v" O% T" Y! t" R' C, t
);+ `# ?- g' |* q3 O  A3 h- Y9 N
还有这个:
6 i& M9 P! }4 w6 i9 B0 ?INSERT INTO person ( id ) VALUES (% u5 w# f  E$ _+ V0 r5 O6 b
  CASE WHEN id IS NULL THEN default ELSE id END3 V8 H. D  ^9 ~5 ~) V
);' l. t" D( T8 L9 u6 O! b
这有效,但是重复了gen_random_uuid()代码:
( F! w8 v3 O6 F/ GINSERT INTO person ( id ) VALUES (
/ z8 s, Z0 D  L% Y: i  COALESCE(id, gen_random_uuid()),' r0 \& G9 i, q; f, l, V) H0 w
);
: _6 G" L; E' O* d9 G同样也可以,但是存在相同的问题:( v+ w, g5 h4 Q/ j- _9 O; p% R
INSERT INTO person ( id ) VALUES (% r  r% Z& I: n8 f; |
    CASE WHEN id IS NULL THEN gen_random_uuid() ELSE id END' S' r6 }* R0 n5 S2 q
);2 x$ l- [+ k: A# A5 o
有没有一种方法可以不必重复执行gen_random_uuid()代码?
7 r9 O5 F& H! ]4 i# D7 w这样做会更好plpgsql吗?+ ^1 O8 s; }. x
                & e; R8 b( Y8 \) S8 u4 B
解决方案:( }$ S* [4 a5 M/ G  e
               
. U; E9 Q. c- Z6 x* C, c( ?5 Q, V4 _# ?; i
( n1 d  W: t4 J1 l- l. _& R
                无法在列上重复使用定义的默认值。默认值仅用于定义INSERT未指定值时会发生的情况。根据此定义,null值仍然是“指定的”,因此不能使用默认值。
1 _; W" w) j  F7 s1 a3 l* k您关于某人可能不使用该功能的评论表明,触发器比简单的功能更适合您的要求。
( F) Q9 A. k+ o* @8 y5 k3 ~  a+ E7 Chttps://www.postgresql.org/docs/current/static/plpgsql-9 m# W0 B4 W* Y9 u, V
trigger.html! u3 A# ^7 U" P% N# b
CREATE OR REPLACE FUNCTION default_id() RETURNS TRIGGER AS $default_id$
/ o$ v9 T2 n3 ~& y% ]    BEGIN       4 Z3 e6 X& a/ Z1 c0 R
        IF (NEW.id IS NULL) THEN; _( R- R) n1 ]4 e) B6 d
            NEW.id := gen_random_uuid();
/ R. q* a4 [6 ]8 ~8 u        END IF;
# j, W. s( [  \3 z; |        RETURN NEW;
; r* ]  D2 K  t6 H' c; Q2 H9 D" L) r" E6 \    END;# B! J6 [  s) S, q
$default_id$ LANGUAGE plpgsql;7 o1 Y3 E) ^8 d3 n
CREATE TRIGGER default_id_trigger
6 |! J  H& z/ ^: e7 EBEFORE INSERT OR UPDATE ON person
1 x" u0 ]1 `5 o- g8 ]; o    FOR EACH ROW EXECUTE PROCEDURE default_id();$ m# ~1 y+ r  u. Q

0 I: b  A$ J7 h& v' l, o5 \如果您确实想使用函数来执行此操作,那么最简单的方法就是在插入之前分配值:
" r' \# n6 O/ s& j$ f1 N- [: ACREATE OR REPLACE FUNCTION create_person(5 w) \' p/ u0 W( k3 ~5 r; v! P
    id UUID
# ]: R8 ?: O! U4 G1 E) RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$
  {. o0 l2 I& e% F0 F  w; W/ R9 z+ r$ KBEGIN$ W% {! W  b7 \4 `* ?
    IF id IS NULL THEN7 R: u6 L6 L" X) O1 A- Q
        id := gen_random_uuid();, ~& l% w- b: N( N# g$ [# z
    END IF;
& A$ v( J/ i6 g' [8 N    -- OR
, [  d3 I( O- u' S. [! M8 w( T7 G    -- id := coalesce(id, gen_random_uuid());) n/ U7 k" u0 h# r1 k/ r
    INSERT INTO person( id )
& B$ H% y6 z' C' u' p6 r    VALUES (id);/ r" q5 u% w; f) O& B9 \. d
    RETURN FOUND;
5 v# S' I& [$ U2 P; b( ]1 IEND;, W  ?1 S; ^7 p
$$;
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则