views:

59

answers:

2

I'm selecting properties and joining them to mapping tables where they get mapped to filters such as location, destination, and property type.

My goal is to grab all the properties and then LEFT JOIN them to the tables, and then basically get data that shows all the locations, destinations a property is attached to and the property type itself.

Here's my query:

SELECT p.slug                                        AS property_slug, 
       p.name                                        AS property_name, 
       p.founder                                     AS founder, 
       IF (p.display_city != '', display_city, city) AS city, 
       d.name                                        AS state,
       type
       GROUP_CONCAT( CONVERT(subcategories_id, CHAR(8)) )  AS foo,
       GROUP_CONCAT( CONVERT(categories_id, CHAR(8)) ) AS bah
     FROM properties AS p 
LEFT JOIN destinations AS d ON d.id = p.state 
LEFT JOIN regions AS r ON d.region_id = r.id 
LEFT JOIN properties_subcategories AS sc ON p.id = sc.properties_id 
LEFT JOIN categories_subcategories AS c  ON c.subcategory_id = sc.subcategories_id 
    WHERE 1 = 1 
      AND p.is_active = 1       
GROUP  BY p.id 

Before I do the GROUP BY and GROUP_CONCAT my data looks like this:

id  name                  type     category_id    subcategory_id    state
--------------------------------------------------------------------------
1   The Hilton Hotel      1        1              2                 7
1   The Hilton Hotel      1        1              3                 7
1   The BlaBla Resort     2        2              5                 7

After the GROUP BY and GROUP_CONCAT it becomes...

id  name                  type     category_id    subcategory_id    state
--------------------------------------------------------------------------
1   The Hilton Hotel      1        1, 1           2, 3              7
1   The BlaBla Resort     2        1              3                 7

Is this the preferred way of grabbing all the possible mappings for the property in one go, with GROUP_CONCAT into a CSV like this?

Using this data, I can render something like...

<div class="property" categories="1" subcategories="2,3">
   <h2>{property_name}</h2>
   <span>{property_location}</span>
</div>

Then use Javascript to show/hide based on if the user clicks on an anchor which has say, a subcategory="2" attribute it would hide each .property that doesn't have 2 inside of its subcategories attribute value.

+1  A: 

You should add DISTINCT, and possibly ORDER BY:

GROUP_CONCAT(DISTINCT CONVERT(subcategories_id, CHAR(8)) 
  ORDER BY subcategories_id)  AS foo,
GROUP_CONCAT(DISTINCT CONVERT(categories_id, CHAR(8)) 
  ORDER BY categories_id) AS bah

It's "de-normalized" if you want to call it like this. If that's the best representation to be used for rendering is another question, I think it's fine. Some may say it's hack, but I guess it's not too bad.

By the way, a comma seems to be missing after the "type".

Thomas Mueller
+1  A: 

I believe you want something like this:

CREATE TABLE property (id INT NOT NULL PRIMARY KEY, name TEXT);

INSERT
INTO    property
VALUES
        (1, 'Hilton'),
        (2, 'Astoria');

CREATE TABLE category (id INT NOT NULL PRIMARY KEY, property INT NOT NULL);

INSERT
INTO    category
VALUES
        (1, 1),
        (2, 1),
        (3, 2);

CREATE TABLE subcategory (id INT NOT NULL PRIMARY KEY, category INT NOT NULL);

INSERT
INTO    subcategory
VALUES
        (1, 1),
        (2, 1),
        (3, 2),
        (5, 3),
        (6, 3),
        (7, 3);


SELECT  id, name,
        CONCAT(
        '{',
        (
        SELECT  GROUP_CONCAT(
                '"', c.id, '": '
                '[',
                (
                SELECT  GROUP_CONCAT(sc.id ORDER BY sc.id SEPARATOR ', ' )
                FROM    subcategory sc
                WHERE   sc.category = c.id
                ),
                ']' ORDER BY c.id SEPARATOR ', ')
        FROM    category c
        WHERE   c.property = p.id
        ), '}')
FROM    property p;

which would output this:

1   Hilton     {"1": [1, 2], "2": [3]}
2   Astoria    {"3": [5, 6, 7]}

The last field is a properly formed JSON which maps category id's to the arrays of subcategory id's.

Quassnoi