使用连接,分组依据和子查询,哦,我的!

时间:2011-07-27 11:57:38

标签: mysql join group-by subquery

我有一个数据库,其中有关于小马的详细信息,另一个有关联系人(所有者和繁殖者)的详细信息,还有其他几个小参数表(颜色,县,区号等)。为了给我一个现有小马配置文件列表,给出各种详细信息,我使用以下查询:

SELECT *
    FROM profiles
        INNER JOIN prm_breedgender
            ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
        LEFT JOIN contacts
            ON profiles.ProfileOwnerID = contacts.ContactID
        INNER JOIN prm_breedcolour
            ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
    ORDER BY profiles.ProfileYearOfBirth ASC $limit

在上面的示例中,'profiles'表是我的主表(保存Ponies信息),'contacts'在重要性保持中排名第二,因为它具有所有者和育种者信息。较小的参数表可以通过其prm_前缀来标识。上面的查询工作正常,但我想做更多。

第一个重要问题是我希望按性别对结果进行分组:种马,马雷斯,阉割......我用过<< GROUP BY prm_breedgender.BreedGender>>或<< GROUP BY ProfileBreedGenderID>>在我的ORDER BY行之前,但只返回我所有可用配置文件中的两个结果。我已经阅读了这个,并且显然需要重新组织我的查询以在我的主要SELECT子句中容纳GROUP。然而,如何做到这一点,让我感到困惑。这里一步一步的帮助将是非常棒的。

作为对上述内容的进一步说明 - 您可能已经注意到我的查询结尾处的$ limit var。这是分页,我想保留的功能。但我不认为这是一个问题。

我的第二个问题更多是组织问题。您可以在此处查看我从联系人表格中提取所有者信息的位置:

    LEFT JOIN contacts
        ON profiles.ProfileOwnerID = contacts.ContactID

我可以补充另一条规定:

        AND profiles.ProfileBreederID = contacts.ContactID

意图是能够列出小马的所有者和饲养员,其中任何一个的信息都可用。我不知道如何回应这些信息,因为$ row ['ContactName']可能适用于所有者或饲养员的能力。

这是一个简单地运行两个查询而不是一个查询的情况吗?为第一次运行查询分配变量$ foo,然后只运行另一个单独的查询并为这些结果分配$ bar?或者是否有更聪明的方法在一个查询中完成所有操作(例如$ row ['ContactName'] First-iteration,$ row ['ContactName'] Second-iteration)?这里的建议将非常感激。

就是这样!我尽量保持清醒,并且非常感谢您提供的任何帮助或建议。提前谢谢。

################################################## ########################编辑

我的查询目前是Cularis和Symcbean提供的混合:

SELECT *
        FROM    (
            profiles
            INNER JOIN prm_breedgender
                ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
            LEFT JOIN contacts AS owners
                ON profiles.ProfileOwnerID = owners.ContactID
            INNER JOIN prm_breedcolour
                ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
            )
        LEFT JOIN contacts AS breeders
            ON profiles.ProfileBreederID = breeders.ContactID
        ORDER BY prm_breedgender.BreedGender ASC, profiles.ProfileYearOfBirth ASC $limit

只要按照我的预期安排结果,即按年龄和性别安排,它就能正常运作。但是,我似乎无法让别名'与联系人查询(饲养员和所有者)相关。没有显示错误,也没有任何所有者或饲养员。任何进一步的澄清将非常感激。

P.S。我通过Symcbean的例子删除了给最终LEFT JOIN的别名,因为我无法得到生成的ORDER BY语句为我工作 - 我自己的错,我确定。尽管如此,它现在可以正常工作,尽管这可能是导致联系人查询问题的原因。

3 个答案:

答案 0 :(得分:2)

SQL术语中的

GROUP表示在一组条目上使用聚合函数。我想你想要的是性别顺序:

ORDER BY prm_breedgender.BreedGender ASC, profiles.ProfileYearOfBirth ASC $limit

这将输出彼此相邻的所有种马等。

要获得育种者联系,您还需要使用别名再次加入联系人表格:

LEFT JOIN contacts AS owners
            ON profiles.ProfileOwnerID = owners.ContactID

LEFT JOIN contacts AS breeders
            ON profiles.ProfileBreederID = breeders.ContactID

答案 1 :(得分:2)

