it-swarm-id.com

Bagaimana cara mencetak VARCHAR (MAX) menggunakan Pernyataan Cetak?

Saya memiliki kode yaitu:

DECLARE @Script VARCHAR(MAX)

SELECT @Script = definition FROM manged.sys.all_sql_modules sq
where sq.object_id = (SELECT object_id from managed.sys.objects 
Where type = 'P' and Name = 'usp_gen_data')

Declare @Pos int

SELECT  @pos=CHARINDEX(CHAR(13)+CHAR(10),@script,7500)

PRINT SUBSTRING(@Script,1,@Pos)

PRINT SUBSTRING(@script,@pos,8000)

Panjang Script adalah sekitar 10.000 Karakter dan Karena saya menggunakan Pernyataan cetak yang hanya dapat menampung maksimal 8000. Jadi saya menggunakan dua pernyataan cetak.

Masalahnya adalah ketika saya memiliki skrip yang mengatakan 18.000 karakter maka saya biasa menggunakan 3 pernyataan cetak.

Jadi apakah ada cara agar saya dapat mengatur jumlah pernyataan cetak tergantung pada panjang naskah?

78
peter

Anda bisa melakukan pengulangan WHILE berdasarkan hitungan pada panjang skrip Anda dibagi 8000.

MISALNYA:

DECLARE @Counter INT
SET @Counter = 0
DECLARE @TotalPrints INT
SET @TotalPrints = (LEN(@script) / 8000) + 1
WHILE @Counter < @TotalPrints 
BEGIN
    -- Do your printing...
    SET @Counter = @Counter + 1
END
14
Kelsey

Saya tahu ini pertanyaan lama, tetapi apa yang saya lakukan tidak disebutkan di sini.

Bagi saya yang berikut ini berhasil.

DECLARE @info NVARCHAR(MAX)

--SET @info to something big

PRINT CAST(@info AS NTEXT)
163
alfoks

Solusi berikut ini tidak menggunakan pernyataan PRINT. Ini bekerja dengan baik dalam kombinasi dengan SQL Server Management Studio.

SELECT CAST('<root><![CDATA[' + @MyLongString + ']]></root>' AS XML)

Anda dapat mengklik pada XML yang dikembalikan untuk mengembangkannya di penampil XML bawaan.

Ada batasan sisi klien yang cukup besar pada ukuran yang ditampilkan. Buka Tools/Options/Query Results/SQL Server/Results to Grid/XML data untuk menyesuaikannya jika perlu.

69
Jirka Hanika

Inilah bagaimana ini harus dilakukan:

DECLARE @String NVARCHAR(MAX);
DECLARE @CurrentEnd BIGINT; /* track the length of the next substring */
DECLARE @offset tinyint; /*tracks the amount of offset needed */
set @string = replace(  replace(@string, char(13) + char(10), char(10))   , char(13), char(10))

WHILE LEN(@String) > 1
BEGIN
    IF CHARINDEX(CHAR(10), @String) between 1 AND 4000
    BEGIN
           SET @CurrentEnd =  CHARINDEX(char(10), @String) -1
           set @offset = 2
    END
    ELSE
    BEGIN
           SET @CurrentEnd = 4000
            set @offset = 1
    END   
    PRINT SUBSTRING(@String, 1, @CurrentEnd) 
    set @string = SUBSTRING(@String, @[email protected], LEN(@String))   
END /*End While loop*/

Diambil dari http://ask.sqlservercentral.com/questions/3102/any-way-around-the-print-limit-of-nvarcharmax-in-s.html

33
Ben B

Datangi pertanyaan ini dan ingin sesuatu yang lebih sederhana ... Coba yang berikut ini:

SELECT [processing-instruction(x)][email protected] FOR XML PATH(''),TYPE
9
Edyn

Proc ini dengan benar mencetak parameter VARCHAR(MAX) yang mempertimbangkan pembungkus:

CREATE PROCEDURE [dbo].[Print]
    @sql varchar(max)
AS
BEGIN
    declare
        @n int,
        @i int = 0,
        @s int = 0, -- substring start posotion
        @l int;     -- substring length

    set @n = ceiling(len(@sql) / 8000.0);

    while @i < @n
    begin
        set @l = 8000 - charindex(char(13), reverse(substring(@sql, @s, 8000)));
        print substring(@sql, @s, @l);
        set @i = @i + 1;
        set @s = @s + @l + 2; -- accumulation + CR/LF
    end

    return 0
END
9
Andrey Morozov

Saya mencari untuk menggunakan pernyataan cetak untuk men-debug sql dinamis seperti yang saya bayangkan sebagian besar dari Anda menggunakan cetak untuk alasan serupa.

Saya mencoba beberapa solusi yang terdaftar dan menemukan bahwa solusi Kelsey bekerja dengan tweeks minor (@sql adalah @script saya) n.b. PANJANG bukan fungsi yang valid:

