tags:

views:

133

answers:

8

Let's say I have these tables, with these fields:

companies: company_id | name | num_employees

companies_countries: company_id | country_id

countries: country_id | country_iso_code

Assuming this is a 1:1 relationship: How can I join the country_iso_code directly into the company recordset, when I fetch all the companies? I think I would need two joins here?

+6  A: 

A simple example :

select c.name, n.country_iso_code
from companies c,
companies_countries x,
countries n
where x.company_id = c.company_id
and n.country_id = x.country_id

Edit

For a good intro to JOIN, have a look at SQL JOIN.

Steve De Caux
No join? really?
openfrog
I learned SQL in the 80s, this is the original form of 'join' syntax, which to me is easier to read and takes less words to write
Steve De Caux
But internally it's the same thing as if I would use JOIN keywords?
openfrog
The implicit join in the sql example I gave is equivalent to specifying an INNER JOIN. Have a squizz at the link in my edited answer.
Steve De Caux
It is not generally exactly equivalent - or rather, it is only equivalent in absence of JOIN conditions in the ON clause. From the manual: INNER JOIN and , (comma) are semantically equivalent in the absence of a join condition: both produce a Cartesian product between the specified tables (that is, each and every row in the first table is joined to each and every row in the second table). You probably want a LEFT JOIN anyway.
mst
@mst : I don't think you understand the fine points : maybe you should have a look at the link in my answer too.
Steve De Caux
+1  A: 

Yes, you would need two joins.

You can create a view and fake a single join though...

Pablo Santa Cruz
There are advantages and disadvantages with a view. Pro: the view will serve as a central definition of the read part of the 1:1 relationship. You will be able to update it centrally when the 1:1 relationship is no longer relevant. Cons: weaker performance (under MySQL anyway - PostgreSQL has the awesome rule tree rewriter which actually makes Postgres views behave more like macros and not stored queries)
mst
+1  A: 
select companies.* from countries, companies_countries, companies where countries.country_id=companies_countries and companies_countries.company_id=company_id and countries.country_iso_code='xxxx'

where xxxx is the iso code you want to match

Charles Ma
is that essentially the same thing as using "join" keywords? I see you write from a,b,c, so I assume this is another syntax for joining? Is there a difference in performance?
openfrog
`@openfrog`: this is a such called implicit join syntax, as opposed to `ANSI`, or explicit join syntax (which used the `JOIN` keywords). In all databases I'm aware of both syntaxes use the same execution plans, but the `ANSI` syntax is generally considered more legible.
Quassnoi
+2  A: 
SELECT co.*, cu.country_iso_code 
FROM companies co 
LEFT JOIN companies_countries cc ON cc.company_id = co.company_id
LEFT JOIN countries c ON c.country_id = cc.country_id

Why LEFT JOIN and not the WHERE condition like in other examples? A join table (companies_countries) is not typically used in 1:1 relationships - it is overnormalization.

When your relationship ceases to be 1:1:

SELECT co.*, GROUP_CONCAT(cu.country_iso_code)
FROM companies co 
LEFT JOIN companies_countries cc ON cc.company_id = co.company_id
LEFT JOIN countries c ON c.country_id = cc.country_id

This will return results like

CompanyA | Canada,USA,Mexico
CompanyB | Ireland,UK,Japan
mst
+3  A: 
SELECT 
    companies.company_id, 
    companies.name, 
    companies.num_employees, 
    countries.country_iso_code
FROM
    companies
LEFT JOIN
    companies_countries ON (companies_countries.company_id = companies.company_id)
LEFT JOIN
    countries ON (countries.country_id = companies_countries.country_id);

A query that uses a LEFT JOIN instead of an INNER JOIN or an implicit join, will return companies even when they have no country assigned. On the other hand, a query with an INNER JOIN would skip companies that do not have an assigned country in companies_countries.

Note that your design is implying that each company can be assigned more than one country. If you want to enforce only one country for each company, simply put a country_id column in your companies table. You would not need the companies_countries table.

Daniel Vassallo
Thanks. Sure that would be easier. I try to maintain flexibility with this, so at any given time in future I could turn the switch and say: "hey, now this is an 1:n relationship, my friends!", and users can start add more than one photo to their profile (for example), without restructuring the database.
openfrog
+1  A: 
select c.company_id, c.name, c.num_employees, co.county_iso_code from
companies c, companies_countries cc, countries co
where c.company_id = cc.company_id 
and cc.country_id = co.country_id
klausbyskov
+2  A: 
select name, country_iso_code 
from companies left join companies_countries 
   on (companies.company_id = companies_countries.company_id)
left join countries 
   on (companies_countries.country_id = countries.country_id)
Arthur Thomas
+2  A: 

This is not a 1:1 relationship. A country can have more the one company.

This is either a 1:N relationship (for some reason implemented using two relational tables), or the M:N relationship which describes multinational companies.

If this is a 1:N relationship, you could just put the country_code field into the companies table, in which case one join would be enough:

SELECT  *
FROM    companies co
LEFT JOIN
        countries cn
ON      cn.country_code = co.country_code

Your design is viable for both 1:N and M:N relationships, in which case two joins are required:

SELECT  co.*, cn.*
FROM    companies co
LEFT JOIN
        company_countries cc
ON      cc.company_id = co.company_id
LEFT JOIN
        countries cn
ON      cn.country_code = cc.country_code

If this is a 1:N relationship, you should make company_id a PRIMARY KEY in the company_country table.

If this is a M:N relationship, you should make a composite PRIMARY KEY on company_country (company_id, country_code)

You may want to read this article in my blog about the difference between entity-relationship model and its relational implementation:

Quassnoi
Your blog article is great. Have commented it! Thanks!
openfrog