【问题标题】:Create vCard file from SQL Server从 SQL Server 创建 vCard 文件
【发布时间】:2014-03-11 01:53:23
【问题描述】:

我想从 SQL Server (v 2012) 创建 vCard,然后我想通过电子邮件从 db_mail 发送它。要创建 vCard 文件,我使用的是 xp_cmdshell。我在一个 varchar 变量中准备所有 cmd 命令,并使用该变量作为命令文本执行 xp_cmdshell。结果并不如我所料。我只收到生成的 vCard 文件中文本的第一行。当我采用相同的文本并将其作为批处理文件运行时,vCard 文件已正确创建。

DECLARE @iIDUser AS INT = 1;
DECLARE @iIDContact AS INT = 1;

DECLARE @iResult AS INT;
DECLARE @sExecute_vCardText AS VARCHAR(8000) = '';
DECLARE @crlf CHAR(2) = CHAR(13) + CHAR(10);
DECLARE @sFile VARCHAR(1000) = ' >> C:\Databases\_tmp_sql\PES_ERP\User.vcf';

SELECT @sExecute_vCardText = @sExecute_vCardText 
    + @crlf + 'ECHO ' + 'BEGIN:VCARD' + ' > C:\Databases\_tmp_sql\PES_ERP\User.vcf' 
+ @crlf + 'ECHO ' + 'VERSION:2.1' + @sFile 
+ @crlf + 'ECHO ' + 'CATEGORIES:' + 
    + ISNULL(Cnt.ContactRole_Name_en,'')  
    + ',' + ISNULL(Cnt.ContactRelationshipType_Name_en,'') 
    + ',' + ISNULL(Cnt.VisibilityType_Name_en,'')  + @sFile 
+ @crlf + 'ECHO ' + 'FN:' + ISNULL(Cnt.ContactTitle_Name_en,'')  + @sFile 
    + ' ' + ISNULL(Cnt.Name,'') + ' ' + ISNULL(Cnt.Surname,'') 
+ @crlf + 'ECHO ' + 'N:' + ISNULL(Cnt.Surname,'')  + @sFile 
    + ';' + ISNULL(Cnt.Name,'') 
    + ';' + ISNULL(Cnt.ContactTitle_Name_en,'')  + @sFile 
+ @crlf + 'ECHO ' + 'TITLE:' + ISNULL(Cnt.JobTitle,'')  + @sFile 
+ @crlf + 'ECHO ' + 'BDAY:' + ISNULL(CONVERT(varchar(16),Cnt.BirthDate,112),'')  + @sFile 
+ @crlf + 'ECHO ' + 'BIRTH:' + ISNULL(Cnt.BirthMunicipality_Name,'')  + @sFile 
+ @crlf + 'ECHO ' + 'TEL;TYPE=work:' + ISNULL(Cnt.Business_Phone,'')  + @sFile 
+ @crlf + 'ECHO ' + 'TEL;TYPE=work:' + ISNULL(Cnt.Business_Phone2,'')  + @sFile 
+ @crlf + 'ECHO ' + 'TEL;TYPE=work,cell:' + ISNULL(Cnt.Business_Mobile,'')  + @sFile 
+ @crlf + 'ECHO ' + 'TEL;TYPE=work,cell:' + ISNULL(Cnt.Business_Mobile2,'')  + @sFile 
+ @crlf + 'ECHO ' + 'TEL;TYPE=work,fax:' + ISNULL(Cnt.Business_FAX,'')  + @sFile 
+ @crlf + 'ECHO ' + 'ADR;TYPE=work:;;' + ISNULL(Cnt.Business_Address,'') + ';' + ISNULL(Cnt.Business_City,'') + ';' + ISNULL(Cnt.Business_Municipality_Name,'') + ' (' + ISNULL(Cnt.Business_Region_Name,'') + ') ' + ';' + ISNULL(Cnt.Business_CAP,'') + ';' + ISNULL(CASE WHEN (@iIDLanguage = 40001) THEN Cnt.Business_Country_Name_en WHEN (@iIDLanguage = 40002) THEN Cnt.Business_Country_Name_it WHEN (@iIDLanguage = 40003) THEN Cnt.Business_Country_Name_de WHEN (@iIDLanguage = 40004) THEN Cnt.Business_Country_Name_fr ELSE Cnt.Business_Country_Name_en END,'') + @sFile 
+ @crlf + 'ECHO ' + 'EMAIL;TYPE=internet,work,pref:' + ISNULL(Cnt.Business_EMail,'')  + @sFile 
+ @crlf + 'ECHO ' + 'EMAIL;TYPE=internet,work:' + ISNULL(Cnt.Business_EMail2,'')  + @sFile 
+ @crlf + 'ECHO ' + 'TEL;TYPE=home:' + ISNULL(Cnt.Home_Phone,'')  + @sFile 
+ @crlf + 'ECHO ' + 'TEL;TYPE=home,cell:' + ISNULL(Cnt.Home_Mobile,'')  + @sFile 
+ @crlf + 'ECHO ' + 'ADR;TYPE=work:;;' + ISNULL(Cnt.Home_Address,'') + ';' + ISNULL(Cnt.Home_City,'') + ';' + ISNULL(Cnt.Home_Municipality_Name,'') + ';' + ISNULL(Cnt.Home_CAP,'') + ';;'  + @sFile 
+ @crlf + 'ECHO ' + 'EMAIL;TYPE=internet,home:' + ISNULL(Cnt.Home_EMail,'')  + @sFile 
+ @crlf + 'ECHO ' + 'NOTE:' + ISNULL(Cnt.Note,'')  + @sFile 
+ @crlf + 'ECHO ' + 'REV:' + REPLACE(REPLACE(REPLACE(CONVERT(varchar,GETDATE(),120),'-',''),':',''),' ','T') + 'Z'  + @sFile 
+ @crlf + 'ECHO ' + 'END:VCARD'  + @sFile 
FROM 
    dbo.fun_Contacts(@iIDUser) AS Cnt 
