I'm trying to create an Oracle SQL*Plus table, but I'm having trouble with a constraint using regular expressions.
The constraint I'm trying to implement is that the field is 4 characters long and cannot contain the following characters: ,.!£$*<>"=
In reality I would be enough to just only allow alphanumeric characters, so I tried the following regular expression constraint:
CONSTRAINT CHK_Foo CHECK (Foo LIKE '[[:alnum:]]'),
However when I attempted to enter AAAAfield it said I had violated the constraint.
I'm a complete newcomer to Regexp, and a relative newcomer to SQL, so any explanations as to why it doesn't work as well as just an alternative would be immensely appreciated!
Two options:
CHECK (REGEXP_LIKE( foo, '[^,.!£$*<>"=]{4}' ) ) will accept all 4-character strings that do not contain ,.!£$*<>"=
CHECK (REGEXP_LIKE( bar, '[a-zA-Z0-9]{4}' ) ) will accept all 4-character strings that only contain a-zA-Z0-9
(If you want less than strings which are less than or equal to 4 characters in length then you can replace {4} with {0,4})
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE test (
foo CHAR(4) NOT NULL,
bar CHAR(4) NOT NULL,
CONSTRAINT chk_foo CHECK (REGEXP_LIKE( foo, '[^,.!£$*<>"=]{4}' ) ),
CONSTRAINT chk_bar CHECK (REGEXP_LIKE( bar, '[a-zA-Z0-9]{4}' ) )
);
Query 1:
INSERT INTO test VALUES ( 'AAAA', '"AAA' );
Result 1:
ORA-02290: check constraint (USER_4_850C2.CHK_BAR) violated : INSERT INTO test VALUES ( 'AAAA', '"AAA' )
Query 2:
INSERT INTO test VALUES ( '$AAA', 'AAAA' );
Result 2:
ORA-02290: check constraint (USER_4_850C2.CHK_FOO) violated : INSERT INTO test VALUES ( '$AAA', 'AAAA' )
Query 3:
INSERT INTO test VALUES ( 'AAAA', 'AAAA' )
Result 3:
CONSTRAINT CHK_Foo CHECK (regexp_LIKE(Foo, '^\w{4}$'))
You should construct a correct Oracle regexp and then use REGEXP_LIKE and not just LIKE.
See here:
http://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_regexp.htm
http://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_regexp.htm#CHDIDJJC
Related
How can I add a not null constraint to a table with 'or' operator? I want either the personal OR work phone number to be present for each entry.
I am trying this:
ALTER TABLE user_data MODIFY ( personal_number NOT NULL || work_number NOT NULL);
but get this error:
ORA-00907: missing right parenthesis
You need a check constraint that checks each column:
ALTER TABLE user_data
ADD CONSTRAINT check_numbers
CHECK ( personal_number IS NOT NULL AND work_number IS NULL ) OR
( personal_number IS NULL AND work_number IS NOT NULL )
)
Note this disallows having both present though. Which may or may not be your business rule. But I think you have enough now to tweak that if you need to.
To check that at least one of personal and work number is present, you can use the OR operator in a CHECK constraint:
ALTER TABLE user_data
ADD CONSTRAINT personal_or_work_number_required__chk
CHECK ( personal_number IS NOT NULL OR work_number IS NOT NULL);
fiddle
Note: The || operator is for string concatenation and is not the logical OR operator.
In the script file, I inserted the following code.
drop table Test;
create table Test(
name char(2) unique not null,
constraint name_c check(
regexp_like(name, '^[A-Z]{1,2}$', 'c')
)
);
insert into Test values ('B');
The developer never budge. It keeps on saying violating the name_c constraint and I don't understand why. The regular expression looks fine for me.
Some variants, however, succeeded, for example, dropping the dollar sign
drop table Test;
create table Test(
name char(2) unique not null,
constraint name_c check(
regexp_like(name, '^[A-Z]{1,2}', 'c')
)
);
insert into Test values ('B');
And I don't understand either.
Why?
Edit: This is the problem: logically the regex is right. But somehow Oracle SQL Developer doesn't budge.
if you went it to start with 1 or 2 capital letter and doesn't matter what coming next you should do it like this :
^[A-Z]{1,2}.*
.* mean 1 or more character exept \n (nex line)
What is the logic when I want to validate one mobile number field i.e mobile no should be numeric,10 digits as well as not start from 0,1,2,3,4,5.??
I am using SQL Developer.
Thanks
Well, you can use constraints. In your case, you want that the field is 10 digits and that it does not start with 0,1,2,3,4,5.
For complex formats is better to use regular expressions, but in your requirement is not needed.
SQL> create table t ( mobile number(10) ) ;
Table created.
SQL> alter table t add constraint chk_mob_phn check ( SUBSTR(TO_CHAR(mobile),1,1) not in ( 0,1,2,3,4,5) ) ;
Table altered.
SQL> alter table t add constraint chk_mob_len check ( length(mobile) = 10 ) ;
Table altered.
SQL> insert into t values ( 0298338383 ) ;
insert into t values ( 0298338383 )
*
ERROR at line 1:
ORA-02290: check constraint (SYS.CHK_MOB_PHN) violated
SQL> insert into t values ( 99999 ) ;
insert into t values ( 99999 )
*
ERROR at line 1:
ORA-02290: check constraint (SYS.CHK_MOB_LEN) violated
SQL> insert into t values ( 6987838322 ) ;
1 row created.
I strongly dissuade you from storing the mobile number as a number. Although you don't want leading zeros, that might change in the future. Plus, the value is not really a number -- arithmetic is not defined on it.
So:
create table t (
mobile_number varchar2(10),
check (regexp_like(mobile_number, '^[6-9][0-9]{9}$')
)
How to add an unique constraint (ignoring special characters) on text column in Postgres?
CREATE TABLE my_table(
SomeTextColumn citext
CONSTRAINT person_u_1 UNIQUE (SomeTextColumn)
);
In the above table, I'm trying to add an unique constraint that will look for uniqueness by ignoring special characters in the incoming data
For example:
1. HelloWorld --> Gets inserted successfully
2. Hello World --> Should fail with duplicate constraint
2. Hello%$^&*W^%orld --> Should fail with duplicate constraint
You can create a unique index that implements the check:
create unique index t_txt_unique on t(regexp_replace(txt, '\W', '', 'g'));
The regexp removes all non-word characters from the string, retaining only alphanumeric characters and the undescore _. You can adjust the character class to as needed.
Demo on DB Fiddle:
create table t (id int, txt citext);
create unique index t_txt_unique on t(regexp_replace(txt, '\W', '', 'g'));
insert into t values(1, 'HelloWorld');
-- ok
insert into t values(1, 'Hello World');
-- ERROR: duplicate key value violates unique constraint "t_txt_unique"
-- DETAIL: Key (regexp_replace(txt, '\W'::text, ''::text, 'g'::text))=(HelloWorld) already exists.
insert into t values(1, 'Hello%$^&*W^%orld');
-- ERROR: duplicate key value violates unique constraint "t_txt_unique"
-- DETAIL: Key (regexp_replace(txt, '\W'::text, ''::text, 'g'::text))=(HelloWorld) already exists.
insert into t values(1, 'Hello Mars');
-- ok
The question is older but I think some additional notes might be useful...
Uniqueness on TEXT is always problematic because text is case-sensitive (not only in PostgreSQL).
You can get duplicates because "HelloWorld" is not the same as "HELLOWORLD". Because of that you might want to add the UPPER function if you create a UNIQUE INDEX on text fields of a database:
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(txt), '\W', '', 'g'));
You might want to use the following REGEXP_REPLACE option to only keep the characters 0-9 and A-Z (removing umlauts):
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(txt), '[^0-9A-Z]', '\1', 'g'));
If you want to preserve umlauts as general character (Ü --> U, Ä --> A, etc.) you could throw in the UNACCENT function (https://www.postgresql.org/docs/current/unaccent.html - it's an extension you need to add to PostgreSQL but I might also help you to search for something - keep in mind that only the superuser or other admin user might be able/allowed to add EXTENSIONs):
CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA public;
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(UNACCENT(txt)), '[^0-9A-Z]', '\1', 'g'));
SQL-Code
--
-- Check REGEXP_REPLACE to remove unwanted characters.
-- Test-String: '^°!"§$%&/()=?`+#äöüÜÖÄ',.-_:;#ABµC123abc123'
--
SELECT '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;#ABµC123abc123' AS original_text
,REGEXP_REPLACE( UPPER( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;#ABµC123abc123' ), '\W', '', 'g') AS replace_word
,REGEXP_REPLACE( UPPER( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;#ABµC123abc123' ), '[^0-9A-Z]', '\1', 'g') AS replace_upper_keep_num_a_to_z
,REGEXP_REPLACE( UPPER(UNACCENT( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;#ABµC123abc123' )), '[^0-9A-Z]', '\1', 'g') AS replace_keep_num_a_to_z_umlaut
;
Result of the above SQL code as HTML table
It was to complicated for the markdown table in the final result (preview was working).
<table border="1"><tr BGCOLOR="#CCCCFF"><th>original_text</th><th>replace_word</th><th>replace_upper_keep_num_a_to_z</th><th>replace_keep_num_a_to_z_umlaut</th></tr>
<tr><td>^°!"§$%&/()=?`+#äöüÜÖÄ',.-_:;#<>ABµC123abc123</td><td>ÄÖÜÜÖÄ_AB?C123ABC123</td><td>ABC123ABC123</td><td>AOUUOAABC123ABC123</td></tr>
</table>
As you might have noticed the character 'µ' has been transformed to upper case 'M' in the second column using the '\W' replacement which is a bit strange.
For a test tomorrow we're told to name our constraints
I know it's possible to create a constraint when you use ALTER TABLE
but can you add a name to a not null constraint when you CREATE TABLE?
f.e.
CREATE TABLE test (
test1 VARCHAR
CONSTRAINT nn_test1 NOT NULL (test1)
)
I get an error when trying to run this query. Am I writing it wrong?
The error I get is
ERROR: syntax error at or near "NOT"
LINE 3: CONSTRAINT nn_test1 NOT NULL (test1))
^
SQL state: 42601
Character: 56
You have two options to define a named not null constraint:
Inline with the column:
CREATE TABLE test
(
test1 VARCHAR CONSTRAINT nn_test1 NOT NULL,
test2 integer --<< no comma because it's the last column
);
Or at the end of columns as an out-of-line constraint. But then you need a check constraint:
CREATE TABLE test
(
test1 VARCHAR,
test2 integer, --<< comma required after the last column
constraint nn_test1 check (test1 is not null)
);
This has become irrelevant, since you're not using SQL Server
First of all, you should always specify a length for a VARCHAR. Not doing so (in SQL Server variables, or parameters) may result in a string of just exactly ONE character in length - typically NOT what you want.
Then, you need to just specify the NOT NULL - there's no need to repeat the column name (actually this is the error) - if you're specifying the CONSTRAINT "inline" with the column definition (which is a perfectly legal and in my opinion the preferred way of doing this).
Try this code:
CREATE TABLE test
(
test1 VARCHAR(50)
CONSTRAINT nn_test1 NOT NULL
)
At least this is the CREATE TABLE statement that works in T-SQL / SQL Server - not sure about PostgreSQL (don't know it well enough, don't have it at hand to test right now).
I, a_horse_with_no_name, the two syntax:
constraint nn_test1 check (test1 is not null)
and
test1 VARCHAR CONSTRAINT nn_test1 NOT NULL
are equivalent ? performance correctly ecc.
Because in first case the SQL server exception return the name nn_test so the system know exactly error.