Entwickler-Ecke

Datenbanken - Übersetzende Abfrage


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


Yogu - Sa 10.04.10 15:27

*push*


BenBE - Sa 10.04.10 17:26

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
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 ENDAS möglicheQualität, (CASE translations.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 ENDAS 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 ENDAS möglicheQualität, (CASE translations.languageID WHEN 3 THEN 2 WHEN 2 THEN 1 ELSE 0 ENDAS 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