tags:

views:

55

answers:

6

I have two databases - one for articles and the another for the articles' meta information (Like author, date, category and atc.). I have the following columns in meta table: ID, article id, meta type and meta value. I wonder how can I join these two tables to get both - article and meta information - with one mysql query. The article id isn't unique in meta table, that is why I can't figure out how to access specific meta type and according value for the article...

Here is the mysql I'm tried to use:

SELECT products.*, product_meta.meta_value
FROM products
LEFT JOIN product_meta ON products.ID = product_meta.product_id

but this query doesn't seem to be what I need. I there are for example two records in articles table and ten in meta table this code displays ten results instead of two:

$products = mysql_query("SELECT products.*, product_meta.meta_value
                         FROM products
                         LEFT JOIN product_meta ON products.ID = product_meta.product_id") or die(mysql_error());

while ($product = mysql_fetch_assoc($products)) {
    echo $product["title"];
}

Can anyone please help?

A: 

just change the LEFT JOIN to a RIGHT JOIN and you should get the results you want. or flip the query: SELECT ... FROM product_meta LEFT JOIN product .. etc.

GSto
Not right. I this case it will retrieve rows only from meta table, despite there is a corresponding record in articles table or not...
Levani
A: 

"I have the following columns in meta table: ID, article id, meta type and meta value."

Are you sure this is an appropriate design? If an article can only ever have at most one author, date etc. then perhaps these should be columns in the "article" table. (On the other hand, it's quite possible to envisage an article being co-authored by several people - but then you would probably want an "article_authors" table specifically to list the authors of articles, rather than this Entity-Attribute-Value system you have going.)

If you're dead set on using this design, then you could:

1) Fetch the metadata for each article in one row, concatenated into a single field.

2) Just look for articles, and for each article run a query to get metadata from the "meta" table:

$products = mysql_query("SELECT products.*, product_meta.meta_value
                         FROM products
                         LEFT JOIN product_meta ON products.ID = product_meta.product_id") or die(mysql_error());

while ($product = mysql_fetch_assoc($products)) {
    $products_meta = mysql_query( /* something else */ );
    echo $product["title"];
}

3) Run the query you already have, but check at each row whether it's a new article, or just more metadata for the previous article:

$products = mysql_query("SELECT products.*, product_meta.meta_value
                         FROM products
                         LEFT JOIN product_meta ON products.ID = product_meta.product_id") or die(mysql_error());

$old_product_id = -1;
while ($product = mysql_fetch_assoc($products)) {
    if ( $product['product_id'] != $old_product_id ) {
        $old_product_id = $product['product_id'];
        echo $product["title"];
    }
}
Hammerite
A: 

Hi Levani, try the following sql statements:

SELECT products.*, product_meta.meta_value
FROM products LEFT OUTER JOIN product_meta 
ON products.ID = product_meta.product_id
WHERE product_meta.product_id NOT IS NULL
Broadhead
A: 

Check out Jeff's guide to SQL joins for some help figuring out which join might be best for your purposes.

Dave McClelland
A: 

Use subqueries:

SELECT products.*, (SELECT product_meta.meta_value FROM product_meta WHERE 
  products.ID = product_meta.product_id AND meta_type = "author") AS meta_author 
FROM products

You can add more subqueries to add more meta_types toe the resultset.

But beware that subqueries don't offer optimal performance. If the mysql performance is important, you could consider using your current join statement and transpose the data in php.

Bob Fanger
A: 

I'd also question the database design as a starter - it strikes me that some 'meta types' (Author, Category) should be separate tables, while others (Date) should live in the article table. Database normalisation is the key, and there's a great intro on the MySQL site: http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html

When it comes to joining tables, you might prefer to use something like:

SELECT 
  products.*, product_meta.meta_value 
FROM 
  products, product_meta 
WHERE 
  products.ID = product_meta.product_id 
  AND product_meta.meta_type = 'author';

ie. listing the tables in the from clause instead of using a join

Then again, for the purpose of simply returning the relevant meta rows, it may be that all you need to do is add a 'WHERE' clause to your existing query:

... WHERE product_meta.meta_type = 'author';
afsk