MySQL: Fallunterscheidung innerhalb eines Queries – SELFHTML-Forum Forum als Ergänzung zum SELFHTML-Wiki und zur Dokumentation SELFHTML https://forum.selfhtml.org/self MySQL: Fallunterscheidung innerhalb eines Queries Sat, 26 Oct 19 23:51:43 Z https://forum.selfhtml.org/self/2019/oct/27/mysql-fallunterscheidung-innerhalb-eines-queries/1759332#m1759332 https://forum.selfhtml.org/self/2019/oct/27/mysql-fallunterscheidung-innerhalb-eines-queries/1759332#m1759332 <p>Hi(gh)!</p> <p>Tabelle "kreis", Datenfelder "id", "name", "regierungsbezirk_id" und "bundesland_id". Da es längst nicht in allen Bundesländern Regierungsbezirke als Verwaltungsebene zwischen Kreis und Land gibt, andererseits bei vorhandenen Regierungsbezirken das Bundesland über die Tabelle "regbez" (für die Regierungsbezirke) ermittelt werden kann, darf entweder das Feld "regierungsbezirk_id" oder das Feld "bundesland_id" NULL sein (nicht aber beide zugleich!).</p> <p>Das Problem ist jetzt: in der Datensatzausgabe (zur Orientierung für mich beim Eingeben, nicht als Endbenutzer-Ausgabe) wird der besseren Übersichtlichkeit halber nicht die aus "regbez" übernommene "id" angezeigt, sondern gleich der Klarname des Regierungsbezirks. Der dazu verwendete Query-String lautet:</p> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> kreis<span class="token punctuation">.</span>id<span class="token punctuation">,</span> kreis<span class="token punctuation">.</span>name<span class="token punctuation">,</span> regierungsbezirk_id <span class="token punctuation">,</span> regbez<span class="token punctuation">.</span>name<span class="token punctuation">,</span> regbez<span class="token punctuation">.</span>id <span class="token punctuation">,</span> kreis<span class="token punctuation">.</span>bundesland_id <span class="token punctuation">,</span> land<span class="token punctuation">.</span>name<span class="token punctuation">,</span> land<span class="token punctuation">.</span>id <span class="token keyword">FROM</span> kreis<span class="token punctuation">,</span> regbez<span class="token punctuation">,</span> land <span class="token keyword">WHERE</span> kreis<span class="token punctuation">.</span>bundesland_id <span class="token operator">=</span> land<span class="token punctuation">.</span>id <span class="token operator">AND</span> regierungsbezirk_id <span class="token operator">=</span> regbez<span class="token punctuation">.</span>id <span class="token keyword">LIMIT</span> <span class="token string">".$offset."</span><span class="token punctuation">,</span> <span class="token string">".$range."</span><span class="token punctuation">;</span> </code></pre> <p>(Edit Rolf B: Query lesbar(er) gemacht)</p> <p>Wird im Eingabeformular jedoch kein Wert für "regierungsbezirk_id" übermittelt, kann kein Datensatz ausgegeben werden, weil der zweite Teil der WHERE-Bedingung nicht erfüllt ist. Wie bringe ich jetzt dem Query mittels einer IF-Klausel bei, dass bei regierungsbezirk_id = NULL in der Spalte für den Regierungsbezirks-Klarnamen "(keiner)" angezeigt wird?</p> <p>Bis bald im Khyberspace!</p> <p>Yadgar</p> MySQL: Fallunterscheidung innerhalb eines Queries Sun, 27 Oct 19 15:42:59 Z https://forum.selfhtml.org/self/2019/oct/27/mysql-fallunterscheidung-innerhalb-eines-queries/1759371#m1759371 https://forum.selfhtml.org/self/2019/oct/27/mysql-fallunterscheidung-innerhalb-eines-queries/1759371#m1759371 <p>Hallo Yadgar,</p> <p>Problem 1 ist, dass Du bei fehlendem Regierungsbezirk überhaupt eine Ausgabezeile bekommst. Problem 2 ist dann, wie Du den fehlenden Regierungsbezirk darstellst.</p> <p>Wenn Du in der kreis-Tabelle nämlich eine Regierungsbezirks-ID hast, die in der regbez-Tabelle nicht vorkommt, wirst Du den Kreis mit der von Dir gezeigten Query gar nicht ausgeben. Dein Vorgehen mit einem Schlüsselvergleich im WHERE führt zu einem INNER JOIN, was Du aber brauchst, ist ein LEFT JOIN. Den bekommst Du über WHERE nicht hin, sondern musst die entsprechende SQL Syntax verwenden.</p> <p>Die ID-Spalten hattest Du sicherlich nur zum Debugging drin, die lasse ich mal weg.</p> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> kreis<span class="token punctuation">.</span>id<span class="token punctuation">,</span> kreis<span class="token punctuation">.</span>name<span class="token punctuation">,</span> regbez<span class="token punctuation">.</span>name<span class="token punctuation">,</span> land<span class="token punctuation">.</span>name <span class="token keyword">FROM</span> kreis <span class="token keyword">JOIN</span> land <span class="token keyword">ON</span> kreis<span class="token punctuation">.</span>bundesland_id <span class="token operator">=</span> land<span class="token punctuation">.</span>id <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> regbez <span class="token keyword">ON</span> kreis<span class="token punctuation">.</span>regierungsbezirk_id <span class="token operator">=</span> regbez<span class="token punctuation">.</span>id <span class="token keyword">LIMIT</span> <span class="token string">".$offset."</span><span class="token punctuation">,</span> <span class="token string">".$range."</span><span class="token punctuation">;</span> </code></pre> <p>"JOIN land" ist ein inner join, "LEFT JOIN regbez" ist ein left outer join. Was das genau ist, verrät Dir das SQL Handbuch.</p> <p>Nun bekommst Du in den Zeilen, wo keine regierungsbezirk_id vorliegt, den Wert NULL in der regbez.name Spalte. Du <strong>kannst</strong> das im SQL fixen, aber eigentlich ist das nichts, was in die DB Zugriffsschicht gehört. Das solltest Du eigentlich im PHP tun.</p> <p>Aber wenn Du es unbedingt im SQL machen willst, dann hat MySQL da mehrere Funktionen im Angebot.</p> <ul> <li>der <a href="https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#operator_case" rel="nofollow noopener noreferrer">CASE</a> Operator</li> <li>die <a href="https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#function_if" rel="nofollow noopener noreferrer">IF</a> Funktion zusammen mit der <a href="https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_isnull" rel="nofollow noopener noreferrer">ISNULL</a> Funktion</li> <li>die <a href="https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#function_ifnull" rel="nofollow noopener noreferrer">IFNULL</a> Funktion</li> <li>die <a href="https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_coalesce" rel="nofollow noopener noreferrer">COALESCE</a> Funktion</li> </ul> <p>Am einfachsten ist wohl hier IFNULL:</p> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> kreis<span class="token punctuation">.</span>id<span class="token punctuation">,</span> kreis<span class="token punctuation">.</span>name<span class="token punctuation">,</span> IFNULL<span class="token punctuation">(</span>regbez<span class="token punctuation">.</span>name<span class="token punctuation">,</span> <span class="token string">'(keiner)'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> land<span class="token punctuation">.</span>name <span class="token keyword">FROM</span> kreis <span class="token keyword">JOIN</span> land <span class="token keyword">ON</span> kreis<span class="token punctuation">.</span>bundesland_id <span class="token operator">=</span> land<span class="token punctuation">.</span>id <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> regbez <span class="token keyword">ON</span> kreis<span class="token punctuation">.</span>regierungsbezirk_id <span class="token operator">=</span> regbez<span class="token punctuation">.</span>id <span class="token keyword">LIMIT</span> <span class="token string">".$offset."</span><span class="token punctuation">,</span> <span class="token string">".$range."</span><span class="token punctuation">;</span> </code></pre> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - clusi </div>