Mon VARCHAR(MAX) champ est le coiffage de lui-même à 4000; ce qui donne?
J'ai une table dans l'un de mes bases de données, qui est une file d'attente d'e-mails. E-mails à certaines adresses obtenir accumulés en un seul e-mail, qui est réalisée par la procédure stockée. Dans la procédure stockée, j'ai une variable de table que j'utilise pour construire le cumul des corps des e-mails, puis faire une boucle pour envoyer chaque e-mail. Dans ma table var, j'ai mon corps de colonne définie comme VARCHAR(MAX)
, car il pourrait y avoir un certain nombre de courriels actuellement accumulé une adresse e-mail. Il semble cependant que même si ma colonne est définie comme VARCHAR(MAX)
elle se comporte comme si elle était VARCHAR(4000)
et est tronquer les données qui vont dans ce, bien qu'il ne PAS de jeter des exceptions, c'est juste silencieusement arrêts de la concaténation de plus de données après 4000 caractères.
L'instruction MERGE est là que c'est la construction de la accumulé email en @e-MAILS.CORPS, qui est le champ qui est à tronquer lui-même à 4000 caractères.
MODIFIER
J'ai mis à jour mon instruction MERGE dans une tentative de jeter le tout attribué chaîne de type VARCHAR(MAX), mais il est toujours silencieusement troncature à 4000 caractères... voici ma nouvelle FUSION:
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)
)
);
FIN MODIFIER
Ci-dessous le code de ma procédure stockée...
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
Serait habillage de l'ensemble du membre de droite de l'expression dans un CONVERT(VARCHAR(MAX), <expression>) pour ma mise à jour à ne pas prendre soin de cela?
Type de données de priorité...
La seule chose que je vois qui n'est pas explicitement converti à VARCHAR(MAX) est la traduction littérale des chaînes de caractères comme '<i>'. Ne littéraux aller en tant que NVARCHAR? La SRC.<champs> sont tous convertis à VARCHAR, et le CHAR de la fonction renvoie un type CHAR.
OriginalL'auteur eidylon | 2010-03-23
Vous devez vous connecter pour publier un commentaire.
Corrigés...
La table peut par varchar(max), mais les valeurs que vous attribuez ne sont nvarchar(4000)
Qui est,
La droite va rester à nvarchar(4000) maximum en raison de type de données de priorité. nvarchar > varchar. Lorsqu'ils sont affectés à la colonne max il tronque
Vous aurez à assurer toutes les valeurs sur le droit à varchar
C'est encore comme la division entière... ce qui me confond a la limite de 4000 quand varchar est de 8000... ce qui implique de type nvarchar quelque part.
Pour Nvarchar(Max), je suis en obtenant seulement 4000 caractères en TSQL?
que dire de l'INSÉRER...?
SRC.CORPS devrait promouvoir l'ensemble de l'expression de MAX, si je suis en train de lire MSDN correctement.
Ma mise à JOUR n'est désormais l'heure d'été.CORPS = HEURE D'ÉTÉ.CORPS + CONVERT(VARCHAR(MAX),<smallstrings>) et l'INSERT de même insère CONVERT(VARCHAR(MAX),<smallstrings>) à l'heure d'été.CORPS, mais il est encore tronquer.
"Si le résultat de la concaténation de chaînes de caractères dépasse la limite de 8 000 octets, le résultat est tronqué. Cependant, si au moins une des chaînes concaténées est un type de grande valeur, la troncature ne se produit pas."
OriginalL'auteur gbn
http://blogs.infosupport.com/blogs/marks/archive/2011/03/22/take-your-varchar-to-the-max.aspx?CommentPosted=true#commentmessage
Ce problème et la solution sont très bien expliqué dans l'article ci-dessus, la solution est d'ajouter à la concaténation du type VARCHAR(MAX)
COMME DANS
DECLARE @SQL DE TYPE VARCHAR(MAX)
SET @SQL ="
SET @SQL = @SQL + 'xxxxxx(n)'
OriginalL'auteur Aedna
Je soupçonne que le problème se situe dans la chaîne et les opérations de conversion. Essayez de changer vos conversions de type VARCHAR(max), ou la conversion de l'ensemble des expressions de type VARCHAR(max).
+1 a résolu mon problème ..
OriginalL'auteur Peter Ruderman
gbn et Jeffrey, je vous remercie pour votre aide, vous me va dans la bonne direction. Si après l'abattage et de la vérification, c'est en fait la concaténation de ma chaîne fine.
Le problème n'était pas avec ma colonne de type de données ou de longueur, mais avec l'appel à mon .NET
SendMail
procédure, qui est le seul à accepter de type NVARCHAR(4000) pour le CORPS de l'argumentation... l'apparente traduction de l' .NETSqlString
type.Alors maintenant, je suis sur une chasse de comprendre comment passer plus de chaînes dans un assembly CLR fonction.
Donc, vous n'avez pas fait de savoir que les données de la table a été OK? Vous n'avez jamais si LEN? La question est donc erroné et trompeur...
J'avais pensé, évidemment à tort, qu'il avait un problème avec le code T-SQL. Je n'avais pas pensé à regarder le .NET code, parce que quand il s'agit de .NET je suis habitué à traiter qu'avec des Chaînes, où il n'y a pas de souci avec la longueur. Je n'ai pas fait beaucoup de .NET/CLR-intégration de SQL, et donc n'ai pas pensé à regarder là. Nous avons tous eu des jours où nous avons manqué à l'évidence pour qu'il nous regarde fixement dans le visage et le besoin d'un regard neuf pour aider à nous orienter dans la bonne direction.
OriginalL'auteur eidylon