ฉันจะล้างบัฟเฟอร์ PRINT ใน TSQL ได้อย่างไร


220

ฉันมีกระบวนงานที่เก็บไว้นานมากใน SQL Server 2005 ที่ฉันพยายามตรวจแก้จุดบกพร่องและฉันใช้คำสั่ง 'พิมพ์' เพื่อทำ ปัญหาคือฉันเพิ่งได้รับข้อความกลับจาก SQL Server ในตอนท้ายสุดของ sproc ของฉัน - ฉันต้องการที่จะสามารถล้างบัฟเฟอร์ข้อความและดูข้อความเหล่านี้ทันทีในช่วงรันไทม์ของ sproc มากกว่าที่ ปลาย


1
เพียงแจ้งให้ทราบสั้น ๆ สำหรับผู้ที่จะ (เหมือนฉัน) คิดว่าคำตอบไม่ได้สำหรับพวกเขา: อย่าลืมสลับไปที่แท็บ "ข้อความ" เมื่อคำค้นหากำลังทำงาน โดยค่าเริ่มต้นคุณจะเห็นแท็บ "ผลลัพธ์"
Tomasz Gandor

คำตอบ:


305

ใช้RAISERRORฟังก์ชั่น:

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

คุณไม่ควรแทนที่งานพิมพ์ทั้งหมดด้วย raiserror หากคุณมีลูปหรือเคอร์เซอร์ขนาดใหญ่ที่ใดที่หนึ่งให้ทำหนึ่งครั้งหรือสองครั้งต่อการทำซ้ำหรือแม้กระทั่งการทำซ้ำหลาย ๆ ครั้ง

นอกจากนี้: ฉันได้เรียนรู้เกี่ยวกับ RAISERROR เป็นครั้งแรกที่ลิงก์นี้ซึ่งตอนนี้ฉันพิจารณาแหล่งข้อมูลที่ชัดเจนเกี่ยวกับการจัดการข้อผิดพลาดของ SQL Server และควรอ่าน:
http://www.sommarskog.se/error-handling-I.html


41
โปรดทราบว่า TRY / CATCH ใน SQL จะตรวจจับข้อผิดพลาดที่มีความรุนแรง> 10 เท่านั้นดังนั้นการใช้ RAISERROR ด้วยวิธีนี้จะไม่ข้ามไปยังคำสั่ง CATCH ของคุณ มันเยี่ยมมากเพราะคุณยังสามารถใช้ RAISERROR แบบนี้กับ TRY / CATCH ได้ ref: msdn.microsoft.com/en-us/library/ms175976.aspx
Rory

13
โปรดทราบว่าสิ่งนี้ไม่ทำงานหลังจาก 500 ข้อความแรก เมื่อคุณพิมพ์มากกว่านั้นมันก็เริ่มบัฟเฟอร์ทันที!
GendoIkari

@MahmoudMoravej ไม่ฉันยังคงใช้กระบวนการที่ใช้เวลานานโดยใช้ RAISEERROR และเพิ่งจัดการกับความจริงที่ว่าหลังจากนั้นไม่นานข้อความก็เริ่มถูกบัฟเฟอร์ ดูเหมือนว่าทางออกเดียวที่จะใช้เครื่องมืออื่นนอกเหนือจาก SSMS
GendoIkari

1
ฉันคิดว่านี่เป็นสิ่งที่เปลี่ยนแปลงใน SS เวอร์ชันล่าสุด ย้อนกลับไปเมื่อฉันเขียนสิ่งนี้เป็นครั้งแรกเราใช้ RAISERROR สำหรับการบันทึกอย่างละเอียดของกระบวนการแบทช์ข้ามคืนที่มีข้อความมากกว่า 500 ข้อความและนั่นก็ไม่ใช่ปัญหา แต่จำนวนมากสามารถเปลี่ยนแปลงได้ใน 7 ปี
Joel Coehoorn

