Andy: Entweder das eine, oder wenn das nicht, das andere...

Hallo,

fällt leider kein bessere Themenbezeichnung ein.

Folgende Tabellen-Struktur (Menu) habe ich:
id INTEGER
lang CHAR(2)
content_id INTEGER
title VARCHAR(255)
pos TINYINT

Damit setze ich Menus in verschiedenen Sprachen zusammen, je nach Sprachenkürzel halt, z. B. en oder de. Wenn lang NULL ist, soll der Menupunkt für alle Sprachen gelten.
Und da habe ich ein Problem. Momentan frage wie ich folgt ab:
1. SELECT title, content_id FROM menu WHERE lang="de" ORDER BY pos
Damit bekomme ich alle Menupunkte, die deutsch sind nach pos sortiert. Möchte ich jetzt die allgemeingültigen Einträge dazu haben, könnte ich wie folgt Abfragen:
2. SELECT title, content_id FROM menu WHERE lang="de" OR lang="null" ORDER BY pos

Beispieleintrag - DB:
1 "de" 1 "punkt 1" -10
2 "en" 1 "point 1" -10
3 "de" 2 "punkt 2" -8
4 NULL 2 "point 2 / punkt 2" -8
5 NULL 3 "point 3 / punkt 3" -7

Nun soll meine Abfrage (Sprache deutsch) folgende Datensätze liefern:
1,3,5
Bei englisch entsprechend: 2 4 5

Wenn ich aber die 2. Query von oben nehme bekomme ich bei Abfrage nach deutsch natürlich:
1,3,4(!),5

Ich stehe momentan komplett auf den Schlauch, ob man das elegant in einer Query formulieren kann. Ansonsten würde ich es halt programmtechnisch lösen.

Also, hat jemand einen Ansatz?

