Bagaimana cara menyiram buffer PRINT dalam TSQL?

220

Saya memiliki prosedur tersimpan yang sangat lama berjalan di SQL Server 2005 yang saya coba debug, dan saya menggunakan perintah 'cetak' untuk melakukannya. Masalahnya adalah, saya hanya mendapatkan pesan kembali dari SQL Server di akhir sproc saya - Saya ingin dapat menyiram buffer pesan dan melihat pesan-pesan ini segera selama runtime sproc, daripada di bagian paling awal akhir.

Erik Forbes
sumber
1
Hanya pemberitahuan singkat untuk orang-orang yang (seperti saya) akan berpikir jawabannya tidak berfungsi untuk mereka: pastikan untuk beralih ke tab "Pesan" ketika kueri berjalan. Secara default Anda akan melihat tab "Hasil".
Tomasz Gandor

Jawaban:

305

Gunakan RAISERRORfungsinya:

RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT

Anda seharusnya tidak sepenuhnya mengganti semua cetakan Anda dengan raiserror. Jika Anda memiliki loop atau kursor besar di suatu tempat, lakukan sekali atau dua kali per iterasi atau bahkan setiap beberapa iterasi.

Juga: Saya pertama kali belajar tentang RAISERROR di tautan ini, yang sekarang saya anggap sebagai sumber definitif penanganan SQL Server Error dan pasti patut dibaca:
http://www.sommarskog.se/error-handling-I.html

Joel Coehoorn
sumber
41
Perhatikan bahwa TRY / CATCH di SQL hanya akan menangkap kesalahan dengan tingkat keparahan> 10, jadi menggunakan RAISERROR dengan cara ini tidak akan masuk ke pernyataan CATCH Anda. Yang hebat, karena itu berarti Anda masih dapat menggunakan RAISERROR seperti ini dengan TRY / CATCH. ref: msdn.microsoft.com/en-us/library/ms175976.aspx
Rory
13
Perhatikan bahwa ini tidak berfungsi setelah 500 pesan pertama; setelah Anda mencetak lebih dari itu tiba-tiba mulai buffering!
GendoIkari
@ MahmoudMoravej Tidak, saya masih menjalankan proses yang berjalan lama menggunakan RAISEERROR, dan hanya berurusan dengan kenyataan bahwa setelah beberapa saat, pesan mulai mendapatkan buffered. Tampaknya satu-satunya solusi adalah menggunakan alat yang berbeda selain SSMS.
GendoIkari
1
Saya pikir ini adalah sesuatu yang berubah di versi SS terbaru. Di masa lalu ketika saya pertama kali menulis ini, kami menggunakan RAISERROR untuk pencatatan ekstensif proses batch semalam dengan lebih dari 500 pesan, dan itu tidak masalah. Tapi banyak yang bisa berubah dalam 7 tahun.
Joel Coehoorn
1
Atas pemberitahuan @ GendoIkari. Saya sudah mencobanya dengan ssms dari 2016SP1 dengan skrip ini. Pada 500 ia beralih ke buffer 50 baris dan pada 1k beralih ke 100 baris masing-masing. Ini berlanjut setidaknya sampai 2k, tetapi kemudian saya menghentikan skrip. menyatakan @ i int set @ i = 0 menyatakan @ t varchar (100) sementara 1 = 1 mulai mengatur @ i = @ i + 1 set @ t = 'print' + convert (varchar, @i) RAISERROR (@t, 10 , 1) DENGAN SEKARANG menunggu penundaan '00: 00: 00.010 'akhir
Zartag
28

Membangun jawaban oleh @ JoelCoehoorn, pendekatan saya adalah meninggalkan semua pernyataan PRINT saya di tempat, dan cukup ikuti mereka dengan pernyataan RAISERROR untuk menyebabkan flush.

Sebagai contoh:

PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT

Keuntungan dari pendekatan ini adalah bahwa pernyataan PRINT dapat menggabungkan string, sedangkan RAISERROR tidak bisa. (Jadi bagaimanapun Anda memiliki jumlah baris kode yang sama, seperti Anda harus mendeklarasikan dan mengatur variabel untuk digunakan dalam RAISERROR).

Jika, seperti saya, Anda menggunakan AutoHotKey atau SSMSBoost atau alat yang setara, Anda dapat dengan mudah mengatur pintasan seperti "] flush" untuk memasukkan baris RAISERROR untuk Anda. Ini menghemat waktu Anda jika itu adalah baris kode yang sama setiap kali, yaitu tidak perlu dikustomisasi untuk menampung teks atau variabel tertentu.

