2014-01-20 38 views
0

如何限制表中的字段为15或16位数字。我有这张表:SQL服务器数字字段上的数字限制

create table Person( 
    ,UserID varchar(30) 
    ,Password varchar(30) not null 
    ,CCtype varchar(8) 
    ,CCNumber numeric 
    ,primary key(UserID) 
    ,constraint CK_CCvalidity check 
     (
      (CCType is null or CCNumber is null) 
      or 
      (
       (CCType = 'Amex' or CCType = 'Discover' or CCType = 'MC' or CCType = 'VISA') 
       and 
       (CCNumber >= 15 and CCNumber <= 16) 
      ) 
     ) 
); 

但是,这实际上检查值15和16,而不是数字的数量。此外,我们可以假定数字可能会保留000 ...作为第一个数字。

感谢您的帮助

+2

与您的问题无关,但用户和信用卡之间的一对多关系可能会更好。另外,请确保您遵守存储信用卡数据的所有相关安全准则。 –

回答

4

CCNumber不应该是数字。那将导致一个痛苦的世界。

它应该是varchar(X)其中X是13-24位数字。

信用卡号码通常用4或5组表示,用空格或破折号分隔的数字或简单地全部没有分隔符的数字组成。

[note:American Express:15 digits;签证:13或16位数字]

在回答您的评论:

ALTER TABLE dbo.Person 
    ADD CONSTRAINT CK_Person_CCNumber 
        CHECK (LEN(CCNumber) = 16 OR LEN(CCNumber) = 15); 

但可能更好:

ALTER TABLE dbo.Person 
    ADD CONSTRAINT CK_Person_CCNumber 
        CHECK (LEN(CCNumber) >= 13 AND LEN(CCNumber) <= 15); 

,并添加一个约束,以确保它可能是一个有效的信用卡号码(网上有很多例子)。

+0

好的谢谢你的回应,但即使我做了varchar,如何检查字段的长度是15还是16个数字字符? – setlio

+1

随着Mitch展示的LEN功能:) – thepirat000

0

您可以创建一个函数来从一个varchar删除非数字字符,如this one

CREATE Function [fnRemoveNonNumericCharacters](@strText VARCHAR(1000)) 
RETURNS VARCHAR(1000) 
AS 
BEGIN 
    WHILE PATINDEX('%[^0-9]%', @strText) > 0 
    BEGIN 
     SET @strText = STUFF(@strText, PATINDEX('%[^0-9]%', @strText), 1, '') 
    END 
    RETURN @strText 
END 

现在,如果你希望只允许数字和希望要检查长度,您可以添加两个像这样的检查约束条件:

Create Table Person 
(
    Id int not null primary key, 
    CCNumber varchar(30), 

    CONSTRAINT CK_Person_CCNumber_Length CHECK (LEN(CCNumber) BETWEEN 15 AND 16), 
    CONSTRAINT CK_Person_CCNumber_IsNumeric CHECK (LEN(dbo.[fnRemoveNonNumericCharacters](CCNumber)) = LEN(CCNumber)) 
) 

第一约束将检查字段的长度为15或16。

第二个将检查该字段是数字(场除去非数字的长度等于原始字段的长度)

您也可以在一个ANDed Check Constraint中执行此操作。

0

存储一个信用卡号码作为...号码保证有朝一日在脚下拍摄你。例如您开始遇到带有前导零的信用卡号码的那一天。它们可能由十进制数字组成,但它们不是号码。他们是文字。

未来计划:当有人开始用信件发出信用卡号码时会发生什么?

所以,试试这个:

create table dbo.some_table 
(
    ... 
    credit_card_type varchar(8) null , 
    credit_card_number varchar(32) null , 

    constraint some_table_ck01 check (
     ( credit_card_type is not null 
     and credit_card_number is not null 
     ) 
    OR ( credit_card_type is  null 
     and credit_card_number is  null 
     ) 
    ) , 
    constraint some_table_ck02 check (
    credit_card_type in ('amex' , 'discover' , 'mc' , 'visa') 
    ) , 
    constraint some_table_ck03 check (
    credit_card_number not like '%[^0-9]%' 
    ) , 
    constraint some_table_ck04 check (
    len(credit_card_number) = case credit_card_type 
           when 'amex'  then 15 
           when 'discover' then 16 
           when 'mc'  then 16 
           when 'visa'  then 16 
           else     -1 -- coerce failure on invalid/unknown type 
           end 
    ) , 
) 
go 

insert some_table values(null , null    ) -- succeeds 
insert some_table values('amex' , null    ) -- violates check constraint #1 
insert some_table values(null , '1'    ) -- violates check constraint #1 
insert some_table values('acme' , '1'    ) -- violates check constraint #2 
insert some_table values('amex' , 'A1B2'   ) -- violates check constraint #3 
insert some_table values('amex' , '12345'   ) -- violates check constraint #4 
insert some_table values('amex' , '123456789') -- success! 
go 

但正如其他人所指出的,你需要修复你的数据模型。信用卡是来自客户的单独的实体。它对客户有着依赖关系(该卡的存在取决于拥有该客户的客户的存在)。你可以像下面这样的数据模型。这

create table credit_card_type 
(
    int   id   not null primary key clustered , 
    description varchar(32) not null unique , 
    ... -- other columns describing validation rules here 
) 

create table credit_card 
(
    customer_id  int   not null , 
    type    int   not null , 
    number    varchar(32) not null , 
    expiry_date  date  not null , 

    primary key (customer_id , number , type , expiry_date) , 
    unique  (number  , customer_id , type , expiry_date) , 

    foreign key customer references customer(id) , 
    foreign key type references credit_card_type(id) , 

) 

另外:你加密使用强大的加密卡号,不是吗?