Apakah ada cara untuk memaksa Resolusi Nama Tangguhan bahkan jika tabel ada saat membuat prosedur tersimpan?

10

Saat membuat prosedur tersimpan dalam SQL Server, Anda diizinkan untuk merujuk ke tabel yang tidak ada. Tetapi, jika tabel benar-benar ada, maka kolom apa pun yang Anda rujuk dalam prosedur harus ada dalam tabel tersebut ( Resolusi Nama Tangguhan ).

Apakah mungkin untuk menginstruksikan SQL Server untuk menunda resolusi nama semua tabel yang dirujuk dalam prosedur terlepas dari apakah mereka ada atau tidak? Saya ingin tetap memeriksa sintaksis secara umum, jadi walaupun itu mungkin, meretas definisi prosedur tersimpan ke dalam tabel sistem bukanlah suatu pilihan.

Saya berharap permintaan saya untuk melakukan ini mungkin tampak sedikit aneh , jadi inilah beberapa latar belakang: Saya otomatis menghasilkan definisi tabel dan prosedur tersimpan dari aplikasi yang ditulis dalam C # dan sangat sulit bagi saya untuk mengubah kode untuk memesan perubahan sesuai kebutuhan SQL mereka. Kode saya "menjamin" bahwa skema tersebut konsisten dalam suatu transaksi, tetapi saat ini saya tidak dapat menjamin bahwa kolom tabel didefinisikan sebelum saya mendefinisikan prosedur tersimpan yang merujuknya.

Di bawah ini adalah contoh kanonik dari SQL yang dibuat oleh C # yang "menggambarkan" masalah yang saya coba selesaikan.

--Say this table already exists.
CREATE TABLE myTable
(
    a NVARCHAR(MAX)
)
GO

--My C# code creates something like this
BEGIN TRAN 
GO

--the stored procedure gets generated first.
CREATE PROCEDURE mySproc
AS
BEGIN
    SELECT a,b FROM myTable
END

--then the table update
ALTER TABLE myTable
    ADD b nvarchar(MAX)

COMMIT TRAN 

Hal ini mungkin bagi saya untuk memperbaiki ini dalam kode C #, tapi aku berharap untuk sederhana "ajaib" tweak saya bisa menarik SQL. Ini akan menghemat banyak waktu untuk saya.

Daniel James Bryars
sumber
1
Tidak bisakah Anda memproses semua perubahan skema sebelum membuat / mengubah prosedur apa pun? Mengapa prosedur harus ada sebelum tabel benar?
Aaron Bertrand
Saya mencari opsi itu dalam kode sekarang. Cara SQL dihasilkan cukup rumit (itu contoh sederhana) tapi sepertinya tidak akan sebanyak PITA seperti yang saya kira.
Daniel James Bryars
2
Anda dapat mengatasinya tentu saja dengan mengisi prosedur tersimpan Anda yang penuh dengan SQL dinamis - tetapi saya tidak dapat membayangkan membuat skrip Anda untuk menangani perubahan skema maka prosedur yang tersimpan akan sangat sulit. Tidak terlalu banyak opsi yang terbuka untuk menentukan cara kerja resolusi nama yang ditunda. Satu-satunya proposal pada buku-buku yang saya tahu, atau setidaknya saya dapat menyimpulkan bahwa mereka tertarik untuk menghibur, sebenarnya adalah cara lain - membuatnya LEBIH ketat - lihat sommarskog.se/strict_checks.html ).
Aaron Bertrand
Ide bagus tentang SQL dinamis. Saya memiliki masalah yang sama untuk Pemicu, Indeks, Tampilan, Sprocs, dan Fungsi. Tapi saya telah mengubah kode sehingga hanya membuat perubahan pada Tabel, lalu Indeks, lalu Pemicu, lalu fungsi, lalu sprocs.
Daniel James Bryars
Saya suka saran sommarskog, pasti akan membantu menghindari bug. Jika mereka benar-benar mengimplementasikan opsi Strict, maka mereka juga dapat mengevaluasi kembali semua sprocs "Strict ON" ketika ada perubahan tabel untuk melihat apakah ia merusak sprocs yang ada - jelas Anda akan perlu memiliki "transaksi logis pada DDL" sehingga Anda kemudian dapat mengubah Tabel dan Sprocs sebagai satu unit.
Daniel James Bryars

Jawaban:

6

Tidak.

Aku merasa sangat bersalah hanya mengetik itu, tapi tidak, sayangnya. Itulah pertama kalinya saya mendengar tentang use case ini, dan itu masuk akal. Cara terbaik untuk mengirimkan permintaan itu di http://connect.microsoft.com dan cucu Anda akan dapat melakukannya. ;-)

Brent Ozar
sumber
5

Jika Anda masih tertarik, ada solusi potensial yang dapat Anda gunakan. Berikut adalah kode yang diperbarui, yang memperkenalkan #deferResolutiontabel sementara untuk setiap permintaan dalam prosedur. Karena tabel sementara hanya akan ada saat runtime, prosedur ini dapat mengkompilasi meskipun kolom yang tepat belum ada myTable.

Anda bahkan akan mendapatkan rencana eksekusi yang sama (tidak ada referensi ke #deferResolutiontabel) untuk setiap pernyataan dalam prosedur karena cara pengoptimal kueri dapat membuktikan ini WHERE NOT EXISTSselalu dinilai benar.

Semua yang mengatakan, ini adalah hack mengerikan yang disajikan sebagian besar untuk kepentingan intelektual dan mungkin ada kasus tepi di mana ia rusak. Seperti yang disebutkan Harun, Anda mungkin akan lebih baik membuat semua perubahan skema Anda dalam urutan yang tepat.

--Say this table already exists.
CREATE TABLE myTable
(
    a NVARCHAR(MAX)
)
GO

--My C# code creates something like this
BEGIN TRAN 
GO

--the sproc gets generated first.
CREATE PROCEDURE mySproc
AS
BEGIN
    CREATE TABLE #deferResolution (dummy INT NOT NULL)
    SELECT a,b FROM myTable WHERE NOT EXISTS (SELECT * FROM #deferResolution WHERE 0=1)
END

--then the table update
ALTER TABLE myTable
    ADD b nvarchar(MAX)

COMMIT TRAN 
Geoff Patterson
sumber