Controlar valores NullHandling Null Values

Los valores NULL se utilizan en bases de datos relacionales cuando el valor de una columna se desconoce o falta.A null value in a relational database is used when the value in a column is unknown or missing. Un NULL no es ni una cadena vacía (en los tipos de datos de caracteres o de fecha y hora) ni un valor cero (en los tipos de datos numéricos).A null is neither an empty string (for character or datetime data types) nor a zero value (for numeric data types). La especificación ANSI SQL-92 afirma que un NULL debe ser igual en todos los tipos de datos; por lo tanto, todos los NULL se tratan de forma coherente.The ANSI SQL-92 specification states that a null must be the same for all data types, so that all nulls are handled consistently. El espacio de nombres System.Data.SqlTypes proporciona semántica para valores NULL mediante la implementación de la interfaz INullable.The System.Data.SqlTypes namespace provides null semantics by implementing the INullable interface. Cada uno de los tipos de datos de System.Data.SqlTypes tiene su propia propiedad IsNull y un valor Null que se puede asignar a una instancia de ese tipo de datos.Each of the data types in System.Data.SqlTypes has its own IsNull property and a Null value that can be assigned to an instance of that data type.

Nota

En la versión 2.0 de .NET Framework se introduce la compatibilidad con tipos que admiten valores NULL, lo que permite a los programadores ampliar un tipo de valor para representar todos los valores del tipo subyacente.The .NET Framework version 2.0 introduced support for nullable types, which allow programmers to extend a value type to represent all values of the underlying type. Estos tipos CLR que admiten valores NULL representan una instancia de la estructura Nullable.These CLR nullable types represent an instance of the Nullable structure. Esta capacidad es especialmente útil cuando a los tipos de valor se les ha aplicado la conversión boxing o la conversión unboxing, lo que proporciona una compatibilidad mejorada con tipos de objeto.This capability is especially useful when value types are boxed and unboxed, providing enhanced compatibility with object types. Los tipos CLR que admiten valores NULL no están pensados para el almacenamiento de valores NULL de base de datos porque un valor NULL ANSI SQL no se comporta del mismo modo que una referencia null (o Nothing, en Visual Basic).CLR nullable types are not intended for storage of database nulls because an ANSI SQL null does not behave the same way as a null reference (or Nothing in Visual Basic). Para trabajar con valores NULL ANSI SQL de base de datos, utilice valores NULL System.Data.SqlTypes en lugar de Nullable.For working with database ANSI SQL null values, use System.Data.SqlTypes nulls rather than Nullable. Para obtener más información sobre cómo trabajar con tipos CLR que admiten valores NULL en Visual Basic Vea tiposde C# valor que aceptan valores NULL y para ver los tipos de valor que aceptan valores NULL.For more information on working with CLR nullable types in Visual Basic see Nullable Value Types, and for C# see Nullable value types.

Valores NULL y la lógica de tres valoresNulls and Three-Valued Logic

Permitir valores NULL en definiciones de columna introduce la lógica de tres valores en la aplicación.Allowing null values in column definitions introduces three-valued logic into your application. Una comparación puede evaluarse en función de una de tres condiciones:A comparison can evaluate to one of three conditions:

  • TrueTrue

  • FalseFalse

  • DesconocidoUnknown

Como un valor NULL se considera que es desconocido, dos valores NULL comparados entre sí no se consideran iguales.Because null is considered to be unknown, two null values compared to each other are not considered to be equal. En expresiones que utilizan operadores aritméticos, si alguno de los operandos es nulo, el resultado también es nulo.In expressions using arithmetic operators, if any of the operands is null, the result is null as well.

Valores NULL y SqlBooleanNulls and SqlBoolean

La comparación entre cualquier System.Data.SqlTypes devolverá un SqlBoolean.Comparison between any System.Data.SqlTypes will return a SqlBoolean. La función IsNull de cada SqlType devuelve un SqlBoolean y se puede utilizar para comprobar si hay valores NULL.The IsNull function for each SqlType returns a SqlBoolean and can be used to check for null values. En las siguientes tablas de tipo truth se muestra cómo funcionan los operadores AND, OR y NOT en presencia de un valor NULL.The following truth tables show how the AND, OR, and NOT operators function in the presence of a null value. (T=true, F=false y U=unknown, o NULL.)(T=true, F=false, and U=unknown, or null.)

Tabla de verdadTruth Table

Descripción de la opción ANSI_NULLSUnderstanding the ANSI_NULLS Option

