tags:

views:

172

answers:

2

Is that possible? I mean, can both ends of the many to many relationship point to the same table?

A: 

If you are using hibernate-annotations, there is a @ManyToMany, not sure about the XML equivalent. It should appear in the API documentation of your distribution

Uri
+1  A: 

I'm not sure how you'd do it without enormous, horrible redundancy. The standard way to handle a many-to-many relationship between two tables is via a third table that contains two primary key values, one for the first table, one for the second table, with a unique constraint (read 'index') on the combination of all those columns, and possibly with one or two duplicate (non-unique) indexes on the separate primary keys. In outline:

CREATE TABLE Table1 (pkcol1 ... PRIMARY KEY, ...);
CREATE TABLE Table2 (pkcol2 ... PRIMARY KEY, ...);
CREATE TABLE MtoM_Table1_Table2
(
     pkcol1 ... REFERENCES Table1,
     pkcol2 ... REFERENCES Table2,
     PRIMARY KEY (pkcol1, pkcol2)
);
-- CREATE INDEX fk1_mtom_table1_table2 ON MtoM_Table1_Table2(pkcol1);
-- CREATE INDEX fk2_mtom_table1_table2 ON MtoM_Table1_Table2(pkcol2);

If your DBMS is intelligent, you can skip the separate index on the leading column of the primary key since the index on the primary key can also be used when searching for the just the leading value.

Suppose Table1 and Table2 are the same table (so, in fact, we have just Table1), as in the question; this would normally still require the MtoM_Table1_Table1 mapping table - a separate table from the main table. The mapping table must have separate names for the PK (primary key) column, but both columns (or sets of columns) in the mapping table will refer to the PK column(s) in Table1.

CREATE TABLE Table1 (pkcol1 ... PRIMARY KEY, ...);
CREATE TABLE MtoM_Table1_Table1
(
     pkcol1 ... REFERENCES Table1(pkcol1),
     akcol1 ... REFERENCES Table1(pkcol1),
     PRIMARY KEY (pkcol1, akcol1)
);
-- CREATE INDEX fk1_mtom_table1_table1 ON MtoM_Table1_Table1(pkcol1);
-- CREATE INDEX fk2_mtom_table1_table1 ON MtoM_Table1_Table1(akcol1);

If you wanted to eliminate the mapping table too, then you would have to have a second column in Table1 to hold the other PK value - call it FKcol1 (for foreign key column). This then leaves you with a quandary: what is the primary key? It has to be the combination of PKCol1 and FKCol1. But FKCol1 is supposed to reference the primary key of another row -- so you have a contradiction. Even supposing you managed to avoid that as a problem (how, exactly?), to have 'many rows' in the referencing side of the many-to-many relationship, you must have multiple rows in the master table with the same data in all columns except FKcol, but these will reference a number (more than one, in general) other rows in the table. This is a contradiction plus a nightmare of redundancy, plus you've lost your simple primary key, plus it would be horrible to work out what the heck is going on.

CREATE TABLE Table1
(
    pkcol1 ... /* PRIMARY KEY */,
    fkcol1 ... /* FOREIGN KEY REFERENCES Table1(pkcol1) */,
    ...
);
-- CREATE INDEX fk1_table1 ON Table1(pkcol1);
-- CREATE INDEX fk2_table1 ON Table1(fkcol1);

So, I'm convinced that the only sane answer is "No - you cannot represent both ends of a many-to-many relationship in the same table; you must use a mapping table to retain much chance of anything working 'as usual' in the system".

Jonathan Leffler