Gestione dei valori nullHandling Null Values

Se il valore di una colonna è sconosciuto o mancante, viene usato un valore Null in un database relazionale.A null value in a relational database is used when the value in a column is unknown or missing. Un valore Null non è né una stringa vuota (per i tipi di dati character o datetime) né un valore zero (per i tipi di dati numerici).A null is neither an empty string (for character or datetime data types) nor a zero value (for numeric data types). La specifica ANSI SQL-92 indica che un valore Null deve essere lo stesso per tutti i tipi di dati, in modo che tutti i valori Null vengano gestiti in modo coerente.The ANSI SQL-92 specification states that a null must be the same for all data types, so that all nulls are handled consistently. Lo spazio dei nomi System.Data.SqlTypes specifica la semantica Null implementando l'interfaccia INullable.The System.Data.SqlTypes namespace provides null semantics by implementing the INullable interface. Ogni tipo di dati in System.Data.SqlTypes ha una propria proprietà IsNull e un valore Null che può essere assegnato a un'istanza di tale tipo di dati.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

In .NET Framework versione 2.0 è stato introdotto il supporto per i tipi di valore nullable, che consentono ai programmatori di estendere un tipo di valore per rappresentare tutti i valori del tipo sottostante.The .NET Framework version 2.0 introduced support for nullable value types, which allow programmers to extend a value type to represent all values of the underlying type. Questi tipi di valore nullable Nullable CLR rappresentano un'istanza della struttura.These CLR nullable value types represent an instance of the Nullable structure. Questa funzionalità è particolarmente utile quando i tipi di valore sono boxed e unboxed, garantendo una maggiore compatibilità con i tipi di oggetto.This capability is especially useful when value types are boxed and unboxed, providing enhanced compatibility with object types. I tipi di valore nullable CLR non sono destinati all'archiviazione di valori null null del database Nothing perché un valore null SQL ANSI non si comporta allo stesso modo di un riferimento (o in Visual Basic).CLR nullable value 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). Per usufruire dei valori Null SQL ANSI del database, usare valori Null System.Data.SqlTypes anziché Nullable.For working with database ANSI SQL null values, use System.Data.SqlTypes nulls rather than Nullable. Per ulteriori informazioni sull'utilizzo di tipi nullable di valori CLR in Visual Basic, vedere Tipi di valore nullablee per C, vedere Tipi di valore nullable.For more information on working with CLR value nullable types in Visual Basic see Nullable Value Types, and for C# see Nullable value types.

Valori null e logica con tre valoriNulls and Three-Valued Logic

Consentendo i valori Null nelle definizioni di colonna si introduce una logica a tre valori nell'applicazione.Allowing null values in column definitions introduces three-valued logic into your application. Un confronto può restituire una delle tre condizioni seguenti:A comparison can evaluate to one of three conditions:

  • TrueTrue

  • FalseFalse

  • UnknownUnknown

Poiché il valore Null è considerato sconosciuto, due valori Null confrontati tra loro non sono considerati uguali.Because null is considered to be unknown, two null values compared to each other are not considered to be equal. Nelle espressioni che usano operatori aritmetici, se uno degli operandi è Null, anche il risultato è Null.In expressions using arithmetic operators, if any of the operands is null, the result is null as well.

Valori Null e SqlBooleanNulls and SqlBoolean

Il confronto tra qualsiasi System.Data.SqlTypes restituisce un elemento SqlBoolean.Comparison between any System.Data.SqlTypes will return a SqlBoolean. La funzione IsNull per ogni SqlType restituisce un elemento SqlBoolean e può essere usata per verificare la presenza di valori Null.The IsNull function for each SqlType returns a SqlBoolean and can be used to check for null values. Le seguenti tabelle di veridicità illustrano la funzione degli operatori AND, OR e NOT in presenza di un valore 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 e U=unknown o Null)(T=true, F=false, and U=unknown, or null.)

Tabella TruthTruth Table

Nozioni di base sull'opzione ANSI_NULLSUnderstanding the ANSI_NULLS Option

System.Data.SqlTypes offre la stessa semantica di quando si imposta l'opzione ANSI_NULLS in SQL Server.System.Data.SqlTypes provides the same semantics as when the ANSI_NULLS option is set on in SQL Server. Tutti gli operatori aritmetici *(Sezione , , , / , |%) , gli operatori bit per bit (Sezione , &, IsNull) e la maggior parte delle funzioni restituiscono null se uno degli operandi o degli argomenti è null, ad eccezione della proprietà .All arithmetic operators (+, -, *, /, %), bitwise operators (~, &, |), and most functions return null if any of the operands or arguments is null, except for the property IsNull.

