I am trying to figure out what would be the most efficient way of achieving the following:
I have two tables:
word_translations(id, word_id, language_id)
and
translations(id, text, word_translation_id, created_at, updated_at, user_id)
So there is a one-to-many relationship between word_translations
and translations
table. If a translation is created with user_id
not null, the user has provided his own translation and therefore overrides the default ones (there can be at most one (user) translation override per word_translation per user, but multiple default translations per word_translation).
I am trying to write SQL query, that returns a list of translation ids with following conditions:
- There is only a single translation id for each word_translation_id
- The translation id points to the latest translation of a specific word_translation (max(id)), unless there is other translation with the same word_translation_id that has user_id not null. In this case, it should point to translation id where the user_id is not null.
I have written the following query to do so, but I am not sure about it’s performance:
SELECT IF(t2.id IS NULL, t1.id, t2.id) as id, t1.word_translation_id
FROM (
SELECT MAX(t.id) as id, t.word_translation_id
FROM translations t
WHERE t.user_id IS NULL
GROUP BY t.word_translation_id) as t1
LEFT JOIN (
SELECT t.id, t.word_translation_id
FROM translations t
WHERE t.user_id IS NOT NULL) t2
ON t1.word_translation_id = t2.word_translation_id;
Is there a more efficient way to do this? (Also, do you see any issues with the query above?)
2
Answers
I think you might be able to simplify this using an anti-join:
For each translation, look for another translation for the same word that has either a later id, or a user_id that is not null (the
JOIN
conditions). Then exclude any rows where that is true (theWHERE
clause).Use two queries that you combine with
UNION
.Query 1 returns the newest default translation for words that don’t have any user translations.
Query 2 returns user translations.
Final query: