需要在SQL中对数字应用CHECK约束和长度检查

时间:2016-02-13 10:41:03

标签: postgresql

我需要对数据类型有一个CHECK约束,该数据类型的格式必须为010000129999且保留为零,但我不知道如何实现这一点。基本上,很明显,这是一个数字月份。

我尝试过使用numeric(6,0)integer,但我不知道如何使用保留前导零的CHECK。

我也不知道如何使用character varying(6)更轻松地实现这一点,并且它也不是首选,因为我认为在应用程序层中使用它会更难。

有什么建议吗?我正在使用Postgres。

2 个答案:

答案 0 :(得分:1)

三种方式(可能还有更多):

        -- (1) use a date type for a date
CREATE TABLE mmyyyy
        ( id SERIAL NOT NULL PRIMARY KEY
        , yyyymm01 DATE NOT NULL CHECK (date_trunc('month', yyyymm01) = yyyymm01)
        );

INSERT INTO mmyyyy(yyyymm01) VALUES
 ('1901-01-01') ,('0001-01-01') ,('2016-02-01') ;

INSERT INTO mmyyyy(yyyymm01) VALUES ('1901-13-01') ;  -- should fail
INSERT INTO mmyyyy(yyyymm01) VALUES ('2016-02-13') ; -- should fail

SELECT id, to_char(yyyymm01, 'mmyyyy') AS this FROM mmyyyy ;

        -- (2) use a char type and apply the check on the cast_to_int result
CREATE TABLE omg
        ( id SERIAL NOT NULL PRIMARY KEY
        , mmyyyy varchar(6) NOT NULL CHECK (
                length(mmyyyy) = 6 AND
                left(mmyyyy,2)::integer BETWEEN 1 AND 12)
        );

INSERT INTO omg(mmyyyy) VALUES ('011901') ,('010001') ,('022016') ;
INSERT INTO omg(mmyyyy) VALUES ('131901') ;  -- should fail
INSERT INTO omg(mmyyyy) VALUES ('002016') ; -- should fail

SELECT id, mmyyyy FROM omg ;

        -- (3) use an int type and apply the check to the value/10000
CREATE TABLE wtf
        ( id SERIAL NOT NULL PRIMARY KEY
        , mmyyyy INTEGER NOT NULL CHECK (
                mmyyyy/10000 BETWEEN 1 AND 12)
        );

INSERT INTO wtf(mmyyyy) VALUES
 (11901) ,(10001) ,(22016)
        ;

INSERT INTO wtf(mmyyyy) VALUES (131901) ;  -- should fail
INSERT INTO wtf(mmyyyy) VALUES (2016) ; -- should fail

SELECT id, to_char(mmyyyy, '099999') AS mmyyyy
FROM wtf
        ;

        -- (extra) use an date/char/int type AS the baseclass for a domain(or type):
        -- (this can come in handy if the "type" is used in more than one place)
CREATE DOMAIN omgwtf AS
        INTEGER CHECK ( value/10000 BETWEEN 1 AND 12)
        ;

CREATE TABLE tralala
        ( id SERIAL NOT NULL PRIMARY KEY
        , mmyyyy omgwtf NOT NULL
        );

INSERT INTO tralala(mmyyyy) VALUES
 (11901) ,(10001) ,(22016)
        ;

INSERT INTO tralala(mmyyyy) VALUES (131901) ;  -- should fail
INSERT INTO tralala(mmyyyy) VALUES (2016) ; -- should fail

SELECT id, to_char(mmyyyy, '099999') AS mmyyyy
FROM tralala
        ;

输出:

CREATE TABLE
INSERT 0 3
ERROR:  date/time field value out of range: "1901-13-01"
LINE 1: INSERT INTO mmyyyy(yyyymm01) VALUES ('1901-13-01') ;
                                             ^
HINT:  Perhaps you need a different "datestyle" setting.
ERROR:  new row for relation "mmyyyy" violates check constraint "mmyyyy_yyyymm01_check"
DETAIL:  Failing row contains (4, 2016-02-13).
 id |  this  
----+--------
  1 | 011901
  2 | 010001
  3 | 022016
(3 rows)

CREATE TABLE
INSERT 0 3
ERROR:  new row for relation "omg" violates check constraint "omg_mmyyyy_check"
DETAIL:  Failing row contains (4, 131901).
ERROR:  new row for relation "omg" violates check constraint "omg_mmyyyy_check"
DETAIL:  Failing row contains (5, 002016).
 id | mmyyyy 
----+--------
  1 | 011901
  2 | 010001
  3 | 022016
(3 rows)

CREATE TABLE
INSERT 0 3
ERROR:  new row for relation "wtf" violates check constraint "wtf_mmyyyy_check"
DETAIL:  Failing row contains (4, 131901).
ERROR:  new row for relation "wtf" violates check constraint "wtf_mmyyyy_check"
DETAIL:  Failing row contains (5, 2016).
 id | mmyyyy  
----+---------
  1 |  011901
  2 |  010001
  3 |  022016
(3 rows)

CREATE DOMAIN
CREATE TABLE
INSERT 0 3
ERROR:  value for domain omgwtf violates check constraint "omgwtf_check"
ERROR:  value for domain omgwtf violates check constraint "omgwtf_check"
 id | mmyyyy  
----+---------
  1 |  011901
  2 |  010001
  3 |  022016
(3 rows)

答案 1 :(得分:-1)

我最终使用yyyymm格式,如@ lad2025所示。