Bagikan melalui


Menangani Nilai Null

Nilai null dalam database relasional digunakan saat nilai dalam kolom tidak diketahui atau hilang. Null bukan string kosong (untuk jenis data karakter atau tanggalwaktu) 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. Masing-masing jenis data di System.Data.SqlTypes memiliki propertinya sendiri IsNull dan Null nilai yang dapat ditetapkan ke instans jenis data tersebut.

Nota

.NET Framework versi 2.0 memperkenalkan dukungan untuk tipe nilai nullable, yang memungkinkan programmer memperluas tipe nilai untuk mewakili semua nilai dasar. Jenis nilai CLR yang dapat bernilai null ini mewakili sebuah instans struktur Nullable. Kemampuan ini sangat berguna ketika jenis nilai dikemas dan dibuka kemasannya, meningkatkan kompatibilitas dengan jenis objek. Tipe nilai clr nullable tidak ditujukan untuk penyimpanan database null karena ANSI SQL null tidak bertingkah sama seperti null referensi (atau Nothing di Visual Basic). Untuk bekerja dengan nilai null ANSI SQL database, gunakan System.Data.SqlTypes null daripada Nullable. Untuk informasi selengkapnya tentang bekerja dengan nilai CLR jenis nullable di Visual Basic lihat Jenis Nilai Nullable, dan untuk C# lihat Jenis nilai nullable.

Nilai Null dan Logika Three-Valued

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

  • Benar

  • Tidak benar

  • Tidak dikenal

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

Null dan SqlBoolean

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

Tabel Kebenaran

Memahami Opsi ANSI_NULLS

System.Data.SqlTypes menyediakan semantik yang sama seperti ketika opsi ANSI_NULLS diatur 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 kekosongan bawaan dalam database dan penilaian 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 tidak diketahui ketika ANSI_NULLS aktif:

colname > NULL  

Perbandingan dengan variabel yang berisi nilai null juga menghasilkan nilai yang tidak diketahui.

colname > @MyVariable  

Gunakan predikat IS NULL atau IS NOT NULL untuk menguji nilai null. Ini dapat menambahkan kompleksitas ke klausa WHERE. Misalnya, kolom TerritoryID dalam tabel Pelanggan AdventureWorks memungkinkan nilai null. Jika pernyataan SELECT adalah menguji nilai null selain yang lain, pernyataan TERSEBUT 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 mengatur ANSI_NULLS nonaktif di SQL Server, Anda dapat membuat ekspresi yang menggunakan operator kesetaraan untuk dibandingkan dengan null. Namun, Anda tidak dapat mencegah koneksi yang berbeda mengatur opsi null untuk koneksi tersebut. Menggunakan IS NULL untuk menguji nilai null selalu berfungsi, terlepas dari pengaturan ANSI_NULLS untuk koneksi.

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

Menetapkan Nilai Null

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

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

DBNull.Value
Penugasan ini berlaku untuk DataColumn jenis apa pun. Jika tipe mengimplementasikan INullable, DBNull.Value diubah ke dalam nilai Null bertipe kuat yang sesuai.

SqlType.Null
Semua jenis data System.Data.SqlTypes mengimplementasikan INullable. Jika nilai null yang bertipe kuat dapat dikonversi menjadi jenis data kolom menggunakan operator cast implisit, penugasan seharusnya berhasil. Jika tidak, pengecualian cast tidak valid akan muncul.

null
Jika 'null' adalah nilai yang sah untuk jenis data yang diberikan DataColumn, itu diubah ke dalam yang sesuai 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 hal ini, jika nilai null bertipe kuat yang terkait dengan kelas turunan ditetapkan, nilai tersebut disimpan sebagai tidak bertipe DbNull.Value, karena penyimpanan null selalu konsisten dengan tipe data DataColumn.

Nota

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

Nilai default untuk instans apa pun System.Data.SqlTypes adalah null.

Null di System.Data.SqlTypes adalah jenis-spesifik dan tidak dapat diwakili oleh satu nilai, 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 SqlTypes variabel 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 melakukan iterasi 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  

Penetapan Beberapa Kolom (Baris)

DataTable.Add, DataTable.LoadDataRow, atau API lain yang dapat menerima ItemArray yang dipetakan ke baris, petakan 'null' dengan nilai default DataColumn. Jika objek dalam array berisi DbNull.Value atau padanan bertipe kuat, aturan yang sama seperti yang dijelaskan di atas diterapkan.

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

  1. Nilai default adalah DbNull.Value untuk semua, kecuali kolom null bertipe kuat di mana nilainya adalah nilai null bertipe kuat yang tepat.

  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 menserialisasikan ke XML. Ini tidak seperti semantik XSD/XML di mana nilai null (xsi:nil) eksplisit dan nilai defaultnya implisit (jika tidak ada di XML, pengurai validasi bisa mendapatkannya dari skema XSD terkait). Sebaliknya berlaku untuk DataTable: nilai null adalah implisit dan nilai defaultnya 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 kedua DbNull.Value dan INullable.Null.

Membandingkan Nilai Null dengan SqlTypes dan tipe CLR

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. System.Data.SqlTypes Equals Semua metode menggunakan semantik database untuk mengevaluasi nilai null: jika salah satu atau kedua nilai null, perbandingan menghasilkan null. Di sisi lain, menggunakan metode CLR Equals pada dua System.Data.SqlTypes akan menghasilkan true jika keduanya null. 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 SqlString.Equals metode dan String.Equals metode ketika masing-masing diteruskan sepasang nilai null dan kemudian sepasang string 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={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

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