0

我很难将 3 张桌子连接起来。我有一个 newsletter_items、newsletter_fields 和 newsletter_mailgroups,我想加入它们以获取新闻通讯列表。

newsletter_items 包含以下字段:

letter_id, letter_date, receivers, template, status

That can look like

    1, 1234567899, 1,2 (comma separated), standard.html, 1

newsletter_fields 包含以下字段:

    field_uid, field_name, field_content, field_letter_uid

That can look like 

    1, letter_headline, A great headline, 1

其中 field_letter_uid 是该字段所属的时事通讯。

和 newsletter_mailgroups 包含以下字段:

mailgroup_id, mailgroup_name, number_of_members

That can look like 

        1, Group1, 233
        2, Group2, 124
        3, Group3, 54

我想要的是将这 3 个表格组合起来,这样我就可以得到所有时事通讯的列表,如下所示:

Letter date | Letter headline | Receivers | Status

2008-01-01 12:00:00 | A great headline | Group1, Group 2 | 1

所以简而言之,我希望我的 SQL 查询加入 3 个表,并在该过程中从邮件组表中选择接收者并显示它们以逗号分隔,如 Group1、Group 2

这是我现在得到的

SELECT A.*, B.* FROM newsletter_items A, newsletter_fields B, WHERE B.field_letter_uid = A.letter_id AND field_name = 'letter_headline' AND A.template = '". $template ."'; 

但我似乎无法弄清楚如何让邮件组进入其中。

4

3 回答 3

2

我建议您明确加入。
它使调试查询和使用左连接更改内部变得更容易。
绝对没有充分的理由使用 SQL '89 隐式连接语法。

SELECT ni.*
       , nf.*
       , group_concat(nm.mailgroup_name) as mailgroups
FROM newsletter_items ni
INNER JOIN newsletter_fields nf 
  ON (nf.field_letter_uid = ni.letter_id)
INNER JOIN newsletter_mailgroups nm  
  ON (find_in_set(nm.mailgroup_id, ni.receivers))
WHERE  
  nf.field_name = 'letter_headline' 
  ni.template = '". $template ."' 
GROUP BY ni.letter_id;

关于您的数据库设计。
我建议您规范化您的数据库,这意味着您将逗号分隔的字段移动到不同的表中。

所以你做一个表接收器

Receivers
----------
id integer auto_increment primary key
letter_id integer not null foreign key references newsletter_items(letter_id)
value integer not null

然后从表中移除现场接收器newsletter_items

然后您的查询变为:

SELECT ni.*
       , group_concat(r.value) as receivers
       , nf.*
       , group_concat(nm.mailgroup_name) as mailgroups

FROM newsletter_items ni
INNER JOIN newsletter_fields nf 
  ON (nf.field_letter_uid = ni.letter_id)
INNER JOIN newsletter_mailgroups nm  
  ON (find_in_set(nm.mailgroup_id, ni.receivers))
LEFT JOIN receiver r ON (r.letter_id = ni.letter_id)
WHERE  
  nf.field_name = 'letter_headline' 
  ni.template = '". $template ."' 
GROUP BY ni.letter_id;

此更改还应显着加快您的查询速度。

于 2011-08-26T07:57:15.527 回答
1

如果允许,为什么不创建一个名为 newsletter_item_receivers 的新表,您可以在其中存储 letter_id、receiver_id 字段?在这样的字段中使用逗号分隔值通常意味着您缺少表格:)

编辑:

通过使用 CSV,当您想要检索“给我所有 receiver_id=5 收到的时事通讯”的答案时,您的生活会变得悲惨:)

这是对 SO 上类似问题的一个很好的答案:Comma separator values in a database field

编辑2:

如果我正确理解您的表关系,那么它将是这样的:

SELECT
  a.letter_date,
  b.receiver_id,
  a.status
FROM newsletter_items_receivers b
  LEFT OUTER JOIN newsletter_items a ON (a.letter_id = b.letter_id)
  LEFT OUTER JOIN newsletter_mailgroups m ON (m.mailgroup_id = b.receiver_id)

笔记!当没有新闻通讯的接收者时,此查询将不会返回新闻通讯。如果您需要该功能,可以尝试以下操作:

SELECT
  x.letter_date,
  y.mailgroup_name,
  x.status
FROM (
SELECT
  a.letter_date,
  b.receiver_id,
  a.status
FROM newsletter_items a
  LEFT OUTER JOIN newsletter_items_rec b ON (b.letter_id = a.letter_id)) x
  LEFT OUTER JOIN newsletter_mailgroups y ON (y.mailgroup_id = x.receiver_id)

我现在无法访问 SQL,所以我可能犯了一些语法错误(希望不是逻辑错误:))。

至于我们为什么这样做,正如@Konerak 指出的那样,建议您阅读数据库规范化及其重要性。

您可以从 about.com 的这篇文章开始,只是浏览了一下似乎可以阅读 http://databases.about.com/od/specificproducts/a/normalization.htm

此外,最好在多个表中保持字段名称相同。例如,您在 newsletter_items 中有 letter_id,但在 newsletter_fields 中有 field_letter_uid。只是一个想法 :)

于 2011-08-26T07:11:55.313 回答
0

尝试使用

SELECT A.*, B.*, group_concat(C.mailgroup_name SEPARATOR ',') 
FROM newsletter_items A,  newsletter_fields B, newsletter_mailgroups C  
WHERE B.field_letter_uid = A.letter_id 
      AND field_name = 'letter_headline' 
      AND A.template = '". $template ."' 
      and find_in_set(c.mailgroup_id, A.receivers) 
group by A.letter_id;
于 2011-08-26T07:16:54.140 回答