0

I am trying to get below constraint work in postgresql which checks the column wcode for the pattern. If the pattern doesn't match should throw an error.

CONSTRAINT wcoding CHECK (wcode::text ~ '[\w]{4,4}-[\w]{2,2}-[\w]{1,1}'::text);

Geniun input string is "AA14-AM-1". which actually works. but the problem is if I enter "AA14-AM-14" or "AA14-AM-1444" it doesn't through an error. I want to restrict input to use this ("AA14-AM-1") pattern.

4
  • FYI added a second method in my answer with the word boundary syntax specific to PostGreSQL. Commented Apr 24, 2014 at 6:55
  • @zx81: a bit nitpicking: it's Postgres or PostgreSQL, but not PostGreSQL Commented Apr 24, 2014 at 6:56
  • @a_horse_with_no_name Thanks for the correction! I love propar speling. :) Commented Apr 24, 2014 at 6:59
  • 1
    Note that {4,4} is redundant, it should be {4}. Also [\w] should be simply \w - for better reading your regex. + Also neither {1,1}, nor {1} is necessary. Commented Apr 24, 2014 at 8:06

3 Answers 3

2

You have an "unbounded" regex (not sure if that is the correct technical term). Which essentially means the pattern has to occur anywhere inside the input string. To match the input string with the exact pattern, you need an "anchored" regex:

CONSTRAINT wcoding CHECK (wcode::text ~ '^[\w]{4,4}-[\w]{2,2}-[\w]{1,1}$');

The ^ and $ "anchor" the pattern at start and ending which results in the fact that the input string must match the pattern exactly (not permitting the pattern as a sub-string of a longer input value).

Sign up to request clarification or add additional context in comments.

3 Comments

I think you need to find a different way to rephrase that last sentence, but I generally agree with the answer. After all, you're not saying that the input string could be AA14-AM-1hello world!AA14-AM-1 which would be an input string that start and end with this pattern.
@Damien_The_Unbeliever: is that better? (If you can phrase it better feel free to edit my answer ;) )
@a_horse_with_no_name thank you. It did work for me. I will consider using ^ and $ in future requirement. as I am new to regex, I am facing little problem understanding it. Thanks again.
2

@a_horse clarifies the role of ^ and $. But simplify overall:

ALTER TABLE ADD CONSTRAINT wcoding
CHECK (wcode::text ~ '^\w{4}-\w\w-\w$');

You don't need a character class for class shorthands like \w.
And why is there a cast to text? Might be redundant.

SQL Fiddle.

2 Comments

Thanks. I made this constraint using many examples. As most of examples I saw used text so I went with it. I am going to change it to varchar.
@MalavShah: text is just fine. I think you don't need to cast at all (depending on the actual data type of the column).
1

Malav, in PostgreSQL, this compact regex does what you want:

First Method

[\w]{4}-[\w]{2}-\w(?!=\w)

Second Method

[\w]{4}-[\w]{2}-\w\y

Please note that instead of {4,4} you can write {4} to mean "exactly four times".

How does this work?

After the last word character, we check that there is no other word character. For this, in the first method, we use a negative lookahead (?=\w)

In the second method, we use a word boundary \y (In most regex flavors I would add a word boundary \b at the end, but in PostgreSQL it is \y )

This is why in the first version I used a negative lookahead instead (more portable). Use whichever version you like.

2 Comments

Thanks for your answer. I found somewhere on google the use of \b and tried it. now I know why it didn't work. Thanks again.
@MalavShah Thanks for your feedback. In my view {4,4} is ugly syntax, I don't know anyone who uses that in real code, please see {4} in my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.