Multiple Column Constraint Issue - sql

I'm trying to write a constraint that says that per ID, there can only be one row with value X.
That might not make much sense so let me give you an example:
Let's say that I have 3 rows and two columns in a table, each row has the same ID (column 1), but the second column has varying values, two of which are identical and the third is unique. How do I ensure that the unique value stays unique?
Here is the constraint I've been using:
ADD CONSTRAINT myConstraint UNIQUE (col1, col2);
I thought that I can make col2 NULL and have duplicates, and then have a NOT NULL when I was it to be unique (as I only care about a single value being unique). The reason this doesn't work is that for some reason my constraint is not allowing duplicate NULLS, almost like it knows how to compare NULLs...
Ideally I'd like to say
ADD CONSTRAINT myConstraint UNIQUE (col1, col2 = 'REQUESTED');
but something like that doesn't exist.
I've looked into CHECK constraints but I'm not sure how to tell it to do this using a check constraint.
Basically I want to take the incoming ID and make sure that there's no other identical ID that has a column2 value of REQUESTED.
Sorry if this doesn't make a lot of sense, I'm doing my best to explain this.

You can use filtered indexes: http://msdn.microsoft.com/en-us/library/cc280372(v=sql.100).aspx
CREATE UNIQUE NONCLUSTERED INDEX [test_idx] ON [dbo].[test] ([col1], [col2])
WHERE ([col2] IS NOT NULL)
It's unique index, so it will not allow you to insert duplicate col2 values for a given ID(col1) and serve as the constraint you want. In your case, you can also use col2 = 'REQUESTED' filter.

Related

Sql combine value of two columns as primary key

I have a SQL server table on which I insert account wise data. Same account number should not be repeated on the same day but can be repeated if the date changes.
The customer retrieves the data based on the date and account number.
In short the date + account number is unique and should not be duplicate.
As both are different fields should I concatenate both and create a third field as primary key or there is option of having a primary key on the merge value.
Please guide with the optimum way.
You can create a composite primary key. When you create the table, you can do this sort of thing in SQL Server;
CREATE TABLE TableName (
Field1 varchar(20),
Field2 INT,
PRIMARY KEY (Field1, Field2))
Take a look at this question which helps with each flavour of SQL
How can I define a composite primary key in SQL?
PLEASE HAVE A LOOK, IT WILL CLEAR MOST OF THE DOUBTS !
We can state 2 or more columns combined as a primary key.
In that case every column included in primary key will be called : Composite Key
And mind you Composite keys can never be null !!
Now, first let me show you how to make 2 or more columns as primary key.
create table table_name ( col1 type, col2 type, primary key(col1, col2));
The benefit is :
col1 has value (X) and col2 has value (Y) then no other row can have col1 as (X) and col2 as (Y).
col1, col2 must have some values, they can't be null !!
HOPE THIS HELPS !
Not at all. Just use a primary key constraint:
alter table t add constraint pk_accountnumber_date primary key (accountnumber, date)
You can also include this in the create table statement.
I might suggest, however, that you use an auto-incrementing/identity/serial primary key -- a unique number for each row. Then declare the account number/date combination as a unique key. I prefer such synthetic primary keys for several reasons:
They make it easy to refer to a row in foreign key relationships.
They show the insert order into the table, so you can readily see the last inserted rows.
They make it simple to identify a single row for updates and deletes.
They hide the "id" information of the row from referring tables and applications.
The alternative is to have a PK which is an autoincrementing number and then put a unique unique index on the natural key. In this way uniqueness is preserved but you have the fastest possible joining to any child tables. If the table will not ever have child tables, the composite PK is a good idea. If there will be many child tables, this is could be a better choice.

Swapping two rows in a table with unique, not null constraint

