Question

I am hoping someone can help me. I have two tables: widget table and reviews table.

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

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

I am trying to work out a sql query for a Codeigniter app. Here’s the scenario: For a given manufacturer (widget.id), return all widget.name, widget.color, widget.msrp AND for each of these returned widgets, return the review(s) of the respective widgets (i.e., reviews.rating, reviews.source, reviews.review). One widget may have one, many or no reviews.

I’m using Phil Stugeon’s REST library, which returns the query as XML, so the returned data construct might look similar to this:

<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>

I have tried solutions using subqueries, foreach loops, and GROUP_CONCAT; however, respondents on Stackoverflow for similar questions suggest the use of a JOIN.

I cannot find the right solution even with a JOIN. Here is my (abbreviated) last attempt, which is incorrect:

$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");

Returned 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>

I am fairly confident I can build the missing reviews and review tags from the table name and column name. The major issue is missing rows. Widget-1 should look like this per the database:

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

My current query only returns the first row that meets the conditions. (The fact that I've presented the result as XML is inconsequential. I thought it may be easier to read than arrays.) Thank you in advance!


EDIT


Given outis and vad soft's explanation of GROUP BY I have a better handle of the problem. When I remove GROUP BY and run the query, the following returns:

<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>

Unfortunately, the resultant XML needs to conform to a particular DTD, which requires all reviews pertaining to a particular widget to be contained within a single parent tag. Are you indicating that this will not be possible; or is there another way to achieve this; or (and likely) have I missed a critical point? -Thanks again.

Was it helpful?

Solution

In your scenerio, the GROUP BY doesn't mean because you want particular id's details and based on you will get the details of your reference table, instead use the same query without using GROUP BY clause hence it will find all the records for the same id in child table also. So it will repeat the master table data as widget.name, widget.color, widget.msrp but don't put here widget.id. Hope this helps.

$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");

Thanks

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top