共用方式為


處理 Null 值

當數據行中的值未知或遺失時,就會使用關係資料庫中的 Null 值。 Null 既不是空字串(針對字元或日期時間數據類型),也不是零值(針對數值數據類型)。 ANSI SQL-92 規格指出所有數據類型的 Null 必須相同,因此所有 Null 都會一致地處理。 命名空間 System.Data.SqlTypes 藉由實作 INullable 介面來提供 Null 語意。 中的每個 System.Data.SqlTypes 數據類型都有自己的 IsNull 屬性和 Null 值,可指派給該數據類型的實例。

備註

.NET Framework 2.0 版引進了可為空的實值型別支援,使程式設計人員可以擴充 NET 實值型別,以代表基礎型別的所有值。 這些 CLR 可為 Null 的實值型別表示 Nullable 結構的實例。 當數值型別被包裝和解除包裝時,這項功能特別有用,能增強與物件型別的相容性。 CLR 可為 Null 的實值型別不適合用來儲存資料庫的 Null 值,因為 ANSI SQL 的 Null 行為與 null 參考(或在 Visual Basic 中的 Nothing)不同。 若要處理資料庫中的 ANSI SQL null 值,請使用 System.Data.SqlTypes null 而不是 Nullable。 如需在 Visual Basic 中使用 CLR 值可為 Null 型別的詳細資訊,請參閱 可為 Null 的實值型別,而針對 C# 請參閱 可為 Null 的實值型別

空值和 Three-Valued 邏輯

允許數據行定義中的 Null 值,會將三個值邏輯引入您的應用程式。 比較可評估為三個條件之一:

  • 未知

因為 Null 被視為未知,因此相較於彼此,兩個 Null 值不被視為相等。 在使用算術運算符的表達式中,如果任一作數為 null,則結果也會是 null。

Null 和 SqlBoolean

任何 System.Data.SqlTypes 之間的比較都會傳回 SqlBoolean。 每個SqlType 的函IsNull式都會傳回SqlBoolean,可用來檢查空值。 下列事實數據表顯示 AND、OR 和 NOT 運算符在 Null 值存在時的運作方式。 (T=true、F=false 和 U=unknown 或 null。)

真值表

瞭解ANSI_NULLS選項

System.Data.SqlTypes 提供與在 SQL Server 中設定 ANSI_NULLS 選項時相同的語意。 所有算術運算子(+、-、*、/、%)、位運算元(~、&、|),如果任一作數或自變數都是 Null,則大多數函式都會傳回 null,但 屬性 IsNull除外。

ANSI SQL-92 標準不支援 WHERE 子句中的 columnName = NULL。 在 SQL Server 中,ANSI_NULLS 選項會控制資料庫中的預設可為 Null 屬性,以及進行與 Null 值比較的評估。 如果開啟ANSI_NULLS (預設值),則測試 Null 值時,必須在表達式中使用 IS NULL 運算符。 例如,當ANSI_NULLS開啟時,下列比較一律會產生未知:

colname > NULL  

與包含空值的變數比較也會導致未知的結果。

colname > @MyVariable  

使用 IS NULL 或 IS NOT NULL 來檢驗是否為空值。 這可將複雜度新增至 WHERE 子句。 例如,AdventureWorks Customer 數據表中的 TerritoryID 數據行允許 Null 值。 如果 SELECT 語句除了其他值之外,還要測試 null 值,必須使用 IS NULL 述詞。

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

如果您在 SQL Server 中設定 ANSI_NULLS 為關閉,您可以建立使用等號來與 null 進行比較的運算式。 不過,您無法防止不同的連線為其各自的連線設定 Null 選項。 不論連線的ANSI_NULLS設定為何,使用IS NULL 來測試 Null 值一律有效。

不支援在 DataSet 設定 ANSI_NULLS 為關閉,因為它一律遵循 ANSI SQL-92 標準來處理 System.Data.SqlTypes 中的 Null 值。

指派空值

Null 值很特殊,其儲存和指派語意在不同類型的系統和儲存系統之間有所不同。 設計Dataset以便能與不同類型和儲存系統搭配使用。

本節描述在不同類型系統中,將空值指派給 DataRow 中的 DataColumn 的空值語義。

DBNull.Value
此指派適用於任何類型的 DataColumn。 如果型別實作 INullableDBNull.Value 則會強制轉換為適當的強型別 Null 值。