System.Data.SqlTypes proporciona la misma semántica que cuando se establece la opción ANSI_NULLS en ON en SQL Server.System.Data.SqlTypes provides the same semantics as when the ANSI_NULLS option is set on in SQL Server. Todos los operadores aritméticos (+,-, *,/,%), los operadores bit a bit (~, &, |) y la mayoría de las funciones devuelven NULL si alguno de los operandos o argumentos es null, salvo el IsNullde propiedad.All arithmetic operators (+, -, *, /, %), bitwise operators (~, &, |), and most functions return null if any of the operands or arguments is null, except for the property IsNull.

El estándar ANSI SQL-92 no admite columnName = null en una cláusula WHERE.The ANSI SQL-92 standard does not support columnName = NULL in a WHERE clause. En SQL Server, la opción ANSI_NULLS controla la posibilidad de aceptar NULL predeterminada en la base de datos y la evaluación de comparaciones con respecto a valores NULL.In SQL Server, the ANSI_NULLS option controls both default nullability in the database and evaluation of comparisons against null values. Si ANSI_NULLS está activado (el valor predeterminado), al comprobar la existencia de valores NULL se debe utilizar el operador IS NULL en las expresiones.If ANSI_NULLS is turned on (the default), the IS NULL operator must be used in expressions when testing for null values. Por ejemplo, la siguiente comparación siempre produce UNKNOWN cuando ANSI_NULLS está activado:For example, the following comparison always yields unknown when ANSI_NULLS is on:

colname > NULL  

La comparación con una variable que contiene un valor NULL también produce UNKNOWN:Comparison to a variable containing a null value also yields unknown:

colname > @MyVariable  

Utilice el predicado IS NULL o IS NOT NULL para comprobar si un valor es NULL.Use the IS NULL or IS NOT NULL predicate to test for a null value. Esto puede agregar complejidad a la cláusula WHERE.This can add complexity to the WHERE clause. Por ejemplo, la columna TerritoryID de la tabla Customer de AdventureWorks permite valores NULL.For example, the TerritoryID column in the AdventureWorks Customer table allows null values. Si se utiliza una instrucción SELECT para comprobar si hay valores NULL además de otros, debe incluir un predicado IS NULL:If a SELECT statement is to test for null values in addition to others, it must include an IS NULL predicate:

SELECT CustomerID, AccountNumber, TerritoryID  
FROM AdventureWorks.Sales.Customer  
WHERE TerritoryID IN (1, 2, 3)  
   OR TerritoryID IS NULL  

Si establece ANSI_NULLS en OFF en SQL Server, puede crear expresiones que utilicen el operador de igualdad para comparar con NULL.If you set ANSI_NULLS off in SQL Server, you can create expressions that use the equality operator to compare to null. Sin embargo, no puede evitar que diferentes conexiones establezcan opciones nulas para esa conexión.However, you can't prevent different connections from setting null options for that connection. El uso de IS NULL para probar si los valores son NULL siempre funciona, con independencia de la configuración de ANSI_NULLS en una conexión.Using IS NULL to test for null values always works, regardless of the ANSI_NULLS settings for a connection.

No se admite el establecimiento de ANSI_NULLS en OFF en un DataSet, ya que siempre sigue el estándar ANSI SQL-92 para el tratamiento de valores NULL en System.Data.SqlTypes.Setting ANSI_NULLS off is not supported in a DataSet, which always follows the ANSI SQL-92 standard for handling null values in System.Data.SqlTypes.

Asignación de valores NULLAssigning Null Values

Los valores NULL son especiales y su semántica de almacenamiento y asignación varía según los diversos sistemas de tipos y sistemas de almacenamiento.Null values are special, and their storage and assignment semantics differ across different type systems and storage systems. Un Dataset se ha diseñado para su uso con diferentes sistemas de tipos y de almacenamiento.A Dataset is designed to be used with different type and storage systems.

En esta sección se describe la semántica de valores NULL para la asignación de dichos valores a una DataColumn de una DataRow entre sistemas de tipos diferentes.This section describes the null semantics for assigning null values to a DataColumn in a DataRow across the different type systems.

DBNull.Value
Esta asignación es válida para una DataColumn de cualquier tipo.This assignment is valid for a DataColumn of any type. Si el tipo implementa INullable, DBNull.Value se convierte en el valor NULL adecuado fuertemente tipado.If the type implements INullable, DBNull.Value is coerced into the appropriate strongly typed Null value.

SqlType.Null
Todos los tipos de datos System.Data.SqlTypes implementan INullable.All System.Data.SqlTypes data types implement INullable. Si el valor NULL fuertemente tipado se puede convertir en el tipo de datos de la columna mediante operadores de conversión implícitos, la asignación debería realizarse.If the strongly typed null value can be converted into the column's data type using implicit cast operators, the assignment should go through. De lo contrario, se produce una excepción de conversión no válida.Otherwise an invalid cast exception is thrown.

null
Si 'null' es un valor válido para el tipo de datos DataColumn dado, se convierte en el DbNull.Value o Null asociado con el tipo INullable (SqlType.Null)If 'null' is a legal value for the given DataColumn data type, it is coerced into the appropriate DbNull.Value or Null associated with the INullable type (SqlType.Null)

derivedUdt.Null
En columnas de tipos definidos por el usuario, los valores NULL se almacenan siempre en el tipo asociado con la DataColumn.For UDT columns, nulls are always stored based on the type associated with the DataColumn. Considere el caso de un tipo definido por el usuario asociado con una DataColumn que no implementa INullable, mientras su subclase sí lo hace.Consider the case of a UDT associated with a DataColumn that does not implement INullable while its sub-class does. En este caso, si se asigna un valor NULL fuertemente tipado asociado a la clase derivada, se almacenará como DbNull.Value sin tipo, porque el almacenamiento de valores NULL es siempre coherente con el tipo de datos de DataColumn.In this case, if a strongly typed null value associated with the derived class is assigned, it is stored as an untyped DbNull.Value, because null storage is always consistent with the DataColumn's data type.

Nota

La estructura Nullable<T> o Nullable no se admite actualmente en DataSet.The Nullable<T> or Nullable structure is not currently supported in the DataSet.

Asignación de varias columnas (filas)Multiple Column (Row) Assignment

DataTable.Add, DataTable.LoadDataRow u otras API que aceptan ItemArray que se asigna a una fila, asignan 'null' al valor predeterminado de DataColumn.DataTable.Add, DataTable.LoadDataRow, or other APIs that accept an ItemArray that gets mapped to a row, map 'null' to the DataColumn's default value. Si un objeto de la matriz contiene DbNull.Value o su equivalente fuertemente tipado, se aplican las mismas reglas que se han descrito anteriormente.If an object in the array contains DbNull.Value or its strongly typed counterpart, the same rules as described above are applied.

Además, las siguientes reglas se aplican para una instancia de asignaciones de NULL de DataRow.["columnName"]:In addition, the following rules apply for an instance of DataRow.["columnName"] null assignments:

  1. El valor predeterminado predeterminado es DbNull.Value para todas las columnas, excepto las nulas con establecimiento inflexible de tipos, donde es el valor null fuertemente tipado adecuado.The default default value is DbNull.Value for all except the strongly typed null columns where it is the appropriate strongly typed null value.

  2. Los valores NULL nunca se escriben durante la serialización a archivos XML (como en "xsi:nil").Null values are never written out during serialization to XML files (as in "xsi:nil").

  3. Todos los valores que no son NULL, incluidos los predeterminados, siempre se escriben durante la serialización a XML.All non-null values, including defaults, are always written out while serializing to XML. Esto no es característico de la semántica de XSD/XML en la que un valor NULL (xsi:nil) es explícito y el valor predeterminado es implícito (si no está presente en XML, un analizador de validación puede obtenerlo de un esquema XSD asociado).This is unlike XSD/XML semantics where a null value (xsi:nil) is explicit and the default value is implicit (if not present in XML, a validating parser can get it from an associated XSD schema). Lo contrario se cumple para DataTable: un valor NULL es implícito y el valor predeterminado es explícito.The opposite is true for a DataTable: a null value is implicit and the default value is explicit.

  4. A todos los valores de columna que faltan en las filas leídas de la información XML introducida se les asigna NULL.All missing column values for rows read from XML input are assigned NULL. A las filas creadas mediante NewRow o métodos similares se les asigna el valor predeterminado de DataColumn.Rows created using NewRow or similar methods are assigned the DataColumn's default value.

  5. El método IsNull devuelve true para DbNull.Value y INullable.Null.The IsNull method returns true for both DbNull.Value and INullable.Null.

Asignación de valores NULLAssigning Null Values

El valor predeterminado de cualquier instancia de System.Data.SqlTypes es NULL.The default value for any System.Data.SqlTypes instance is null.

Los valores NULL de System.Data.SqlTypes son específicos del tipo y no se pueden representar con un único valor, como DbNull.Nulls in System.Data.SqlTypes are type-specific and cannot be represented by a single value, such as DbNull. Utilice la propiedad IsNull para comprobar si hay valores NULL.Use the IsNull property to check for nulls.

