在一对多查询中使用SQL JOIN

时间:2014-02-12 05:36:56

标签: sql join one-to-many

我希望有人可以帮助我。我有两个表:小部件表和评论表。

widget
-------------------
widget_id   PK
id  (foreign key)
name
color
msrp

reviews
------------
review_id PK
widget_id (foreign key)
rating
source
review

我正在尝试为Codeigniter应用程序编写SQL查询。这是场景:对于给定的制造商(widget.id),返回所有widget.name,widget.color,widget.msrp和这些返回的小部件中的每一个,返回相应小部件的评论(即评论)。评级,reviews.source,reviews.review)。一个小部件可能有一个,很多或没有评论。

我正在使用Phil Stugeon的REST库,它将查询作为XML返回,因此返回的数据结构可能与此类似:

<root>
   <widget>
           <name>widget-1</name>
            <color>blue</color>
            <msrp>75.50</msrp>
            <reviews>
               <review>
                 <rating>95</rating>
                 <source>some reviewer 1</source>
                 <review>great widget!</review>
               </review>
               <review>
                 <rating>65</rating>
                 <source>some reviewer 2</source>
                 <review>Poor widget.</review>
               </review>
            <reviews>
    </widget>
    <widget>
           <name>widget-2</name>
           <color>red</color>
           <msrp>25.50</msrp>
    </widget>
 </root>

我尝试过使用子查询,foreach循环和GROUP_CONCAT的解决方案;但是,Stackoverflow上针对类似问题的受访者建议使用JOIN。

即使使用JOIN,我找不到合适的解决方案。这是我的(缩写)最后一次尝试,这是不正确的:

$widget = $this->db->query("SELECT
    widget.name
    , widget.color
    , reviews.rating AS rating
FROM
    widget
LEFT JOIN reviews
ON (widget.widget_id = reviews.widget_id)
WHERE widget.id = 46
GROUP BY widget.widget_id");

返回XML:

<root>
   <widget>
      <name>widget-1</name>
      <color>red</color>
      <rating>92</rating>
   </widget>
   <widget>
      <name>widget-2</name>
      <color>green</color>
      <rating>86</rating>
   </widget>
   <widget>
      <name>widget-3</name>
      <color>blue</color>
   </widget>
</root>

我相信我可以根据表名和列名构建缺少的评论和评论标签。主要问题是缺少行。根据数据库,Widget-1应如下所示:

<root>
   <widget>
      <name>widget-1</name>
      <color>red</color>
      <reviews>
         <review>
            <rating>92</rating>
            ...
         <review>
         <review>
            <rating>99</rating>
            ...
         <review>
      </reviews>
    </widget>
  …

我当前的查询仅返回满足条件的第一行。 (事实上​​,我将结果呈现为XML是无关紧要的。我认为它比数组更容易阅读。)提前感谢您!


修改


鉴于outis和vad soft对GROUP BY的解释,我可以更好地处理问题。当我删除GROUP BY并运行查询时,以下内容将返回:

<root>
   <widget>
      <name>widget-1</name>
      <color>red</color>
      <rating>92</rating>
   </widget>
   <widget>
      <name>widget-1</name>
      <color>red</color>
      <rating>99</rating>
   </widget>
   <widget>
      <name>widget-2</name>
      <color>green</color>
      <rating>86</rating>
   </widget>
   <widget>
      <name>widget-3</name>
      <color>blue</color>
   </widget>
</root>

不幸的是,生成的XML需要符合特定的DTD,这要求所有与特定小部件相关的评论都包含在单个父标记中。你是否表示这是不可能的;还是有另一种方法来实现这一目标;或者(可能)我错过了一个临界点? - 再次感谢。

1 个答案:

答案 0 :(得分:1)

在你的场景中,GROUP BY并不意味着你想要特定id的详细信息,并且基于你将获得你的引用表的细节,而不使用GROUP BY子句使用相同的查询因此它将找到所有记录对于子表中的相同id也。所以它会将主表数据重复为widget.name,widget.color,widget.msrp,但不要放在widget.id中。希望这会有所帮助。

$widget = $this->db->query("SELECT
    widget.name
    , widget.color
    , reviews.rating AS rating
FROM
    widget
LEFT JOIN reviews
ON (widget.widget_id = reviews.widget_id)
WHERE widget.id = 46");

由于