Jika Anda pernah berada dalam situasi di mana Anda perlu mengaktifkan kembali CHECK
kendala yang sebelumnya telah dinonaktifkan, Anda harus memastikan bahwa Anda tahu apa yang Anda lakukan.
Secara khusus, Anda harus memahami perbedaan antara WITH NOCHECK
dan WITH CHECK
argumen.
Argumen ini dapat digunakan pada saat Anda mengaktifkan batasan. Mereka menentukan apakah data yang ada divalidasi terhadap Anda yang diaktifkan kembali (atau baru ditambahkan) CHECK
paksaan. Pada dasarnya Anda memiliki opsi untuk memeriksa semua data yang ada untuk setiap pelanggaran terhadap batasan. Jika Anda tidak menentukan apa pun, data yang ada tidak akan diperiksa. Itulah mengapa penting untuk memahami cara kerjanya.
Omong-omong, argumen ini juga berlaku untuk batasan kunci asing.
Seperti yang Anda harapkan, WITH CHECK
menentukan bahwa data yang ada divalidasi dan WITH NOCHECK
menentukan bahwa itu tidak. Standarnya adalah WITH NOCHECK
.
Jika Anda menggunakan WITH NOCHECK
, batasan akan ditandai sebagai tidak tepercaya. Sebenarnya, ini ditandai sebagai tidak tepercaya saat Anda menonaktifkan batasan. Tetapi ketika Anda mengaktifkannya kembali, itu akan tetap tidak dipercaya kecuali Anda menggunakan WITH CHECK
. Dengan kata lain, jika Anda ingin menyatakan kembali "kepercayaan", Anda harus secara eksplisit menentukan ini.
Dengan kata lain:
- Bila Anda menggunakan
WITH NOCHECK
, batasan akan tetap tidak dipercaya. - Bila Anda menggunakan
WITH CHECK
itu akan menjadi tepercaya, tetapi hanya jika semua data yang ada sesuai dengan batasan. Jika ada data yang melanggar batasan, batasan tidak akan diaktifkan dan Anda akan menerima pesan kesalahan.
Tentu saja, ketika saya mengatakan "semua data yang ada", saya hanya mengacu pada data yang batasannya berlaku.
Mungkin ada skenario di mana Anda dengan sengaja menonaktifkan batasan karena Anda harus memasukkan data yang melanggar batasan. Dalam kasus seperti itu, jika data yang tidak valid harus tetap berada di database, Anda harus menggunakan WITH NOCHECK
jika Anda ingin mengaktifkan kembali batasan. Ini akan memungkinkan Anda untuk mengaktifkan batasan tanpa ada data yang menghalangi.
Di bawah ini adalah contoh yang menunjukkan hal ini.
Contoh 1 – Tinjau Periksa Batasan
Pertama, mari kita gunakan sys.check_constraints
untuk melihat semua CHECK
batasan dalam database saat ini.
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Hasil:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Kita dapat melihat bahwa semuanya diaktifkan dan dipercaya (karena semuanya memiliki nol di is_disabled dan is_not_trusted kolom).
Untuk artikel ini, saya akan menonaktifkan dan mengaktifkan kembali chkJobTitle kendala.
Contoh 2 – Nonaktifkan Batasan
Di sini, saya menonaktifkan chkJobTitle kendala:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Selesai.
Sekarang mari kita tinjau kembali semua kendala:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Hasil:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 1 | 1 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Kami dapat melihat bahwa itu telah dinonaktifkan (karena is_disabled kolom disetel ke 1 ).
Anda mungkin memperhatikan bahwa
is_not_trusted
kolom juga disetel ke
1
. Ini menunjukkan bahwa CHECK
batasan belum diverifikasi oleh sistem untuk semua baris.
Seperti disebutkan, sebuah CHECK
kendala hanya dapat dipercaya jika semua data telah berhasil melewati kondisi kendala. Saat kami menonaktifkan batasan, ini membuka potensi data yang tidak valid untuk masuk ke database. Oleh karena itu, kami tidak dapat 100% yakin bahwa semua data valid, sehingga batasan ditandai sebagai tidak tepercaya.
Cara untuk memastikan kendala dipercaya lagi adalah dengan mengaktifkannya kembali menggunakan WITH CHECK
argumen. Ini akan menyebabkan batasan untuk memeriksa semua data sebelum diaktifkan kembali. Jika ada data yang tidak valid, itu tidak akan dapat diaktifkan kembali. Anda harus memperbarui data agar valid, atau mengaktifkan kembali batasan menggunakan WITH NOCHECK
sebagai gantinya (yang akan menyebabkan kendala tetap tidak dipercaya).
Contoh 3 – Aktifkan Batasan menggunakan Pengaturan Default (DENGAN NOCHECK)
Mari aktifkan kembali batasan dan jalankan kueri lagi.
Untuk mengaktifkan batasan, saya akan malas dan menggunakan pengaturan default:
ALTER TABLE Occupation CHECK CONSTRAINT chkJobTitle;
Sekarang verifikasi perubahannya:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Hasil:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 1 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Apakah Anda melihat apa yang baru saja terjadi? Meskipun saya mengaktifkan batasan lagi, itu masih tidak dipercaya.
Ini karena saya malas (atau mungkin hanya pelupa) ketika saya mengaktifkan kendala. Ketika saya mengaktifkan batasan, saya lupa menentukan WITH CHECK
. Standarnya adalah WITH NOCHECK
yang berarti bahwa data yang ada tidak diperiksa saat mengaktifkan kembali batasan.
Inilah sebabnya mengapa Anda harus benar-benar tahu apa yang Anda lakukan saat mengaktifkan CHECK
(dan FOREIGN KEY
) kendala. Dengan malas dan tidak secara eksplisit menentukan pengaturan yang berpotensi penting, kami memberikan izin kepada SQL Server untuk menutup mata terhadap masalah apa pun dengan data yang ada.
Namun, jika seluruh alasan Anda perlu menonaktifkan batasan adalah untuk memasukkan data yang melanggar batasan, maka default WITH NOCHECK
mungkin yang Anda inginkan.
Omong-omong, untuk batasan baru, defaultnya adalah WITH CHECK
.
Tetapi dalam kasus saya, saya tidak memasukkan atau memperbarui apa pun data setelah menonaktifkan kendala, jadi jika sebelumnya dapat dipercaya, sekarang harus tetap dapat dipercaya.
Jadi bagaimana saya bisa membuat batasan saya dipercaya lagi?
Contoh 4 – Aktifkan Batasan menggunakan WITH CHECK
Jika saya ingin batasan saya dipercaya lagi, saya perlu secara eksplisit menentukan WITH CHECK
saat mengaktifkannya kembali.
Mari kita nonaktifkan kendala lagi:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Jadi sekarang saya kembali ke tempat saya sebelum saya mengaktifkannya kembali.
Apa yang seharusnya saya lakukan ketika saya mengaktifkannya kembali adalah ini:
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Sekarang lihat lagi batasannya:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Hasil:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Fiuh! Batasan saya dapat dipercaya sekali lagi.
Contoh 5 – Aktifkan Batasan CHECK dengan Data Tidak Valid
Tentu saja kendala saya hanya dipercaya lagi karena saya tidak memasukkan data yang tidak valid saat dinonaktifkan. Jika saya melakukan ini, saya tidak akan dapat mengaktifkannya menggunakan WITH CHECK
, seperti yang ditunjukkan di bawah ini.
Jika saya menonaktifkannya lagi:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Sekarang masukkan data yang tidak valid (dan kembalikan hasilnya):
INSERT INTO Occupation VALUES ( 7, 'Digital Nomad' ); SELECT OccupationId, JobTitle FROM Occupation;
Hasil:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Digital Nomad | +----------------+-----------------+
Jadi kami berhasil memasukkan data yang tidak valid (baris terakhir).
Ini tidak valid karena definisi batasan berjalan sebagai berikut:([JobTitle]<>'Digital Nomad')
Artinya
JobTitle
kolom tidak boleh berisi teks Digital Nomad
.
Sekarang mari kita coba aktifkan kembali CHECK
kendala menggunakan WITH CHECK
dan lihat apa yang terjadi.
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Hasil:
Msg 547, Level 16, State 0, Line 1 The ALTER TABLE statement conflicted with the CHECK constraint "chkJobTitle". The conflict occurred in database "Test", table "dbo.Occupation", column 'JobTitle'.
Jadi kami tidak dapat mengaktifkan kembali batasan menggunakan WITH CHECK
sementara kita punya data di tabel yang melanggar CHECK
paksaan. Entah kita perlu memperbarui data atau kita perlu menggunakan WITH NOCHECK
(atau cukup hilangkan sama sekali).
Mari kita coba lagi menggunakan WITH NOCHECK
.
ALTER TABLE Occupation WITH NOCHECK CHECK CONSTRAINT chkJobTitle;
Hasil:
Commands completed successfully. Total execution time: 00:00:00.015
Jadi kita bisa berhasil mengaktifkan kendala jika kita tidak memeriksa data yang ada.
Tentu saja, dalam hal ini CHECK
kendala masih belum dipercaya. Jika kita ingin batasan dipercaya, kita perlu memperbarui data agar tidak melanggar batasan.
Contoh:
UPDATE Occupation SET JobTitle = 'Unemployed' WHERE OccupationId = 7; SELECT OccupationId, JobTitle FROM Occupation;
Hasil:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Unemployed | +----------------+-----------------+
Sekarang kita dapat mengubah CHECK
kendala untuk dipercaya kembali.
Mari kita lakukan ketiganya bersama-sama:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle; ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle; SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Hasil:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Jadi sekarang batasan kami diaktifkan dan dipercaya sekali lagi, dan database kami bebas dari digital nomad!