WHERE 
    (Cnt.IDContact = @iIDContact);

EXEC @iResult = master..xp_cmdshell @sExecute_vCardText;

select @iResult as a;

谁能告诉我我哪里做错了?

【问题讨论】:

  • sp_cmdshell 默认禁用,这是有充分理由的。你的架构说“请拥有我,我是一个运行不佳的 sql 服务器”。在应用程序中运行逻辑会更好。
  • 我知道这个TomTom,我必须用这种代。这是设计师的要求。我可以通过 CLR 做到这一点,这是设计师所禁止的。所以我必须坚持这个方法。我也很奇怪为什么我不能得到预期的结果。
  • 好吧,不管你做什么,你都记得你有一个关键问题 - 你有一个硬编码的 vcf 文件名。这很糟糕 - 同时对 SP 的 2 次调用将导致文件访问重叠。
  • 是的,你是对的TomTom。我的错。我忘了说这只是为了演示。在实际代码中,这将是一个唯一参数。

标签: sql-server sql-server-2012


【解决方案1】:

为什么要使用所有 ECHO 命令?

它使代码更复杂。

这是一个只创建格式化字符串的重写。请检查语法。

-- Declare variables
DECLARE @CrLf CHAR(2) = CHAR(13) + CHAR(10);
DECLARE @SqlStmt varchar(max) = '';

