Share via


Menangani nilai null

Nilai null dalam database relasional digunakan ketika nilai dalam kolom tidak diketahui atau hilang. Null bukanlah string kosong (untuk jenis data karakter atau datetime) atau nilai nol (untuk jenis data numerik). Spesifikasi ANSI SQL-92 menyatakan bahwa null harus sama untuk semua jenis data, sehingga semua null ditangani secara konsisten. Namespace System.Data.SqlTypes menyediakan semantik null dengan mengimplementasikan antarmuka INullable. Setiap jenis data di System.Data.SqlTypes memiliki properti IsNull sendiri dan nilai Null yang dapat ditetapkan ke instans jenis data tersebut.

Catatan

.NET Framework versi 2.0 memperkenalkan dukungan untuk jenis nilai yang dapat diubah ke null, yang memungkinkan pemrogram untuk memperluas jenis nilai untuk mewakili semua nilai dari jenis yang mendasarinya. Jenis nilai yang dapat diubah ke null CLR ini mewakili turunan dari struktur Nullable. Kemampuan ini sangat berguna ketika jenis nilai dikotak dan tidak dikotak, memberikan peningkatan kompatibilitas dengan jenis objek. Jenis nilai yang dapat diubah ke null CLR tidak dimaksudkan untuk penyimpanan null database karena ANSI SQL null tidak berperilaku dengan cara yang sama seperti referensi null (atau Nothing dalam Visual Basic). Untuk bekerja dengan nilai null database ANSI SQL, gunakan System.Data.SqlTypes null dan bukan Nullable. Untuk informasi selengkapnya tentang bekerja dengan jenis nilai yang dapat diubah ke null CLR di Visual Basic baca Jenis Nilai yang Dapat diubah ke Null, dan untuk C# lihat Jenis nilai yang Dapat diubah ke Null.

Null dan Logika Tiga-Nilai

Mengizinkan nilai null dalam definisi kolom memperkenalkan logika tiga nilai ke dalam aplikasi Anda. Perbandingan dapat mengevaluasi salah satu dari tiga kondisi:

  • Benar

  • Salah

  • Tidak dikenal

Karena null dianggap tidak diketahui, dua nilai null dibandingkan satu sama lain tidak dianggap sama. Dalam ekspresi yang menggunakan operator aritmatika, jika salah satu operan adalah null, hasilnya juga null.

Nulls dan SqlBoolean

Perbandingan antara System.Data.SqlTypes mana pun akan menghasilkan SqlBoolean. Fungsi IsNull untuk setiap SqlType mengembalikan SqlBoolean dan dapat digunakan untuk memeriksa nilai null. Tabel kebenaran berikut menunjukkan cara operator AND, OR, dan NOT berfungsi dengan adanya nilai null. (T=true, F=false, dan U=unknown, atau null.)

Truth Table

Memahami Opsi ANSI_NULLS

System.Data.SqlTypes memberikan semantik yang sama seperti saat opsi ANSI_NULLS diaktifkan di SQL Server. Semua operator aritmatika (+, -, *, /, %), operator bitwise (~, &, |), dan sebagian besar fungsi mengembalikan null jika salah satu operand atau argumen null, kecuali untuk properti IsNull.

Standar ANSI SQL-92 tidak mendukung columnName = NULL dalam klausa WHERE. Di SQL Server, opsi ANSI_NULLS mengontrol nullabilitas default dalam database dan evaluasi perbandingan terhadap nilai null. Jika ANSI_NULLS diaktifkan (default), operator IS NULL harus digunakan dalam ekspresi saat menguji nilai null. Misalnya, perbandingan berikut selalu menghasilkan unknwon saat ANSI_NULLS aktif:

colname > NULL  

Perbandingan dengan variabel yang berisi nilai null juga menghasilkan unknown:

colname > @MyVariable  

Gunakan predikat IS NULL atau IS NOT NULL untuk menguji nilai null. Predikat ini dapat menambah kerumitan pada klausa WHERE. Misalnya, kolom TerritoryID di tabel Pelanggan AdventureWorks memungkinkan nilai null. Jika pernyataan SELECT adalah untuk menguji nilai null selain yang lain, pernyataan ini harus menyertakan predikat IS NULL:

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

Jika Anda menonaktifkan ANSI_NULLS di SQL Server, Anda dapat membuat ekspresi yang menggunakan operator persamaan untuk membandingkan dengan null. Namun, Anda tidak dapat mencegah koneksi yang berbeda dari pengaturan opsi null untuk koneksi tersebut. Menggunakan IS NULL untuk menguji nilai null selalu berhasil, terlepas dari pengaturan ANSI_NULLS untuk koneksi.

Menonaktifkan ANSI_NULLS tidak didukung di DataSet, yang selalu mengikuti standar ANSI SQL-92 untuk menangani nilai null di System.Data.SqlTypes.

Menetapkan Nilai Null

Nilai null adalah khusus, dan semantik penyimpanan dan penugasannya berbeda di berbagai jenis sistem dan sistem penyimpanan. Dataset dirancang untuk digunakan dengan jenis dan sistem penyimpanan yang berbeda.