Lo standard ANSI SQL-92 non supporta columnName = NULL in una clausola WHERE.The ANSI SQL-92 standard does not support columnName = NULL in a WHERE clause. In SQL Server l'opzione ANSI_NULLS controlla sia il supporto di valori Null predefinito nel database, sia la valutazione dei confronti con i valori Null.In SQL Server, the ANSI_NULLS option controls both default nullability in the database and evaluation of comparisons against null values. Se l'opzione ANSI_NULLS è attivata (impostazione predefinita), è necessario usare l'operatore IS NULL nelle espressioni quando si effettuano test dei valori Null.If ANSI_NULLS is turned on (the default), the IS NULL operator must be used in expressions when testing for null values. Ad esempio, se l'opzione ANSI_NULLS è impostata su ON, il confronto seguente restituisce sempre UNKNOWN:For example, the following comparison always yields unknown when ANSI_NULLS is on:

colname > NULL  

Il confronto con una variabile che contiene un valore Null restituisce anche Unknown:Comparison to a variable containing a null value also yields unknown:

colname > @MyVariable  

Per verificare la presenza di un valore Null, usare il predicato IS NULL o IS NOT NULL.Use the IS NULL or IS NOT NULL predicate to test for a null value. La clausola WHERE potrebbe risultare in tal modo più complessa.This can add complexity to the WHERE clause. Ad esempio, la colonna TerritoryID nella tabella Customer di AdventureWorks consente i valori Null.For example, the TerritoryID column in the AdventureWorks Customer table allows null values. Un'istruzione SELECT che oltre ad altri valori deve verificare i valori Null deve includere il predicato 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 si imposta ANSI_NULLS come disattivata in SQL Server, è possibile creare espressioni che usano l'operatore di uguaglianza per eseguire il confronto con il valore Null.If you set ANSI_NULLS off in SQL Server, you can create expressions that use the equality operator to compare to null. Tuttavia, non è possibile impedire a diverse connessioni di impostare opzioni Null per tale connessione.However, you can't prevent different connections from setting null options for that connection. L'uso di IS NULL per testare i valori Null funziona sempre, indipendentemente dalle impostazioni di ANSI_NULLS per una connessione.Using IS NULL to test for null values always works, regardless of the ANSI_NULLS settings for a connection.

L'impostazione di ANSI_NULLS come disattivata non è supportata in un oggetto DataSet, che segue sempre lo standard ANSI SQL-92 per la gestione dei valori Null in 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.

Assegnazione di valori nullAssigning Null Values

I valori Null sono speciali e la relativa semantica di archiviazione e assegnazione varia tra sistemi di tipi e sistemi di archiviazione diversi.Null values are special, and their storage and assignment semantics differ across different type systems and storage systems. Un oggetto Dataset è progettato per essere usato con sistemi di tipi e di archiviazione diversi.A Dataset is designed to be used with different type and storage systems.

In questa sezione viene descritta la semantica Null per l'assegnazione di valori Null a un DataColumn in un DataRow nei diversi sistemi di tipi.This section describes the null semantics for assigning null values to a DataColumn in a DataRow across the different type systems.

DBNull.Value
Questa assegnazione è valida per un DataColumn di qualsiasi tipo.This assignment is valid for a DataColumn of any type. Se il tipo implementa INullable, DBNull.Value viene assegnato forzatamente al valore Null fortemente tipizzato appropriato.If the type implements INullable, DBNull.Value is coerced into the appropriate strongly typed Null value.

SqlType.Null
Tutti i tipi di dati System.Data.SqlTypes implementano INullable.All System.Data.SqlTypes data types implement INullable. Se il valore Null fortemente tipizzato può essere convertito nel tipo di dati della colonna usando gli operatori di cast impliciti, l'assegnazione ha esito positivo.If the strongly typed null value can be converted into the column's data type using implicit cast operators, the assignment should go through. In caso contrario, viene generata un'eccezione di cast non valido.Otherwise an invalid cast exception is thrown.

null
Se "null" è un valore valido per il tipo di dati DataColumn specificato, viene assegnato forzatamente all'oggetto DbNull.Value o Null appropriato associato al 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
Per le colonne con tipo definito dall'utente (UDT), i valori Null vengono sempre archiviati in base al tipo associato a DataColumn.For UDT columns, nulls are always stored based on the type associated with the DataColumn. Si consideri il caso di un UDT associato a un DataColumn che non implementa un elemento INullable mentre la relativa sottoclasse lo implementa.Consider the case of a UDT associated with a DataColumn that does not implement INullable while its sub-class does. In questo caso, se viene assegnato un valore Null fortemente tipizzato associato alla classe derivata, viene archiviato come DbNull.Value non tipizzato, perché l'archiviazione Null è sempre coerente con il tipo di dati di 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 struttura di Nullable<T> o Nullable non è attualmente supportata in DataSet.The Nullable<T> or Nullable structure is not currently supported in the DataSet.

