循环遍历多行表并发送一封电子邮件

时间:2018-01-12 21:14:09

标签: sql sql-server tsql

作为一个菜鸟,我真的在与此作斗争。

我有一张表如下

SELECT [AuditFieldID]
      ,[CompanyRuleID]
      ,[CompanyRule]
      ,[VipUserName]
      ,[EffectiveDate]
      ,[FieldName]
      ,[SourceCode]
      ,[Action]
      ,[AccountNoOldValue]
      ,[AccountNoNewValue]
      ,[AccountTypeOldValue]
      ,[AccountTypeNewValue]
      ,[BankOldValue]
      ,[BankNewValue]
      ,[BranchOldValue]
      ,[BranchNewValue]
      ,[AccountHolderOldValue]
      ,[AccountHolderNewValue]
  FROM [SageStaging].[MASSMART].[AuditCondensed]

每个员工的表格中有5行。前5个字段包含相同的数据,然后fieldname字段包含不同的记录类型。

所以你会有

Auditfieldid = 111111
CompanyRuleID = 12
CompanyRule = Walmart
VipUsername = john.doe
EffectiveDate = date()
Fieldname = 'Account Holder Name'
SourceCode = 1234 - John Doe
Action = I
AccountNoOldValue = NULL
AccountNoNewValue = NULL
AccountTypeOldValue = NULL
AccountTypeNewValue = NULL
BankOldValue = NULL
BankNewValue = NULL
BranchOldValue = NULL
BranchNewValue = NULL
AccountHoldOldValue = ''
AcccountHolderNewValue = 'John Doe'

有五种字段名称类型:

FieldName = 'Account Holder Name'
FieldName = 'Account Number'
FieldName = 'Account Type'
FieldName = 'Bank'
FieldName = 'Bank Branch'

如果FieldName为='帐户持有人',则记录将包含AccountHoldOldValue和AccountHoldNewValue中的值

如果FieldName为='帐号',则记录将包含AccountNoOldValue和AccountNoNewValue中的值

等等。总而言之,您有5个不同fieldname类型的记录,并且在行中根据fieldname类型填充了相应的值字段。

我需要发送一封包含这些值的电子邮件。一封电子邮件创建了以下内容:

SET @MailSubject = 'Banking Details Change Notification for Employee' + ' ' + @SOURCECODE
SET @MessageBody = '<html>
<head>
  <meta content="text/html; charset=ISO-8859-1"
 http-equiv="content-type">
  <title></title>
</head>
<body>
<br>
The following bank details have been changed: 
<br>
<br>

 Date Changed:    ' + @EFFECTIVEDATE + '<br>' +
' Company:    ' + @COMPANYRULE + '<br>' +
' Username:    ' + @VIPUSERNAME + '<br>' +
' Employee Details:    ' + @SOURCECODE + '<br>' +
' Action:    ' + @ACTION + '<br>' +
' Account Holder:  ' + ' Old Value:    ' + @ACCOUNTHOLDEROLDVALUE + ' New Value:    ' + @ACCOUNTHOLDERNEWVALUE + '<br>' +
' Account Number:  ' + ' Old Value:    ' + @ACCOUNTNOOLDVALUE + ' New Value:    ' + @ACCOUNTNONEWVALUE + '<br>' +
' Account Type:  ' + ' Old Value:    ' + @ACCOUNTTYPEOLDVALUE + ' New Value:    ' + @ACCOUNTTYPENEWVALUE + '<br>' +
' Bank:  ' + ' Old Value:    ' + @BANKOLDVALUE + ' New Value:    ' + @BANKNEWVALUE + '<br>' +
' Bank Branch:  ' + ' Old Value:    ' + @BRANCHOLDVALUE + ' New Value:    ' + @BRANCHNEWVALUE + '<br>' +
'<br>
<br>
<b>
Please do not respond to this email. If you have any questions regarding this email, please
contact your payroll administrator <br>
<br>
<br>
</body>'

我似乎无法弄清楚如何只发送一封包含所有必要字段的电子邮件。

我似乎在所有字段中都收到五封空白的电子邮件,只记录了记录的前四个字段。

3 个答案:

答案 0 :(得分:0)

此查询应该为每封电子邮件提供一条记录。

laravel 5.4

您获得了令人震惊的数据库设计;我发现很难,我并不感到惊讶。该名称表明它是精简数据。它不是。这实际上是一个非常浪费的结构。

我担心每个员工有5行的断言。如果有些人没有全部5行,则必须进行外连接。如果是这种情况,您将需要为每位员工提供一种可靠的记录类型。

答案 1 :(得分:0)

从个人经验来看,每当你构建一个这样的字符串,将一堆字符串连接在一起时,你应该将每个变量包装在一个ISNULL检查中。一个空变量,整个字符串将为null。

您应该在功能中隔离用于创建电子邮件正文的逻辑。以下是一个完整的示例,其中包含用于测试的示例DDL和DML语句:

CREATE TABLE AuditCondensed (
       [AuditFieldID] INT
      ,[CompanyRuleID] INT
      ,[CompanyRule] VARCHAR(10)
      ,[VipUserName] VARCHAR(10)
      ,[EffectiveDate] DATE
      ,[FieldName] VARCHAR(25)
      ,[SourceCode] VARCHAR(25)
      ,[Action] CHAR(1)
      ,[AccountNoOldValue] VARCHAR(25)
      ,[AccountNoNewValue] VARCHAR(25)
      ,[AccountTypeOldValue] VARCHAR(25)
      ,[AccountTypeNewValue] VARCHAR(25)
      ,[BankOldValue] VARCHAR(25)
      ,[BankNewValue] VARCHAR(25)
      ,[BranchOldValue] VARCHAR(25)
      ,[BranchNewValue] VARCHAR(25)
      ,[AccountHolderOldValue] VARCHAR(25)
      ,[AccountHolderNewValue] VARCHAR(25))

INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Account Number', '1234 - John Doe', 'I', '12345', '1234567-123', NULL,  NULL, NULL, NULL, NULL, NULL, NULL, NULL)
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Account Type', '1234 - John Doe', 'I', NULL, NULL, NULL, 'Savings', NULL, NULL, NULL, NULL, NULL, NULL)
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Bank', '1234 - John Doe', 'I', NULL, NULL, NULL,  NULL, 'Old Bank', 'New Bank', NULL, NULL, NULL, NULL)
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Branch', '1234 - John Doe', 'I', NULL, NULL, NULL,  NULL, NULL, NULL, 'Branch 1', 'Branch 2', NULL, NULL)
INSERT INTO AuditCondensed VALUES (111111, 12, 'Walmart', 'john.doe', GETDATE(), 'Account Holder', '1234 - John Doe', 'I', NULL, NULL, NULL,  NULL, NULL, NULL, NULL, NULL, '', 'John Doe')

CREATE FUNCTION dbo.fn_create_email_body(@SourceCode VARCHAR(25)) RETURNS NVARCHAR(MAX)
AS
BEGIN

    DECLARE @MailSubject NVARCHAR(200) = ''
    DECLARE @MessageBody NVARCHAR(MAX) = ''
    DECLARE @EFFECTIVEDATE DATE
    DECLARE @COMPANYRULE VARCHAR(10)
    DECLARE @VIPUSERNAME VARCHAR(10)
    DECLARE @ACTION CHAR(1)
    DECLARE @ACCOUNTHOLDEROLDVALUE VARCHAR(25)
    DECLARE @ACCOUNTHOLDERNEWVALUE VARCHAR(25)
    DECLARE @ACCOUNTNOOLDVALUE VARCHAR(25)
    DECLARE @ACCOUNTNONEWVALUE VARCHAR(25)
    DECLARE @ACCOUNTTYPEOLDVALUE VARCHAR(25)
    DECLARE @ACCOUNTTYPENEWVALUE VARCHAR(25)
    DECLARE @BANKOLDVALUE VARCHAR(25)
    DECLARE @BANKNEWVALUE VARCHAR(25)
    DECLARE @BRANCHOLDVALUE VARCHAR(25)
    DECLARE @BRANCHNEWVALUE VARCHAR(25)

    SELECT TOP 1 @EFFECTIVEDATE = EffectiveDate, @COMPANYRULE = CompanyRule, @VIPUSERNAME = VipUserName, @ACTION = Action,
        @ACCOUNTHOLDEROLDVALUE = (SELECT AccountHolderOldValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Account Holder'),
        @ACCOUNTHOLDERNEWVALUE = (SELECT AccountHolderNewValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Account Holder'),
        @ACCOUNTNOOLDVALUE = (SELECT AccountNoOldValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Account Number'),
        @ACCOUNTNONEWVALUE = (SELECT AccountNoNewValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Account Number'),
        @ACCOUNTTYPEOLDVALUE = (SELECT AccountTypeOldValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Account Type'),
        @ACCOUNTTYPENEWVALUE = (SELECT AccountTypeNewValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Account Type'),
        @BANKOLDVALUE = (SELECT BankOldValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Bank'),
        @BANKNEWVALUE = (SELECT BankNewValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Bank'),
        @BRANCHOLDVALUE = (SELECT BranchOldValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Branch'),
        @BRANCHNEWVALUE = (SELECT BranchNewValue FROM AuditCondensed WHERE SourceCode = @SourceCode AND FieldName = 'Branch')
    FROM AuditCondensed 
    WHERE SourceCode = @SourceCode

    SET @MessageBody = '<html>
    <head>
      <meta content="text/html; charset=ISO-8859-1"
     http-equiv="content-type">
      <title></title>
    </head>
    <body>
    <br>
    The following bank details have been changed: 
    <br>
    <br>

     Date Changed:    ' + ISNULL(FORMAT(@EFFECTIVEDATE, 'M/d/yyyy'), '') + '<br>' +
    ' Company:    ' + ISNULL(@COMPANYRULE, '') + '<br>' +
    ' Username:    ' + ISNULL(@VIPUSERNAME, '') + '<br>' +
    ' Employee Details:    ' + ISNULL(@SOURCECODE, '') + '<br>' +
    ' Action:    ' + ISNULL(@ACTION, '') + '<br>' +
    ' Account Holder:  ' + ' Old Value:    ' + ISNULL(@ACCOUNTHOLDEROLDVALUE, '') + ' New Value:    ' + ISNULL(@ACCOUNTHOLDERNEWVALUE, '') + '<br>' +
    ' Account Number:  ' + ' Old Value:    ' + ISNULL(@ACCOUNTNOOLDVALUE, '') + ' New Value:    ' + ISNULL(@ACCOUNTNONEWVALUE, '') + '<br>' +
    ' Account Type:  ' + ' Old Value:    ' + ISNULL(@ACCOUNTTYPEOLDVALUE, '') + ' New Value:    ' + ISNULL(@ACCOUNTTYPENEWVALUE, '') + '<br>' +
    ' Bank:  ' + ' Old Value:    ' + ISNULL(@BANKOLDVALUE, '') + ' New Value:    ' + ISNULL(@BANKNEWVALUE, '') + '<br>' +
    ' Bank Branch:  ' + ' Old Value:    ' + ISNULL(@BRANCHOLDVALUE, '') + ' New Value:    ' + ISNULL(@BRANCHNEWVALUE, '') + '<br>' +
    '<br>
    <br>
    <b>
    Please do not respond to this email. If you have any questions regarding this email, please
    contact your payroll administrator <br>
    <br>
    <br>
    </body>'

    RETURN @MessageBody
END
GO

SELECT dbo.fn_create_email_body('1234 - John Doe')

请注意设置所有变量值的函数中的查询。它使用TOP来设置所有常量变量的值,使用子查询来有条件地设置依赖于FieldName的变量。如果使用此方法,则需要确保变量(和长度)的数据类型与数据库匹配。

答案 2 :(得分:0)

也许是另一种方法 dbFiddle

示例

-- Just creating a DUMMY dataset --
-----------------------------------
Declare @YourTable table (ID int,Active bit,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50))
Insert into @YourTable values
(1,1,'John','Smith','johnsmith.@email.com'),
(2,0,'Jane','Doe','janedoe.@email.com')

-- Here we have our Pattern/Template --
---------------------------------------
Declare @Pattern varchar(max) = '
Dear [[First_Name]] [[Last_Name]]

Please confirm your email address <b>[[EMail]]</b>

Thank You
'


-- The actual query --
----------------------
Select A.ID
      ,Formatted = [dbo].[svf-Str-Tokenize]((Select A.* for XML Raw),@Pattern)
 From  @YourTable A

<强>返回

ID  Formated
1   Dear John Smith

    Please confirm your email address <b>johnsmith.@email.com</b>

    Thank You

2   Dear Jane Doe

    Please confirm your email address <b>janedoe.@email.com</b>

    Thank You

感兴趣的UDF

CREATE FUNCTION [dbo].[svf-Str-Tokenize](@XML xml,@Template varchar(max))
Returns varchar(max)
Begin
    Select @Template = Replace(@Template,Item,Value)
     From (
            Select Item   = '[['+attr.value('local-name(.)','varchar(100)')+']]'
                  ,Value  = attr.value('.','varchar(max)') 
             From  @XML.nodes('/row') as xn(n)
             Cross Apply xn.n.nodes('./@*') AS xa(attr)
            Union All
            Select Item  = left(Item,charindex(']]',Item)+1)
                  ,Value = ' ' 
             From (
                Select Item  = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
                 From  (Select x = Cast('<x>' + replace((Select replace(replace(@Template,'[[','||[['),'||','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
                 Cross Apply x.nodes('x') AS B(i)
                  ) P 
             Where charindex('[[',Item)>0 and charindex(']]',Item)>0
          ) A 

    Return ltrim(rtrim(replace(replace(replace(@Template,' ','><'),'<>',''),'><',' ')))
End