Claudius L.: Bei Bedingung andere Tabelle verwenden

Hallo zusammen!
Ich bin gerade dabei mich mit einem kleinen Projekt in Datenbanken einzuarbeiten und verwende dabei PHP5 und MySQL5. Bei meinem momentanen Problem weiß ich leider nicht, in welche Richtung ich mich informieren muss - Joins, Bedingungen oder verschachtelte Selects. Mit allem will ich mich früher oder später auseinander setzen, doch ich würde mich über einen Rat freuen, was ich zuerst tun sollte, um mein Problem lösen zu können.
Also, folgende Situation: Ich habe im Prinzip zwei Tabellen, beide mit den Spalten 'id' und 'value'.
Nun möchte ich aus Tabelle1 den value zu einer bestimmten id ermitteln. Soweit mit einem einfachen Select kein Problem.  Ist 'value' aber NULL, so möchte ich 'value' aus Tabelle2 verwenden (wo der Datensatz die richtige id hat versteht sich).
Dieses 'wenn' hört sich für mich als Laie stark danach an, als bräuchte ich ein 'if' und einen weiteren Select in meinem Query - oder lässt sich ein solches Problem auch per Join lösen?
Versteht mich nicht falsch, ich erwarte kein komplettes SQL-Statement als Antwort - ich will ja was lernen - sondern hoffe nur auf einen Rat, welchen Weg ich gehen sollte.

