2

I was tasked to implement a table with a variable groupcode. There are several requirements.

  1. char(5)
  2. 2 or 4 uppercase letters plus 1 digit whose value is between 1 and 4 (e.g., AA1, AABB1)
  3. Any input other violating point 1 and 2 should be banned

The only thing I can come up with is regexp_like but my efforts are in vain, for example

create table Test(
groupcode char(5) check(
regexp_like(groupcode, '^[A-Z]{2}[0-9]$', 'c') 
)
);

INSERT INTO Test(groupcode) VALUES ('AA1');

I inserted this but it keep telling me there's some violation, in which I don't understand.

I specify ^ and $ because I don't want something like 'bbAA1' or 'AA1bb' appear.

I am also open to non-regex solution. After all the work in this afternoon, I am starting to doubt my approach.

Edit--To Tim:enter image description here

Andes Lam
  • 192
  • 2
  • 8

2 Answers2

2

Your regex ^[A-Z]{2}[0-9]$ only allows (exactly) three characters. But a column defined as char(5) gets padded with spaces if you provide less than three, so in reality 'AA1' will be stored as 'AA1 ' which violates your regex.

Use char(3) instead.

Better yet, never use char at all (you just experienced one of the reasons why), use varchar(5) or varchar(3) both will work with your regex.


2 or 4 uppercase letters plus 1 digit whose value is between 1 and 4

That's not what your regex does. [A-Z]{2} is exactly two uppercase letters. If you want to allow patterns of different lengths there is no way you can use char(5) unless you also include the spaces in the regex:

create table test
(
  groupcode char(5) check(
      regexp_like(groupcode, '(^[A-Z]{2}[0-9]  $)|(^[A-Z]{4}[0-9]$)', 'c'))
);

The above regex allows two uppercase characters followed by on digit and two spaces or four uppercase characters followed by one digit.

  • Good news: I am so grateful that I understand the concept of `'AA1 '`; Bad news: I need to follow strictly the char(5 constraint. :(. – Andes Lam Oct 30 '20 at 10:23
  • @AndesLam: the part "2 uppercase letters plus 1 digit" can't be satisfied with a regex on a `char(5)` column. You **really** should be using `varchar(5)` instead. There is absolutely no advantage whatsoever (neither in performance nor in storage space) when using `char(5)` - only disadvantages. –  Oct 30 '20 at 10:25
  • 1
    Was any reason given for the `char(5)`? It's not only wrong here, `char` is always wrong. I have never seen a good use for it as a column datatype. There's an argument that it documents the intention that the value will always have a certain length, but I've never found that convincing - if the length is so important, add a check constraint. Perhaps the person demanding this is thinking of some other RDBMS where it works differently. – William Robertson Oct 30 '20 at 13:23
  • I don't see how CHAR(3) or VARCHAR(3) could accommodate the longer codes (in the same column). Separately: the regexp can be simplified to `^([A-Z]{2}){1,2}[1-4]$`. Note `[1-4]` at the end - the OP used `[0-9]` but the requirements he gave say "between 1 and 4". –  Oct 30 '20 at 14:46
0

I would suggest:

CREATE TABLE Test (
    groupcode VARCHAR(5),
    CONSTRAINT (CHECK(REGEXP_LIKE(groupcode, '^[A-Z]{2}([A-Z]{2})?[1-4]$', 'c')))
);

Here is an explanation of the regex pattern:

^                from the start of the column
    [A-Z]{2}     match AA, AB, BB, etc.
    ([A-Z]{2})?  then match another optional AA, AB, BB, etc.
    [1-4]        match 1-4
$                end of the column

Demo

Late Edit: The @Horse answer correctly points out that you should use VARCHAR here. But your regex also had a problem, which I fixed.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • @AndesLam I botched the check constraint syntax (but also was assuming you had that right). Try listing the check constraint as a formal constraint in the create table statement. My answer seems to be working, at least in a demo. – Tim Biegeleisen Oct 30 '20 at 10:18
  • Is formal constraint mean `constraint test_c check(regexp_like(groupcode, '^[A-Z]{2}([A-Z]{2})?[1-4]$', 'c'))`? Because in this case, Oracle SQL Developer still doesn't budge. But I understand the logic. :(( – Andes Lam Oct 30 '20 at 10:31