Saya harus memperbaiki dan mendokumentasikan sejumlah foo.sql
pertanyaan yang akan dibagikan oleh tim dukungan teknis DB (untuk konfigurasi pelanggan dan hal-hal seperti itu). Ada beberapa jenis tiket yang datang secara teratur di mana setiap pelanggan memiliki server dan database mereka sendiri, tetapi jika tidak, skemanya sama di seluruh papan.
Prosedur tersimpan bukan merupakan pilihan saat ini. Saya berdebat apakah akan menggunakan dinamis atau SQLCMD, saya belum banyak menggunakan karena saya agak baru di SQL Server.
Skrip SQLCMD Saya merasa "terlihat" lebih bersih bagi saya, dan lebih mudah membaca dan membuat perubahan kecil pada permintaan yang diperlukan, tetapi juga memaksa pengguna untuk mengaktifkan mode SQLCMD. Dinamis lebih sulit karena penyorotan sintaksnya hilang karena kueri ditulis menggunakan manipulasi string.
Ini sedang diedit dan dijalankan menggunakan Management Studio 2012, SQL versi 2008R2. Apa saja pro / kontra dari salah satu metode, atau beberapa "praktik terbaik" SQL Server pada satu metode atau yang lain? Apakah salah satu dari mereka "lebih aman" dari yang lain?
Contoh dinamis:
declare @ServerName varchar(50) = 'REDACTED';
declare @DatabaseName varchar(50) = 'REDACTED';
declare @OrderIdsSeparatedByCommas varchar(max) = '597336, 595764, 594594';
declare @sql_OrderCheckQuery varchar(max) = ('
use {@DatabaseName};
select
-- stuff
from
{@ServerName}.{@DatabaseName}.[dbo].[client_orders]
as "Order"
inner join {@ServerName}.{@DatabaseName}.[dbo].[vendor_client_orders]
as "VendOrder" on "Order".o_id = "VendOrder".vco_oid
where "VendOrder".vco_oid in ({@OrderIdsSeparatedByCommas});
');
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@ServerName}', quotename(@ServerName) );
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@DatabaseName}', quotename(@DatabaseName) );
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@OrderIdsSeparatedByCommas}', @OrderIdsSeparatedByCommas );
print (@sql_OrderCheckQuery); -- For debugging purposes.
execute (@sql_OrderCheckQuery);
Contoh SQLCMD:
:setvar ServerName "[REDACTED]";
:setvar DatabaseName "[REDACTED]";
:setvar OrderIdsSeparatedByCommas "597336, 595764, 594594"
use $(DatabaseName)
select
--stuff
from
$(ServerName).$(DatabaseName).[dbo].[client_orders]
as "Order"
inner join $(ServerName).$(DatabaseName).[dbo].[vendor_client_orders]
as "VendOrder" on "Order".o_id = "VendOrder".vco_oid
where "VendOrder".vco_oid in ($(OrderIdsSeparatedByCommas));
sumber
use ...
naskah Anda? Apakah penting untuk eksekusi yang benar dari query selanjutnya? Saya bertanya karena jika mengubah basis data saat ini adalah salah satu hasil yang diharapkan dari permintaan Anda, versi SQL dinamis hanya akan mengubahnya dalam lingkup permintaan dinamis, bukan dalam lingkup luar, tidak seperti variasi SQLCMD (yang, dari tentu saja, hanya memiliki satu ruang lingkup).use
Pernyataan mungkin bisa ditinggalkan, karena ruang lingkup tidak akan berubah selama skrip tertentu lagian. Saya memiliki sejumlah kecil kasus penggunaan di mana akan ada pencarian lintas-server tapi itu mungkin berada di luar cakupan tulisan ini.Jawaban:
Hanya untuk mendapatkan ini:
Secara teknis, kedua opsi ini adalah "dinamis" / kueri ad hoc yang tidak diuraikan / divalidasi hingga diajukan. Dan keduanya rentan terhadap SQL Injection karena mereka tidak diparameterisasi (meskipun dengan skrip SQLCMD, jika Anda mengirimkan variabel dari skrip CMD maka Anda memiliki kesempatan untuk mengganti
'
dengan''
, yang mungkin atau mungkin tidak bekerja tergantung di mana variabel sedang digunakan).Ada pro dan kontra untuk setiap pendekatan:
Jika orang-orang pendukung Anda tidak melakukan kueri ad hoc dan hanya mengisi variabel-variabel itu, maka mereka tidak perlu berada di SSMS tempat mereka dapat mengedit skrip tersebut dan membuat perubahan yang tidak diinginkan.
Saya akan membuat skrip CMD untuk meminta pengguna untuk nilai variabel yang diinginkan dan kemudian memanggil SQLCMD.EXE dengan nilai-nilai itu. Skrip CMD bahkan bisa mencatat eksekusi ke file, lengkap dengan cap waktu dan nilai variabel yang dikirimkan.
Buat satu skrip CMD per skrip SQL dan letakkan di folder bersama jaringan. Pengguna mengklik dua kali pada skrip CMD dan hanya berfungsi.
Berikut ini contohnya:
%OrderIDsSeparatedByCommas%
sebagai variabel SQLCMD$(OrderIDsSeparatedByCommas)
Uji skrip SQL (bernama: FixProblemX.sql ):
Skrip CMD (bernama: FixProblemX.cmd ):
Pastikan untuk mengedit
ScriptLogPath
variabel di bagian atas skrip.Juga, skrip SQL (ditentukan oleh
-i
saklar baris perintah untuk SQLCMD.EXE ) mungkin mendapat manfaat dari memiliki jalur yang sepenuhnya memenuhi syarat, tetapi tidak sepenuhnya yakin.sumber