--http://stackoverflow.com/questions/7850477/how-to-print-varcharmax-using-print-statement
--Kelsey
DECLARE @Counter INT
SET @Counter = 0
DECLARE @TotalPrints INT
SET @TotalPrints = (LEN(@sql) / 4000) + 1
WHILE @Counter < @TotalPrints 
BEGIN
    PRINT SUBSTRING(@sql, @Counter * 4000, 4000)
    SET @Counter = @Counter + 1
END
PRINT LEN(@sql)

Kode ini tidak seperti yang dikomentari menambahkan baris baru ke dalam output, tetapi untuk debugging ini bukan masalah bagi saya.

Solusi Ben B sempurna dan paling elegan, meskipun untuk debugging banyak baris kode jadi saya memilih untuk menggunakan sedikit modifikasi Kelsey. Mungkin layak membuat sistem seperti prosedur tersimpan dalam msdb untuk kode Ben B yang dapat digunakan kembali dan dipanggil dalam satu baris?

Sayangnya kode Alfoks tidak berfungsi karena itu akan lebih mudah.

7
Matthew Radford
 buat prosedur dbo.PrintMax @teks nvarchar (maks) 
 sebagai 
 mulai 
 mendeklarasikan @i int, @newline nchar (2), @print varchar (max); 
 set @newline = nchar (13) + nchar (10); 
 pilih @i = charindex (@newline, @text); 
 while (@i> 0) 
 mulai
 pilih @print = substring (@ text, 0, @ i); 
 while (len (@print)> 8000) 
 mulai
 print substring (@ print, 0,8000); 
 pilih @print = substring (@ print, 8000, len (@print)); 
 akhir
 print @print; 
 pilih @ teks = substring (@ teks, @ i + 2, len (@ teks)); 
 pilih @i = charindex (@newline, @text); 
 akhir
 print @text; 
 end 
3
Adam Gering

Anda bisa menggunakan ini

declare @i int = 1
while Exists(Select(Substring(@Script,@i,4000))) and (@i < LEN(@Script))
begin
     print Substring(@Script,@i,4000)
     set @i = @i+4000
end
3
Marwan Almukh

Menggunakan Umpan dan spasi Garis sebagai titik istirahat yang baik:

declare @sqlAll as nvarchar(max)
set @sqlAll = '-- Insert all your sql here'

print '@sqlAll - truncated over 4000'
print @sqlAll
print '   '
print '   '
print '   '

print '@sqlAll - split into chunks'
declare @i int = 1, @nextspace int = 0, @newline nchar(2)
set @newline = nchar(13) + nchar(10)


while Exists(Select(Substring(@sqlAll,@i,3000))) and (@i < LEN(@sqlAll))
begin
    while Substring(@sqlAll,@[email protected],1) <> ' ' and Substring(@sqlAll,@[email protected],1) <> @newline
    BEGIN
        set @nextspace = @nextspace + 1
    end
    print Substring(@sqlAll,@i,[email protected])
    set @i = @[email protected]
    set @nextspace = 0
end
print '   '
print '   '
print '   '
2
BickiBoy

Ada fungsi hebat yang disebut PrintMax yang ditulis oleh Bennett Dill.

