Manipulando valores nulosHandling Null Values

Um valor nulo em um banco de dados relacional é usado quando o valor em uma coluna é desconhecido ou ausente.A null value in a relational database is used when the value in a column is unknown or missing. Um nulo não é uma cadeia de caracteres vazia (para os tipos de dados character ou datetime) nem um valor zero (para tipos de dados numéricos).A null is neither an empty string (for character or datetime data types) nor a zero value (for numeric data types). A especificação ANSI SQL-92 indica que um valor nulo deve ser o mesmo para todos os tipos de dados, para que todos os nulos sejam tratados consistentemente.The ANSI SQL-92 specification states that a null must be the same for all data types, so that all nulls are handled consistently. O namespace System.Data.SqlTypes fornece uma semântica nula implementando a interface INullable.The System.Data.SqlTypes namespace provides null semantics by implementing the INullable interface. Cada um dos tipos de dados no System.Data.SqlTypes tem sua própria propriedade IsNull e um valor Null que pode ser atribuído a uma instância desse tipo de dados.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.

Observação

O .NET Framework versão 2.0 incorporou o suporte a tipos que permitem valores nulos, proporcionando aos programadores meios de estender um tipo de valor para representar todos os valores do tipo subjacente.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. Esses tipos CLR que permitem valores nulos representam uma instância da estrutura Nullable.These CLR nullable types represent an instance of the Nullable structure. Esse recurso é especialmente útil quando os tipos de valor são boxed e unboxed, fornecendo uma compatibilidade aprimorada com os tipos de objeto.This capability is especially useful when value types are boxed and unboxed, providing enhanced compatibility with object types. Os tipos CLR que permitem valores nulos não se destinam ao armazenamento dos valores nulos do banco de dados, pois um valor nulo ANSI SQL não se comporta da mesma maneira que uma referência null (ou Nothing no 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 trabalhar com valores nulos ANSI SQL do banco de dados, use os valores nulos System.Data.SqlTypes, em vez de Nullable.For working with database ANSI SQL null values, use System.Data.SqlTypes nulls rather than Nullable. Para obter mais informações sobre como trabalhar com tipos anuláveis CLR em Visual Basic consulte tipos de valor anulávele para ver tipos de C# valor anulável.For more information on working with CLR nullable types in Visual Basic see Nullable Value Types, and for C# see Nullable value types.

Valores nulos e lógica de três valoresNulls and Three-Valued Logic

A permissão de valores nulos em definições de coluna incorpora a lógica de três valores no aplicativo.Allowing null values in column definitions introduces three-valued logic into your application. Uma comparação pode ser avaliada como uma das três condições:A comparison can evaluate to one of three conditions:

  • verdadeiroTrue

  • FalseFalse

  • UnknownUnknown

Como o valor número é considerado desconhecido, dois valores nulos comparados entre si não são considerados iguais.Because null is considered to be unknown, two null values compared to each other are not considered to be equal. Nas expressões que usam operadores aritméticos, se qualquer um dos operandos for nulo, o resultado também será nulo.In expressions using arithmetic operators, if any of the operands is null, the result is null as well.

Valores nulos e SqlBooleanNulls and SqlBoolean

A comparação entre qualquer System.Data.SqlTypes retornará SqlBoolean.Comparison between any System.Data.SqlTypes will return a SqlBoolean. A função IsNull de cada SqlType retornará SqlBoolean e poderá ser usada para verificar valores nulos.The IsNull function for each SqlType returns a SqlBoolean and can be used to check for null values. As seguintes tabelas da verdade mostram como os operadores AND, OR e NO funcionam na presença de um valor nulo.The following truth tables show how the AND, OR, and NOT operators function in the presence of a null value. (T=verdadeiro, F=falso e U=desconhecido ou nulo.)(T=true, F=false, and U=unknown, or null.)

Tabela da verdadeTruth Table

Noções básicas sobre a opção ANSI_NULLSUnderstanding the ANSI_NULLS Option

System.Data.SqlTypes fornece a mesma semântica do que a proporcionada quando a opção ANSI_NULLS é definida no SQL Server.System.Data.SqlTypes provides the same semantics as when the ANSI_NULLS option is set on in SQL Server. Todos os operadores aritméticos (+,-, *,/,%), operadores de bit (~, &, |) e a maioria das funções retornarão nulo se qualquer um dos operandos ou argumentos for nulo, exceto para a IsNullde propriedades.All arithmetic operators (+, -, *, /, %), bitwise operators (~, &, |), and most functions return null if any of the operands or arguments is null, except for the property IsNull.

O padrão ANSI SQL-92 não oferece suporte a ColumnName = NULL em uma cláusula WHERE.The ANSI SQL-92 standard does not support columnName = NULL in a WHERE clause. No SQL Server, a opção ANSI_NULLS controla a nulidade padrão no banco de dados e a avaliação das comparações com valores nulos.In SQL Server, the ANSI_NULLS option controls both default nullability in the database and evaluation of comparisons against null values. Se ANSI_NULLS for ativado (o padrão), o operador IS NULL deverá ser usado nas expressões durante o teste de valores nulos.If ANSI_NULLS is turned on (the default), the IS NULL operator must be used in expressions when testing for null values. Por exemplo, a comparação a seguir sempre produzirá unknown quando ANSI_NULLS for ativado:For example, the following comparison always yields unknown when ANSI_NULLS is on:

colname > NULL  

A comparação com uma variável contendo um valor nulo também produz unknown:Comparison to a variable containing a null value also yields unknown:

colname > @MyVariable  

Use o predicado IS NULL ou IS NOT NULL para testar um valor nulo.Use the IS NULL or IS NOT NULL predicate to test for a null value. Isso pode adicionar complexidade à cláusula WHERE.This can add complexity to the WHERE clause. Por exemplo, a coluna TerritoryID na tabela Customer do AdventureWorks permite valores nulos.For example, the TerritoryID column in the AdventureWorks Customer table allows null values. Se uma instrução SELECT for destinada a testar valores nulos além de outros, ela deverá incluir um 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  

Se você desativar ANSI_NULLS no SQL Server, poderá criar expressões que usam o operador de igualdade para comparar com o valor nulo.If you set ANSI_NULLS off in SQL Server, you can create expressions that use the equality operator to compare to null. No entanto, você não pode impedir que as diferentes conexões definam opções nulas para essa conexão.However, you can't prevent different connections from setting null options for that connection. O uso de IS NULL para testar valores nulos sempre funciona, independentemente das configurações de ANSI_NULLS para uma conexão.Using IS NULL to test for null values always works, regardless of the ANSI_NULLS settings for a connection.

Não há suporte para a desativação de ANSI_NULLS em um DataSet, que sempre segue o padrão ANSI SQL-92 para manipular valores nulos no 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.

Atribuindo valores nulosAssigning Null Values

Os valores nulos são especiais, e as semânticas de armazenamento e de atribuição diferem entre sistemas de tipo e sistemas de armazenamento.Null values are special, and their storage and assignment semantics differ across different type systems and storage systems. Um Dataset foi projetado para ser usado com diferentes sistemas de tipo e de armazenamento.A Dataset is designed to be used with different type and storage systems.

Esta seção descreve as semânticas nulas para atribuir valores nulos a DataColumn em um DataRow entre diferentes sistemas de tipo.This section describes the null semantics for assigning null values to a DataColumn in a DataRow across the different type systems.

DBNull.Value
Esta atribuição é válida para uma DataColumn de qualquer tipo.This assignment is valid for a DataColumn of any type. Se o tipo implementar INullable, DBNull.Value será forçado no valor nulo fortemente tipado apropriado.If the type implements INullable, DBNull.Value is coerced into the appropriate strongly typed Null value.

SqlType.Null
Todos os tipos de dados System.Data.SqlTypes implementam INullable.All System.Data.SqlTypes data types implement INullable. Se o valor nulo fortemente tipado puder ser convertido no tipo de dados da coluna usando operadores de conversão implícitos, a atribuição deverá ser feita.If the strongly typed null value can be converted into the column's data type using implicit cast operators, the assignment should go through. Caso contrário, uma exceção de conversão inválida será lançada.Otherwise an invalid cast exception is thrown.

null
Se 'null' for um valor válido para o tipo de dado de dados DataColumn, ele será forçado no DbNull.Value ou Null associado ao 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
Para colunas UDT, os valores nulos sempre são armazenados com base no tipo associado à DataColumn.For UDT columns, nulls are always stored based on the type associated with the DataColumn. Considere o caso de um UDT associado a uma DataColumn que não implementa INullable quando sua subclasse o faz.Consider the case of a UDT associated with a DataColumn that does not implement INullable while its sub-class does. Nesse caso, se um valor nulo fortemente tipado associado à classe derivada for atribuído, ele será armazenado como um DbNull.Value não tipado, porque o armazenamento nulo é sempre consistente com o tipo de dados 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.

Observação

Não há suporte no momento para a estrutura Nullable<T> ou Nullable no DataSet.The Nullable<T> or Nullable structure is not currently supported in the DataSet.

Atribuição de várias colunas (linha)Multiple Column (Row) Assignment

DataTable.Add, DataTable.LoadDataRow ou outras APIs que aceitam um ItemArray que é mapeado para uma linha mapeiam 'null' para o valor padrão 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. Se um objeto na matriz contiver DbNull.Value ou seu equivalente fortemente tipado, as mesmas regras serão aplicadas conforme descrito acima.If an object in the array contains DbNull.Value or its strongly typed counterpart, the same rules as described above are applied.

Além disso, as seguintes regras se aplicam a uma instância de atribuições nulas de DataRow.["columnName"]:In addition, the following rules apply for an instance of DataRow.["columnName"] null assignments:

  1. O valor padrão default é DbNull.Value para todos, exceto para as colunas NULL com rigidez de tipos, em que é o valor NULL fortemente tipado apropriado.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. Os valores nulos nunca são gravados durante a serialização para arquivos XML (como em “xsi:nil").Null values are never written out during serialization to XML files (as in "xsi:nil").

  3. Todos os valores não nulos, incluindo os valores padrão, sempre são gravados durante a serialização para XML.All non-null values, including defaults, are always written out while serializing to XML. Esta é a semântica XSD/XML improvável, em que um valor nulo (xsi:nil) é explícito e o valor padrão é implícito (caso não esteja presente no XML, um analisador de validação poderá obtê-lo em um esquema XSD associado).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). O oposto é verdadeiro para DataTable: um valor nulo é implícito e o valor padrão é explícito.The opposite is true for a DataTable: a null value is implicit and the default value is explicit.

  4. Todos os valores de coluna ausentes para as linhas lidas na entrada XML recebem NULL.All missing column values for rows read from XML input are assigned NULL. As linhas criadas por meio de NewRow ou de métodos similares recebem o valor padrão de DataColumn.Rows created using NewRow or similar methods are assigned the DataColumn's default value.

  5. O método IsNull retorna true para DbNull.Value e INullable.Null.The IsNull method returns true for both DbNull.Value and INullable.Null.

Atribuindo valores nulosAssigning Null Values

O valor padrão para qualquer instância de System.Data.SqlTypes é nulo.The default value for any System.Data.SqlTypes instance is null.

Os valores nulos em System.Data.SqlTypes são específicos de tipo e não podem ser representado por um único valor, como DbNull.Nulls in System.Data.SqlTypes are type-specific and cannot be represented by a single value, such as DbNull. Use a propriedade IsNull para verificar valores nulos.Use the IsNull property to check for nulls.

Os valores nulos podem ser atribuídos a DataColumn conforme mostrado no exemplo de código a seguir.Null values can be assigned to a DataColumn as shown in the following code example. Você pode atribuir diretamente valores nulos a variáveis SqlTypes sem disparar uma exceção.You can directly assign null values to SqlTypes variables without triggering an exception.

ExemploExample

O exemplo de código a seguir cria DataTable com duas colunas definidas como SqlInt32 e SqlString.The following code example creates a DataTable with two columns defined as SqlInt32 and SqlString. O código adiciona uma linha de valores conhecidos, uma linha de valores nulos e faz a iteração por DataTable, atribuindo os valores às variáveis e exibindo a saída na janela do console.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

Esse exemplo exibe os seguintes resultados:This example displays the following results:

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

Comparando valores nulos com SqlTypes e os tipos CLRComparing Null Values with SqlTypes and CLR Types

Durante a comparação dos valores nulos, é importante compreender a diferença entre a maneira como o método Equals avalia os valores nulos no System.Data.SqlTypes e a maneira como ele funciona nos 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 os métodos System.Data.SqlTypesEquals usam a semântica de banco de dados para avaliar valores nulos: se qualquer um ou ambos os valores forem nulos, a comparação produzirá um valor nulo.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 outro lado, o uso do método CLR Equals em dois System.Data.SqlTypes produzirá verdadeiro se ambos forem nulos.On the other hand, using the CLR Equals method on two System.Data.SqlTypes will yield true if both are null. Isso refletirá a diferença entre o uso de um método de instância, como o método CLR String.Equals, e o uso do método estático/compartilhado, 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.

O exemplo a seguir mostra a diferença nos resultados entre os métodos SqlString.Equals e String.Equals quando cada um recebe um par de valores nulos e, em seguida, um par de cadeias de caracteres vazias.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

O código produz a seguinte saída: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   

Consulte tambémSee also