Мое поле VARCHAR (MAX) ограничено 4000; что дает? - PullRequest
4 голосов
/ 23 марта 2010

У меня есть таблица в одной из моих баз данных, которая является очередью писем. Письма по определенным адресам накапливаются в одном письме, что делается sproc. В sproc у меня есть переменная таблицы, которую я использую для построения накопленных тел писем, а затем перебираю для отправки каждого письма. В моей таблице var мой столбец тела определен как VARCHAR(MAX), так как в настоящее время может быть любое количество электронных писем, накопленных для данного адреса электронной почты. Кажется, что хотя мой столбец определен как VARCHAR(MAX), он ведет себя так, как если бы он был VARCHAR(4000), и обрезает входящие в него данные, хотя он НЕ выдает любые исключения, он просто молча перестает объединять больше данных после 4000 символов.

Оператор MERGE - это место, где он встраивает накопленное тело письма в @ EMAILS.BODY, то есть поле, которое усекает себя до 4000 символов.

EDIT

Я обновил свой оператор MERGE, пытаясь привести всю назначенную строку к VARCHAR (MAX), но он все еще молча усекает себя до 4000 символов ... вот мой новый MERGE:

MERGE @EMAILS AS DST 
USING (SELECT * FROM @ROWS WHERE ROWID = @CURRID) AS SRC 
ON SRC.ADDRESS = DST.ADDRESS 
WHEN MATCHED THEN 
    UPDATE SET 
        DST.ALLIDS = DST.ALLIDS + ', ' + CONVERT(VARCHAR,ROWID), 
        DST.BODY = DST.BODY + 
            CONVERT(VARCHAR(MAX),
                '<i>'+CONVERT(VARCHAR,SRC.DATED,101)+
                ' '+CONVERT(VARCHAR,SRC.DATED,8)+
                ':</i> <b>'+SRC.SUBJECT+'</b>'+CHAR(13)+
                SRC.BODY+' (Message ID '+
                CONVERT(VARCHAR,SRC.ROWID)+')'+
                CHAR(13)+CHAR(13)
            )
WHEN NOT MATCHED BY TARGET THEN 
    INSERT (ADDRESS, ALLIDS, BODY) VALUES (
        SRC.ADDRESS, 
        CONVERT(VARCHAR,ROWID), 
        CONVERT(VARCHAR(MAX),
            '<i>'+CONVERT(VARCHAR,SRC.DATED,101)+
            ' '+CONVERT(VARCHAR,SRC.DATED,8)+
            ':</i> <b>'+SRC.SUBJECT+'</b>'+CHAR(13)+
            SRC.BODY+' (Message ID '+CONVERT(VARCHAR,SRC.ROWID)+')'
            +CHAR(13)+CHAR(13)
        )
    );

КОНЕЦ РЕДАКТИРОВАНИЯ

Ниже приведен код моего спрока ...

