Agregar clave única para columnas anulables - SQL Server
Frecuentes
Visto 2,648 equipos
2
I'm using sql server 2008 R2 and would like to apply unique key constraint to nullable columns. This code works good, but if I have multiple columns to add this rule to, it would generate as many 'nullbuster' columns.
ALTER TABLE tblBranch
ADD nullbuster AS (CASE WHEN column1 IS NULL THEN BranchID ELSE NULL END);
CREATE UNIQUE INDEX UK_Column1 ON tblBranch(column1,nullbuster);
Is there any way that I could achieve the goal without generating new columns.
EDIT:
Followed @marc_s suggestion, here to create an unique key constraint. The target column is BranchCode. Now, there is one record in the table that has NULL for BranchCode. When I try to insert a new record, with Null BranchCode, from c#, it gives an error saying - Cannot insert duplicate key for unique index UK_BranchCode. But, when I manually insert a record in the database, it does accept null values. Where am I going wrong.
CS
Guid gId = Guid.NewGuid();
cmd = new sqlcommand("insert into tblBranch(BranchId,BranchCode)
values(@BranchId,@BranchCode)",con);
cmd.Parameters.AddWithValue("@BranchId",gId);
cmd.Parameters.AddWithValue("@BranchCode",txtBranchCode.Text);//empty text here
con.Open();
cmd.ExecuteNonQuery();
cmd.Close();
3 Respuestas
3
So you're creating a nullbuster
column for each nullable column you want to index? Seems like overkill....
No seria más fácil to just create índices filtrados for those nullable columns, something like:
CREATE UNIQUE INDEX UK_Column1 ON tblBranch(column1) WHERE column1 IS NOT NULL;
and thus allow any number of NULL
entries, while uniquely indexing the other values. That way, you don't need to add all those nullbuster
columns just to make indexing possible...
Read more about filtered indexes:
- Create Filtered Indexes (on Technet)
- Introduction to Filtered Index – Improve performance with Filtered Index
Actualizar: in order to set a parameter to NULL (and not an empty string), use this code:
if(string.IsNullOrEmpty(txtBranchCode.Text))
{
cmd.Parameters.AddWithValue("@BranchCode", DBNull.Value);
}
else
{
cmd.Parameters.AddWithValue("@BranchCode", txtBranchCode.Text);
}
respondido 04 nov., 13:05
Thank you. If I try to insert values manually in the database table, it accepts multiple null values for that column and also the Unique key constraint works good. But, I'm unable to insert a second null value for the target column through a c# program. It says SQLException. Cannot insert Duplicate values. - Rubí
@Ruby that is not a problem with the index then. Find the bug in your app. - usr
I am unable to find out and updated my question. Someone please help me out - Rubí
THANK YOU MARC. That worked. Could you plz tell me how it would be using objects. The same way didnt work here. tblBranch objBranch = new tblBranch; objBranch.BranchCode = DBNull.value //cant implicity convert.... - Rubí
@Ruby: you can use the DBNull.Value
, solamente when you're dealing with ADO.NET stuff - like calling a stored procedure or something like that. Otherwise in your regular .NET code, just use Null
en lugar de - marc_s
1
Use the filtered index suggestion provided by marc_s. You say that you are still getting a unique index violation. What does that tell you? It tells you you are inserting a duplicate key with regards to the index definition. You think, you aren't, but you definitely are.
How to debug that? You look at what you are inserting. You look at gId
y txtBranchCode.Text
in the debugger. Also, you look at the error message, because it says:
The duplicate key value is ...
All of these clues lead you to find that txtBranchCode.Text
is not null, but an empty string. Insert NULL
preferiblemente.
respondido 03 nov., 13:16
0
I suggest you move column1 to a new table and make it unique and non-nullable. Reference the Branch table using a foreign key in the new table. Populate the new table only where you have a (non-null) value for column1.
Creating a new table is the surest way to support any dependencies on column1. A column that permits nulls is not a clave column but column1 apparently should be. Putting that column into a new table also happens to be the only way to satisfy Normal Form and that ought to be the default approach unless you have a very compelling reason to "denormalise" column1 into the Branch table where it doesn't seem to belong.
respondido 03 nov., 13:21
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c# sql-server-2008-r2 or haz tu propia pregunta.
Bueno el texto vacío is NO lo mismo que
NULL
!! If you want to actually store aNULL
, UtilizarDBNull.Value
(en lugar destring.Empty
) - marc_sI tried cmd.Parameters.AddWithValue("@BranchCode",txtBranchCode.Text.Length > 0 ? txtBranchCode.Text : DBNull.Value.ToString();....It says, Cant insert duplicate key row... - Ruby
Sólo tiene que utilizar
DBNull.Value
- Sin.ToString()
! Maybe you'll need to do the check outside the.AddWithValue()
llamada - marc_sDeclared a string sName, Outside Addwithvalue. When I say sName=DBNull.Value, it says cannot implicitly convert null to string. When I add , ToString(), it errors out at ExecuteNonQuery :( - Ruby
See my updated response - you should NO asignar
DBNull.Value
to a temporary string, of course - see my code snippet, use that. - marc_s