Yogu - Do 08.04.10 12:00
Titel: Übersetzende Abfrage
Moin,
ich habe eine multilinguale Webseite, bei der aber nicht unbedingt alle Inhalte in alle Sprachen übersetzt sein müssen. Wenn eine Übersetzung fehlt, soll zuerst die in die als international deklariere Sprache Übersetzung, dann irgendeine andere ausgewählt werden.
Die Inhalte sind in einer Tabelle namens
strings (jeder String hat eine ID) aufgelistet, die Übersetzungen in
translations, die die String-ID und eine Sprach-ID enthält.
Da ich alle Strings haben möchte, verwende ich zuerst folgende Query:
SQL-Anweisung
1: 2:
| SELECT strings.id FROM strings |
Um nun an die Übersetzungen zu kommen, verwende ich derzeit eine Subquery:
SQL-Anweisung
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| SELECT strings.id, ( SELECT translations.value FROM translations WHERE strings.id = translation.stringID ORDER BY translation.languageID = 3 DESC, translation.languageID = 2 DESC LIMIT 0,1 ) AS value FROM strings |
Wobei
languageID 3 die aktive Sprache und
2 die internationale ist.
Da dieses Schema aber sehr häufig vorkommt, möchte ich von einer Subquery absehen und das ganze lieber mit JOINS realisieren. Ein Ansatz dafür ist:
SQL-Anweisung
1: 2: 3: 4: 5: 6: 7:
| SELECT strings.id, translations.value FROM strings LEFT JOIN translations ON translations.stringID = strings.id ORDER BY translation.languageID = 3 DESC, translation.languageID = 2 DESC |
Jetzt muss ich nur noch doppelte Strings entfernen. Weiß jemand, wie das in diesem Fall geht?
DISTINCT funktioniert nur, wenn ich
translation.value aus der
SELECT-Klausel entferne - und die Spalte brauche ich natürlich unbedingt.
GROUP BY wäre auch noch eine Idee, aber das entfernt doppelte Strings aus,
bevor nach Sprache sortiert wird, und dann wird per Zufall entschieden, welche Sprache ausgewählt wird.
Danke für eure Mühe!
Grüße,
Yogu
BenBE - Sa 10.04.10 17:26
Yogu hat folgendes geschrieben : |
Moin,
ich habe eine multilinguale Webseite, bei der aber nicht unbedingt alle Inhalte in alle Sprachen übersetzt sein müssen. Wenn eine Übersetzung fehlt, soll zuerst die in die als international deklariere Sprache Übersetzung, dann irgendeine andere ausgewählt werden.
Die Inhalte sind in einer Tabelle namens strings (jeder String hat eine ID) aufgelistet, die Übersetzungen in translations, die die String-ID und eine Sprach-ID enthält. |
Gibt es eine weitere Tabelle mit der Vorzugsreihenfolge der Sprachen? Wenn ja, könnte man da glaube was mit GROUP BY + HAVING\MAX\MIN machen.
Müsste das aber auch erst raussuchen.
Yogu - Sa 10.04.10 20:32
Hallo,
danke für den Tipp mit
MAX, vielleicht bin ich jetzt einen Schritt weiter.
Folgende Abfrage gibt mir zwar immer noch eine willkürliche Übersetzung zurück, aber wenigstens wird schon mal markiert, wie richtig die Sprache sein
kann (also wie nah die beste Übersetzung an den Benutzerwunsch hinkommt), und dann noch, wie richtig die der tatsächlich gewählten Übersetzung ist:
SQL-Anweisung
1: 2: 3: 4: 5:
| SELECT strings.id, translations.value, translations.languageID, MAX(CASE translations.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 END) AS möglicheQualität, (CASE translations.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 END) AS tatsächlicheQualität FROM strings LEFT JOIN translations ON strings.id = translations.stringID GROUP BY strings.id |
Meine Idee war nun, die tatsächliche mit der möglichen Qualität in einer
HAVING-Klausel gleichzusetzen.
Das hier:
SQL-Anweisung
1: 2: 3: 4: 5: 6:
| SELECT strings.id, translations.value, translations.languageID, MAX(CASE translations.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 END) AS möglicheQualität, (CASE translations.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 END) AS tatsächlicheQualität FROM strings LEFT JOIN translations ON strings.id = translations.stringID GROUP BY strings.id HAVING tatsächlicheQualität = möglicheQualität |
gibt aber einfach nur die Strings aus, bei denen die Übersetzung zufällig passt, und die anderen werden gar nicht ausgegeben.
Das Problem könnte ich wiederum mit einer Subquery lösen:
SQL-Anweisung
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| SELECT strings1.id, translation.value, translation.languageID FROM strings AS strings1 LEFT JOIN translations AS translations1 ON strings1.id = translations1.stringID WHERE (CASE translation1.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 END) = ( SELECT MAX(CASE translation2.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 END) FROM strings AS strings2 LEFT JOIN translations AS translations2 ON strings2.id = translations2.stringID WHERE string1.id = strings2.id ) |
Womit ich wieder am Anfang wäre: Bei einer Subquery, die wertvolle Zeit verbraucht.
Hat jemand eine Idee, wie ich ohne Subquery auf den Maximalen Wert der Case-Anweisung
SQL-Anweisung
1:
| CASE translations.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 END |
komme?
Danke!
Grüße,
Yogu