我们如何使用约束来确保数组的所有值都不是 NULL?

Ogr*_*gre 3 sql postgresql plpgsql

假设我有下表:

CREATE TABLE test (
    arr_column VARCHAR[] NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

这不会阻止在插入行时将数组的值设置为 NULL。所以,我想要一个约束来强制执行这个规则。我的尝试如下:

CREATE TABLE test (
    arr_column VARCHAR[] NOT NULL 
        CHECK (NOT (ARRAY[NULL]::VARCHAR[] <@ arr_column))
)
Run Code Online (Sandbox Code Playgroud)

但不幸的是,如果我插入,这不会失败:

INSERT INTO test (ARRAY['some_string', NULL]::VARCHAR[])
Run Code Online (Sandbox Code Playgroud)

Jim*_*nes 5

进行此类检查的一种简单直接的方法是使用触发器,但您也可以简单地创建一个函数并在CHECK子句中使用它,就像您迄今为止所做的那样:

CREATE OR REPLACE FUNCTION check_null_element(arr TEXT[]) 
RETURNS BOOLEAN AS $BODY$
DECLARE j INT;
BEGIN
  FOR j IN 1 .. ARRAY_UPPER(arr, 1) LOOP
    IF arr[j] IS NULL THEN
       RETURN FALSE;
    END IF;
  END LOOP;
RETURN TRUE;
END;
$BODY$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

因此,在创建表时,您只需要:

CREATE temp TABLE test (
    arr_column VARCHAR[] NOT NULL 
        CHECK (check_null_element(arr_column))
);
Run Code Online (Sandbox Code Playgroud)

尝试插入一个带有NULL值的数组:

db=# INSERT INTO test VALUES (ARRAY['some_string', NULL]::VARCHAR[]);
FEHLER:  neue Zeile für Relation »test« verletzt Check-Constraint »test_arr_column_check«
DETAIL:  Fehlgeschlagene Zeile enthält ({some_string,NULL}).
Run Code Online (Sandbox Code Playgroud)

并有一个有效的..

db=# INSERT INTO test VALUES (ARRAY['some_string', 'NOT NULL :-)']::VARCHAR[]);
INSERT 0 1
Run Code Online (Sandbox Code Playgroud)

编辑:很高兴有:

为了避免不必要的异常,您可以另外检查参数本身是否NULL- 对于这个问题来说是多余的,因为它已经NOT NULL在CREATE TABLE语句中使用约束进行了检查。这可以通过向函数添加以下条件来完成:IF arr IS NULL THEN RETURN FALSE; END IF;

CREATE OR REPLACE FUNCTION check_null_element(arr TEXT[]) 
RETURNS BOOLEAN AS $BODY$
DECLARE j INT;
BEGIN
  IF arr IS NULL THEN RETURN FALSE; END IF;
  FOR j IN 1 .. ARRAY_UPPER(arr, 1) LOOP
    IF arr[j] IS NULL THEN
       RETURN FALSE;
    END IF;
  END LOOP;
RETURN TRUE;
END;
$BODY$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

  • 一个小的性能改进:如果你找到第一个 NULL,你可以立即离开循环。也不需要测试所有剩余的元素。你可以用 `return false;` 替换 `res := false;` (2认同)