Danke,
Andy

  1. Huhu

    1. SELECT title, content_id FROM menu WHERE lang="de" OR lang="null" ORDER BY pos

    So ist es jedenfalls verkehrt.
    Du vergleichst gegen einen String "null" meinst aber vermutlich
    [...] OR lang IS NULL [...]

    Lies das am besten nochmal in der Doku nach da man sich immer wieder tückische Fehler mit NULL-Werten einhandelt wenn das Konzept dahinter unklar ist.

    Viele Grüße

    lulu

    --
    bythewaythewebsuxgoofflineandenjoytheday
    1. Hallo,

      1. SELECT title, content_id FROM menu WHERE lang="de" OR lang="null" ORDER BY pos

      So ist es jedenfalls verkehrt.
      Du vergleichst gegen einen String "null" meinst aber vermutlich
      [...] OR lang IS NULL [...]

      Typischer "Schreibfehler" :) Ist natürlich IS NULL gemeint!
      War halt auf die schnelle hingehackt.
      Korregiert: SELECT title, content_id FROM menu WHERE lang="de" OR lang IS NULL ORDER BY pos
      Geht ums Prinzip. Jede Kombination aus lang und content_id ist UNIQUE. Ich will aber nur eine content_id haben, zuerst die spezifische zur Sprache, dann die Allgemeine, bei der lang NULL ist.

      Andy

  2. Hi, hallo, hoi und Grüezi!

    Du könntest die ISNULL(feld, ersatzwert wenn null) Funktion verwenden, die müsste sogar ein MySQL kennen. :)

    Und dann baust du deine Query wie folgt zusammen: (@variable ersetzt du dann mit 'de' oder 'en'):

    SELECT title, content_id FROM menu WHERE ISNULL(lang, @variable) = @variable ORDER BY pos

    Damit solltest du für jede der möglichen Sprachen auch alle NULL Datensätze bekommen.

    Ansonsten gilt naturellement: Auf NULL prüft man mit dem IS Operator (IS NULL / IS NOT NULL)

    :)

    Grüessli
    Frank

    1. Hallo!

      SELECT title, content_id FROM menu WHERE ISNULL(lang, @variable) = @variable ORDER BY pos

      MySQL kennt zwar ISNULL, aber den Alternativausdruck glaube ich nicht.
      Aber ist ja egal, ist leider nicht das was ich will, da spuckt mir die Abfrage ja auch die content_id doppelt aus, wenn sie mal auf deutsch und einmal allgemein existiert.

      Gruß,
      Andy

  3. yo,

    Ich stehe momentan komplett auf den Schlauch, ob man das elegant in einer Query formulieren kann. Ansonsten würde ich es halt programmtechnisch lösen.

    ich vermute mal, du willst immer nur einen datensatz für eine content_id haben, weswegen auch der 4 datensatz bei lang = de ausgeschlossen wird.

    SELECT m.title, m.content_id
    FROM menu m
    WHERE m.lang = "de"
    OR m.lang IS NULL AND m.conten_id NOT IN
      (SELECT m2.content_id FROM menu m2 WHERE m2.lang = "de")
    ORDER BY m.pos

    Ilja

    1. Hallo!

      ich vermute mal, du willst immer nur einen datensatz für eine content_id haben, weswegen auch der 4 datensatz bei lang = de ausgeschlossen wird.

      Yup, genau!

      SELECT m.title, m.content_id

      FROM menu m
      WHERE m.lang = "de"
      OR m.lang IS NULL AND m.content_id NOT IN
        (SELECT m2.content_id FROM menu m2 WHERE m2.lang = "de")
      ORDER BY m.pos

      Jawohl, ein Subselect! Hätte ich programmiertechisch ja auch nicht anders gelöst. Funktioniert so einwandfrei!  
        
      Vielen Dank,  
      Andy
      
  4. Folgende Tabellen-Struktur (Menu) habe ich:
    id INTEGER
    lang CHAR(2)
    content_id INTEGER
    title VARCHAR(255)
    pos TINYINT

    Beispieleintrag - DB:
    1 "de" 1 "punkt 1" -10
    2 "en" 1 "point 1" -10
    3 "de" 2 "punkt 2" -8
    4 NULL 2 "point 2 / punkt 2" -8
    5 NULL 3 "point 3 / punkt 3" -7

    Vielleicht hats schon jemand angemerkt, dennoch:

    • lang darf nicht nullable sein, u.a. die vermurksten Beispieldaten belegen warum
    • Was heisst hier content_id? Sind da zwei Identifikationssysteme am Start? (Nein, wohl nicht, da gibts Dubletten, also was soll der Murks?)
    • "pos" deutet auf weiteren Murks hin. Welche Semantik haben wir da?
    1. Hallo!

      Folgende Tabellen-Struktur (Menu) habe ich:
      id INTEGER
      lang CHAR(2)
      content_id INTEGER
      title VARCHAR(255)
      pos TINYINT

      Beispieleintrag - DB:
      1 "de" 1 "punkt 1" -10
      2 "en" 1 "point 1" -10
      3 "de" 2 "punkt 2" -8
      4 NULL 2 "point 2 / punkt 2" -8
      5 NULL 3 "point 3 / punkt 3" -7

      Vielleicht hats schon jemand angemerkt, dennoch:

      • lang darf nicht nullable sein, u.a. die vermurksten Beispieldaten belegen warum

      Die Angaben sind ja nur so hingeschrieben! "lang" darf natürlich in der richtigen Tabelle NULL sein!

      • Was heisst hier content_id? Sind da zwei Identifikationssysteme am Start? (Nein, wohl nicht, da gibts Dubletten, also was soll der Murks?)

      lang+content_id sind UNIQUE! Die id wäre theoretisch überflüssig, da lang+content_id einen Primärschlüssel ausmachen.

      • "pos" deutet auf weiteren Murks hin. Welche Semantik haben wir da?

      pos ist einfach ein Parameter zum Sortieren der Menueinträge: Um so größer pos, um so weiter unten steht der Menupunkt!

      Gruß,
      Andy

      P.S.: Problem ist gelöst.

      1. Vielleicht hats schon jemand angemerkt, dennoch:

        • lang darf nicht nullable sein, u.a. die vermurksten Beispieldaten belegen warum
          Die Angaben sind ja nur so hingeschrieben! "lang" darf natürlich in der richtigen Tabelle NULL sein!

        Das beisst sich allerdings mit der später von Dir getätigten Aussage: "lang+content_id sind UNIQUE!"

        • Was heisst hier content_id? Sind da zwei Identifikationssysteme am Start? (Nein, wohl nicht, da gibts Dubletten, also was soll der Murks?)
          lang+content_id sind UNIQUE! Die id wäre theoretisch überflüssig, da lang+content_id einen Primärschlüssel ausmachen.

        Es wäre U.E. vorteilhaft mit einer weiteren Tabelle "languages" zu kommen und in die Tabelle nur die Zeiger (und den einen Text) einzutragen. Dann mit einem nichtzusammengesetzten Primärschlüssel kommen. (Letzteres machst Du ja schon richtigerweise (PK:id).)

        • "pos" deutet auf weiteren Murks hin. Welche Semantik haben wir da?
          pos ist einfach ein Parameter zum Sortieren der Menueinträge: Um so größer pos, um so weiter unten steht der Menupunkt!

        Ob das man gut ist für die Datenintegrität und so.   ;)

        P.S.: Problem ist gelöst.

        ;)