Berikut adalah versi yang sedikit dimodifikasi yang menggunakan prosedur tersimpan untuk menghindari "skema skema" (ide dari https://github.com/Toolien/sp_GenMerge/blob/master/sp_GenMerge.sql )

EXEC (N'IF EXISTS (SELECT * FROM tempdb.sys.objects 
                   WHERE object_id = OBJECT_ID(N''tempdb..#PrintMax'') 
                   AND type in (N''P'', N''PC''))
    DROP PROCEDURE #PrintMax;');
EXEC (N'CREATE PROCEDURE #PrintMax(@iInput NVARCHAR(MAX))
AS
BEGIN
    IF @iInput IS NULL
    RETURN;

    DECLARE @ReversedData NVARCHAR(MAX)
          , @LineBreakIndex INT
          , @SearchLength INT;

    SET @SearchLength = 4000;

    WHILE LEN(@iInput) > @SearchLength
    BEGIN
    SET @ReversedData = LEFT(@iInput COLLATE DATABASE_DEFAULT, @SearchLength);
    SET @ReversedData = REVERSE(@ReversedData COLLATE DATABASE_DEFAULT);
    SET @LineBreakIndex = CHARINDEX(CHAR(10) + CHAR(13),
                          @ReversedData COLLATE DATABASE_DEFAULT);
    PRINT LEFT(@iInput, @SearchLength - @LineBreakIndex + 1);
    SET @iInput = RIGHT(@iInput, LEN(@iInput) - @SearchLength 
                        + @LineBreakIndex - 1);
    END;

    IF LEN(@iInput) > 0
    PRINT @iInput;
END;');

Demo DBFiddle

EDIT:

Menggunakan CREATE OR ALTER kita bisa menghindari dua panggilan EXEC:

EXEC (N'CREATE OR ALTER PROCEDURE #PrintMax(@iInput NVARCHAR(MAX))
AS
BEGIN
    IF @iInput IS NULL
    RETURN;

    DECLARE @ReversedData NVARCHAR(MAX)
          , @LineBreakIndex INT
          , @SearchLength INT;

    SET @SearchLength = 4000;

    WHILE LEN(@iInput) > @SearchLength
    BEGIN
    SET @ReversedData = LEFT(@iInput COLLATE DATABASE_DEFAULT, @SearchLength);
    SET @ReversedData = REVERSE(@ReversedData COLLATE DATABASE_DEFAULT);
    SET @LineBreakIndex = CHARINDEX(CHAR(10) + CHAR(13), @ReversedData COLLATE DATABASE_DEFAULT);
    PRINT LEFT(@iInput, @SearchLength - @LineBreakIndex + 1);
    SET @iInput = RIGHT(@iInput, LEN(@iInput) - @SearchLength + @LineBreakIndex - 1);
    END;

    IF LEN(@iInput) > 0
    PRINT @iInput;
END;');

db <> Demo biola

1
Lukasz Szozda

Jika kode sumber tidak akan mengalami masalah dengan LF yang akan diganti oleh CRLF, Tidak perlu debugging dengan mengikuti output kode sederhana.

--http://stackoverflow.com/questions/7850477/how-to-print-varcharmax-using-print-statement
--Bill Bai
SET @SQL=replace(@SQL,char(10),char(13)+char(10))
SET @SQL=replace(@SQL,char(13)+char(13)+char(10),char(13)+char(10) )
DECLARE @Position int 
WHILE Len(@SQL)>0 
BEGIN
SET @Position=charindex(char(10),@SQL)
PRINT left(@SQL,@Position-2)
SET @SQL=substring(@SQL,@Position+1,len(@SQL))
end; 
0
Bill Bai

Atau sederhananya:

PRINT SUBSTRING(@SQL_InsertQuery, 1, 8000)
PRINT SUBSTRING(@SQL_InsertQuery, 8001, 16000)
0
Yovav

Ini harus bekerja dengan baik. Ini hanyalah peningkatan dari jawaban sebelumnya.

DECLARE @Counter INT
DECLARE @Counter1 INT
SET @Counter = 0
SET @Counter1 = 0
DECLARE @TotalPrints INT
SET @TotalPrints = (LEN(@QUERY) / 4000) + 1
print @TotalPrints 
WHILE @Counter < @TotalPrints 
BEGIN
-- Do your printing...
print(substring(@query,@COUNTER1,@COUNTER1+4000))

set @COUNTER1 = @Counter1+4000
SET @Counter = @Counter + 1
END
0
vinbhai4u

Ini versi lain. Yang ini mengekstraksi setiap substring untuk mencetak dari string utama alih-alih mengambil pengurangan string utama sebanyak 4000 pada setiap loop (yang mungkin membuat banyak string yang sangat panjang di bawah tenda - tidak yakin).

CREATE PROCEDURE [Internal].[LongPrint]
    @msg nvarchar(max)
AS
BEGIN

    -- SET NOCOUNT ON reduces network overhead
    SET NOCOUNT ON;

    DECLARE @MsgLen int;
    DECLARE @CurrLineStartIdx int = 1;
    DECLARE @CurrLineEndIdx int;
    DECLARE @CurrLineLen int;   
    DECLARE @SkipCount int;

    -- Normalise line end characters.
    SET @msg = REPLACE(@msg, char(13) + char(10), char(10));
    SET @msg = REPLACE(@msg, char(13), char(10));

    -- Store length of the normalised string.
    SET @MsgLen = LEN(@msg);        

    -- Special case: Empty string.
    IF @MsgLen = 0
    BEGIN
        PRINT '';
        RETURN;
    END

    -- Find the end of next substring to print.
    SET @CurrLineEndIdx = CHARINDEX(CHAR(10), @msg);
    IF @CurrLineEndIdx BETWEEN 1 AND 4000
    BEGIN
        SET @CurrLineEndIdx = @CurrLineEndIdx - 1
        SET @SkipCount = 2;
    END
    ELSE
    BEGIN
        SET @CurrLineEndIdx = 4000;
        SET @SkipCount = 1;
    END     

    -- Loop: Print current substring, identify next substring (a do-while pattern is preferable but TSQL doesn't have one).
    WHILE @CurrLineStartIdx < @MsgLen
    BEGIN
        -- Print substring.
        PRINT SUBSTRING(@msg, @CurrLineStartIdx, (@CurrLineEndIdx - @CurrLineStartIdx)+1);

        -- Move to start of next substring.
        SET @CurrLineStartIdx = @CurrLineEndIdx + @SkipCount;

        -- Find the end of next substring to print.
        SET @CurrLineEndIdx = CHARINDEX(CHAR(10), @msg, @CurrLineStartIdx);
        SET @CurrLineLen = @CurrLineEndIdx - @CurrLineStartIdx;

        -- Find bounds of next substring to print.              
        IF @CurrLineLen BETWEEN 1 AND 4000
        BEGIN
            SET @CurrLineEndIdx = @CurrLineEndIdx - 1
            SET @SkipCount = 2;
        END
        ELSE
        BEGIN
            SET @CurrLineEndIdx = @CurrLineStartIdx + 4000;
            SET @SkipCount = 1;
        END
    END
END
0
redcalx