Bagian ini menjelaskan semantik null untuk menetapkan nilai null ke DataColumn di DataRow di berbagai jenis sistem.

DBNull.Value
Penetapan ini berlaku untuk DataColumn jenis apa pun. Jika jenis mengimplementasikan INullable, DBNull.Value dipaksa menjadi nilai Null yang berjenis dengan kuat dan sesuai.

SqlType.Null
Semua System.Data.SqlTypes jenis data menerapkan INullable. Jika nilai null yang berjenis dengan kuat dapat dikonversi menjadi jenis data kolom menggunakan operator konversi implisit, penetapan harus dilakukan. Jika tidak, pengecualian konversi eksplisit yang tidak valid akan ditampilkan.

null
Jika 'null' adalah nilai legal untuk jenis data DataColumn yang diberikan, nilai tersebut akan dipaksakan ke dalam DbNull.Value atau Null yang terkait dengan jenis INullable (SqlType.Null)

derivedUdt.Null
Untuk kolom UDT, null selalu disimpan berdasarkan jenis yang terkait dengan DataColumn. Pertimbangkan kasus UDT yang terkait dengan DataColumn yang tidak mengimplementasikan INullable sementara sub-kelasnya melakukannya. Dalam kasus ini, jika nilai null yang berjenis kuat terkait dengan kelas turunan ditetapkan, nilai tersebut disimpan sebagai DbNull.Value yang tidak berjenis, karena penyimpanan null selalu konsisten dengan jenis data Kolom Data.

Catatan

Struktur Nullable<T> atau Nullable saat ini tidak didukung di DataSet.

Nilai default untuk setiap instans System.Data.SqlTypes adalah null.

Null di System.Data.SqlTypes adalah jenis khusus dan tidak dapat diwakili oleh nilai tunggal, seperti DbNull. Gunakan properti IsNull untuk memeriksa null.

Nilai null dapat ditetapkan ke DataColumn seperti yang ditunjukkan pada contoh kode berikut. Anda dapat langsung menetapkan nilai null ke variabel SqlTypes tanpa memicu pengecualian.

Contoh

Contoh kode berikut membuat DataTable dengan dua kolom yang didefinisikan sebagai SqlInt32 dan SqlString. Kode menambahkan satu baris nilai yang diketahui, satu baris nilai null dan kemudian beralih melalui DataTable, menetapkan nilai ke variabel dan menampilkan output di jendela konsol.

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

Contoh ini menampilkan hasil berikut:

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

Beberapa Kolom (Baris) Tugas

DataTable.Add, DataTable.LoadDataRow, atau API lain yang menerima ItemArray yang dipetakan ke baris, memetakan 'null' ke nilai default DataColumn. Jika objek dalam larik berisi DbNull.Value atau pasangannya yang berjenis dengan kuat, aturan yang sama seperti yang dijelaskan di atas akan diterapkan.

Selain itu, aturan berikut berlaku untuk instans DataRow.["columnName"] penetapan null:

  1. Nilai default adalah DbNull.Value untuk semua kecuali kolom null yang berjenis dengan kuat yang merupakan nilai null yang berjenis dengan kuat.

  2. Nilai null tidak pernah ditulis selama serialisasi ke file XML (seperti dalam "xsi:nil").

  3. Semua nilai non-null, termasuk default, selalu ditulis saat membuat serial ke XML. Operasi ini tidak seperti semantik XSD/XML ketika nilai null (xsi:nil) eksplisit dan nilai default-nya implisit (jika tidak ada dalam XML, parser yang memvalidasi bisa mendapatkannya dari skema XSD terkait). Kebalikannya berlaku untuk DataTable: nilai null adalah implisit dan nilai default-nya adalah eksplisit.

  4. Semua nilai kolom yang hilang untuk baris yang dibaca dari input XML ditetapkan NULL. Baris yang dibuat menggunakan NewRow atau metode serupa diberi nilai default DataColumn.

  5. Metode IsNull mengembalikan true untuk DbNull.Value dan INullable.Null.

Membandingkan Nilai Null dengan SqlTypes dan CLR Types

Saat membandingkan nilai null, penting untuk memahami perbedaan antara cara metode Equals mengevaluasi nilai null di System.Data.SqlTypes dibandingkan dengan cara kerjanya dengan jenis CLR. Semua metode System.Data.SqlTypesEquals menggunakan semantik basis data untuk mengevaluasi nilai null: jika salah satu atau kedua nilai adalah null, perbandingan akan menghasilkan null. Di sisi lain, menggunakan metode CLR Equals pada dua System.Data.SqlTypes akan menghasilkan true jika keduanya null. Operasi ini mencerminkan perbedaan antara menggunakan metode instans seperti metode CLR String.Equals, dan menggunakan metode statis/bersama, SqlString.Equals.

Contoh berikut menunjukkan perbedaan hasil antara metode SqlString.Equals dan metode String.Equals ketika masing-masing melewati sepasang nilai null dan kemudian sepasang string yang kosong.

    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={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));
    }

    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

Kode menghasilkan output berikut:

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

Lihat juga