Saya mencoba membuat Pemicu, untuk mengubah susunan database pada pembuatannya, tetapi bagaimana saya bisa menangkap nama database untuk digunakan di dalam pelatuk?
USE master
GO
CREATE TRIGGER trg_DDL_ChangeCOllationDatabase
ON ALL SERVER
FOR CREATE_DATABASE
AS
declare @databasename varchar(200)
set @databasename =db_name()
ALTER DATABASE @databasename COLLATE xxxxxxxxxxxxxxxxxxx
GO
Jelas, ini tidak berhasil.
sql-server
sql-server-2008-r2
trigger
collation
ddl
SQL pembalap
sumber
sumber
Jawaban:
Anda tidak dapat, secara umum, mengeluarkan
ALTER DATABASE
dalam Pemicu (atau Transaksi apa pun yang memiliki pernyataan lain di dalamnya). Jika Anda berusaha, Anda akan mendapatkan kesalahan berikut:Alasan bahwa kesalahan ini tidak ditemukan dalam jawaban @ sp_BlitzErik adalah hasil dari kasus uji khusus yang disediakan: kesalahan yang ditunjukkan di atas adalah kesalahan run-time, sedangkan kesalahan yang ditemukan dalam jawabannya adalah kesalahan waktu kompilasi. Kesalahan waktu kompilasi mencegah eksekusi perintah dan karenanya tidak ada "run-time". Kita dapat melihat perbedaannya dengan menjalankan yang berikut ini:
Batch di atas akan error, sedangkan yang berikut tidak akan:
Ini memberi Anda dua opsi:
Melakukan Transaksi dalam Pemicu DDL sedemikian rupa sehingga tidak ada pernyataan lain dalam Transaksi. Ini bukan ide yang baik jika ada beberapa Pemicu DDL yang dapat dipecat oleh
CREATE DATABASE
pernyataan, dan mungkin ide yang buruk secara umum, tetapi itu berhasil ;-). Kuncinya adalah bahwa Anda juga perlu memulai Transaksi baru di Trigger SQL Server yang lain akan melihat bahwa nilai awal dan akhir untuk@@TRANCOUNT
tidak cocok dan akan menimbulkan kesalahan terkait dengan itu. Kode di bawah tidak hanya ini, dan juga hanya mengeluarkanALTER
jika Collation bukan yang diinginkan, jika tidak maka lompatanALTER
perintah.Uji dengan:
Gunakan SQLCLR untuk membuat biasa / eksternalSqlConnection
, denganEnlist = false;
di Connection Connection, untuk mengeluarkanALTER
perintah karena itu tidak akan menjadi bagian dari Transaksi.Tampaknya SQLCLR bukan benar-benar pilihan, meskipun bukan karena batasan spesifik SQLCLR. Entah bagaimana, mengetik " karena itu tidak akan menjadi bagian dari Transaksi " langsung di atas tidak cukup menyoroti fakta bahwa, pada kenyataannya, ada Transaksi aktif di sekitar
CREATE DATABASE
operasi. Masalahnya di sini adalah bahwa sementara SQLCLR dapat digunakan untuk melangkah keluar dari Transaksi saat ini, masih belum ada cara bagi Sesi lain untuk memodifikasi Database yang saat ini sedang dibuat sampai Transaksi awal tersebut dilakukan.Artinya, Sesi A menciptakan Transaksi untuk pembuatan Database dan penembakan Pemicu. Pemicu, menggunakan SQLCLR, akan membuat Sesi B untuk memodifikasi Database yang telah dibuat, tetapi Transaksi belum dilakukan sejak ditahan sampai Sesi B selesai, yang tidak bisa karena menunggu Transaksi awal untuk lengkap. Ini adalah jalan buntu, tetapi tidak dapat dideteksi seperti itu oleh SQL Server karena tidak tahu bahwa Sesi B dibuat oleh sesuatu dalam Sesi A. Perilaku ini dapat dilihat dengan mengganti bagian pertama dari
IF
pernyataan dalam contoh. di atas dalam # 1 dengan yang berikut:The
-t 15
saklar untuk SQLCMD set perintah / permintaan batas waktu sehingga tes tidak menunggu selamanya dengan batas waktu default. Tapi, Anda bisa mengaturnya menjadi lebih dari 15 detik dan di sesi lain periksasys.dm_exec_requests
untuk melihat semua pemblokiran yang indah terjadi ;-).Antri acara di suatu tempat yang kemudian akan membaca dari antrian itu dan jalankan
ALTER DATABASE
pernyataan yang sesuai . Ini akan memungkinkan untuk menyelesaikanCREATE DATABASE
pernyataan dan transaksinya, setelahALTER DATABASE
pernyataan dapat dieksekusi. Broker Layanan dapat digunakan di sini. ATAU, buat tabel, minta Pemicu menyisipkan ke dalam tabel itu, lalu minta pekerjaan SQL Server Agent memanggil Prosedur Tersimpan yang membaca dari tabel itu dan menjalankanALTER DATABASE
pernyataan dan kemudian menghapus catatan dari Tabel antrian.NAMUN, opsi di atas terutama disediakan untuk membantu dalam skenario di mana seseorang benar-benar perlu melakukan beberapa jenis
ALTER DATABASE
dalam Pemicu DDL. Dalam skenario khusus ini, jika Anda benar-benar tidak ingin database menggunakan sistem / Collation default tingkat Instance, maka Anda mungkin akan dilayani oleh:Setup.exe /Q /ACTION=Rebuilddatabase /INSTANCENAME=<instancename> /SQLCOLLATION=...
; opsi ini menciptakan kembali sistem DB, jadi Anda akan perlu untuk skrip keluar objek tingkat server, dll untuk membuat ulang nanti, ditambah menerapkan kembali tambalan, dll, MENYENANGKAN, MENYENANGKAN, MENYENANGKAN).Atau, untuk para petualang, ada opsi yang tidak terdokumentasi (yaitu tidak didukung, digunakan dengan risiko Anda sendiri tetapi beresiko sangat baik)
sqlservr.exe -q
yang memperbarui SEMUA DB dan kolom ALL (silakan lihat Mengubah Kolaborasi Instance, Basis Data, dan Semua Kolom di Semua Basis Data Pengguna: Apa yang Mungkin Salah? untuk deskripsi terperinci tentang perilaku opsi ini, serta potensi lingkup dampak).Terlepas dari opsi yang dipilih: selalu pastikan untuk memiliki cadangan
master
danmsdb
sebelum mencoba hal-hal seperti itu.Alasan yang sepadan dengan upaya untuk mengubah Collation default tingkat Server adalah bahwa Collation default Instance (yaitu Server-level) mengontrol beberapa area fungsional yang dapat menyebabkan perilaku tak terduga / tidak konsisten adalah semua orang mengharapkan operasi string berfungsi sepanjang garis Collation default untuk semua Database Pengguna Anda:
Kolasi Default untuk kolom string dalam tabel sementara. Ini adalah masalah hanya ketika membandingkan / Menyatukan dengan kolom string lain JIKA ada ketidakcocokan antara dua kolom string. Masalahnya di sini adalah bahwa ketika tidak menentukan Kolasi secara eksplisit melalui
COLLATE
kata kunci, kemungkinan besar (meskipun tidak dijamin) akan mengalami masalah.Ini bukan masalah untuk tipe data XML, variabel tabel, atau Database yang Terkandung.
Meta-data tingkat instan. Misalnya,
name
bidang dalamsys.databases
akan menggunakan Kolasi default tingkat Instance. Tampilan katalog sistem lain juga terpengaruh, tetapi saya tidak memiliki daftar lengkap.Meta-data tingkat basis data, seperti
sys.objects
dansys.indexes
, tidak terpengaruh.@variable
)GOTO
labelMisalnya, jika Instance-level Collation adalah case-insensitive sedangkan Collation-level Database adalah biner (yaitu diakhiri dengan
_BIN
atau_BIN2
), maka resolusi nama objek level-Database akan menjadi biner (misalnya[TableA] <> [tableA]
) namun nama variabel akan memungkinkan untuk case-insensitivity (misalnya@VariableA = @variableA
).sumber
Anda perlu menggunakan SQL dinamis, dan fungsi EVENTDATA () .
Cukup masukkan dalam koleksimu untuk yang palsu .
Sekarang ketika saya membuat database ...
Saya mendapatkan pesan ini (dari cetakan):
Perhatikan bahwa jika basis data lain (termasuk tempdb) menggunakan kumpulan yang berbeda, Anda dapat mengalami masalah ketika membandingkan data string. Anda harus menambahkan klausa COLLATE ke perbandingan string di mana casing atau aksen penting, dan bahkan ketika mereka tidak Anda dapat menekan kesalahan. Pertanyaan terkait di mana saya mengalami masalah kode serupa di sini .
sumber
Anda tidak bisa
ALTER DATABASE
dalam pemicu. Anda harus kreatif dengan evaluasi dan koreksi. Sesuatu seperti:Meskipun Anda tidak harus menggunakan sp_MSforeachdb .
sumber