You betcha. Man I miss my keyboard :P
Not a PHP join (join in PHP is an alias of implode which lets you combine a string into an array). We want an SQL join.
This is essentially your tables:
Code:
+------------+ +----------------+
| Phrase | | PhrasePair |
+------------++o-----o<+----------------+
| phrase [PK]| | pair1 [PK][FK] |
+------------+ | pair2 [PK][FK] |
+----------------+
Pair1 and Pair2 are both belonging to phrase. Now, how you handle the two is kinda where you make a choice, and effect the query used (will use an OR in the query, or not). Personally, I'm a fan directional control, so I will build it that way. That is, each phrase is associated with a Rhyme, and you can only search for phrase not the ryhme. So, if the table had memory linked with melody, but not melody linked with memory, it would return melody when searching for memory, but would not return memory when searching for melody. This creates more data, but once again adds a level of flexibility.
To create these:
Code:
CREATE TABLE Phrase
(
phrase varchar(255) NOT NULL PRIMARY KEY
) ENGINE = INNODB;
CREATE TABLE PhrasePair
(
phrase varchar(255) NOT NULL,
rhyme varchar(255) NOT NULL,
PRIMARY KEY(phrase, rhyme),
FOREIGN KEY (phrase) REFERENCES Phrase(phrase) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (rhyme) REFERENCES Phrase(phrase) ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE = INNODB;
I believe that the composite PK on the phrase, rhyme will get around the complaints of non-indexed fields. If it does not (I'm not 100% sure how the indexing of composite keys come into play when its foreign key referenced on individual fields), add this on the PhrasePair table between the
PRIMARY KEY(phrase, rhyme) and
FOREIGN KEY (phrase)....:
Code:
INDEX(phrase),
INDEX(rhyme),
But I'm pretty sure you don't need it.
Querying:
Code:
SELECT p.phrase, pp.rhyme
FROM Phrase p
LEFT JOIN PhrasePair USING (phrase)
WHERE p.phrase = 'memory'
Say our tables have the following records (these are each records, not a text block):
Code:
// Phrase
memory
melody
tenably
// PhrasePair
memory | melody
memory | tenably
melody | tenably
tenably | melody
tenably | memory
The above query (using memory) would return:
Code:
memory | melody
memory | tenably
And notice the recordset for PhrasePair doesn't include a link between melody and memory, so if you queried melody you would only have one record with melody and tenably returned.
Cascades were added, so if you choose to delete or update a record from Phrase, all associated entries within the PhrasePair will also be updated / deleted. This should update / destroy the entire record even if only one is updated / removed.