为了进一步扩展@cularis所说的内容,group by用于聚合到最低级别的“分组”标准。例如,我没有根据您的具体表格进行操作,但您会看到影响。假设您要显示按品种分组的页面。然后,用户选择一个品种,他们可以看到该品种的所有条目。

PonyID   ProfileGenderID    Breeder
1        1                  1
2        1                  1
3        2                  2
4        3                  3
5        1                  2
6        1                  3
7        2                  3

Assuming your Gender table is a lookup where ex:
BreedGenderID   Description
1               Stallion
2               Mare
3               Geldings

SELECT *     FROM个人资料         INNER JOIN prm_breedgender             ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID

select
      BG.Description,
      count(*) as CountPerBreed
   from
      Profiles P
         join prm_BreedGender BG
            on p.ProfileGenderID = BG.BreedGenderID
   group by
      BG.Description
   order by 
      BG.Description

会产生类似的结果(计数只是偶然顺序)

Description   CountPerBreed
Geldings      1
Mare          2
Stallion      4

将“order by”子句更改为“按CountsPerBreed Desc排序”(用于降序),您将获得

Description   CountPerBreed
Stallion      4
Mare          2
Geldings      1

要扩展,如果您希望每个种鸽分解聚合...最佳做法是将所有非聚集的东西分组(例如MIN(),MAX(),AVG(),COUNT (),SUM()等)

select
      BG.Description,
      BR.BreaderName,
      count(*) as CountPerBreed
   from
      Profiles P

         join prm_BreedGender BG
            on p.ProfileGenderID = BG.BreedGenderID

         join Breeders BR
            on p.Breeder = BR.BreaderID
   group by
      BG.Description,
      BR.BreaderName
   order by 
      BG.Description

会产生类似的结果(计数只是偶然顺序)

Description   BreaderName  CountPerBreed
Geldings      Bill         1
Mare          John         1
Mare          Sally        1
Stallion      George       2
Stallion      Tom          1
Stallion      Wayne        1

正如您所看到的,您为组提供的粒度越多,每个级别的聚合就越小。

根据您提供的内容,您的加入条件显然是明白的。希望此示例清楚地提供查询过程将执行的操作。你的小组不必与最终订单相同......只是通常看到有人看到结果并不是想要猜测数据是如何组织的。

在您的样本中,您有出生年份的订单。当进行聚合时,你将永远不会有单个小马的特定出生年份,以便按顺序排序......除非......你将YEAR(ProfileYearOfBirth)作为一个列包含在BirthYear中,并包含在你的小组中。 ..例如,1岁时有100匹小马,给定品种的2岁时有37只。

答案 2 :(得分:0)

如果您提供了表结构和大致行数的详细信息,那将会很有帮助。使用'*'作为SELECT也是一种混乱的做法 - 以后会引起你的问题(见下文)。

这是什么版本的MySQL?

  

显然需要重新组织我的查询以容纳我的主要SELECT子句中的GROUP

不一定从v4(?IIRC)开始,您可以将查询包装在合并选择中(但将限制移到外部选择中:

SELECT ProfileGenderID, COUNT(*)
FROM (
 [your query without the LIMIT]
) ilv
GROUP BY ProfileGenderID
LIMIT $limit;

(注意你不能通过ilv.ProfileYearOfBirth ORDER BY,因为它不是按表达式选择的列/组)

prm_breedgender中有多少条记录/列?它只是Stallions,Mares,Geldings ......?你认为这个清单可能会改变吗?你有多种性别的小马吗?我怀疑这个域可以更好地由配置文件表中的枚举表示。

  

旨在能够列出小马的所有者和饲养员,

使用您建议的代码,您将只返回所有者和饲养员相同的返回实例!您需要使用不同的别名添加contacts表的第二个实例以获取所有这些实例,例如

SELECT *
FROM (
  SELECT *
  FROM profiles
    INNER JOIN prm_breedgender
        ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
    LEFT JOIN contacts ownerContact
        ON profiles.ProfileOwnerID = ownerContact.ContactID
    INNER JOIN prm_breedcolour
        ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
) ilv LEFT JOIN contacts breederContact
     ON ilv.ProfileBreederID = breederContact.ContactID
ORDER BY ilv.ProfileYearOfBirth ASC $limit