使用GROUP_CONCAT

时间:2013-08-20 03:04:22

标签: mysql sql

我有三张桌子。 TB_Main是实体表。 TB_BoardMembers是一个人员表。 TB_BoardMembersLINK是一个桥接表,它通过ID引用其他两个,并且还有一个Person在一个实体的董事会上的开始和结束日期。这些日期通常不完整。

我被要求作为报告的一部分导出CSV,每个实体每年一行,其中我有一个当年的董事会成员列表,其职业位于由换行符分隔的单个字段中。

我在结果中不需要bml.Entity,但添加它以尝试调试。我得到一行,我期望85.尝试使用和没有GROUP BY,结果是相同的事实表明我滥用GROUP_CONCAT。我应该如何构建它以获得他们想要的结果?

SELECT 
GROUP_CONCAT(
DISTINCT CONCAT(bm.First, ' ', bm.Last, 
IF (bm.Occupation != '', ' - ', ''),
bm.Occupation)  SEPARATOR "\n") as Board,
bml.Entity
FROM  
TB_Main arfe,
TB_BoardMembers  bm,
TB_BoardMembersLINK  bml
WHERE YEAR(bml.start) <= 2011 
AND (YEAR(bml.end) >= 2011 OR bml.end IS NULL)
AND bml.start > 0 
AND bml.Entity = arfe.ID
GROUP BY bml.Entity
ORDER BY Board

2 个答案:

答案 0 :(得分:2)

此查询存在一些问题。主要问题似乎是您缺少将董事会成员链接到链接表的条件,因此您有一个交叉联接,即您将返回每个宽带成员,无论其开始/结束日期如何,并假设您有85行在标准匹配的情况下,您实际上将返回每个董事会成员85次。这突出了从您使用的ANSI 89隐式连接切换到ANSI 92显式连接语法的一个很好的理由。 This article强调了进行转换的一些非常好的理由。

所以你的查询会变成(我不得不猜测你的字段名称):

SELECT  *
FROM    TB_Main arfe
        INNER JOIN TB_BoardMembersLINK  bml
            ON bml.Entity = arfe.ID
        INNER JOIN TB_BoardMembers  bm
            ON bm.ID = bml.BoardMemberID

我注意到你的查询的下一件事是使用where子句中的函数根本不是很有效,所以因为这个:

WHERE   YEAR(bml.start) <= 2011 
AND     (YEAR(bml.end) >= 2011 OR bml.end IS NULL)

您正在为每一行操作YEAR函数两次,并删除在bml.Startbml.End(如果存在)上使用索引的任何可能性。然而,Aaron Bertrand在查询日期范围时写了a nice article突出显示良好做法,它是SQL-Server的目标,但原则仍然相同,因此你的where子句将成为:

WHERE   bml.Start <= '20110101'
AND     (bml.End >= '20110101' OR bml.End IS NULL)
AND     bml.start > 0 

您的最终查询应该是:

SELECT  bml.Entity,
        GROUP_CONCAT(DISTINCT CONCAT(bm.First, ' ', bm.Last, 
            IF (bm.Occupation != '', ' - ', ''), bm.Occupation) 
            SEPARATOR "\n") as Board
FROM    TB_Main arfe
        INNER JOIN TB_BoardMembersLINK  bml
            ON bml.Entity = arfe.ID
        INNER JOIN TB_BoardMembers  bm
            ON bm.ID = bml.BoardMemberID
WHERE   bml.Start <= '20110101'
AND     (bml.End >= '20110101' OR bml.End IS NULL)
AND     bml.start > 0
GROUP BY bml.Entity
ORDER BY Board;

<强> Example on SQL Fiddle

答案 1 :(得分:0)

如果你读了Group_Concat

“此函数返回一个字符串结果,其中包含来自组的连接非NULL值。”

在这种情况下,该组似乎只是一个组,正如您所说,只有一个实体?我不确定你的描述是否属于这种情况。为什么不按名字,姓氏和职业分组,这可能会给你所有的成员。

我也不确定你的连接,没有真正的数据很难解释那个部分,因为每个连接都适用于某些数据集,即使它不是编写查询的最佳方式