Setting column constraint on a table (SQL Server) - sql

I have a column that should contain one of values of 2 power n: 2,4,8,16,32 etc. I want to enforce that on table schema level - is there a way to specify such a column constraint?
Thanks!

Shamelessly stealing from this answer you could use bitwise operations to do this pretty efficiently.
ALTER TABLE tablename ADD CONSTRAINT
ckname CHECK (colName > 0 AND (colName & (colName - 1) =0))

In SQL Server:
ALTER TABLE [dbo].[PowerOfTwo]
WITH CHECK ADD CONSTRAINT [CK_PowerOfTwo]
CHECK ((log([Value])/log(2)=round(log([Value])/log(2), 0, 1)))

how about defining the column to be N. then all uses of that column would be 2^n by definition instead of constraint.
otherwise - you could put trigger logic in place to validate each value as it is entered or updated.

Assume your column name is N. Try something like
CHECK(LOG(N)/LOG(2) = TRUNC(LOG(N)/LOG(2)))
The intent is to verify that the binary logarithm of the value N is an integer, which would mean that N was a power of 2. Not sure if SQL Server supports the LOG and TRUNC functions - substitute in the correct names as needed.
Edit: as I re-read this I realized that rounding might cause a problem (I forgot the Second Commandment of Floating Point, which is: Thou Shalt Never Compare Floating Point Values For Equality!). OK, how about
CHECK(ABS(LOG(N)/LOG(2) - TRUNC(LOG(N)/LOG(2))) < 0.00001)
or substitute whatever error tolerance you'd like for the 0.00001.
Share and enjoy.

Create a column check:
CHECK (column_name IN (2, 4, 8, 16, 32, ..., 2147483648))

Related

Oracle SQL Developer Postal Code

I am having a problem with a check constraint in Oracle SQL Developer with Oracle 11g Express Edition.
I want to check if my postal code which is stored as CHAR just contains numbers and no other signs.
Tried various possibilities but nothing worked...
PLZ VARCHAR(5) NOT NULL
ADD CONSTRAINT TC_PLZ CHECK (PLZ LIKE '[0-9][0-9][0-9][0-9][0-9]')
Thanks and best regards,
Michael
Use regexp_like():
ADD CONSTRAINT TC_PLZ CHECK ( regexp_like(PLZ, '^[0-9]{5}$') )
Oracle -- like most databases -- only supports the ANSI standard wildcards in LIKE. These are % for zero or more characters and _ for exactly one character.
Regular expressions are much more powerful (although generally slower).
This might be a bit more efficient:
ADD CONSTRAINT TC_PLZ CHECK (translate(PLZ, '0123456789', '000000000') = '00000')
although I would go with the regular expression for clarity.
If you want to use regular expression patterns you need to use a regex function in the CHECK constraint. This will work:
create table t23 (
PLZ VARCHAR(5) NOT NULL
, CONSTRAINT TC_PLZ CHECK (regexp_LIKE(plz, '^[0-9]{5}$'))
);
Although there's no need for regex; here's an alternative implementation:
create table t42 (
PLZ NUMBER(5,0) NOT NULL
, CONSTRAINT T42_PLZ CHECK (length(plz)=5)
);
It's good practice to store numeric values using the correct datatype.
Check out this LiveSQL demo.
As #MT0 points out, the numeric implementation is not correct if a valid value can start with a leading zero. My purist data modeller persona states that values which must be a fixed number of digits should start at 10000 (for five digit values). However, I must admit I know of one system that did permit leading zeroes in a "numeric" field; they compounded this by allowing variable level values, which meant code 0300 identified something different from 00300. What larks!

SQL- limit number of words in a varchar field

