如何限制oracle number(10)数据类型的最大值为2147483647

时间:2018-04-03 14:25:28

标签: sql oracle sqldatatypes

我试图在oracle中找到一种方法来限制数字(10)数据类型的最大值为2,147,483,647。根据oracle网站,下面是数字(10)的详细范围。但我可以看到我们可以添加值> 2,147,483,647直到它是十位数。有没有办法(除了添加约束)限制价值?

NUMBER(10)

有符号长整数。

大小:4个字节

范围:-2147483648至+2147483647

1 个答案:

答案 0 :(得分:13)

使用检查约束的最简单解决方案:

(说真的,只需使用此解决方案)

CREATE TABLE x (i NUMBER(10) CHECK (i BETWEEN -2147483648 AND 2147483647));

不那么简单(因为你似乎不想要约束):

CREATE TABLE x (i NUMBER(10));

CREATE TRIGGER x_int_trg
BEFORE INSERT OR UPDATE
ON x
REFERENCING NEW AS new
FOR EACH ROW
BEGIN
  IF :new.i NOT BETWEEN -2147483648 AND 2147483647 THEN
    raise_application_error(-20000, 'Not a 32 bit integer');
  END IF;
END x_int_trg;
/

更简单(但很难知道):

使用带有WITH CHECK OPTION子句的视图,并始终通过该视图插入/更新数据。通过设置适当的授权来防止直接访问表。 (当然,我仍然会添加约束,但你不想这样做。)

CREATE TABLE x_hidden_implementation (i NUMBER(10));

CREATE OR REPLACE VIEW x AS
SELECT * FROM x_hidden_implementation 
WHERE i BETWEEN -2147483648 AND 2147483647
WITH CHECK OPTION;

全押OBJECT类型:

当然,如果你真的想要一个类型,那么创建它!

CREATE OR REPLACE TYPE my_integer AS OBJECT (
  i NUMBER(10),

  CONSTRUCTOR FUNCTION my_integer (SELF IN OUT NOCOPY my_integer, i NUMBER)
    RETURN SELF AS RESULT
) FINAL;
/

CREATE OR REPLACE TYPE BODY my_integer AS
  CONSTRUCTOR FUNCTION my_integer (SELF IN OUT NOCOPY my_integer, i NUMBER) 
    RETURN SELF AS RESULT IS
  BEGIN
    IF i NOT BETWEEN -2147483648 AND 2147483647 THEN
      raise_application_error(-20000, 'Not a 32 bit integer');
    END IF;

    SELF.i := i;
    RETURN;
  END;
END;
/

CREATE TABLE x (i my_integer);

现在,尝试插入这些。第二个将失败:

INSERT INTO x VALUES (my_integer(1));
INSERT INTO x VALUES (my_integer(9999999999));

将其标准化!

如果您已正确规范化架构,则不会发生这种情况。只需创建

CREATE TABLE int4 (i NUMBER(10) PRIMARY KEY);
INSERT INTO int4
SELECT -2147483649 + level
FROM dual
CONNECT BY level <= 2 * 2147483648;
CREATE TABLE x (i NUMBER(10) REFERENCES int4);

适用于SMALLINTTINYINT。如果您购买Exadata,那么您也可以尝试使用BIGINT。确保没有人修改表格!

Kjetil S.在评论中提供此想法的信用

Future Oracle

我听说标准的SQL断言很可能是Oracle未来的一个特性:https://community.oracle.com/ideas/13028

他们喜欢CHECK约束,但可以跨越几个表。当然,在您的情况下过度设计,但至少不是实际的CHECK约束。

$$$企业客户解决方案:

如果您愿意付费,并且您似乎希望通过而不是使用简单的检查约束来解决此问题,那么Oracle已通过Virtual Private Database功能对您进行了介绍

只是拒绝访问数据库用户所需范围之外的所有值,然后重新设置。

使用PostgreSQL的髋关节解决方案

既然你没有提到任何关于你的动机的事情,那么,为什么不使用PostgreSQL作为你的Oracle数据库的接口呢?您可以在PostgreSQL中使用Oracle Foreign Data Wrapper的此实现,然后将表格声明为:

CREATE FOREIGN TABLE x (
  id integer
) SERVER oracle_server OPTIONS (schema 'MY_USER', table 'X');

您将获得大量其他免费酷炫功能,例如:

  • 提高标准合规性
  • FILTER子句
  • 这样的酷SQL功能
  • 实际BOOLEAN数据类型,而不是1 / 0无意义
  • 撰写博客文章并将其置于hackernews上以获得大量流量,因为PostgreSQL