Es posible asignar valores NULL a una DataColumn, como se muestra en el siguiente código de ejemplo.Null values can be assigned to a DataColumn as shown in the following code example. Puede asignar directamente valores NULL a variables SqlTypes sin desencadenar una excepción.You can directly assign null values to SqlTypes variables without triggering an exception.

EjemploExample

El siguiente código de ejemplo crea una DataTable con dos columnas definidas como SqlInt32 y SqlString.The following code example creates a DataTable with two columns defined as SqlInt32 and SqlString. El código agrega una fila de valores conocidos, una fila de valores NULL y, luego, establece una iteración en la DataTable, de modo que los valores se asignan a variables y el resultado se muestra en la ventana de la consola.The code adds one row of known values, one row of null values and then iterates through the DataTable, assigning the values to variables and displaying the output in the console window.

static private void WorkWithSqlNulls()
{
    DataTable table = new DataTable();

    // Specify the SqlType for each column.
    DataColumn idColumn =
        table.Columns.Add("ID", typeof(SqlInt32));
    DataColumn descColumn =
        table.Columns.Add("Description", typeof(SqlString));

    // Add some data.
    DataRow nRow = table.NewRow();
    nRow["ID"] = 123;
    nRow["Description"] = "Side Mirror";
    table.Rows.Add(nRow);

    // Add null values.
    nRow = table.NewRow();
    nRow["ID"] = SqlInt32.Null;
    nRow["Description"] = SqlString.Null;
    table.Rows.Add(nRow);

    // Initialize variables to use when
    // extracting the data.
    SqlBoolean isColumnNull = false;
    SqlInt32 idValue = SqlInt32.Zero;
    SqlString descriptionValue = SqlString.Null;

    // Iterate through the DataTable and display the values.
    foreach (DataRow row in table.Rows)
    {
        // Assign values to variables. Note that you 
        // do not have to test for null values.
        idValue = (SqlInt32)row["ID"];
        descriptionValue = (SqlString)row["Description"];

        // Test for null value in ID column.
        isColumnNull = idValue.IsNull;

        // Display variable values in console window.
        Console.Write("isColumnNull={0}, ID={1}, Description={2}",
            isColumnNull, idValue, descriptionValue);
        Console.WriteLine();
    }
Private Sub WorkWithSqlNulls()
    Dim table As New DataTable()

    ' Specify the SqlType for each column.
    Dim idColumn As DataColumn = _
      table.Columns.Add("ID", GetType(SqlInt32))
    Dim descColumn As DataColumn = _
      table.Columns.Add("Description", GetType(SqlString))

    ' Add some data.
    Dim row As DataRow = table.NewRow()
    row("ID") = 123
    row("Description") = "Side Mirror"
    table.Rows.Add(row)

    ' Add null values.
    row = table.NewRow()
    row("ID") = SqlInt32.Null
    row("Description") = SqlString.Null
    table.Rows.Add(row)

    ' Initialize variables to use when
    ' extracting the data.
    Dim isColumnNull As SqlBoolean = False
    Dim idValue As SqlInt32 = SqlInt32.Zero
    Dim descriptionValue As SqlString = SqlString.Null

    ' Iterate through the DataTable and display the values.
    For Each row In table.Rows
        ' Assign values to variables. Note that you 
        ' do not have to test for null values.
        idValue = CType(row("ID"), SqlInt32)
        descriptionValue = CType(row("Description"), SqlString)

        ' Test for null value with ID column
        isColumnNull = idValue.IsNull

        ' Display variable values in console window.
        Console.Write("isColumnNull={0}, ID={1}, Description={2}", _
          isColumnNull, idValue, descriptionValue)
        Console.WriteLine()
    Next row
End Sub

Este ejemplo muestra el siguiente resultado:This example displays the following results:

isColumnNull=False, ID=123, Description=Side Mirror  
isColumnNull=True, ID=Null, Description=Null  

Comparación de valores NULL con SqlTypes y tipos CLRComparing Null Values with SqlTypes and CLR Types

Al comparar valores NULL, es importante comprender la diferencia entre la forma en que el método Equals evalúa los valores NULL en System.Data.SqlTypes por contraposición a cómo funciona con tipos CLR.When comparing null values, it is important to understand the difference between the way the Equals method evaluates null values in System.Data.SqlTypes as compared with the way it works with CLR types. Todos los métodos de System.Data.SqlTypesEquals usan semántica de base de datos para evaluar valores NULL: si alguno de los valores es NULL, o lo son ambos, la comparación produce NULL.All of the System.Data.SqlTypesEquals methods use database semantics for evaluating null values: if either or both of the values is null, the comparison yields null. Por otra parte, el uso del método Equals de CLR en dos System.Data.SqlTypes producirá TRUE si ambos son NULL.On the other hand, using the CLR Equals method on two System.Data.SqlTypes will yield true if both are null. Esto refleja la diferencia entre el uso de un método de instancia como el método String.Equals de CLR y el uso del método estático o compartido SqlString.Equals.This reflects the difference between using an instance method such as the CLR String.Equals method, and using the static/shared method, SqlString.Equals.

En el siguiente ejemplo se muestra la diferencia entre los resultados del método SqlString.Equals y del método String.Equals cuando se pasa a cada uno un par de valores NULL y, a continuación, un par de cadenas vacías.The following example demonstrates the difference in results between the SqlString.Equals method and the String.Equals method when each is passed a pair of null values and then a pair of empty strings.

    private static void CompareNulls()
    {
        // Create two new null strings.
        SqlString a = new SqlString();
        SqlString b = new SqlString();

        // Compare nulls using static/shared SqlString.Equals.
        Console.WriteLine("SqlString.Equals shared/static method:");
        Console.WriteLine("  Two nulls={0}", SqlStringEquals(a, b));

        // Compare nulls using instance method String.Equals.
        Console.WriteLine();
        Console.WriteLine("String.Equals instance method:");
        Console.WriteLine("  Two nulls={0}", StringEquals(a, b));

        // Make them empty strings.
        a = "";
        b = "";

        // When comparing two empty strings (""), both the shared/static and
        // the instance Equals methods evaluate to true.
        Console.WriteLine();
        Console.WriteLine("SqlString.Equals shared/static method:");
        Console.WriteLine("  Two empty strings={0}", SqlStringEquals(a, b));

        Console.WriteLine();
        Console.WriteLine("String.Equals instance method:");
        Console.WriteLine("  Two empty strings={0}", StringEquals(a, b));
    }
    
    private static string SqlStringEquals(SqlString string1, SqlString string2)
    {
        // SqlString.Equals uses database semantics for evaluating nulls.
        string returnValue = SqlString.Equals(string1, string2).ToString();
        return returnValue;
    }

    private static string StringEquals(SqlString string1, SqlString string2)
    {
        // String.Equals uses CLR type semantics for evaluating nulls.
        string returnValue = string1.Equals(string2).ToString();
        return returnValue;
    }
}
Private Sub CompareNulls()
    ' Create two new null strings.
    Dim a As New SqlString
    Dim b As New SqlString

    ' Compare nulls using static/shared SqlString.Equals.
    Console.WriteLine("SqlString.Equals shared/static method:")
    Console.WriteLine("  Two nulls={0}", SqlStringEquals(a, b))

    ' Compare nulls using instance method String.Equals.
    Console.WriteLine()
    Console.WriteLine("String.Equals instance method:")
    Console.WriteLine("  Two nulls={0}", StringEquals(a, b))

    ' Make them empty strings.
    a = ""
    b = ""

    ' When comparing two empty strings (""), both the shared/static and
    ' the instance Equals methods evaluate to true.
    Console.WriteLine()
    Console.WriteLine("SqlString.Equals shared/static method:")
    Console.WriteLine("  Two empty strings={0}", SqlStringEquals(a, b))

    Console.WriteLine()
    Console.WriteLine("String.Equals instance method:")
    Console.WriteLine("  Two empty strings={0}", StringEquals(a, b))
End Sub

Private Function SqlStringEquals(ByVal string1 As SqlString, _
    ByVal string2 As SqlString) As String

    ' SqlString.Equals uses database semantics for evaluating nulls.
    Dim returnValue As String = SqlString.Equals(string1, string2).ToString()
    Return returnValue
End Function

Private Function StringEquals(ByVal string1 As SqlString, _
    ByVal string2 As SqlString) As String

    ' String.Equals uses CLR type semantics for evaluating nulls.
    Dim returnValue As String = string1.Equals(string2).ToString()
    Return returnValue
End Function

El código produce el siguiente resultado:The code produces the following output:

SqlString.Equals shared/static method:  
  Two nulls=Null  
  
String.Equals instance method:  
  Two nulls=True  
  
SqlString.Equals shared/static method:  
  Two empty strings=True  
  
String.Equals instance method:  
  Two empty strings=True   

Vea tambiénSee also