Mike
sumber
6
Catatan yang RAISERROR()mendukung printf()interpolasi string gaya. Misalnya, jika @MyVariableNameadalah jenis stringish (misalnya, VARCHAR(MAX), NVARCHAR(MAX), dll), Anda dapat menggunakan RAISERROR()dengan satu baris: RAISERROR(N'MyVariableName: %s', 0, 1, @MyVariableName).
binki
Ini sangat nyaman! Saya tahu bahwa RAISERROR dapat melakukan beberapa penggantian sederhana, tetapi cobalah mengganti waktu [tanggal], atau memanggil fungsi dari dalam pernyataan RAISERROR! Jawaban ini memberi Anda FLUSH sederhana dalam bentuk meningkatkan kesalahan kosong (dengan biaya baris baru).
Tomasz Gandor
19

Ya ... Parameter pertama dari fungsi RAISERROR membutuhkan variabel NVARCHAR. Jadi coba yang berikut ini;

-- Replace PRINT function
DECLARE @strMsg NVARCHAR(100)
SELECT @strMsg = 'Here''s your message...'
RAISERROR (@strMsg, 0, 1) WITH NOWAIT

ATAU

RAISERROR (n'Here''s your message...', 0, 1) WITH NOWAIT
tcbrazil
sumber
10
Lihat tab Pesan di bagian bawah, di sebelah tab Hasil atau alihkan ke mode Hasil Ke Teks.
Mehmet Ergut
Untuk beralih ke hasil ke mode Teks, di SSMS, Alat menu -> Pilihan -> Hasil Kueri -> SQL Server -> Umum -> Tujuan Default untuk Hasil, dan pilih "Hasil ke Teks" daripada "Hasil ke Grid", ulang -Buka jendela permintaan dan kemudian Anda tidak akan duduk di sana melihat tab Hasil kosong seperti boneka sementara output RAISERROR pergi ke tab Pesan.
Adam
12

Pilihan lain yang lebih baik adalah untuk tidak bergantung pada PRINT atau RAISERROR dan hanya memuat pernyataan "cetak" Anda ke tabel Temp ## di TempDB atau tabel permanen di database Anda yang akan memberi Anda visibilitas ke data segera melalui pernyataan SELECT dari jendela lain . Ini yang terbaik bagi saya. Menggunakan tabel permanen kemudian juga berfungsi sebagai log untuk apa yang terjadi di masa lalu. Pernyataan cetak berguna untuk kesalahan, tetapi menggunakan tabel log Anda juga dapat menentukan titik kegagalan yang tepat berdasarkan nilai log terakhir untuk eksekusi tertentu (dengan asumsi Anda melacak waktu mulai eksekusi keseluruhan dalam tabel log Anda.)

Eric Isaacs
sumber
2
Ini mungkin menjadi masalah jika Anda menulis skrip transaksional yang benar dengan komit dan kembalikan. Saya tidak percaya Anda akan dapat meng-query tabel temp Anda langsung - dan itu akan hilang jika transaksi Anda gagal.
SteveJ
@SteveJ Anda dapat menanyakannya langsung dengan menggunakan SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;sesi pemantauan Anda
TheConstructor
1
@TheConstructor; Itu adalah tip yang membantu - saya akan memanfaatkannya, terima kasih. Namun, bukankah kita masih pergi dengan meja temp pergi di rollback? Jika melakukan analisis kegagalan, sepertinya itu akan menjadi kekurangan besar.
SteveJ
1
@ SeveJ ya, pasti ada ini. Anda tentu saja dapat menyalin data dalam READ UNCOMMITTEDtransaksi ke tabel lain, tetapi Anda mungkin melewatkan momen sebelumnya ROLLBACK. Jadi itu mungkin memecahkan 'seberapa jauh?' bukan 'kenapa kembalikan?'
TheConstructor
4

Hanya untuk referensi, jika Anda bekerja dalam skrip (pemrosesan batch), tidak dalam prosedur tersimpan , output pembilasan dipicu oleh perintah GO, misalnya

print 'test'
print 'test'
go

Secara umum, kesimpulan saya adalah sebagai berikut: output dari eksekusi skrip mssql, mengeksekusi dalam SMS GUI atau dengan sqlcmd.exe, dihapus ke file, stdoutput, jendela gui pada pernyataan GO pertama atau sampai akhir skrip.

Pembilasan di dalam fungsi prosedur yang tersimpan berbeda, karena Anda tidak dapat menempatkan GO di dalamnya.

Referensi: Pernyataan tsql Go

Robert Lujo
sumber
2
gotidak hanya menyiram output, itu mengakhiri batch sesuai tautan yang Anda berikan. Apa pun yang Anda declaredibuang, jadi tidak dapat digunakan untuk debugging. declare @test int print "I want to read this!" go set @test=5meskipun Anda mengklaim kesalahan @testtidak terdefinisi karena ada dalam batch baru.
asontu
1
Saya setuju, ini bukan jawaban yang tepat untuk pertanyaan ini, tetapi saya meletakkan jawabannya (lihat disclaimer di awal) karena ini bisa berguna untuk orang lain - misalnya seseorang yang menjalankan batch sql.
Robert Lujo