Assegnazione di più colonne (riga)Multiple Column (Row) Assignment

DataTable.Add, DataTable.LoadDataRow o altre API che accettano un elemento ItemArray che viene mappato a una riga, eseguono il mapping di "null" al valore predefinito di 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 un oggetto nella matrice contiene DbNull.Value o la relativa controparte fortemente tipizzata, vengono applicate le stesse regole descritte sopra.If an object in the array contains DbNull.Value or its strongly typed counterpart, the same rules as described above are applied.

Per un'istanza di assegnazioni di valori Null di DataRow.["columnName"] si applicano inoltre le regole seguenti:In addition, the following rules apply for an instance of DataRow.["columnName"] null assignments:

  1. Il valore predefinito default è DbNull.Value per tutte le colonne ad eccezione di quelle Null fortemente tipizzate, alle quali si applica il valore Null fortemente tipizzato appropriato.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. I valori Null non vengono mai scritti durante la serializzazione nei file XML (come in "xsi:nil").Null values are never written out during serialization to XML files (as in "xsi:nil").

  3. Tutti i valori non Null, incluse le impostazioni predefinite, vengono sempre scritti durante la serializzazione in XML,All non-null values, including defaults, are always written out while serializing to XML. a differenza della semantica XSD/XML in cui un valore Null (xsi:nil) è esplicito e il valore predefinito è implicito (se non è presente in XML, un parser di convalida può ottenerlo da uno schema XSD associato).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). Per un oggetto DataTable è vero il contrario: un valore Null è implicito e il valore predefinito è esplicito.The opposite is true for a DataTable: a null value is implicit and the default value is explicit.

  4. A tutti i valori di colonna mancanti per le righe lette dall'input XML viene assegnato NULL.All missing column values for rows read from XML input are assigned NULL. Alle righe create con NewRow o metodi simili viene assegnato il valore predefinito di DataColumn.Rows created using NewRow or similar methods are assigned the DataColumn's default value.

  5. Il metodo IsNull restituisce true sia per DbNull.Value che per INullable.Null.The IsNull method returns true for both DbNull.Value and INullable.Null.

Assegnazione di valori nullAssigning Null Values

Il valore predefinito per qualsiasi istanza di System.Data.SqlTypes è Null.The default value for any System.Data.SqlTypes instance is null.

I valori Null in System.Data.SqlTypes sono specifici del tipo e non possono essere rappresentati da un singolo valore, ad esempio DbNull.Nulls in System.Data.SqlTypes are type-specific and cannot be represented by a single value, such as DbNull. Usare la proprietà IsNull per verificare la presenza di valori Null.Use the IsNull property to check for nulls.

È possibile assegnare valori Null a un DataColumn come illustrato nell'esempio di codice seguente.Null values can be assigned to a DataColumn as shown in the following code example. È possibile assegnare direttamente i valori Null alle variabili SqlTypes senza generare un'eccezione.You can directly assign null values to SqlTypes variables without triggering an exception.

EsempioExample

Nell'esempio di codice seguente viene creato un DataTable con due colonne definite come SqlInt32 e SqlString.The following code example creates a DataTable with two columns defined as SqlInt32 and SqlString. Il codice aggiunge una riga di valori noti, una riga di valori Null e quindi scorre esegue l'iterazione in DataTable, assegnando i valori alle variabili e visualizzando l'output nella finestra della 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

L'esempio visualizza i risultati seguenti:This example displays the following results:

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

Confronto di valori null con SqlTypes e tipi CLRComparing Null Values with SqlTypes and CLR Types

Quando si confrontano i valori Null, è importante comprendere la differenza tra il modo in cui il metodo Equals valuta i valori Null in System.Data.SqlTypes e il modo in cui funziona con i tipi 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. Tutti i metodi System.Data.SqlTypesEquals usano la semantica del database per valutare i valori Null: se uno o entrambi i valori sono Null, il confronto restituisce 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. D'altra parte, l'uso del metodo CLR Equals per due System.Data.SqlTypes genera True se entrambi i valori sono Null.On the other hand, using the CLR Equals method on two System.Data.SqlTypes will yield true if both are null. Ciò riflette la differenza tra l'uso di un metodo di istanza, ad esempio il metodo CLR String.Equals, e l'uso del metodo statico/condiviso, 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.

Nell'esempio seguente viene illustrata la differenza nei risultati tra il metodo SqlString.Equals e il metodo String.Equals quando a ognuno viene passata una coppia di valori Null e quindi una coppia di stringhe vuote.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

Il codice produce l'output seguente: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

Vedere ancheSee also