1
ตามที่แจ้งให้ทราบ @ GendoIkari ฉันได้ลองใช้ ssms จาก 2016SP1 ด้วยสคริปต์นี้แล้ว ที่ 500 จะเปลี่ยนเป็นบัฟเฟอร์ 50 บรรทัดและที่ 1k จะเปลี่ยนเป็น 100 บรรทัดแต่ละรายการ อย่างน้อยก็ดำเนินต่อไปจนถึง 2k แต่หลังจากนั้นฉันก็หยุดสคริปต์ ประกาศ @i int set @i = 0 ประกาศ @t varchar (100) ในขณะที่ 1 = 1 เริ่มตั้ง @i = @i + 1 ชุด @t = 'พิมพ์' + แปลง (varchar, @i) RAISERROR (@t, 10 , 1) ด้วย NOWAIT รอการหน่วงเวลา '00: 00: 00.010 'สิ้นสุด
Zartag

28

การสร้างคำตอบโดย @JoelCoehoorn วิธีการของฉันคือการปล่อยข้อความ PRINT ทั้งหมดของฉันไว้ที่เดิมและเพียงทำตามพวกเขาด้วยคำสั่ง RAISERROR เพื่อทำให้เกิดการลบเลือน

ตัวอย่างเช่น:

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

ข้อดีของวิธีนี้คือคำสั่ง PRINT สามารถต่อสตริงเข้าด้วยกันในขณะที่ RAISERROR ไม่สามารถทำได้ (ดังนั้นวิธีใดก็ตามที่คุณมีจำนวนบรรทัดของรหัสเท่ากันคุณต้องประกาศและตั้งค่าตัวแปรเพื่อใช้ใน RAISERROR)

หากเช่นฉันคุณใช้ AutoHotKey หรือ SSMSBoost หรือเครื่องมือที่เทียบเท่าคุณสามารถตั้งค่าทางลัดเช่น "] flush" เพื่อป้อนบรรทัด RAISERROR ให้กับคุณ วิธีนี้จะช่วยคุณประหยัดเวลาหากเป็นรหัสบรรทัดเดียวกันทุกครั้งนั่นคือไม่จำเป็นต้องปรับแต่งเพื่อเก็บข้อความหรือตัวแปรเฉพาะ


6
โปรดทราบว่าRAISERROR()จะสนับสนุนการprintf()แก้ไขสตริง -style ตัวอย่างเช่นถ้า@MyVariableNameเป็นชนิด stringish (เช่นVARCHAR(MAX), NVARCHAR(MAX)ฯลฯ ) คุณสามารถใช้กับหนึ่งบรรทัด:RAISERROR() RAISERROR(N'MyVariableName: %s', 0, 1, @MyVariableName)
binki

สะดวกมาก ๆ ! ฉันรู้ว่า RAISERROR สามารถทำการทดแทนได้ง่าย แต่ลองแทนที่เวลา [date] หรือเรียกใช้ฟังก์ชันจากภายในคำสั่ง RAISERROR! คำตอบนี้จะช่วยให้คุณล้างข้อมูลในรูปแบบของการเพิ่มข้อผิดพลาดที่ว่างเปล่า (ที่ค่าใช้จ่ายของการขึ้นบรรทัดใหม่)
Tomasz Gandor

19

ใช่ ... พารามิเตอร์แรกของฟังก์ชัน RAISERROR ต้องการตัวแปร NVARCHAR ดังนั้นลองต่อไปนี้;

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

หรือ

RAISERROR (n'Here''s your message...', 0, 1) WITH NOWAIT

10
ดูที่แท็บข้อความที่ด้านล่างถัดจากแท็บผลลัพธ์หรือเปลี่ยนเป็นโหมดผลลัพธ์เป็นข้อความ
เมห์เม็ตเออร์กุท

หากต้องการเปลี่ยนไปใช้โหมดผลลัพธ์เป็นโหมดข้อความใน SSMS เมนูเครื่องมือ -> ตัวเลือก -> ผลลัพธ์การค้นหา -> เซิร์ฟเวอร์ SQL -> ทั่วไป -> ปลายทางเริ่มต้นสำหรับผลลัพธ์และเลือก "ผลลัพธ์เป็นข้อความ" แทน "ผลลัพธ์เป็นกริด" - เปิดหน้าต่างคิวรีแล้วคุณจะไม่นั่งอยู่ที่นั่นดูแท็บผลลัพธ์ว่างเปล่าเหมือนดัมมี่ในขณะที่เอาต์พุต RAISERROR ไปที่แท็บข้อความ
อดัม

13