Gruß,
Claudius

  1. moin,

    Dieses 'wenn' hört sich für mich als Laie stark danach an, als bräuchte ich ein 'if' und einen weiteren Select in meinem Query - oder lässt sich ein solches Problem auch per Join lösen?

    viele wege führen nach rom, es lassen sich durchaus die gleichen ergebnisse mit anderen mtteln erzeugen. grundsätzlich würde ich bei deiner aufgabenstellung sagen, eine korrelierte unterabfrage ist dein freund und nicht der join.

    Versteht mich nicht falsch, ich erwarte kein komplettes SQL-Statement als Antwort - ich will ja was lernen - sondern hoffe nur auf einen Rat, welchen Weg ich gehen sollte.

    so weit ist es schon hier gekommen, dass man anfängt sich zu rechtferitigen oder zu entschuldigen, wenn man eine frage hat. auch wenn du eine fertige SQL abfrage wolltest, was spricht dagegen, solange sich heir jemand bereit erklärt, diese auch zu liefern, nichts.

    Ilja

    1. Hallo Ilja,

      Dieses 'wenn' hört sich für mich als Laie stark danach an, als bräuchte ich ein 'if' und einen weiteren Select in meinem Query - oder lässt sich ein solches Problem auch per Join lösen?

      viele wege führen nach rom, es lassen sich durchaus die gleichen ergebnisse mit anderen mtteln erzeugen. grundsätzlich würde ich bei deiner aufgabenstellung sagen, eine korrelierte unterabfrage ist dein freund und nicht der join.

      was spräche bei einer 1:1-Beziehung, d.h. jeweils einem UNIQUE-Index auf der Spalte id, zwischen den beiden Tabellen gegen einen Join und den Einsatz der Funktion COALESCE(), angewandt auf die beiden value-Spalten?

      Freundliche Grüße

      Vinzenz

      1. moin Vinzenz,

        was spräche bei einer 1:1-Beziehung, d.h. jeweils einem UNIQUE-Index auf der Spalte id, zwischen den beiden Tabellen gegen einen Join und den Einsatz der Funktion COALESCE(), angewandt auf die beiden value-Spalten?

        wie gesagt, viele wege führen nach rom, vom ergebnis her spricht nichts dagegen, von der vorgehensweise eventuell schon. erstens besteht bei JOINS immer die latente gefahr der vervielfachung der Datensätze. ich würde sie vermeiden, wenn es geht (JOINS sind böse). und zweitens könnte die abfrage ohne den JOIN schneller sein. der JOIN wird immer den entsprechenden partner aus der anderen tabelle verknüpfen müssen, die korrelierte unterabfragen nur, wenn der wert auch NULL ist.

        Ilja

    2. Hallo!

      Das ging aber schnell - dankeschön! ;)
      Kann zwar jetzt antworten (bin auf Reisen und lebe gerade in einem Van, da ist das manchmal etwas schwierig ...) hatte seitdem dafür aber schon ein wenig Zeit, mir Gedanken zu machen.

      viele wege führen nach rom, es lassen sich durchaus die gleichen ergebnisse mit anderen mtteln erzeugen. grundsätzlich würde ich bei deiner aufgabenstellung sagen, eine korrelierte unterabfrage ist dein freund und nicht der join.

      Hm, ich habe mir mal die Handbuchseite zu korellierten Unterabfragen angesehen, aber mir ist nicht ganz klar dabei geworden, wie ich das auf mein Problem anwenden kann. Der Haken dabei ist, dass ich nicht weiß, was ich eigentlich hinter das SELECT schreiben soll. Ich habe das Gefühl, zu versuchen, das Pferd von hinten aufzuzäumen, da ich ja gerade herausfinden muss, was denn zu selektieren ist (also ob SELECT tabelle1.text ... oder SELECT tabelle2.text ... benötigt wird). So, wie ich das Handbuchbeispiel verstehe, wird die korellierte Unteraubfrage ja verwendet, um eine große Ergebnismenge anhand von Kriterien, die sich aus der Unterabfrage ergeben, zu reduzieren. Aber ich habe ja nicht viele Datensätze, sondern nur einen in jeder (von zwei) Tabellen ...
      Da ich mich von Joins lieber noch ein wenig fernhalten würde, habe ich auf eigene Faust mal etwas ausprobiert (und gehofft, dass es keinen Grund dafür gibt, dass mir das keiner von euch beiden empfohlen hat ...). Ich dachte, IF() sei mein Freund - entworfen habe ich folgendes SQL:
      SELECT IF(text__general_en.text= NULL, (SELECTtextFROM text__general_de WHEREid= "foo"), (SELECTtextFROM text__general_en WHEREid= "foo"))
      ... und bekommen habe ich folgenden Fehler: "#1054 - Unknown column 'text__general_en.text' in 'field list'"
      Ich schätze mal, das sich die unter Korellierte Unterabfragen beschriebene "Bereichsregel" ("MySQL wertet von innen nach außen aus") also nur auf Korellierte Unterabfragen bezieht und sich nicht auf IF() übertragen lässt. Denn - wenn ich das richtig sehe, ist das Problem doch, dass wenn die Bedingung geprüft wird, text\_\_general\_en.text noch unbekannt ist, weil es eben erst später, im letzten SELECT ermittelt wird. Oder liege ich da falsch?
      Auf jeden Fall komme ich so wohl nicht ans Ziel. Aber was ist der Fehler? Ist mein IF-Konzept prinzipiell der Holzweg und korellierte Unterabfragen bringen mich doch einfacher ans Ziel, wenn man sie richtig anzuwenden weiss? Oder bleibt am Ende nur der Join?

      Gruß,
      Claudius

      1. Hallo nochmal!

        Ich dachte, IF() sei mein Freund - entworfen habe ich folgendes SQL:
        SELECT IF(text__general_en.text= NULL, (SELECTtextFROM text__general_de WHEREid= "foo"), (SELECTtextFROM text__general_en WHEREid= "foo"))

        Ich habe an diesem Ansatz noch ein wenig herumgewerkelt. Nach ein klein wenig nachdenken ist mir klar geworden, dass das Problem, dass text\_\_general\_en.text nicht bekannt ist, eigentlich ja ganz einfach zu lösen ist. Schließlich kann ich an dieser Stelle ja auch einfach ein SELECT schreiben und den gewünschten Wert ermitteln:

        SELECT IF(  
        	((SELECT `text` FROM `text__general_en` WHERE `id` = "foo") = NULL),  
        	(SELECT `text` FROM `text__general_de` WHERE `id` = "foo"),  
        	(SELECT `text` FROM `text__general_en` WHERE `id` = "foo")  
        	)  
        AS `text`
        

        Soweit so gut - oder nicht. Denn die Prüfung auf = NULL scheint so nicht zu stimmen. Jedenfalls erhalte ich nicht die gewünschten Werte. Daraufhin habe ich ein wenig herumgestochert und wild mit Werten wie true und false herumgetestet. Was dabei herauskam funktioniert zwar, ist aber unlogisch:

        SELECT IF(  
        	((SELECT `text` FROM `text__general_en` WHERE `id` = "foo") = false),  
        	(SELECT `text` FROM `text__general_en` WHERE `id` = "foo"),  
        	(SELECT `text` FROM `text__general_de` WHERE `id` = "foo")  
        	)  
        AS `text`
        

        Mit diesem SQL erhalte ich:
        - text.text__general_en wenn dieses nicht NULL ist
        - text.text__general_de wenn text.text__general_en NULL ist

        Das will ich. Allerdings scheint es mir eher zufällig, dass ich das bei meinem SQL auch bekomme. Denn immerhin sollte ich ja eigentlich (laut SQL) text__general_en.text bekommen, wenn dieses false ist.

        Ich denke, das Problem ist, dass ich die Bedingung nicht korrekt formuliere. Kann mir jemand verraten, wie ich die Bedingung abändern muss, damit ich text__general_en.text bekomme, wenn dieses nicht NULL ist und ich text__general_de.text bekomme, wenn text__general_en.text NULL ist (unabhängig von text__general_de.text)?

        Grüße,

        Claudius

        1. moin,

          Schließlich kann ich an dieser Stelle ja auch einfach ein SELECT schreiben und den gewünschten Wert ermitteln:

          du machst dir das leben schwere als es ist, geh schritt für schritt vor. als erstes mach einfach nur den SELECT, der dir den richtigen datensatz gibt.

          SELECT t1.text
          FROM text__general_en t1
          WHERE t1.id = 'foo'
          ;

          jetzt haben wir erst mal die richtige basis, um damit weiter zu arbeiten. btw. warum zwei unterschriche hintereinander im tabellennamen ?

          der nächste schritt besteht darin, eine funktion zu benutzen, die text auf NULL prüft und dann entsprechend verzweigt. und prüfungen auf NULL sollte man niemals mit dem "=" operator machen. bei mysql gibt es dafür zum beispiel die funktion IFNULL:

          SELECT IFNULL(t1.text, (SELECT t2.text
                                  FROM text__general_de t2
                                  WHERE t2.id = t1.id
                                 )
                       ) MeineSpalte
          FROM text__general_en t1
          WHERE t1.id = 'foo'
          ;

          und schon sind wir am ziel, mehr ist nicht zu tun.

          Ilja

          1. noch mal als nachtrag, ich vermute dein design und die tabellen sind nur zu testzwecken, um ein wenig zu üben. in einem live system würde aber davon abraten, solch ein design zu wählen, wo man für jede weitere sprache, die hinzukommt, die struktur der datenbank verändern muss.

            Ilja

            1. Hallo!

              Danke fuer die Hilfe, vorallem der Hinweis auf IFNULL() hat mir sehr geholfen, dass es jetzt funktioniert, wie es soll. Allerdings auch mit einem ein wenig geaenderten Datenbankdesign, denn:

              noch mal als nachtrag, ich vermute dein design und die tabellen sind nur zu testzwecken, um ein wenig zu üben. in einem live system würde aber davon abraten, solch ein design zu wählen, wo man für jede weitere sprache, die hinzukommt, die struktur der datenbank verändern muss.

              Bisher waren es nur Testzwecke, soll aber irgendwann ein Livesystem werden. Daher habe ich ueber den Rat mal nachgedacht und ihn dann umgesetzt - jetzt steht alles in der gleichen Tabelle.

              Danke und viele Gruesse,

              Claudius