SqlType.Null
所有 System.Data.SqlTypes 資料類型都會實作 INullable。 如果可以使用隱含轉換運算符將強型別空值轉換成欄位的資料類型,則賦值應該能夠進行。 否則會拋出無效的轉換例外。

null
如果 'null' 是指定 DataColumn 資料類型的法律值,則會強制轉換為適當的 DbNull.ValueNullINullable 類型相關聯的值 (SqlType.Null

derivedUdt.Null
針對UDT數據行,Null 一律會根據與 DataColumn相關聯的類型來儲存。 考慮與未實作 INullableDataColumn 相關聯的 UDT 的情況,而其子類別則有實作 INullable。 在這種情況下,如果指派與衍生類別相關聯的強型別空值,則會將其儲存為不具類型的DbNull.Value,因為空值儲存始終與DataColumn的資料類型一致。

備註

Nullable<T> 結構或 Nullable 結構目前在 DataSet 中不受支援。

任何 System.Data.SqlTypes 實例的預設值為 null。

中的 System.Data.SqlTypes Null 為特定類型,且無法以單一值表示,例如 DbNull。 使用IsNull屬性來檢查空值。

Null 值可以指派給 DataColumn,如下列程式代碼範例所示。 您可以直接將 Null 值指派給 SqlTypes 變數,而不觸發例外狀況。

範例

下列程式代碼範例會建立一個 DataTable,其中兩個欄位定義為 SqlInt32SqlString。 程序代碼會新增一列已知值、一列 Null 值,然後逐一查看 DataTable,將值指派給變數,並在控制台視窗中顯示輸出。

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

    // 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

此範例會顯示下列結果:

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

多個欄位(列)指派

DataTable.AddDataTable.LoadDataRow 或其他接受 ItemArray 並將其映射到列的 API,將 'null' 映射到 DataColumn 的預設值。 如果陣列中的物件包含 DbNull.Value 或其相應的強型別,則會套用與上述相同的規則。

此外,下列規則適用於空指派的DataRow.["columnName"]實例:

  1. 除了DbNull.Value強型別 Null 數據行是適當的強型別 Null 值以外,預設值為all。

  2. 在串行化至 XML 檔案期間,絕不會寫出 Null 值(如 “xsi:nil” 所示)。

  3. 串行化為 XML 時,一律會寫出所有非 Null 值,包括預設值。 這與 XSD/XML 語意不同,其中 null 值 (xsi:nil) 是明確的,而且預設值是隱含的(如果 XML 中不存在,驗證剖析器可以從相關聯的 XSD 架構取得它)。 情況則相反:DataTablenull 值是隱含的,預設值是明顯的。

  4. 從 XML 輸入讀取之數據列的所有遺漏數據行值都會指派 NULL。 使用 NewRow 或類似方法建立的數據列會指派 DataColumn 的預設值。

  5. IsNull 方法會針對 DbNull.ValueINullable.Null 傳回 true

比較 Null 值與 SqlTypes 和 CLR 型別

比較 Null 值時,請務必瞭解方法在System.Data.SqlTypes中評估 Null 值的方式Equals,以及它與評估 CLR 類型時的方式的差異。 所有方法都會 System.Data.SqlTypesEquals 使用資料庫語意來評估 Null 值:如果其中一個或兩個值都是 Null,則比較會產生 Null。 另一方面,使用 CLR Equals 方法在兩個System.Data.SqlTypes上,如果兩者皆為 Null 則會產生 true。 這反映了使用實例方法,例如CLR String.Equals 方法,以及使用靜態/共用方法 SqlString.Equals之間的差異。

下列範例示範當每個方法分別傳入一對 Null 值,然後分別傳入一對空字串時,SqlString.Equals 方法與 String.Equals 方法之間結果的差異。

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

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

        // Compare nulls using instance method String.Equals.
        Console.WriteLine();
        Console.WriteLine("String.Equals instance method:");
        Console.WriteLine($"  Two nulls={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={SqlStringEquals(a, b)}");

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

    static string SqlStringEquals(SqlString string1, SqlString string2)
    {
        // SqlString.Equals uses database semantics for evaluating nulls.
        var returnValue = SqlString.Equals(string1, string2).ToString();
        return returnValue;
    }

    static string StringEquals(SqlString string1, SqlString string2)
    {
        // String.Equals uses CLR type semantics for evaluating nulls.
        var 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

程式代碼會產生下列輸出:

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

另請參閱