【问题标题】:Add date format constraint to varchar attribut向 varchar 属性添加日期格式约束
【发布时间】:2022-01-14 07:55:52
【问题描述】:

我正在尝试在 oracle 中创建此表,但我想为 datexp(日期格式 'MM/YYYY')属性添加一个约束,但遗憾的是我的尝试都没有正常工作:

create table carte
(
    idcarte char(5) primary key,
    typec varchar(20) 
        check(typec in ('E-dinars smart', 'E-dinars universel', 'visa electron', 'visa international', 'mastercard international')),
    datexp varchar(9) ,
    numerocarte number(20),
    signaturecvv2 number(3)
);

我试过了:

datexp varchar(9) check(to_date(datexp, 'MM/YYYY')),

datexp varchar(9) check(date_exp = to_date(datexp, 'MM/YYYY')),

【问题讨论】:

  • 不要尝试在您的 varchar 列中强制使用正确的“日期格式” - 而是直接使用适当的日期或日期和时间数据类型 - 否如果从一开始就正确存储它们,则根本需要摆弄“日期格式”!

标签: sql oracle date


【解决方案1】:

在我看来,那将是大错特错。永远,永远将日期存储为字符串。 从不。它容易出错,您不应该将时间浪费在弄清楚如何 创建约束以防止用户输入无效日期 - 让数据库来处理。如何?只需为该列设置DATE 数据类型。

此外,我建议您为 carte types 创建参照完整性约束:

SQL> CREATE TABLE carte_type
  2  (
  3     typec   NUMBER CONSTRAINT pk_cartyp PRIMARY KEY,
  4     name    VARCHAR2 (50) NOT NULL
  5  );

Table created.

SQL> CREATE TABLE carte
  2  (
  3     idcarte         CHAR (5) PRIMARY KEY,
  4     typec           NUMBER CONSTRAINT fk_cart_typ REFERENCES carte_type (typec),
  5     datexp          DATE,
  6     numerocarte     NUMBER (20),
  7     signaturecvv2   NUMBER (3)
  8  );

Table created.

SQL>

如果您担心日期格式 (mm/yyyy),请不要担心 - 输入属于该月/年的 任何 日期,然后 - 将该信息呈现给最终用户 - 将所需的格式掩码应用于to_char 函数,例如

select to_char(datexp, 'mm/yyyy') as datexp
from ...

你是否输入并不重要,例如08/12/2021 (dd/mm/yyyy) 或 23/12/2021 - 两者都在 12/2021。

或者,如果您使用的是 GUI 工具(或报告生成器),它已经提供了格式掩码属性,所以请使用它。

【讨论】:

    【解决方案2】:

    您应该将日期值存储为DATE,并且可以使用检查约束将其限制为月初的值。您甚至可以添加一个虚拟列以生成所需格式的DATEXP

    CREATE TABLE carte(
      idcarte       VARCHAR2(5)
                    CONSTRAINT carte__idcarte__pk PRIMARY KEY,
      typec         VARCHAR2(20)
                    CONSTRAINT carte__typec__chk CHECK(
                      typec in(
                        'E-dinars smart',
                        'E-dinars universel',
                        'visa electron',
                        'visa international',
                        'mastercard international'
                      )
                    ),
      datexp        DATE
                    CONSTRAINT carte__datexp__chk CHECK(datexp = TRUNC(datexp, 'MM')),
      formatted_datexp
                    VARCHAR2(7)
                    GENERATED ALWAYS AS (TO_CHAR(datexp, 'MM/YYYY')),
      numerocarte   NUMBER(20),
      signaturecvv2 NUMBER(3)
    );
    

    但是,如果您有正当的商业理由将其存储为字符串(您可能没有,即使您认为有),您可以尝试从 Oracle 12 转换为日期并使用 DEFAULT NULL ON CONVERSION ERROR in具有精确格式模型的检查约束:

    CREATE TABLE carte(
      idcarte       VARCHAR2(5)
                    CONSTRAINT carte__idcarte__pk PRIMARY KEY,
      typec         VARCHAR2(20)
                    CONSTRAINT carte__typec__chk CHECK(
                      typec in(
                        'E-dinars smart',
                        'E-dinars universel',
                        'visa electron',
                        'visa international',
                        'mastercard international'
                      )
                    ),
      datexp        VARCHAR2(7)
                    CONSTRAINT carte__datexp__chk CHECK(
                      TO_DATE(datexp DEFAULT NULL ON CONVERSION ERROR, 'FXMM/YYYY')
                        IS NOT NULL
                    ),
      numerocarte   NUMBER(20),
      signaturecvv2 NUMBER(3)
    );
    

    (注意:在早期版本中,您可以删除 DEFAULT NULL ON CONVERSION ERROR 并且仍然会检查约束,但它会失败并出现与解析日期相关的异常,而不是约束失败的更具描述性的错误。 )

    db小提琴here

    【讨论】:

    • 非常感谢
    • datexp DATE CONSTRAINT carte__datexp__chk CHECK(datexp = TRUNC(datexp, 'MM')),我尝试了这个解决方案,但是当我想插入时:插入到付款值('N0001','CO001', 'jan-2021','CA001','有效');或插入付款值('N0001','CO001','01/2021','CA001','valide');我收到此错误((第 1 行错误:ORA-01843:无效月份))
    • @MedOussemaZaier 这些都不是日期,它们是字符串。您需要使用TO_DATE 转换为日期INSERT INTO carte (idcarte, typec, datexp, numerocarte, signaturecvv2) values ('N0001','visa electron', TO_DATE('jan-2021', 'mon-yyyy'),1,2); 或使用日期文字INSERT INTO carte (idcarte, typec, datexp, numerocarte, signaturecvv2) values ('N0002','visa electron', DATE '2021-01-01', 1, 2);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    • 2021-03-27
    相关资源
    最近更新 更多