Dav*_* J. 23 postgresql constraints
向PostgreSQL添加约束以检查一列(来自一组列)是否包含非空值的好方法是什么?
更新:我可能想要使用Create Table和Alter Table中check
详细说明的表达式.
更新:我正在查看可用的功能.
更新:仅供后台使用,这是我目前正在使用的Rails验证逻辑:
validate :multi_column_validation
def multi_column_validation
n = 0
n += 1 if column_1
n += 1 if column_2
n += 1 if column_3
unless 1 == n
errors.add(:base, "Exactly one column from " +
"column_1, column_2, column_3 must be present")
end
end
Run Code Online (Sandbox Code Playgroud)
要清楚,我在这里寻找的是PSQL,而不是Ruby.我只想展示我正在使用的逻辑,因为它比枚举所有"真值表"的可能性更紧凑.
ger*_*nll 43
从 PostgreSQL 9.6 开始,您拥有接受任意数量 VARIADIC 参数的num_nonnulls
和num_nulls
比较函数。
例如,这将确保三列中的一列不为空。
ALTER TABLE your_table
ADD CONSTRAINT chk_only_one_is_not_null CHECK (num_nonnulls(col1, col2, col3) = 1);
Run Code Online (Sandbox Code Playgroud)
Dav*_* J. 37
这是一个优雅的两列解决方案,根据"约束 - 一个或另一个列不为空"PostgreSQL消息板:
ALTER TABLE my_table ADD CONSTRAINT my_constraint CHECK (
(column_1 IS NULL) != (column_2 IS NULL));
Run Code Online (Sandbox Code Playgroud)
(但上述方法不能推广到三列或更多列.)
如果您有三列或更多列,则可以使用a_horse_with_no_name说明的真值表方法.但是,我认为以下内容更容易维护,因为您不必键入逻辑组合:
ALTER TABLE my_table
ADD CONSTRAINT my_constraint CHECK (
(CASE WHEN column_1 IS NULL THEN 0 ELSE 1 END) +
(CASE WHEN column_2 IS NULL THEN 0 ELSE 1 END) +
(CASE WHEN column_3 IS NULL THEN 0 ELSE 1 END) = 1;
Run Code Online (Sandbox Code Playgroud)
为了压缩它,创建一个自定义函数以便CASE WHEN column_k IS NULL THEN 0 ELSE 1 END
可以删除样板,这将是很有用的,例如:
(non_null_count(column_1) +
non_null_count(column_2) +
non_null_count(column_3)) = 1
Run Code Online (Sandbox Code Playgroud)
这可能与PSQL允许(?)一样紧凑.也就是说,如果可能的话,我更愿意使用这种语法:
non_null_count(column_1, column_2, column_3) = 1
Run Code Online (Sandbox Code Playgroud)
Mat*_*sOl 18
我认为最干净和通用的解决方案是创建一个函数来计算某些参数的空值.为此你可以使用伪类型anyarray
和SQL函数:
CREATE FUNCTION count_not_nulls(p_array anyarray)
RETURNS BIGINT AS
$$
SELECT count(x) FROM unnest($1) AS x
$$ LANGUAGE SQL IMMUTABLE;
Run Code Online (Sandbox Code Playgroud)
使用该功能,您可以创建您CHECK CONSTRAINT
的:
ALTER TABLE your_table
ADD chk_only_one_is_not_null CHECK(count_not_nulls(array[col1, col2, col3]) = 1);
Run Code Online (Sandbox Code Playgroud)
仅当列具有相同的数据类型时,这才有效.如果不是这种情况,你可以将它们作为文本进行转换(因为你只关心空的情况):
ALTER TABLE your_table
ADD chk_only_one_is_not_null CHECK(count_not_nulls(array[col1::text, col2::text, col3::text]) = 1);
Run Code Online (Sandbox Code Playgroud)
正如@muistooshort所记得的那样,您可以使用可变参数创建函数,这使得它可以清楚地调用:
CREATE FUNCTION count_not_nulls(variadic p_array anyarray)
RETURNS BIGINT AS
$$
SELECT count(x) FROM unnest($1) AS x
$$ LANGUAGE SQL IMMUTABLE;
ALTER TABLE your_table
ADD chk_only_one_is_not_null CHECK(count_not_nulls(col1, col2, col3) = 1);
Run Code Online (Sandbox Code Playgroud)
Clo*_*eto 16
alter table t
add constraint only_one_null check (
(col1 is not null)::integer + (col2 is not null)::integer = 1
)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
8530 次 |
最近记录: |