I'm creating a database, and I would like to limit one of the table's fields to contain no more than 50 words but I'm not sure what is the way to create this constraint....?
You can add a CHECK constraint to your column. The question is, how do you define 'a word'?
In a rather simplistic approach we could assume that words are 'split' by spaces. In MSSQL you'd then have to add a check like this:
ALTER TABLE [myTable] ADD CONSTRAINT [chk_max_words] CHECK (Len(Replace([myField], N' ', N'')) > (Len([myField]) - 3))
When you try to insert or update a record and put the [myField] to 'test' it would pass, but if you set it to 'test test test test' it will fail because the number of spaces is 3 and our check will not let that pass.
Off course this approach is far from perfect. It does not consider double spaces, trailing spaces, etc...
From a practical point of view you probably want to write a function that counts the number of words according to your (elaborate) rules and then use that in the check.
ALTER TABLE [myTable] ADD CONSTRAINT [chk_max_words] CHECK (dbo.fn_number_of_words([myField] <= 3)

Can I force SQL Server to use a 2 digit int as primary key?

I am working on a question bank and each question will have a numerical serial number. My idea was to use each table's primary key and simply compound them into a new column in a view as required. But obviously, SQL Server will automatically start numbering int's at 1. I would like them to instead be 01, 02, 03...09, 10.
Is this even possible? Or is there another way to accomplish what I am trying to do? I am using SQL Server 2014 Standard. Thanks!
This sounds like a presentation issue. I would suggest adding a computed column to zero pad. Here is one way:
alter table add questionid as (right(cast(10000 + id as varchar(255)), 2))
Then you can have an identity id and a zero padded version for output purposes.
No, that is not possible. What you could do is create a Sql View that returns the id formatted as a varchar(2) and append a 0 to the id if it is less than 10. Alternatively you can use a varchar(2) as the primary identifier but you would have to manually create the id at creation time.

CHECK CONSTRAINT of string to contain only digits. (Oracle SQL)

I have a column, say PROD_NUM that contains a 'number' that is left padded with zeros. For example 001004569. They are all nine characters long.
I do not use a numeric type because the normal operation on numbers do not make sense on these "numbers" (For example PROD_NUM * 2 does not make any sense.) And since they are all the same length, the column is defined as a CHAR(9)
CREATE TABLE PRODUCT (
PROD_NUM CHAR(9) NOT NULL
-- ETC.
)
I would like to constrain PROD_NUM so it can only contain nine digits. No spaces, no other characters besides '0' through '9'
REGEXP_LIKE(PROD_NUM, '^[[:digit:]]{9}$')
You already received some nice answers on how to continue on your current path. Please allow me to suggest a different path: use a number(9,0) datatype instead.
Reasons:
You don't need an additional check constraint to confirm it contains a real number.
You are not fooling the optimizer. For example, how many prod_num's are "BETWEEN '000000009' and '000000010'"? Lots of character strings fit in there. Whereas "prod_num between 9 and 10" obviously selects only two numbers. Cardinalities will be better, leading to better execution plans.
You are not fooling future colleagues who have to maintain your code. Naming it "prod_num" will have them automatically assume it contains a number.
Your application can use lpad(to_char(prod_num),9,'0'), preferably exposed in a view.
Regards,
Rob.
(update by MH) The comment thread has a discussion which nicely illustrates the various things to consider about this approach. If this topic is interesting you should read them.
Works in all versions:
TRANSLATE(PROD_NUM,'123456789','000000000') = '000000000'
I think Codebender's regexp will work fine but I suspect it is a bit slow.
You can do (untested)
replace(translate(prod_num,'0123456789','NNNNNNNNNN'),'N',null) is null
Cast it to integer, cast it back to varchar, and check that it equals the original string?
In MSSQL, I might use something like this as the constraint test:
PROD_NUM NOT LIKE '%[^0-9]%'
I'm not an Oracle person, but I don't think they support bracketed character lists.
in MS SQL server I use this command:
alter table add constraint [cc_mytable_myfield] check (cast(myfield as bigint) > 0)
Not sure about performance but if you know the range, the following will work.
Uses a CHECK constraint at the time of creating the DDL.
alter table test add jz2 varchar2(4)
check ( jz2 between 1 and 2000000 );
as will
alter table test add jz2 varchar2(4)
check ( jz2 in (1,2,3) );
this will also work
alter table test add jz2 varchar2(4)
check ( jz2 > 0 );

Script SQL constraint for a number to fall within a Range?

How to script a constraint on a field in a table, for an acceptable range of values is between 0 and 100?
ALTER TABLE Table
ADD CONSTRAINT CK_Table_Column_Range CHECK (
Column >= 0 AND Column <= 100 --Inclusive
)
Try:
ALTER TABLE myTableName
ADD CONSTRAINT myTableName_myColumnName_valZeroToOneHundred
CHECK (myColumnName BETWEEN 0 AND 100)
This check would be inclusive - here is some info about BETWEEN from MSDN:
BETWEEN (Transact SQL)
A check constraint like "fieldname BETWEEN 0 AND 100" should do it.
According to me, the right question isn't "how" but "why".
This 0-100 rule sounds to me like a business rule. Why should it be implemented on the server/database side? If an incorrect value is entered, who will get the error message?
If the user gets the error message, wouldn't it be easier to have the code giving him the message before the transaction reaches the server?
What about range modification? May the rule change? I guess yes: rules ALLWAYS change. Can the range be updated from 0-100 to 101-200? In this case, what about values already entered in the database?