Overview
I'm simplifying the description of my application to make the query clearer.  The application stores saved phrases.  These phrases are each assigned a category.  The phrases can be posted by users.  An English description of my query:
I need to pass a
categoryanduserinto theprepared statement. The result will include onlyphraseswith thecategorypassed as an argument. From thephrasesof thiscategory, onlyphraseswill be returned where there does not exist any posted instances of thisphrasefor theuserargument with thetimePostedfield in the last two weeks.
Minimal Schema
savedPhrase
- phraseIdentifier - INT UNSIGNED
- textContent - VARCHAR
- associatedCategory - VARCHAR
- ___primary key is phraseIdentifier
postedPhrase
- savedPhrase - INT UNSIGNED - foreign key references savedPhrase(phraseIdentifier)
- username - VARCHAR
- timeReposted - TIMESTAMP
- ___primary key is combination of all listed fields
Current Best Attempt with Behavior
I'm self-taught/learning MySQL and believe I struggle with joins.  I think I should be using at least one left outer join as seen in the graphic below.  The left table will be savedPhrase and the right will be postedPhrase.
SELECT * FROM savedPhrase S 
LEFT JOIN postedPhrase P
ON (S.phraseIdentifier = P.savedPhrase AND P.username = ?)
WHERE
(P.savedPhrase IS NULL OR P.timeReposted < DATE_SUB(NOW(), INTERVAL 14 day)) AND
S.associatedCategory = ?
The query above ALMOST works.  However, once a single postedPhrase row exists at least two weeks ago, it will return the joined savedPhrase, even if one has been posted on the same account with the same identifier less than two weeks ago.
Further Discussion
The place where I'm having difficulty is the "absence condition".  This is where a savedPhrase must not exist within the last two weeks.  In the previous paragraph I explained how the absence is not functioning because the postedPhrases are being returned based on their own independent timeReposted.  It seems I should be adding the absence condition to the right circle of the left outer join.  Simplification of when to apply the conditions to the ON versus the WHERE would be very helpful.
I've worked at fixing this problem for a while and would appreciate any direction. Please let me know if I can include any other information.

 
    