อีกตัวเลือกที่ดีกว่าคือไม่ต้องพึ่งพา PRINT หรือ RAISERROR และเพียงโหลดคำสั่ง "print" ของคุณลงใน ## Temp table ใน TempDB หรือตารางถาวรในฐานข้อมูลของคุณซึ่งจะทำให้คุณมองเห็นข้อมูลได้ทันทีผ่านคำสั่ง SELECT จากหน้าต่างอื่น . สิ่งนี้ทำงานได้ดีที่สุดสำหรับฉัน การใช้ตารางถาวรแล้วยังทำหน้าที่เป็นบันทึกสิ่งที่เกิดขึ้นในอดีต คำสั่งการพิมพ์มีประโยชน์สำหรับข้อผิดพลาด แต่การใช้ตารางบันทึกคุณยังสามารถกำหนดจุดที่แน่นอนของความล้มเหลวตามค่าบันทึกล่าสุดสำหรับการดำเนินการนั้น (สมมติว่าคุณติดตามเวลาเริ่มต้นการดำเนินการโดยรวมในตารางบันทึกของคุณ)


2
นี่อาจเป็นปัญหาหากคุณกำลังเขียนสคริปต์ธุรกรรมอย่างแท้จริงด้วยการส่งและย้อนกลับ ฉันไม่เชื่อว่าคุณจะสามารถสืบค้นตารางชั่วคราวของคุณได้ - และมันจะหายไปถ้าธุรกรรมของคุณล้มเหลว
SteveJ

@SteveJ คุณสามารถค้นหาแบบสดๆโดยใช้SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;ในเซสชันการตรวจสอบของคุณ
TheConstructor

1
@TheConstructor; นั่นเป็นเคล็ดลับที่มีประโยชน์ - ฉันจะใช้ประโยชน์จากสิ่งนั้นขอบคุณ อย่างไรก็ตามเรายังไม่เหลือตารางเทมเพลตที่จะย้อนกลับใช่ไหม หากทำการวิเคราะห์ความล้มเหลวดูเหมือนว่าจะเป็นข้อบกพร่องที่ยิ่งใหญ่
SteveJ

1
@teveJ ใช่มีสิ่งนี้อย่างแน่นอน แน่นอนคุณสามารถคัดลอกข้อมูลในการREAD UNCOMMITTEDทำธุรกรรมไปยังตารางอื่น แต่คุณอาจพลาดช่วงเวลาก่อนหน้าROLLBACKนี้ ดังนั้นมันอาจจะแก้ 'ไกลแค่ไหน' ไม่ใช่ 'ทำไมจึงย้อนกลับ'
TheConstructor

4

สำหรับการอ้างอิงเท่านั้นหากคุณทำงานในสคริปต์ (การประมวลผลแบบแบทช์) ไม่ได้อยู่ในขั้นตอนการจัดเก็บการล้างข้อมูลเอาต์พุตจะถูกทริกเกอร์โดยคำสั่ง GO เช่น

print 'test'
print 'test'
go

โดยทั่วไปข้อสรุปของฉันคือการส่งออกของการดำเนินการสคริปต์ mssql ดำเนินการใน SMS GUI หรือกับ sqlcmd.exe จะถูกล้างไปที่ไฟล์ stdoutput หน้าต่าง gui ในคำสั่ง GO แรกหรือจนกว่าจะสิ้นสุดของสคริปต์

การล้างข้อมูลภายในของกระบวนงานที่เก็บไว้มีความแตกต่างกันเนื่องจากคุณไม่สามารถวาง GO เข้าไปได้

การอ้างอิง: คำสั่ง tsql Go


2
goไม่เพียงแค่ล้างเอาต์พุตมันจะจบแบตช์ตามลิงก์ที่คุณให้ไว้ ทุกสิ่งที่คุณdeclareถูกทิ้งจึงไม่สามารถใช้ในการดีบั๊กได้declare @test int print "I want to read this!" go set @test=5จะแม้ว่าคุณจะมีข้อผิดพลาดในการอ้างสิทธิ์@testไม่ได้กำหนดเพราะมันอยู่ในชุดใหม่
asontu

1
ฉันเห็นด้วยนี่ไม่ใช่คำตอบที่เหมาะสมสำหรับคำถามนี้ แต่ฉันใส่คำตอบ (ดูข้อจำกัดความรับผิดชอบในการเริ่มต้น) เนื่องจากมันอาจเป็นประโยชน์สำหรับคนอื่น - เช่นคนที่รัน batch sql
Robert Lujo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.