ALTER PROCEDURE [system].[SendAccumulatedEmails]
AS 
BEGIN
    SET NOCOUNT ON;

    DECLARE @SENTS  BIGINT = 0;

    DECLARE @ROWS TABLE (
        ROWID    ROWID, 
        DATED    DATETIME, 
        ADDRESS  NAME, 
        SUBJECT  VARCHAR(1000), 
        BODY     VARCHAR(MAX)
    )
    INSERT INTO @ROWS SELECT ROWID, DATED, ADDRESS, SUBJECT, BODY 
    FROM system.EMAILQUEUE 
        WHERE ACCUMULATE = 1 AND SENT IS NULL
        ORDER BY ADDRESS, DATED

    DECLARE @EMAILS TABLE (
        ADDRESS  NAME, 
        ALLIDS   VARCHAR(1000),
        BODY     VARCHAR(MAX) 
    )

    DECLARE @PRVRID ROWID = NULL, @CURRID ROWID = NULL
    SELECT @CURRID = MIN(ROWID) FROM @ROWS
    WHILE @CURRID IS NOT NULL BEGIN
        MERGE @EMAILS AS DST 
        USING (SELECT * FROM @ROWS WHERE ROWID = @CURRID) AS SRC 
        ON SRC.ADDRESS = DST.ADDRESS 
        WHEN MATCHED THEN 
            UPDATE SET 
                DST.ALLIDS = DST.ALLIDS + ', ' + CONVERT(VARCHAR,ROWID), 
                DST.BODY = DST.BODY + '<i>'+CONVERT(VARCHAR,SRC.DATED,101)+' '
                            +CONVERT(VARCHAR,SRC.DATED,8)
                            +':</i> <b>'+SRC.SUBJECT+'</b>'+CHAR(13)+SRC.BODY
                            +' (Message ID '+CONVERT(VARCHAR,SRC.ROWID)+')'
                            +CHAR(13)+CHAR(13)
        WHEN NOT MATCHED BY TARGET THEN 
            INSERT (ADDRESS, ALLIDS, BODY) VALUES (
                SRC.ADDRESS, 
                CONVERT(VARCHAR,ROWID), 
                '<i>'+CONVERT(VARCHAR,SRC.DATED,101)+' '
                    +CONVERT(VARCHAR,SRC.DATED,8)+':</i> <b>'
                    +SRC.SUBJECT+'</b>'+CHAR(13)+SRC.BODY
                    +' (Message ID '+CONVERT(VARCHAR,SRC.ROWID)+')'
                    +CHAR(13)+CHAR(13));

        SELECT @PRVRID = @CURRID, @CURRID = NULL
        SELECT @CURRID = MIN(ROWID) FROM @ROWS WHERE ROWID > @PRVRID
    END 

    DECLARE @MAILFROM VARCHAR(100) = system.getOption('MAILFROM'), 
    DECLARE @SMTPHST VARCHAR(100) = system.getOption('SMTPSERVER'), 
    DECLARE @SMTPUSR VARCHAR(100) = system.getOption('SMTPUSER'), 
    DECLARE @SMTPPWD VARCHAR(100) = system.getOption('SMTPPASS')

    DECLARE @ADDRESS NAME, @BODY VARCHAR(MAX), @ADDL VARCHAR(MAX)
    DECLARE @SUBJECT VARCHAR(1000) = 'Accumulated Emails from LIJSL'

    DECLARE @PRVID NAME = NULL, @CURID NAME = NULL 
    SELECT @CURID = MIN(ADDRESS) FROM @EMAILS
    WHILE @CURID IS NOT NULL BEGIN
        SELECT @ADDRESS = ADDRESS, @BODY = BODY 
        FROM @EMAILS WHERE ADDRESS = @CURID

        SELECT @BODY = @BODY + 'This is an automated message sent from an unmonitored mailbox.'+CHAR(13)+'Do not reply to this message; your message will not be read.'
        SELECT @BODY = 
            '<style type="text/css">
                * {font-family: Tahoma, Arial, Verdana;}
                p {margin-top: 10px; padding-top: 10px; border-top: single 1px dimgray;} 
                p:first-child {margin-top: 10px; padding-top: 0px; border-top: none 0px transparent;}
            </style>' 
            + @BODY 

        exec system.LogIt @SUBJECT, @BODY

        BEGIN TRY 
            exec system.SendMail @SMTPHST, @SMTPUSR, @SMTPPWD, @MAILFROM, 
                             @ADDRESS, NULL, NULL, @SUBJECT, @BODY, 1
        END TRY 
        BEGIN CATCH
            DECLARE @EMSG NVARCHAR(2048) = 'system.EMAILQUEUE.AI:'+ERROR_MESSAGE()
            SELECT @ADDL = 'TO:'+@ADDRESS+CHAR(13)+'SUBJECT:'+@SUBJECT+CHAR(13)+'BODY:'+@BODY
            exec system.LogIt @EMSG,@ADDL
        END CATCH

        SELECT @PRVID = @CURID, @CURID = NULL
        SELECT @CURID = MIN(ADDRESS) FROM @EMAILS WHERE ADDRESS > @PRVID
    END

    UPDATE system.EMAILQUEUE SET SENT = getdate()
    FROM system.EMAILQUEUE E, @ROWS R WHERE E.ROWID = R.ROWID
END

Ответы [ 4 ]

5 голосов
/ 23 марта 2010

Исправлены ...

Таблица может иметь значение varchar (max), но вы можете присвоить только следующие значения: nvarchar (4000)

То есть

maxcolumn = maxvalues + smallstring1 + **unicodestring** + smallstring3 + smallstring4 ...

Правая сторона останется в nvarchar (4000) максимум из-за приоритета типа данных. nvarchar> varchar. При назначении столбцу max он усекается

Вам нужно будет убедиться, что все значения справа в varchar

Это все еще как целочисленное деление ... меня смутило ограничение 4000, когда varchar равен 8000 ... это подразумевает где-то nvarchar.

Для Nvarchar (Max) я получаю только 4000 символов в TSQL?

3 голосов
/ 10 августа 2011

http://blogs.infosupport.com/blogs/marks/archive/2011/03/22/take-your-varchar-to-the-max.aspx?CommentPosted=true#commentmessage

Эта проблема и ее решение очень хорошо объяснены в вышеприведенной статье, решение состоит в добавлении в конкатенацию VARCHAR (MAX)

КАК ВНУТРИ

ОБЪЯВИТЬ @SQL VARCHAR (МАКС.) SET @SQL = '' SET @SQL = @SQL + 'xxxxxx (n)'

1 голос
/ 23 марта 2010

Гбн и Джеффри, спасибо за вашу помощь, вы меня направили в правильном направлении. Хотя после некоторой регистрации и проверки, это на самом деле просто отлично соединяет мою строку.

Проблема была не в типе или длине моего столбца, а в вызове моей процедуры .NET SendMail, которая принимает только NVARCHAR (4000) для аргумента BODY ... очевидный перевод .NET SqlString тип.

Так что теперь я собираюсь выяснить, как передать более длинные строки в функцию сборки CLR.

1 голос
/ 23 марта 2010

Я подозреваю, что проблема заключается в операциях преобразования строк. Попробуйте изменить ваши преобразования на VARCHAR (макс.) Или преобразовать все выражение в VARCHAR (макс.).

...