简体   繁体   中英

T-SQL long dynamic query gets cut off

I am working with a query that will produce a html page. In the beginning that page is just a simple HTML table with tags. The tags will later be processed and replaced with subqueries (mostly scalar functions). This way combined HTML with replaced tags will be executed with sp_executesql to produce final html.

Excerpt of that HTML:

...Arial, Helvetica, Verdana, sans-serif; font-weight: bold;">Firma:</td><td style="font-size: 14px; font-family: Arial, Helvetica, Verdana, sans-serif;">'+(select cast(coalesce(Companyname,'') as nvarchar(max)) as result from Customer WHERE CustomerID=988082)+'</td></tr><tr><td style="font-size: 14px; font-family: Arial, Helvetica, Verdana, sans-serif; font-weight: bold;">Anrede:</td><td style="font-size: 14px; font-family: Arial, Helvetica, Verdana, sans-serif;">'+(select cast(coalesce(Anrede,'') as nvarchar(max)) as result from Customer WHERE CustomerID=988082)+'</td></tr><tr><td style="font-size: 14px; font-family: Arial, Helvetica, Verdana, sans-serif; font-weight: bold;">Vorname:</td><td style="font-size: 14px; font-family: Arial, Helvetica, Verdana, sans-serif;">'+(select cast(coalesce(Firstname,'') as nvarchar(max)) as result from Customer WHERE CustomerID=988082)+'</td></tr><tr><td style="font-size: 14px; font-family: Arial, Helvetica, Verdana, sans-serif; font-weight: bold;">Nachname:</td><td style="font-size: 14px; font-family: Arial, Helvetica, Verdana, sans-serif;">'+(select cast(coalesce(Lastname,'') as nvarchar(max)) as result from Customer WHERE CustomerID=988082)+'</td></tr><tr><td style="font-size: 1...

Now, I know that if I use anything but nvarchar(max) my result will be truncated to 4000, so I do casting of all function results to nvarchar(max) and my results is more than that but still strangely cut of from inside.

So when I run an example script I get 9043 characters as the result (with len function), and the result is cut off (note: from inside, near the end but not at the end). Now I append one letter and result is 9044 . But if I add that letter 100 characters before the end result is still 9043 ??

What is wrong with this? Why I can;t build a long T-SQL query to be executed with the expected results?

Thanks

UPDATE 1

Because the original solution is too long to display it here I will try to display smaller version just for you to see how I did it and what is my final doing with it:

declare @BodyTXT nvarchar(max)
set @BodyTXT =  N'select ''some string' + (select cast('result of some function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max))) +
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another AAA string' + (select cast('result of antoher function' as nvarchar(max))) + N''''

execute sp_executesql @BodyTXT

Let's say that this is LEN = 9043 characters long and now, notice AAA if I add characters there the final results stays to be LEN = 9043, but if I add some strings at the very beginning string size will change and increase for the number of strings I add there.

Result will be cut off this way:

some stringresult of some function another stringresult of antoher function
 another stringresult of antoher function another stringresult of antoher 
function another stringresult of antoher function another stringresult of antoher
 function another stringresult of antoher function another ...ult of antoher function

Can you see those... dots almost at the end of the result it is there where I am missing rest of string that should be in the output (approx 12000, and I am having 9043)

UPDATE 2

Because this all is part of automated emailing system and it was running live I had to find solution and what I have done is removing some style information from the result table. So after cutting 1/3 of html I finally got result as expected BUT because size of the final string depends on how many products customer purchases for certainly this issue will come again. And also I want to know what is the reason for this behavior and how to overcome it.

I once have encountered an issue using += operator to concatenate long strings, it was cutting characters down.

So instead using @SQL = @SQL + N'a really long text'; has solved it.

I know this is an old Post but still a current subject. This is just as an FYI, to help anyone that would need help on this subject.

I just ran into a problem where my @SqlStr (that is set to NVARCHAR(MAX)) kept on cutting off causing errors during the SP_ExecuteSQL call.

The only concatenation that is done to this long script was @TableName which was set to NVARCHAR(100).

After several hours of debugging, the issue was caused by the @tablename

it seems like when nvarchar(###) is used instead of NVarchar(max), SQL sees it as a slightly different datatype and cuts the long string to 4000 characters.

To fix the issue I had to change the @Tablename to match the nvarchar(max) data type.

I recall something similar while generating large html output as a string. Can't recall what exactly was the issue, probably some limitation of management studio. The workaround was to generate table as xml. Below is a sample you can experiment with. Generate sql table first and then replace "select * from (values..)" with your table.

declare
 @baseTable xml = (select * from ( Values
   (123, 'Firma:', 'Google'),
   (123, 'Anrede:', 'NYC'),
   (123, 'Vorname:', 'John'),
   (123, 'Nachname:', 'Doe')
  ) T(CustID, property, Val)
 for XML PATH('row'), ELEMENTS XSINIL)

,@tblClass VARCHAR(100)
,@thClass VARCHAR(100) 
,@TRstyle VARCHAR(100) = 'font-size: 14px'
,@TDstyle VARCHAR(100) = 'font-size: 14px; font-family: Arial, Helvetica, Verdana, sans-serif; font-weight: bold'

 SELECT @tblClass AS [@class]  
    ,@thClass AS [thead/@class]
    ,@baseTable.query(
              N'let $first:=/row[1]
                return 
                <tr> 
                {
                for $th in $first/*
                return <th>{local-name($th)}</th>
                }
                </tr>') AS thead
            ,@baseTable.query(                 
               N'for $tr in /row
                 return 
                 <tr style="{sql:variable("@TRstyle")}">
                  {
                   for $td in $tr/*
                     return <td style="{sql:variable("@TDstyle")}">{string($td)}</td>
                  }
                 </tr>') AS tbody
    FOR XML PATH('table'),TYPE

The problem is almost certainly that your @BodyTXT may be nvarchar(max), but something you are putting into it is not. By doing set @BodyTxt = a + b + c + d +..... , all of the concatenation is being done first, and then stuck into your variable at once. Which is great, until somewhere SQL decides because of type coercion (or something) that the results of the latest bit are nvarchar (default length 4000), not nvarchar(max), and truncates some of it.

You can go through your whole query, checking everything and looking for the problem, but it would probably be simpler to break the concatenation up into bits that will all be small enough, something like this.

declare @BodyTXT nvarchar(max)

set @BodyTXT =  N'select ''some string' + (select cast('result of some function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max)))

set @BodyTXT = @BodyTXT +
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max))) +

set @BodyTXT = @BodyTXT +
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another string' + (select cast('result of antoher function' as nvarchar(max))) + 
N' another AAA string' + (select cast('result of antoher function' as nvarchar(max))) + N''''

LEN will trim trailing spaces, DATALENGTH will not. select len('a '), datalength('a ') . So if you insert that letter 100 characters back then the last character is a space. Just use DATALENGTH instead and you should get your expected results.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM