在MS Access中创建一个邮件列表,其中有多个具有相同姓氏和地址的记录

时间:2015-06-28 00:51:42

标签: ms-access

我需要从访问查询中创建一个邮件列表,其中丈夫和妻子单独输入,但需要使用一个邮件标签邮寄给他们

2 个答案:

答案 0 :(得分:0)

对此回复的长篇大论表示抱歉。如果我理解正确,您希望为数据库中的每个唯一地址创建一个邮件标签,其中丈夫和妻子是或可以单​​独输入。

你没有提供太多细节,所以我将提供两个如何实现你想要的例子,一个基于能够通过性别,性别或称呼栏来区分丈夫和妻子的例子(例如先生或者夫人) )和另一个基于简单的最小值和最大值,以获得你需要的每个元素。

每个解决方案都需要使用SubQueries,它是括在括号中的一组Select和From语句。由于它们返回一组数据,因此可以将它们视为表或查询,并在外部From子句中使用。我们还将进行防御性编码,以确保我们不会通过Null Propogation获得一点,这意味着如果表达式中的任何一个或多个项目评估为Null,则整个表达式将返回Null。

如果你需要一点Sql复习,我会建议W3Schools Sql Tutorial

出于以下示例的目的,我在MS Access中使用了一个Family表,定义如下:

enter image description here

输入一些测试数据,包括个人,已婚夫妇和至少一个有三个地址相同的记录。

为了获得所需的结果,我们将结合使用表和子查询以及Union All。我们将首先从最佳解决方案开始,即您可以通过主表中的某些列或通过外键将男性和女性记录区分为关联表。在上面的例子中,我们可以通过性别或称呼列来区分男性和女性。我将使用Sex列来区分它们。

在任何一种情况下,我们都会使用Group By子句来帮助我们获得所需的结果。将Group By视为查询用于在处理数据之前对数据进行排序的内部排序。 Group By的规则非常简单,您不能引用Select语句中未包含在Group By子句中的任何列,除非它与仅返回一个值的Aggregate Function一起使用。因此,在我们的示例中,我们无法直接访问FirstName或LastName列,但可以通过Min或Max函数引用它们。我们使用哪一个并不重要,因为到那时我们只有一条记录可供处理。

要查看,我们需要三个结果集,一个具有唯一地址的单个记录,一个具有两个唯一地址记录,另一个具有其他所有地址。后一种情况不是预期的,但确保在出现这种情况时至少处理它们。

第一种情况最简单,如下面的代码所示。从技术上讲,我们确实不需要在First和Last名称列上使用别名,但在测试时它不会伤害任何东西并击败Expression1,Expression2等。

我们正在对Address1,Address2,City,State和ZipCode进行分组。 Having子句将Group By限制为单行或多于2行的唯一地址。

Select Max(FirstName) As FirstName2, Max(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
From Family
Group By Address1, Address2, City, State, ZipCode
Having Count(*) = 1 Or Count(*) > 2

接下来,我们需要匹配丈夫和妻子的记录。我们使用两个基本相同的SubQueries别名为tMen和tWomen。 Inner Join的使用确保了我们每个人都有匹配的man and women行,并且使用Having子句确保我们只处理两个记录。

下面的代码中有几个感兴趣的项目

  1. 访问要求列别名与任何列名称不同
  2. 可以在Select
  3. 中直接选择Group By中引用的列
  4. Group By中未引用的列需要Select
  5. 中的功能
  6. 在可能包含Null数据的任何列上一起使用IIf和IsNull函数以保护我们免受Null传播
  7. 在SubQueries中,我们将函数别名为FirstName2和LastName2。然后,在外部Select中,我们将FirstName2和LastName2别名改为FirstName和LastName。

    Select (tMen.FirstName2 + ' and ' + tWomen.FirstName2) As FirstName, tMen.LastName2 As LastName, tMen.Address1, tMen.Address2, tMen.City, tMen.State, tMen.ZipCode, tMen.GroupCount
    From 
          (Select Min(FirstName) As FirstName2, Min(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
           From Family 
           Where Sex ='Male'
           Group By Address1, Address2, City, State, ZipCode
           Having Count(*) = 1) As tMen Inner Join
    
          (Select Min(FirstName) As FirstName2, Min(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
           From Family
           Where Sex ='Female'
           Group By Address1, Address2, City, State, ZipCode
           Having Count(*) = 1) As tWomen
    
                   On (tWomen.Address1 = tMen.Address1) And 
                      (IIf(IsNull(tWomen.Address2), '', tWomen.Address2) = IIf(IsNull(tMen.Address2), '', tMen.Address2)) And 
                      (tWomen.City = tMen.City) And  
                      (tWomen.State = tMen.State) And 
                      (tWomen.ZipCode = tMen.ZipCode)
    

    最后,我们将它们全部放在一起用于解决方案1. Order By子句是最后一个并且属于整个结果集,而不仅仅是Union All下的最后一个Select语句。此外,Union All连接的各种Select语句中列的计数和类型必须匹配。列名来自第一个外部Select语句。

    Select (tMen.FirstName2 + ' and ' + tWomen.FirstName2) As FirstName, tMen.LastName2 As LastName, tMen.Address1, tMen.Address2, tMen.City, tMen.State, tMen.ZipCode, tMen.GroupCount
    From 
          (Select Min(FirstName) As FirstName2, Min(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
           From Family 
           Where Sex ='Male'
           Group By Address1, Address2, City, State, ZipCode
           Having Count(*) = 1) As tMen Inner Join
    
          (Select Min(FirstName) As FirstName2, Min(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
           From Family
           Where Sex ='Female'
           Group By Address1, Address2, City, State, ZipCode
           Having Count(*) = 1) As tWomen
    
                   On (tWomen.Address1 = tMen.Address1) And 
                      (IIf(IsNull(tWomen.Address2), '', tWomen.Address2) = IIf(IsNull(tMen.Address2), '', tMen.Address2)) And 
                      (tWomen.City = tMen.City) And  
                      (tWomen.State = tMen.State) And 
                      (tWomen.ZipCode = tMen.ZipCode)
    
    Union All
    
    Select Max(FirstName) As FirstName2, Max(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
    From Family
    Group By Address1, Address2, City, State, ZipCode
    Having Count(*) = 1 Or Count(*) > 2
    
    Order By LastName, FirstName, State, CIty, ZipCode
    

    由于这篇文章的篇幅,我将分别发布第二个解决方案。

答案 1 :(得分:0)

继续之前的解决方案,第二种解决方案更为通用,如果您没有可用的列,则可以使用该解决方案,以便您在定义的方案中区分男性和女性。它以与上面发布的原始解决方案类似的方式使用SubQueries,但使用Min和Max返回两个唯一地址中的一个或另一个。这种解决方案不太可取,因为它取决于丈夫和妻子的姓名,因此不能首先或最后拥有丈夫或妻子。

此解决方案与上面发布的第一个解决方案非常相似。因为我们无法区分男性和女性,所以性别=男性和性别=女性的Where子句被删除。而是在每个SubQueries中的Group By子句下面添加Having Count(*)= 2。然后我们使用FirstName和LastName上的Min和Max函数来获取它们中的每一个。 Select语句中的Distinct语句确保我们只从每个SubQuery获得一个结果。

Select (tMin.FirstName2 + ' and ' + tMax.FirstName2) As FirstName, tMax.LastName2 As LastName, tMax.Address1, tMax.Address2, tMax.City, tMax.State, tMax.ZipCode, tMax.GroupCount
From 
      (Select Distinct Max(FirstName) As FirstName2, Max(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
       From Family
       Group By Address1, Address2, City, State, ZipCode
       Having Count(*) = 2) As tMax Inner Join

       (Select Distinct Min(FirstName) As FirstName2, Min(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
       From Family
       Group By Address1, Address2, City, State, ZipCode
       Having Count(*) = 2) As tMin

               On (tMax.Address1 = tMin.Address1) And 
                  (IIf(IsNull(tMax.Address2), '', tMax.Address2) = IIf(IsNull(tMin.Address2), '', tMin.Address2)) And 
                  (tMax.City = tMin.City) And  
                  (tMax.State = tMin.State) And 
                  (tMax.ZipCode = tMin.ZipCode)

Union All

Select Max(FirstName) As FirstName2, Max(LastName) As LastName2, Address1, Address2, City, State, ZipCode, Count(*) As GroupCount
From Family
Group By Address1, Address2, City, State, ZipCode
Having Count(*) = 1 Or Count(*) > 2

Order By LastName, FirstName, State, CIty, ZipCode