回答

收藏

插入一个COALESCE(NULL,默认)

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

我有使用UUID的表。我希望能够插入有或没有UUID的新行,因为有时客户端有时会生成UUID。
9 Z" p6 I! {; u  u# j$ b" b每个表的核心是这样的:
, a: e) A: F- m* m7 MCREATE TABLE IF NOT EXISTS person (
+ V5 D+ d2 \) S* o0 H4 a    id UUID PRIMARY KEY DEFAULT gen_random_uuid()
" l& x) ^* J' K" i( \6 @' a);
; ~( V  Q' R1 j5 R! k; a1 M我正在尝试使用一个函数来插入行。我希望能够提供一个NULL ID并获取默认值(生成的UUID)。我有这样的事情:8 r8 O( `% h. [5 Z0 Q) }, j
CREATE OR REPLACE FUNCTION create_person(
5 b9 D% V7 z3 O& j. z    id UUID
/ b. }' e8 ^/ x7 d7 Q( a, b) RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$
/ F" Y5 ~, [# `3 q! R2 S2 H1 FBEGIN
2 I7 p  g0 p9 O( w5 ]    INSERT INTO person( id )/ L- `! |/ o! X& P, W
    VALUES (  b0 V' ?3 Z  I9 U" p
        COALESCE(id,default)0 W% W  r( e# I6 W9 d
    );
' o  P7 K) b7 z; B7 x6 C3 v8 K    RETURN FOUND;' g3 j) L; p! a! \. C0 U) U7 H
END;' m$ J/ T& X! p: }
$$;* ?& y- P9 D! S3 x+ h
我已经试过了:/ l( ~3 b3 ]" ^( \
INSERT INTO person ( id ) VALUES (" Q) ]2 E4 z% v0 a& L5 @; J! F
    COALESCE(id, default),
# n0 a6 f; N* Y7 X6 {4 I, W0 @1 `);
% @- z2 z: q1 E" t" E4 ^3 W还有这个:
2 A: L; A8 B" @( AINSERT INTO person ( id ) VALUES (. ]& i; ]2 q7 n5 D
  CASE WHEN id IS NULL THEN default ELSE id END9 T6 H4 ?1 x7 Q2 l8 t5 G( m
);
8 X# C  ?( s, S2 \8 p  m这有效,但是重复了gen_random_uuid()代码:
; {, j5 v9 z/ [, \8 f, @INSERT INTO person ( id ) VALUES (* |, V: [4 C- M; [7 E& t
  COALESCE(id, gen_random_uuid()),3 {. ]  h) F3 y9 h! p
);; Q0 c" `, L5 H& X
同样也可以,但是存在相同的问题:: J* h' Z- y$ V7 \
INSERT INTO person ( id ) VALUES (' A. [( S/ U5 U# V/ I1 u
    CASE WHEN id IS NULL THEN gen_random_uuid() ELSE id END
& b$ Y" Z: c8 g" j# J: b);
& g3 Q2 \! y+ a7 q有没有一种方法可以不必重复执行gen_random_uuid()代码?3 w, A+ C: X" V0 F
这样做会更好plpgsql吗?: w: u$ q$ C4 k; s: U* ], ?7 t
               
+ ~$ g7 a2 j0 |& B9 q; a. a: [解决方案:6 r) @/ l" r& [
               
: z3 m$ m: S0 J7 f6 R; l, E. Q; `( M
8 t7 x: U" T3 q" F, u
" n+ H( @, J, U1 z- ]* r# h                无法在列上重复使用定义的默认值。默认值仅用于定义INSERT未指定值时会发生的情况。根据此定义,null值仍然是“指定的”,因此不能使用默认值。% v2 G0 u5 K: x: C, s5 w: g4 {
您关于某人可能不使用该功能的评论表明,触发器比简单的功能更适合您的要求。
, l% s7 r! ~2 k$ X( C: M& w7 Ahttps://www.postgresql.org/docs/current/static/plpgsql-
3 Q( S1 S3 c. ctrigger.html# k7 ?& t0 Z/ I. n  b5 K
CREATE OR REPLACE FUNCTION default_id() RETURNS TRIGGER AS $default_id$) Y6 Q( d4 G6 _6 F  l9 ~" |2 o" D# Q
    BEGIN      
' ^- m$ l$ Q" C. K& ^: q( }: ?. C        IF (NEW.id IS NULL) THEN9 o) X- I9 v/ U# \+ J) N
            NEW.id := gen_random_uuid();8 `9 n7 M1 N+ B% @3 c& r) N9 V
        END IF;
, T& e3 P9 a# p, ^        RETURN NEW;
0 H  r, a. P' v    END;
  L* m. v1 ]; L: K" z1 ~' Z0 o$default_id$ LANGUAGE plpgsql;
; T9 h' ]/ D- JCREATE TRIGGER default_id_trigger
# M; e+ W* c+ T% _. C; d2 U' GBEFORE INSERT OR UPDATE ON person
# \! E/ j, f& ?" j; S    FOR EACH ROW EXECUTE PROCEDURE default_id();" }. I, f- e7 I4 ?! v( ?
* e& K: h3 V9 O
如果您确实想使用函数来执行此操作,那么最简单的方法就是在插入之前分配值:
5 |. B5 \: j' U. s( j7 ~6 h: _CREATE OR REPLACE FUNCTION create_person(
9 M1 e5 z/ J# t1 U7 F& Q. {5 V    id UUID
8 b, ~" M/ U2 U% R) RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$
- U% |! j3 F+ G3 q# IBEGIN
0 U( ^( [; X# ?$ F' _    IF id IS NULL THEN
  T. e& i. B- A& C9 U$ Z! R        id := gen_random_uuid();) l9 ?+ e! {! X% f( c
    END IF;
3 E) W2 {  E0 x* J' m" m    -- OR0 g- S) z# T( B6 _
    -- id := coalesce(id, gen_random_uuid());/ h) K: j  \3 i, R
    INSERT INTO person( id )
& n/ W7 S; |, L9 o1 {0 Z    VALUES (id);
! N9 t0 \1 @/ E+ n$ Q: U+ B    RETURN FOUND;/ ~4 }7 Q* C; P* b2 |
END;9 {' y& C( R0 X# `5 T+ c& t
$$;
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则