-- Make up the string
SELECT @SqlStmt = 
    'BEGIN:VCARD' + @CrLf +
    'VERSION:2.1' + @CrLf +
    'CATEGORIES:' + 
        ISNULL(C.ContactRole_Name_en,'') + ',' + 
        ISNULL(C.ContactRelationshipType_Name_en,'') + ',' + 
        ISNULL(C.VisibilityType_Name_en,'') + @CrLf + 
    'FN:' + 
        ISNULL(C.ContactTitle_Name_en,'') +  ' ' + 
        ISNULL(C.Name,'') + ' ' + ISNULL(C.Surname,'') + @CrLf + 
    'N:' + 
        ISNULL(C.Surname,'') + ';' + 
        ISNULL(C.Name,'') + ';' + 
        ISNULL(C.ContactTitle_Name_en,'')  + @CrLf + 
    'TITLE:' + ISNULL(C.JobTitle,'')  + @CrLf + 
    'BDAY:' + ISNULL(CONVERT(varchar(16),C.BirthDate,112),'')  + @CrLf + 
    'BIRTH:' + ISNULL(C.BirthMunicipality_Name,'')  + @CrLf + 
    'TEL;TYPE=work:' + ISNULL(C.Business_Phone,'')  + @CrLf + 
    'TEL;TYPE=work:' + ISNULL(C.Business_Phone2,'')  + @CrLf + 
    'TEL;TYPE=work,cell:' + ISNULL(C.Business_Mobile,'')  + @CrLf + 
    'TEL;TYPE=work,cell:' + ISNULL(C.Business_Mobile2,'')  + @CrLf + 
    'TEL;TYPE=work,fax:' + ISNULL(C.Business_FAX,'')  + @CrLf + 
    'ADR;TYPE=work:;;' + 
        ISNULL(C.Business_Address,'') + ';' + 
        ISNULL(C.Business_City,'') + ';' + 
        ISNULL(C.Business_Municipality_Name,'') + 
        ' (' + ISNULL(C.Business_Region_Name,'') + ') ' + ';' + 
        ISNULL(C.Business_CAP,'') + ';' + 
        ISNULL
        (
            CASE 
                WHEN (@iIDLanguage = 40001) THEN C.Business_Country_Name_en 
                WHEN (@iIDLanguage = 40002) THEN C.Business_Country_Name_it 
                WHEN (@iIDLanguage = 40003) THEN C.Business_Country_Name_de 
                WHEN (@iIDLanguage = 40004) THEN C.Business_Country_Name_fr 
                ELSE C.Business_Country_Name_en END,'')
        ) + @CrLf + 
    'EMAIL;TYPE=internet,work,pref:' + ISNULL(C.Business_EMail,'')  + @CrLf + 
    'EMAIL;TYPE=internet,work:' + ISNULL(C.Business_EMail2,'')  + @CrLf + 
    'TEL;TYPE=home:' + ISNULL(C.Home_Phone,'')  + @CrLf + 
    'TEL;TYPE=home,cell:' + ISNULL(C.Home_Mobile,'')  + @CrLf + 
    'ADR;TYPE=work:;;' + 
        ISNULL(C.Home_Address,'') + ';' + 
        ISNULL(C.Home_City,'') + ';' + 
        ISNULL(C.Home_Municipality_Name,'') + ';' + 
        ISNULL(C.Home_CAP,'') + ';;'  + @CrLf + 
    'EMAIL;TYPE=internet,home:' + ISNULL(C.Home_EMail,'')  + @CrLf + 
    'NOTE:' + ISNULL(C.Note,'')  + @CrLf + 
    'REV:' + 
         REPLACE(REPLACE(REPLACE(CONVERT(varchar,GETDATE(),120),'-',''),':',''),' ','T') + 
         'Z'  + @CrLf + 
    'END:VCARD'  + @CrLf
FROM 
    dbo.fun_Contacts(@iIDUser) AS C 
WHERE 
    (C.IDContact = @iIDContact);

我故意没有对字符串做任何事情,因为我想涵盖一些设计决策。

1 - 命令提示符的限制为略低于 8K(8192 个字符)。

这可能是你的问题。所有额外的 ECHO 和目的地都超过了这个限制。

从批处理文件而不是从 SQL Server 工作。

2 - 如果您认为自己会超出此限制,有几个解决方案。

A - 将命令分解为单独的调用。使用 GUID 等来保证文件的唯一性。那就是如果你真的需要一个文件输出。

B - 如果您只是通过电子邮件发送文件,为什么不使用@attach_query_result_as_file 选项?此选项将查询的输出转换为附件。

http://technet.microsoft.com/en-us/library/ms190307.aspx

就像生活中的任何事情一样,解决问题并创造另一个问题。我认为默认的文件附件大小是 1 MB。如果文件附件超出限制,则必须增加此值。

http://blogs.msdn.com/b/sqlagent/archive/2010/11/10/sql-database-mail-send-emails-with-attachment.aspx

C - 这一切都可以在 SSIS 而不是直接的 T-SQL 中完成。两者都可以。但是 SSIS 在解决非常复杂的问题时更加灵活。

祝你任务顺利。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    相关资源
    最近更新 更多