I have a table with column position, which has unique and not null constraint.
I have move up/down the selected table item requirement,
for that I am taking the selected index and swapping the indexes.
And saving those two items as in DB.
whenever I am trying to insert first item itself its giving UNIQUE constraint..
Because the item's index is already there in DB.
There is a possibility that I can take temporary index, swapping... and saving .. I think it works.
But is there any other way to achieve this requirement
If you do the update in one Update statement, it'll work fine.
create table t (id number primary key);
insert into t values (1);
insert into t values (2);
commit;
update t set id = case when id = 1 then 2 else 1 end
where id in (1,2);
The easiest way would be to use a temporary value like you say because the constraint will not let you have two rows with the same value at any time.
You can probably derive a temporary value that is in itself unique by basing it on the original value and looking at what kind of data you cannot normally have. For example, negative numbers might work.
Other than that, you could declare the constraint as deferred. Then it won't be enforced until the end of your transaction. But that is probably a bit too much effort/impact.
If the field in question is really only used for sorting (and not for object identity), you could consider dropping the uniqueness altogether. You can use a unique primary key as a tie-breaker if necessary.

How to force duplicate key insert mssql

I know this sounds crazy (And if I designed the database I would have done it differently) but I actually want to force a duplicate key on an insert. I'm working with a database that was designed to have columns as 'not null' pk's that have the same value in them for every row. The records keeping software I'm working with is somehow able to insert dups into these columns for every one of its records. I need to copy data from a column in another table into one column on this one. Normally I just would try to insert into that column only, but the pk's are set to 'not null' so I have to put something in them, and the way the table is set up that something has to be the same thing for every record. This should be impossible but the company that made the records keeping software made it work some how. I was wondering if anyone knows how this could be done?
P.S. I know this is normally not a good idea at all. So please just include suggestions for how this could be done regardless of how crazy it is. Thank you.
A SQL Server primary key has to be unique and NOT NULL. So, the column you're seeing duplicate data in cannot be the primary key on it's own. As urlreader suggests, it must be part of a composite primary key with one or more other columns.
How to tell what columns make up the primary key on a table: In Enterprise Manager, expand the table and then expand Columns. The primary key columns will have a "key" symbol next to them. You'll also see "PK" in the column description after, like this:
MyFirstIDColumn (PK, int, not null)
MySecondIDColumn (PK, int, not null)
Once you know which columns make up the primary key, simply ensure that you are inserting a combination of unique data into the columns. So, for my sample table above, that would be:
INSERT INTO MyTable (MyFirstIDColumn, MySecondIDColumn) VALUES (1,1) --SUCCEED
INSERT INTO MyTable (MyFirstIDColumn, MySecondIDColumn) VALUES (1,2) --SUCCEED
INSERT INTO MyTable (MyFirstIDColumn, MySecondIDColumn) VALUES (1,1) --FAIL because of duplicate (1,1)
INSERT INTO MyTable (MyFirstIDColumn, MySecondIDColumn) VALUES (1,3) --SUCCEED
More on primary keys:
http://msdn.microsoft.com/en-us/library/ms191236%28v=sql.105%29.aspx

Uniqueidentifier Philosophy in my scneario

i have a three column table which none of the columns are unique. so I added an Id column to my table as uniqueidentifier and made it primary. Just One Quesion: If two rows with the same values in those columns will be added to the table, what happens to the second one? will it be added or not? How Can I avoid such things in my scenario?
If your three non-ID columns do not have a unique constraint, and are not part of the Primary Key, you can add multiple rows with the exact same values.
If you want to avoid duplicate rows, your best bet would be to apply a unique constraint on at least one or more of the three columns. If you can't do that for some reason, you should post your schema and where you think the problem is to get some more help with it.
If you can't use a unique constraint, one way to avoid duplicates would be: when you're going to insert a record, first check to see if the record already exists, and if it already exists, decide how you want to handle it.
If your goal is to enforce uniqueness across the three columns then you basically have a choice of two structures:
Create Table tbl_1
(
ColA int
,ColB varchar(32)
,ColC varchar(256)
,Primary Key (ColA, ColB, ColC)
)
GO
OR
Create Table tbl_2
(
ID int identity(1,1) Primary Key
,ColA int
,ColB varchar(32)
,ColC varchar(256)
,Unique (ColA, ColB, ColC)
)
GO
There are advantages to either technique, which is better depends on the nature of the data and your interactions with it. However in both structures the values in any given column can repeat but the combination of the three must be unique for each row.
On the other hand if you are just trying to set a PK on data which may or may not be unique then you can use structure 2 but without the unique constraint. In which case each row is uniquely identified by the ID column but the values of the other columns can repeat freely.
The second one will be added. You can avoid it by creating a unique constraint.

Field value must be unique unless it is NULL

I'm using SQL Server 2005.
I have a field that must either contain a unique value or a NULL value. I think I should be enforcing this with either a CHECK CONSTRAINT or a TRIGGER for INSERT, UPDATE.
Is there an advantage to using a constraint here over a trigger (or vice-versa)? What might such a constraint/trigger look like?
Or is there another, more appropriate option that I haven't considered?
I create a view with the an index that ignores the nulls through the where clause...i.e. if you insert null into the table the view doesn't care but if you insert a non null value the view will enforce the constraint.
create view dbo.UniqueAssetTag with schemabinding
as
select asset_tag
from dbo.equipment
where asset_tag is not null
GO
create unique clustered index ix_UniqueAssetTag
on UniqueAssetTag(asset_tag)
GO
So now my equipment table has an asset_tag column that allows multiple nulls but only unique non null values.
Note:
If using mssql 2000, you'll need to "SET ARITHABORT ON" right before any insert, update or delete is performed on the table. Pretty sure this is not required on mssql 2005 and up.
Here is an alternative way to do it with a constraint. In order to enforce this constraint you'll need a function that counts the number of occurrences of the field value. In your constraint, simply make sure this maximum is 1.
Constraint:
field is null or dbo.fn_count_maximum_of_field(field) < 2
EDIT I can't remember right now -- and can't check it either -- whether the constraint check is done before the insert/update or after. I think after with the insert/update being rolled back on failure. If it turns out I'm wrong, the 2 above should be a 1.
Table function returns an int and uses the following select to derive it
declare #retVal int
select #retVal = max(occurrences)
from (
select field, count(*) as occurrences
from dbo.tbl
where field = #field
group by field
) tmp
This should be reasonably fast if your column as a (non-unique) index on it.
You can accomplish this by creating a computed column and put the unique index on that column.
ALTER TABLE MYTABLE
ADD COL2 AS (CASE WHEN COL1 IS NULL THEN CAST(ID AS NVARCHAR(255)) ELSE COL1 END)
CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2)
This is assuming that ID is the PK of your table and COL1 is the "unique or null" column.
The computed column (COL2) will use the PK's value if your "unique" column is null.
There is still the possibility of collisions between the ID column and COL1 in the following example:
ID COL1 COL2
1 [NULL] 1
2 1 1
To get around this I usually create another computed column which stores whether the value in COL2 comes from the ID column or the COL1 column:
ALTER TABLE MYTABLE
ADD COL3 AS (CASE WHEN COL1 IS NULL THEN 1 ELSE 0 END)
The index should be changed to:
CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2, COL3)
Now the index is on both computed columns COL2 and COL3 so there is no issue:
ID COL1 COL2 COL3
1 [NULL] 1 1
2 1 1 0
In Oracle, a unique key will permit multiple NULLs.
In SQL Server 2005, a good approach is to do your inserts through a view, and disable direct inserts into the table.
Here is some sample code.
Is there a primary key on this table, maybe an Identity column? You could create a unique key that is a composite of the field you are enforcing uniqueness on in combination with the primary key.
There is a discussion about just this kind of issue here: http://blog.sqlauthority.com/2008/09/07/sql-server-explanation-about-usage-of-unique-index-and-unique-constraint/
FYI - SQL Server 2008 introduces filtered indexes which would allow you to approach this a bit differently.
Usually a trigger will allow you to provide a more verbose and explanatory message than a check constraint, so I have used those to avoid the "which column was bad" game in debugging.
A constraint is far lighter than a trigger, even though a unique constraint is effectively an index.
However, you are only allowed one NULL in a unique constraint/index.
So, you'll have to use a trigger to detect duplicates.
It's been requested from MS to ignore NULLS, but SQL 2008 has filtered indexes (as mentioned while I type this)