mysql: Left Join an dieser Stelle? – SELFHTML-Forum Forum als Ergänzung zum SELFHTML-Wiki und zur Dokumentation SELFHTML https://forum.selfhtml.org/self mysql: Left Join an dieser Stelle? Tue, 04 May 21 15:21:26 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788067#m1788067 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788067#m1788067 <p>Hallo,</p> <p>ich habe eine Query</p> <pre><code class="block">SELECT ... FROM tabelle_stunden std LEFT JOIN tabelle_sonder s ON (std.User = s.User AND std.Datum BETWEEN s.Start AND s.End AND std.User = '".$_POST['myUser']."') LEFT JOIN tabelle_mein m ON std.MID = m.MID WHERE std.User = '".$_POST['myUser']."' AND std.Datum BETWEEN '".$_POST['datum_min']."' AND '".$_POST['datum_max']."' </code></pre> <pre><code class="block">Tabelle: stunden ID, Datum, Tabelle sonder: ID, Kategorie, Start,End Tabelle mein: ID, MID, ... </code></pre> <p>Die funktioniert perfekt, aber listet mir nur die Tage auf, die auch in der Tabelle stunden vorhanden sind. Ich hätte aber gerne alle Tage aufgelistet, auch wenn sie in der Tabelle stunden gar nicht vorhanden ist.</p> <p>Deshalb habe ich eie weitere Tabelle mit allen Daten bis ins Jahr 2100 angelegt.</p> <p>Nun dachte ich, dass ich den SELECT auf diese Tabelle leite und alle anderen tabellen per LEFT JOIN einbinde. Aber ich erhalte trotzdem nur die in der tabelle stunden enthaltenen Daten. Vermutlich, weil ich über das Datum joinen muss.</p> <p>Wie schaffe ich es, dass mir alle Tage im min-max-Zeitraum angezeigt werden und die entsprechenden Daten aus den anderen Tabellen dazu gejoint werden?</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Tue, 04 May 21 17:26:33 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788069#m1788069 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788069#m1788069 <p>Hallo Jörg,</p> <p>SQL Queries operieren ausschließlich auf den Daten, die sie vorfinden.</p> <p>Wenn der 03.10.2021 in keiner der Tabellen vorkommt, findet der Tag der Deutschen Einheit in deiner Liste nicht statt.</p> <p>Ab MySQL8 oder MariaDB 10.2.1 könnte man es mit einer rekursiven CTE versuchen (WITH Befehl). Davor wirst Du Dir mit einer temporären Table behelfen müssen, die die benötigten Tage enthält. Dafür schreibst Du am besten eine Stored Procedure, denn darin kannst Du Schleifenbefehle verwenden:</p> <pre><code class="block language-sql"><span class="token keyword">delimiter</span> <span class="token comment">//</span> <span class="token keyword">create</span> <span class="token keyword">procedure</span> createDays<span class="token punctuation">(</span>anfang <span class="token keyword">DATE</span><span class="token punctuation">,</span> ende <span class="token keyword">DATE</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token keyword">drop</span> <span class="token keyword">temporary</span> <span class="token keyword">table</span> <span class="token keyword">if</span> <span class="token keyword">exists</span> days<span class="token punctuation">;</span> <span class="token keyword">create</span> <span class="token keyword">temporary</span> <span class="token keyword">table</span> days <span class="token punctuation">(</span>datum <span class="token keyword">date</span><span class="token punctuation">)</span> <span class="token keyword">engine</span> memory<span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>anfang <span class="token operator"><=</span> ende<span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token keyword">insert</span> <span class="token keyword">into</span> days<span class="token punctuation">(</span>datum<span class="token punctuation">)</span> <span class="token keyword">values</span><span class="token punctuation">(</span>anfang<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">set</span> anfang <span class="token operator">=</span> date_add<span class="token punctuation">(</span>anfang<span class="token punctuation">,</span> <span class="token keyword">interval</span> <span class="token number">1</span> <span class="token keyword">day</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">while</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token comment">//</span> <span class="token keyword">delimiter</span><span class="token punctuation">;</span> </code></pre> <p>Die Delimiter-Story ist wichtig, weil Du sonst mit einen ; den create procedure beendest. Argh…</p> <p>Den Namen für die Temp-Tabelle kannst Du nicht als Parameter verwenden. D.h. du kannst schon, müsstest dann in der Prozedur aber mit dynamischem SQL hantieren (PREPARE / EXECUTE), das könnte das Tempo wieder drosseln. Ich habe es nicht ausprobiert.</p> <p>Wichtig ist auch "ENGINE MEMORY", andernfalls ist das laaaangsam. Oder Du stellst sicher, dass dein SQL Server für default_tmp_storage_engine die Einstellung "MEMORY" hat. Bei mir war's InnoDB und ich hab mich gewundert, warum er nur 30 Inserts pro Sekunde machte.</p> <p>Wenn Du dann deine Query machst, rufst Du erstmal die Stored Procedure auf, um die days-Tabelle mit dem gewünschten Intervall zu befüllen, und kannst dann die days-Tabelle als führende Tabelle für deinen Join verwenden.</p> <p>Gerne lasse ich mich von MYSQL Experten einer besseren Lösung belehren </p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 07:59:30 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788090#m1788090 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788090#m1788090 <p>Hallo,</p> <p>nachdem ich nun meine Daten aus der DB in php vorliegen habe und mit diesen ein wenig rechnen muss, stellt sich mir die Frage nach der sinnvollsten Programmiertechnik.</p> <p>Zur Ausgangslage:</p> <p>Ich möchte eine Tabelle ausgeben, die tageweise, vorgangsbezogene Werte ausgibt.</p> <p>Also:</p> <p><a href="/images/08eabaea-ad77-11eb-8e84-b42e9947ef30.jpg" rel="noopener noreferrer"><img src="/images/08eabaea-ad77-11eb-8e84-b42e9947ef30.jpg?size=medium" alt="Tabelle" title="Tabelle" loading="lazy"></a></p> <p>Dazu habe ich ja grundsätzlich wenigstens 2 Alternativen:</p> <ol> <li> <p>Ich sammle und verarbeite zweilenweise meine Daten, bis sich der Vorgang oder das Datum ändert und schreibe dann meine Zeile.</p> </li> <li> <p>So habe ich es mopmentan angefangen: Ich sammle und verarbeite Daten und speichere sie in einem mehrdimensionalen Array ala $myArray[$Datum][$VorgangsID]['Unterpunkt123'] und nach Durchlaufen der while-Schleife der Ergebnismenge habe ich in meinem Array alle nötigen Werte. Anschließend löse ich das Array nach $Datum und innerhalb dessen nach $VorgangsID auf und schreibe hieurbei meine Tabelle.</p> </li> </ol> <p>Frage: Ist Punkt 2 unnötiges Hin- und Herkopieren von Daten? Es erscheint mir auf den ersten Blick etwas übersichtlicher zu handeln für mich.</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Tue, 04 May 21 17:34:42 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788070#m1788070 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788070#m1788070 <p>Hallo Rolf,</p> <p>danke für Deine Antwort.</p> <blockquote> <p>Wenn der 03.10.2021 in keiner der Tabellen vorkommt, findet der Tag der Deutschen Einheit in deiner Liste nicht statt.</p> </blockquote> <p>Er kommt doch vor. Ich habe ja eine echte (also keine Temp-Tabelle) erstellt, die die Daten (also alle Tage) von 2000-2100 enthält.</p> <p>Mir ist es nicht gelungen, sie so zu joinen, dass alle Daten (Datums) aus der Datum-Tabelle genommen werden und hierzu leftgejoint die restölichen Daten geNULLt oder eben verwendet werden.</p> <p>Darauf bezog sich meine Frage.</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Tue, 04 May 21 17:52:23 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788071#m1788071 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788071#m1788071 <p>Hallo Jörg,</p> <p>oh. Sorry - jetzt hast Du eine Zusatzlösung wie man die Tabelle auf der Fliege (on the fly) erstellt.</p> <p>Hättest Du besser mal deine um diese Tabelle erweiterte Abfrage vorgestellt.</p> <p>Du machst also jetzt so was?</p> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> d<span class="token punctuation">.</span>datum<span class="token punctuation">,</span> std<span class="token punctuation">.</span>bla<span class="token punctuation">,</span> s<span class="token punctuation">.</span>fuu<span class="token punctuation">,</span> m<span class="token punctuation">.</span>baa <span class="token keyword">FROM</span> datum_ref d <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_stunden std <span class="token keyword">ON</span> std<span class="token punctuation">.</span>datum <span class="token operator">=</span> d<span class="token punctuation">.</span>datum <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_sonder s <span class="token keyword">ON</span> <span class="token punctuation">(</span>std<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">AND</span> std<span class="token punctuation">.</span>Datum <span class="token operator">BETWEEN</span> s<span class="token punctuation">.</span><span class="token keyword">Start</span> <span class="token operator">AND</span> s<span class="token punctuation">.</span><span class="token keyword">End</span> <span class="token operator">AND</span> std<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">=</span> <span class="token string">'".$_POST['</span>myUser<span class="token string">']."'</span><span class="token punctuation">)</span> <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_mein m <span class="token keyword">ON</span> std<span class="token punctuation">.</span>MID <span class="token operator">=</span> m<span class="token punctuation">.</span>MID </code></pre> <p>Das sollte aber funktionieren - bis auf das direkte Einsetzen von $_POST['myUser'] - das ist ein Kontextwechsel und du musst escapen.</p> <p>Es ist natürlich so, dass für die Tage, die in deinen Tabellen nicht vorkommen, nur die d.datum Spalte gefüllt ist und der Rest NULL enthält; aber das wolltest Du ja so, oder?</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> mysql: Left Join an dieser Stelle? Tue, 04 May 21 18:07:31 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788073#m1788073 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788073#m1788073 <p>Hallo Rolf,</p> <blockquote> <p>oh. Sorry - jetzt hast Du eine Zusatzlösung wie man die Tabelle auf der Fliege (on the fly) erstellt.</p> </blockquote> <p> </p> <blockquote> <p>Hättest Du besser mal deine um diese Tabelle erweiterte Abfrage vorgestellt.</p> </blockquote> <p>Ja,. denke ich im Nachhinein auch.</p> <blockquote> <p>Du machst also jetzt so was?</p> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> d<span class="token punctuation">.</span>datum<span class="token punctuation">,</span> std<span class="token punctuation">.</span>bla<span class="token punctuation">,</span> s<span class="token punctuation">.</span>fuu<span class="token punctuation">,</span> m<span class="token punctuation">.</span>baa <span class="token keyword">FROM</span> datum_ref d <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_stunden std <span class="token keyword">ON</span> std<span class="token punctuation">.</span>datum <span class="token operator">=</span> d<span class="token punctuation">.</span>datum <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_sonder s <span class="token keyword">ON</span> <span class="token punctuation">(</span>std<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">AND</span> std<span class="token punctuation">.</span>Datum <span class="token operator">BETWEEN</span> s<span class="token punctuation">.</span><span class="token keyword">Start</span> <span class="token operator">AND</span> s<span class="token punctuation">.</span><span class="token keyword">End</span> <span class="token operator">AND</span> std<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">=</span> <span class="token string">'".$_POST['</span>myUser<span class="token string">']."'</span><span class="token punctuation">)</span> <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_mein m <span class="token keyword">ON</span> std<span class="token punctuation">.</span>MID <span class="token operator">=</span> m<span class="token punctuation">.</span>MID </code></pre> </blockquote> <p>Ja, genau so hatte ichs mir vorgestellt.</p> <blockquote> <p>Das sollte aber funktionieren - bis auf das direkte Einsetzen von $_POST['myUser'] - das ist ein Kontextwechsel und du musst escapen.</p> </blockquote> <p>Hätte ich auch gedacht. Umso besser wärs gewesen, wenn ich die nicht funktionierende Query gepostet hätte. Escapen ist auch klar, das mache ich, bevors in den Produktivbetrieb geht.</p> <blockquote> <p>Es ist natürlich so, dass für die Tage, die in deinen Tabellen nicht vorkommen, nur die d.datum Spalte gefüllt ist und der Rest NULL enthält; aber das wolltest Du ja so, oder?</p> </blockquote> <p>Ganz genauso wollte ich es.</p> <p>Ich schraub nochmal daran herum,. wenns dann wieder nicht funktioniert, komme ich mal mit der Querty um die Ecke.</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Tue, 04 May 21 18:23:30 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788075#m1788075 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788075#m1788075 <p>Hallo Rolf,</p> <blockquote> <blockquote> <p>Du machst also jetzt so was?</p> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> d<span class="token punctuation">.</span>datum<span class="token punctuation">,</span> std<span class="token punctuation">.</span>bla<span class="token punctuation">,</span> s<span class="token punctuation">.</span>fuu<span class="token punctuation">,</span> m<span class="token punctuation">.</span>baa <span class="token keyword">FROM</span> datum_ref d <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_stunden std <span class="token keyword">ON</span> std<span class="token punctuation">.</span>datum <span class="token operator">=</span> d<span class="token punctuation">.</span>datum <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_sonder s <span class="token keyword">ON</span> <span class="token punctuation">(</span>std<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">AND</span> std<span class="token punctuation">.</span>Datum <span class="token operator">BETWEEN</span> s<span class="token punctuation">.</span><span class="token keyword">Start</span> <span class="token operator">AND</span> s<span class="token punctuation">.</span><span class="token keyword">End</span> <span class="token operator">AND</span> std<span class="token punctuation">.</span><span class="token keyword">User</span> <span class="token operator">=</span> <span class="token string">'".$_POST['</span>myUser<span class="token string">']."'</span><span class="token punctuation">)</span> <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_mein m <span class="token keyword">ON</span> std<span class="token punctuation">.</span>MID <span class="token operator">=</span> m<span class="token punctuation">.</span>MID </code></pre> </blockquote> <p>Ja, genau so hatte ichs mir vorgestellt.</p> </blockquote> <p>Und jetzt habe ichs umgesetzt und habe wieder denselben Effekt wie heute schonmal. Ich bekomme die Daten nicht durchgängig angezeigt, sondern nur die Daten, die auch in der stunden-Tabelle stehen.</p> <p>Das ist doch dann kein LEFT JOIN. </p> <p>Woran kanns also liegen?</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Tue, 04 May 21 18:51:20 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788077#m1788077 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788077#m1788077 <p>Hallo Jörg,</p> <p>ich hab grad mal angefangen, Testtabellen aufzubauen.</p> <p>Test 1: Datum und Stunden.</p> <p>LEFT JOIN ergibt zuerst alle Rows, wo die Stunden-Table nicht null ist. Die null-Rows dahinter.</p> <p>Der Optimizer hat also offenbar beschlossen, primär über die Stundentabelle zu laufen und die Datumstabelle zuzumischen. Das mag an der Verteilung der Datenzeilen liegen (1000 Zeilen für 3 Jahre und 3 Zeilen in den Stunden). Jedenfalls brauchte ich einen ORDER BY um die Datümer in die richtige Ordnung zu bringen.</p> <p>Ist das bei Dir vielleicht auch so? Und Du hast so viele befüllte Datenzeilen, dass die Null-Zeilen außer Sicht sind?</p> <p>Wenn sie echt fehlen: ich würde so vorgehen wie ich im phpmyadmin (oder was Du verwendest) Schritt für Schritt aufbauen. Erst nur die Datums-Tabelle, dann die Stunden dazu, dann die Sonder-Tabelle.</p> <p>Eine Frage nebenbei: Wenn Du die Abfrage auf std.User in die ON-Bedingung für tabelle_sonder hängst, dann bekommst Du (<em>solltest</em> Du bekommen) die tabelle_stunden-Einträge für alle User und nur die Sonder-Einträge werden auf den genannten User limitiert. Ist das das, was Du willst?</p> <p>Zuerst die Datu <em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> mysql: Left Join an dieser Stelle? Tue, 04 May 21 19:03:17 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788079#m1788079 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788079#m1788079 <p>Hallo Rolf,</p> <blockquote> <p>ich hab grad mal angefangen, Testtabellen aufzubauen.</p> </blockquote> <p>Kannst Du mir mal nen Dump Deiner Tabellen geben?</p> <blockquote> <p>Test 1: Datum und Stunden.</p> <p>LEFT JOIN ergibt zuerst alle Rows, wo die Stunden-Table nicht null ist. Die null-Rows dahinter.</p> <p>Der Optimizer hat also offenbar beschlossen, primär über die Stundentabelle zu laufen und die Datumstabelle zuzumischen. Das mag an der Verteilung der Datenzeilen liegen (1000 Zeilen für 3 Jahre und 3 Zeilen in den Stunden). Jedenfalls brauchte ich einen ORDER BY um die Datümer in die richtige Ordnung zu bringen.</p> <p>Ist das bei Dir vielleicht auch so? Und Du hast so viele befüllte Datenzeilen, dass die Null-Zeilen außer Sicht sind?</p> </blockquote> <p>Nein, ich habe ja auf einen Monat reduziert, daher kann ich mir alle Zeilen anschauen.</p> <blockquote> <p>Wenn sie echt fehlen: ich würde so vorgehen wie ich im phpmyadmin (oder was Du verwendest) Schritt für Schritt aufbauen. Erst nur die Datums-Tabelle, dann die Stunden dazu, dann die Sonder-Tabelle.</p> </blockquote> <p>Ich verwende auch phpmyadmin. Und genauso habe ichs versucht. Einfach nur einen einzigen LEFT JOIN auf die Stunden. Hat schon nicht funktioniert.</p> <blockquote> <p>Eine Frage nebenbei: Wenn Du die Abfrage auf std.User in die ON-Bedingung für tabelle_sonder hängst, dann bekommst Du (<em>solltest</em> Du bekommen) die tabelle_stunden-Einträge für alle User und nur die Sonder-Einträge werden auf den genannten User limitiert. Ist das das, was Du willst?</p> </blockquote> <p>Ich limitiere eigentlich 2 x auf den User. 1x in der on-Bedingung und 1x in der WHERE-Bedingung der Query.</p> <pre><code class="block">SELECT STD.Datum, a.Datum FROM alletage a LEFT JOIN stunden STD ON a.Datum = STD.Datum WHERE STD.Datum BETWEEN '2021-04-01' AND '2021-04-30' AND STD.User='xyz' ORDER BY STD.Datum ASC </code></pre> <p>Und ich fürchte, genau zweitere lässt meine Query meine Ergebnismange so reduzieren.</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Tue, 04 May 21 19:16:56 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788080#m1788080 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788080#m1788080 <p>Hallo Jörg,</p> <blockquote> <p>Kannst Du mir mal nen Dump Deiner Tabellen geben?</p> </blockquote> <p>Das bringt kaum was - eine Tabelle mit Datümern vom 1.1.2020 bis 31.12.2022 und eine Mini-Tabelle aus datum, user und Stundenzahl mit 3 Einträgen drin.</p> <p>Aber - Mist - den WHERE hab ich übersehen. Das hatte ich als Teil der ON Bedingung gelesen.</p> <p>Ein WHERE wird nach den JOINs durchgeführt und schmeißt deswegen die Rows raus, wo der User NULL ist.</p> <p>Filtere den User mal vorne, beim Join von alletage und stunden. Dann wird das nur auf die Stundentabelle angewendet.</p> <p>Den Datums-Bereich kannst Du im WHERE belassen. Er <strong>müsste</strong> aber auch als Teil der ON-Bedingung funktionieren; ggf. sogar performanter, aber das müsste man messen bzw. mit EXPLAIN untersuchen. Das kann ich bei mir nicht, meine DB ist zu klein und mein MySQL wird deshalb anders optimieren.</p> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> STD<span class="token punctuation">.</span>Datum<span class="token punctuation">,</span> a<span class="token punctuation">.</span>Datum <span class="token keyword">FROM</span> alletage a <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> stunden STD <span class="token keyword">ON</span> a<span class="token punctuation">.</span>Datum <span class="token operator">=</span> STD<span class="token punctuation">.</span>Datum <span class="token operator">AND</span> STD<span class="token punctuation">.</span>Datum <span class="token operator">AND</span> STD<span class="token punctuation">.</span><span class="token keyword">User</span><span class="token operator">=</span><span class="token string">'xyz'</span> <span class="token keyword">WHERE</span> a<span class="token punctuation">.</span>Datum <span class="token operator">BETWEEN</span> <span class="token string">'2021-04-01'</span> <span class="token operator">AND</span> <span class="token string">'2021-04-30'</span> <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> STD<span class="token punctuation">.</span>Datum <span class="token keyword">ASC</span> </code></pre> <p>Beim Zumischen der Sonder-Tabelle brauchst keinen Vergleich des Users mit den $_POST Daten. Denke ich jedenfalls. Denn da hast Du ja eh schon std.user = s.user im ON.</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> mysql: Left Join an dieser Stelle? Wed, 05 May 21 07:14:40 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788086#m1788086 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788086#m1788086 <p>Hallo Rolf,</p> <blockquote> <p>Filtere den User mal vorne, beim Join von alletage und stunden. Dann wird das nur auf die Stundentabelle angewendet.</p> </blockquote> <p>Habe ich versucht, leider ohne Erfolg:</p> <pre><code class="block"> SELECT STD.Datum, a.Datum FROM alletage a LEFT JOIN stunden STD ON ( a.Datum = STD.Datum AND STD.User = 'xyz' ) WHERE STD.Datum BETWEEN '2021-04-01' AND '2021-04-30' ORDER BY STD.Datum ASC </code></pre> <p>ergibt bei mir immer noch erst Daten ab dem 06.04.2021. </p> <pre><code class="block"> SELECT STD.Datum, a.Datum FROM alletage a LEFT JOIN stunden STD ON ( a.Datum = STD.Datum ) WHERE STD.Datum BETWEEN '2021-04-01' AND '2021-04-30' ORDER BY STD.Datum ASC </code></pre> <p>ergibt alle Daten ab dem 01.04.2021, aber dann eben nicht mehr für meinen User "xyz", sondern über alle User hinweg.</p> <blockquote> <p>Beim Zumischen der Sonder-Tabelle brauchst keinen Vergleich des Users mit den $_POST Daten. Denke ich jedenfalls. Denn da hast Du ja eh schon std.user = s.user im ON.</p> </blockquote> <p>Ja, das sehe ich genauso.</p> <p>Aber es gelingt mir leider immer noch nicht, meinen LeftJoin wirksam zu erzeugen. Kenne ich so gar nicht </p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Wed, 05 May 21 07:26:28 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788087#m1788087 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788087#m1788087 <p>Hi,</p> <blockquote> <blockquote> <p>Filtere den User mal vorne, beim Join von alletage und stunden. Dann wird das nur auf die Stundentabelle angewendet.</p> </blockquote> <p>Habe ich versucht, leider ohne Erfolg:</p> <pre><code class="block"> SELECT STD.Datum, a.Datum FROM alletage a LEFT JOIN stunden STD ON ( a.Datum = STD.Datum AND STD.User = 'xyz' ) WHERE STD.Datum BETWEEN '2021-04-01' AND '2021-04-30' ORDER BY STD.Datum ASC </code></pre> </blockquote> <p>mach mal die Datums-Einschränkung im WHERE auf alletage, nicht auf stunden.</p> <p>cu,<br> Andreas a/k/a MudGuard</p> mysql: Left Join an dieser Stelle? Wed, 05 May 21 07:43:48 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788088#m1788088 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788088#m1788088 <p>Hallo MudGuard,</p> <p>yup - so schrub ich es gestern abend. Aber beim Lesen von Jörgs Posting ist es mir auch nicht aufgefallen. Unglaublich, welche Lapsūs (sic!)<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> einem alle unterlaufen können.</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> <hr class="footnotes-sep"> <section class="footnotes"> <ol class="footnotes-list"> <li id="fn1" class="footnote-item"><p>Wie Status: Der Plural ist lapsus mit langem U, weder lapsi noch lapsen oder lapsusse... <a href="#fnref1" class="footnote-backref">↩︎</a></p> </li> </ol> </section> mysql: Left Join an dieser Stelle? Wed, 05 May 21 08:00:03 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788091#m1788091 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788091#m1788091 <p>Hallo Andreas a/k/a MudGuard,</p> <blockquote> <p>mach mal die Datums-Einschränkung im WHERE auf alletage, nicht auf stunden.</p> </blockquote> <p>Jaaa! </p> <p>Jetzt läufts! Das war das letzte fehlende (bzw. falsche) Puzzleteilchen. Und ich erhalte genau das Ergebnis, das ich möchte und auch über den LeftJoin erwartet hätte.</p> <p>Vielen Dank an Dich und Rolf! </p> <p>Ich habe jetzt zwar noch eine Frage zur grundsätzlichen Problemstellunmg und Programmiertechnik, die mache ich aber in einem <a href="https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788090#m1788090" rel="noopener noreferrer">Teilstrang dieses Themas</a> auf.</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Wed, 05 May 21 08:02:30 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788092#m1788092 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788092#m1788092 <p>Hallo Rolf,</p> <blockquote> <p>yup - so schrub ich es gestern abend. Aber beim Lesen von Jörgs Posting ist es mir auch nicht aufgefallen. Unglaublich, welche Lapsūs (sic!)[^1] einem alle unterlaufen können.</p> </blockquote> <p>Und mir ist es in Deinem Post nicht aufgefallen Schön, dass wir dem Lapus mit vereinten Kräften den Garaus gemacht haben. ☺️</p> <p>Jörg</p> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 08:14:18 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788094#m1788094 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788094#m1788094 <p>Hallo Jörg,</p> <p>aber unterschlägst Du jetzt nicht was? Nämlich den Umstand, dass es Datumswerte ohne Vorgang gibt. Denn das war ja vorhin noch Thema und Trigger für den Thread.</p> <p>Wie gibst Du so was aus?</p> <p>Aber damit hätten wir das Thema besser eröffnet, denn dann wäre uns mutmaßlich der Ärger mit der alledaten Tabelle erspart geblieben. Wenn es nur darum ging, nicht vorhandene Datumswerte als "kein Eintrag" in dieser Liste aufzunehmen, hätte man das einfacher lösen können.</p> <p>Bevor ich hier auf Abgleich und <a href="https://wiki.selfhtml.org/wiki/Programmiertechnik/Gruppenwechsel" rel="nofollow noopener noreferrer">Gruppenwechsel</a> eingehe, hätte ich diese Voraussetzung gerne geklärt.</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> mysql: Left Join an dieser Stelle? Wed, 05 May 21 08:05:27 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788093#m1788093 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788093#m1788093 <p>Hi,</p> <blockquote> <p>Schön, dass wir dem Lapus mit vereinten Kräften den Garaus gemacht haben. ☺️</p> </blockquote> <p>Ist das jetzt Rekursion? Ein Lapsus beim Lapsus? </p> <p>cu,<br> Andreas a/k/a MudGuard</p> mysql: Left Join an dieser Stelle? Wed, 05 May 21 08:38:12 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788097#m1788097 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788097#m1788097 <blockquote> <p>Ist das jetzt Rekursion? Ein Lapsus beim Lapsus? </p> </blockquote> <p>Genau darum ging es mir </p> <p>Noch eine Frage:</p> <pre><code class="block">SELECT s.Kategorie, a.Datum FROM alletage a LEFT JOIN stunden STD ON ( a.Datum = STD.Datum AND STD.User = 'xyz' ) LEFT JOIN _436sdw_zz_sonder s ON ( STD.User = s.User AND a.Datum BETWEEN s.Start AND s.End ) WHERE a.Datum BETWEEN '2021-04-01' AND '2021-04-30' ORDER BY `a`.`Datum` ASC </code></pre> <p>hat noch ein kleines Problem, es setzt mir grundsätzlich die s.Kategorie auf NULL, auch wenn zu einem Datum ein Eintrag für den User in der Tabelle "sonder" besteht, der innerhalb von <code>Start</code> und <code>End</code> liegt.</p> <p>Jörg</p> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 08:21:14 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788095#m1788095 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788095#m1788095 <p>Hallo Rolf,</p> <blockquote> <p>aber unterschlägst Du jetzt nicht was? Nämlich den Umstand, dass es Datumswerte ohne Vorgang gibt. Denn das war ja vorhin noch Thema und Trigger für den Thread.</p> </blockquote> <p>Richtig, die gibt es.</p> <blockquote> <p>Wie gibst Du so was aus?</p> </blockquote> <p>Die hatte ich mit im Array geplant. $myArray[$Datum][0][0], also quasi eine Art "Fakeeintrag".</p> <blockquote> <p>Aber damit hätten wir das Thema besser eröffnet, denn dann wäre uns mutmaßlich der Ärger mit der alledaten Tabelle erspart geblieben. Wenn es nur darum ging, nicht vorhandene Datumswerte als "kein Eintrag" in dieser Liste aufzunehmen, hätte man das einfacher lösen können.</p> </blockquote> <p>Einverstanden. Nur ist es natürlich so, dass man nicht jedes Thema der Entwicklung zuerst einmal ins Forum einbringt, sondern man fängt an und stösst ggf. auf ein Problem, wo man nicht weiter kommt. Und dann entwickelt sich das Thema und man merkt, dass es hierzu bessere Lösungsansätze gibt (wie jetzt?).</p> <blockquote> <p>Bevor ich hier auf Abgleich und <a href="https://wiki.selfhtml.org/wiki/Programmiertechnik/Gruppenwechsel" rel="nofollow noopener noreferrer">Gruppenwechsel</a> eingehe, hätte ich diese Voraussetzung gerne geklärt.</p> </blockquote> <p>Ich bin gerne bereit, auf einen besseren Ansatz, gerne auch ohne die alleDatenTabelle umzusatteln.</p> <p>Jörg</p> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 12:10:21 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788109#m1788109 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788109#m1788109 <p>Hallo Jörg,</p> <blockquote> <p>Nur ist es natürlich so, dass man nicht jedes Thema der Entwicklung zuerst einmal ins Forum einbringt, sondern man fängt an und stösst ggf. auf ein Problem, wo man nicht weiter kommt.</p> </blockquote> <p>Ja, ich weiß schon. Das klassische XY-Problem. X ist zu lösen, man hat ein Detailproblem Y und sucht dafür nach Hilfe. Dabei könnte man Y ganz vermeiden.</p> <p>Ich würde es vermutlich mit zwei Queries lösen und für den User die Stundensätze im gewünschten Datumsintervall lesen sowie die Sondersätze, deren Start/End Intervall das gewünschte Datumsintervall überschneidet. Die Tabelle "mein" haben wir aus dem Auge verloren, die schreib ich jetzt einfach mal dazu und hoffe, dass sie keine zusätzliche Komplikation bringt.</p> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> datum<span class="token punctuation">,</span> std<span class="token punctuation">,</span> bla1<span class="token punctuation">,</span> bla2 <span class="token keyword">FROM</span> stunden std <span class="token keyword">LEFT</span> <span class="token keyword">JOIN</span> tabelle_mein m <span class="token keyword">ON</span> std<span class="token punctuation">.</span>MID <span class="token operator">=</span> m<span class="token punctuation">.</span>MID <span class="token keyword">WHERE</span> <span class="token keyword">user</span> <span class="token operator">=</span> $<span class="token keyword">user</span> <span class="token operator">AND</span> datum <span class="token operator">BETWEEN</span> $von <span class="token operator">AND</span> $bis <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> datum </code></pre> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> <span class="token keyword">start</span><span class="token punctuation">,</span> <span class="token keyword">end</span><span class="token punctuation">,</span> blub1<span class="token punctuation">,</span> blub2 <span class="token keyword">FROM</span> sonder s <span class="token keyword">WHERE</span> <span class="token keyword">user</span> <span class="token operator">=</span> $<span class="token keyword">user</span> <span class="token operator">AND</span> <span class="token keyword">start</span> <span class="token operator"><=</span> $bis <span class="token operator">AND</span> <span class="token keyword">end</span> <span class="token operator">>=</span> $von <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> datum </code></pre> <p>Zur Erklärung der "Überschneiden sich die Intervalle" Abfrage: Es gibt 6 mögliche Lagen von start/end und von/bis. Wenn man genau hinguckt, ist es dann "bad", wenn start > bis ODER end < von. Invertiert man das, ergibt sich mit der De Morgan Regel die obige Abfrage.</p> <pre><code class="block">start <= end < von <= bis bad start <= von <= end <= bis good start <= von <= bis < end good von < start <= end <= bis good von < start <= bis < end good von < <= bis < start <= end bad </code></pre> <p>Im Ergebnis hast Du zwei Arrays. Eins mit den Stunden pro Tag, eins mit den Sonder-Intervallen für den gewünschten Zeitraum. Die Datumsangaben stehen da - meine ich - im Format yyyy-mm-dd drin.</p> <p>Das Problem, wie man das darstellen muss, ist mir unklar. Das ist deine Fachlichkeit.</p> <p>Aber grundsätzlich würde ich nun die Datümer im PHP generieren, und nicht in der DB.</p> <pre><code class="block language-php"><span class="token variable">$datum</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token variable">$_POST</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'von'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$bis</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token variable">$_POST</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'bis'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$einTag</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTimeInterval</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"P1D"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token variable">$datum</span> <span class="token operator"><</span> <span class="token variable">$bis</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$cDatum</span> <span class="token operator">=</span> <span class="token variable">$datum</span><span class="token operator">-></span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"Y-m-d"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Verarbeitung</span> <span class="token variable">$datum</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$einTag</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>Ob das mit dem new DateTime so einfach ist, hängt von dem Format ab, in dem Du das Datum vom Client bekommst. Ggf. musst Du <code>DateTime::createFromFormat</code> verwenden.</p> <p>Wie die Verarbeitung aussieht, hängt nun von deiner Fachlichkeit ab. Wenn Du pro Datum über die Vorgänge gruppieren willst, müsstest Du die nun herausfinden. Und dann pro Vorgang die Ausgaben durchführen. Dazu suchst Du Dir die entsprechenden Einträge aus den Arrays heraus. Das kann man alles ordentlich auf Funktionen verteilen und strukturieren.</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> mysql: Left Join an dieser Stelle? Wed, 05 May 21 10:14:55 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788101#m1788101 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788101#m1788101 <blockquote> <p>hat noch ein kleines Problem, es setzt mir grundsätzlich die s.Kategorie auf NULL, auch wenn zu einem Datum ein Eintrag für den User in der Tabelle "sonder" besteht, der innerhalb von <code>Start</code> und <code>End</code> liegt.</p> </blockquote> <p>Das konnte ich aber über</p> <pre><code class="block">SELECT s.Kategorie, a.Datum FROM alletage a LEFT JOIN stunden STD ON ( a.Datum = STD.Datum AND STD.User = 'xyz' ) LEFT JOIN _436sdw_zz_sonder s ON ( a.Datum BETWEEN s.Start AND s.End AND STD.User = 'xyz' ) WHERE a.Datum BETWEEN '2021-04-01' AND '2021-04-30' ORDER BY `a`.`Datum` ASC </code></pre> <p>lösen.</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Wed, 05 May 21 10:47:44 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788102#m1788102 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788102#m1788102 <p>Hallo Jörg,</p> <blockquote> <p>Das konnte ich aber über ... lösen</p> </blockquote> <p>Hm. So langsam beginne ich, den Überblick zu verlieren - bzw. ich habe ihn offenbar noch nie gehabt. Denn mir fällt jetzt ein möglicher Defekt auf.</p> <p>Du hast die Datümer in alledaten.</p> <p>Da mischst Du mit LEFT JOIN Sätze hinzu, die zu einem bestimmten User gehören. Aus der Stunden-Tabelle die vom Datum, aus der Sonder-Tabelle die, deren Datumsintervall das Datum einschließt.</p> <p>Heißt doch eigentlich: Zwischen Stunden und Sonder gibt es überhaupt keinen Bezug - außer der User-ID. Aber das könnte zu wenig sein.</p> <p>Wenn man deine Daten nicht kennt, ist es ja so, dass Du zu einem Datum x Sätze in der Stundentabelle und y Sätze in der Sondertabelle finden kannst. x und y sind Zahlen von 0 bis N. In dem Moment, wo x>1 UND y>1 wird, bekommst Du alle möglichen Kombinationen dieser Sätze geliefert.</p> <p>Fall 1: Das ist okay so und deine Auswertung kommt damit klar.</p> <p>Fall 2: Es ist nicht okay, aber dann musst Du die Garantie haben, dass x>1 UND y>1 nicht zutreffen kann. Ist diese Voraussetzung gegeben? Gibt es zu einem User und Tag maximal einen Stunden-Eintrag? Oder zu einem User und Intervall maximal einen Sonder-Eintrag? Ist vielleicht sogar generell x>1 ODER y>1 ausgeschlossen?</p> <p>Fall 3: Es ist nicht okay, und du kannst die Garantie nicht geben. In dem Fall musst Du überlegen, wie Du damit umgehst.</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> mysql: Left Join an dieser Stelle? Wed, 05 May 21 11:18:33 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788105#m1788105 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788105#m1788105 <p>Hallo Rolf,</p> <blockquote> <p>Hm. So langsam beginne ich, den Überblick zu verlieren - bzw. ich habe ihn offenbar noch nie gehabt. Denn mir fällt jetzt ein möglicher Defekt auf.</p> </blockquote> <p>Da ist definitiv noch etwas nicht so, wie gewünscht. Denn der LEFT JOIN zur sonder-Tabelle gibt mir teilweise noch nicht die korrekte Kategorie aus.</p> <blockquote> <p>Du hast die Datümer in alledaten.</p> </blockquote> <p>Ja.<br> ID(int,autoincremnt)<br> Datum(date)<br> Wochentag(varchar)</p> <blockquote> <p>Da mischst Du mit LEFT JOIN Sätze hinzu, die zu einem bestimmten User gehören. Aus der Stunden-Tabelle die vom Datum, aus der Sonder-Tabelle die, deren Datumsintervall das Datum einschließt.</p> </blockquote> <p>Genau.</p> <blockquote> <p>Heißt doch eigentlich: Zwischen Stunden und Sonder gibt es überhaupt keinen Bezug - außer der User-ID. Aber das könnte zu wenig sein.</p> </blockquote> <p>User-ID und ggf. Datum, wenn es zwischen Start und End liegt.</p> <blockquote> <p>Wenn man deine Daten nicht kennt, ist es ja so, dass Du zu einem Datum x Sätze in der Stundentabelle und y Sätze in der Sondertabelle finden kannst. x und y sind Zahlen von 0 bis N. In dem Moment, wo x>1 UND y>1 wird, bekommst Du alle möglichen Kombinationen dieser Sätze geliefert.</p> </blockquote> <p>Ok. Deshalb an dieser Stelle:<br> X kann 0, 1 oder n sein.<br> Y kann auch 0,1 oder n sein.</p> <blockquote> <p>Fall 1: Das ist okay so und deine Auswertung kommt damit klar.</p> </blockquote> <p>Wenn die Ergebnismenge aus meiner Abfrage stimmen würde, würde meine Auswertung damit klar kommen (müssen).</p> <p>Ich hadere also doch immer noch mir meiner Query.</p> <p><strong>Edit an dieser Stelle (manchmal hilft das Schreiben eines Post bei der Lösung - hier wieder geschehen):</strong></p> <p>Ich habe den LEFTJOIN der Sondertabelle wieder falsch gemacht, auch dort muss ich auf den User dieser Tabelle Bezug nehmen!!</p> <p>Also:</p> <pre><code class="block">SELECT s.Kategorie, a.Datum FROM alletage a LEFT JOIN stunden STD ON ( a.Datum = STD.Datum AND s.User = 'xyz' ) LEFT JOIN _436sdw_zz_sonder s ON ( a.Datum BETWEEN s.Start AND s.End AND STD.User = 'xyz' ) WHERE a.Datum BETWEEN '2021-04-01' AND '2021-04-30' ORDER BY `a`.`Datum` ASC </code></pre> <p>Das scheint mir von der Abfrage her das gewünschte Ergebnis zu bringen.</p> <p>....</p> <p>Habs gerade nochmal in den Echtdaten ausprobiert, die Ergebnismenge sieht sehr aus, wie mein gewünschtes Ergebnis ☺️</p> <p>Siehst du denn noch irgendwo einen möglichen Defekt?</p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Wed, 05 May 21 11:48:02 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788107#m1788107 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788107#m1788107 <p>Hallo Jörg,</p> <blockquote> <p>Siehst du denn noch irgendwo einen möglichen Defekt?</p> </blockquote> <p>Ja - wollte ich eben schon aufgeschrieben haben, ist mir aber scheinbar untergegangen. Du fragst im ON der Sonder-Tabelle STD.User statt S.user ab. Das kann nicht stimmen. Bzw. es würde dazu führen (denke ich), dass Du nur dann Sondersätze bekommst, wenn es einen Satz in der Stundentabelle gibt.</p> <p>Die Frage, was Du mit dem Fall tun willst, wenn Du 2 Stundensätze und 2 Sondersätze zu einem Datum hast, ist Dir also noch total unklar? Denn die Query liefert Dir dann 4 Ergebniszeilen.</p> <p>Stunden:</p> <table> <thead> <tr> <th>Datum</th> <th>User</th> <th>bla</th> </tr> </thead> <tbody> <tr> <td>03.05.2021</td> <td>Rolf</td> <td>17</td> </tr> <tr> <td>03.05.2021</td> <td>Rolf</td> <td>22</td> </tr> <tr> <td>04.05.2021</td> <td>Rolf</td> <td>42</td> </tr> </tbody> </table> <p>Sonder:</p> <table> <thead> <tr> <th>Start</th> <th>Ende</th> <th>User</th> <th>Kategorie</th> <th>blub</th> </tr> </thead> <tbody> <tr> <td>01.01.2021</td> <td>10.05.2021</td> <td>Rolf</td> <td>Kat1</td> <td>99</td> </tr> <tr> <td>01.05.2021</td> <td>31.05.2021</td> <td>Rolf</td> <td>Kat2</td> <td>47</td> </tr> </tbody> </table> <p>Ergibt</p> <table> <thead> <tr> <th>Datum</th> <th>User</th> <th>bla</th> <th>Start</th> <th>Ende</th> <th>Kategorie</th> <th>blub</th> </tr> </thead> <tbody> <tr> <td>03.05.2021</td> <td>Rolf</td> <td>17</td> <td>01.01.2021</td> <td>10.05.2021</td> <td>Kat1</td> <td>99</td> </tr> <tr> <td>03.05.2021</td> <td>Rolf</td> <td>22</td> <td>01.01.2021</td> <td>10.05.2021</td> <td>Kat1</td> <td>99</td> </tr> <tr> <td>03.05.2021</td> <td>Rolf</td> <td>17</td> <td>01.05.2021</td> <td>31.05.2021</td> <td>Kat2</td> <td>47</td> </tr> <tr> <td>03.05.2021</td> <td>Rolf</td> <td>22</td> <td>01.05.2021</td> <td>31.05.2021</td> <td>Kat2</td> <td>47</td> </tr> <tr> <td>04.05.2021</td> <td>Rolf</td> <td>42</td> <td>01.01.2021</td> <td>10.05.2021</td> <td>Kat1</td> <td>99</td> </tr> <tr> <td>04.05.2021</td> <td>Rolf</td> <td>42</td> <td>01.05.2021</td> <td>31.05.2021</td> <td>Kat2</td> <td>47</td> </tr> </tbody> </table> <p>Da sind etliche Daten mehrfach vorhanden. Willst Du die dann auch mehrfach in deiner Auswertung anzeigen? Den "Vorgang" finde ich in deinen Tabellenbeschreibungen bisher nicht, deswegen weiß ich nicht wie der ins Spiel kommt. Ist das die Kategorie?</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> mysql: Left Join an dieser Stelle? Wed, 05 May 21 11:55:52 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788108#m1788108 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788108#m1788108 <blockquote> <p>Hallo Jörg,</p> <blockquote> <p>Siehst du denn noch irgendwo einen möglichen Defekt?</p> </blockquote> <p>Ja - wollte ich eben schon aufgeschrieben haben, ist mir aber scheinbar untergegangen. Du fragst im ON der Sonder-Tabelle STD.User statt S.user ab. Das kann nicht stimmen. Bzw. es würde dazu führen (denke ich), dass Du nur dann Sondersätze bekommst, wenn es einen Satz in der Stundentabelle gibt.</p> </blockquote> <p>Ganz kurz an dieser Stelle, auf den Rest antworte ich gesondert:</p> <p>Aaahh!!! </p> <p>Verteufelt, ich hatte den fehler schon bemerkt:</p> <blockquote> <p>Ich habe den LEFTJOIN der Sondertabelle wieder falsch gemacht, auch dort muss ich auf den User dieser Tabelle Bezug nehmen!!</p> </blockquote> <p>Ich habe dann aber das <strong>s</strong> innerhalb des Quellcodes fett machen woillen, damit der Unterschied überhaupt auffällt. Das geht hier aber nicht (leider), deshalb hab ichs wieder rückgängig gemacht und damit die aölte (falsche) Query wieder hergestellt.</p> <p>Insofern: Ja, dieser Fehler war in der Tat noch vorhanden (jedoch schon bemerkt).</p> <p>Jetzt schau ich mir mal den Rest des Posts an </p> <p>Jörg</p> mysql: Left Join an dieser Stelle? Wed, 05 May 21 12:17:27 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788111#m1788111 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788111#m1788111 <p>Hallo Rolf,</p> <blockquote> <p>Da sind etliche Daten mehrfach vorhanden. Willst Du die dann auch mehrfach in deiner Auswertung anzeigen? Den "Vorgang" finde ich in deinen Tabellenbeschreibungen bisher nicht, deswegen weiß ich nicht wie der ins Spiel kommt. Ist das die Kategorie?</p> </blockquote> <p>Ok, jetzt weiß ich, was Du meinst.<br> Sorry für das pfennigweise Fallen dieses Groschens </p> <p>Naja, das ist teilweise gewollt.<br> Aber eben wirklich nur teilweise.</p> <p>Die Einträge aus der Stunden-Tabelle müssen tatsächlich alle aufgeführt werden.</p> <p>Die anderen sind eher störend.</p> <p>Bevor ich jetzt hier weiter Zeit investiere, gehe ich mal Deiner parallel eingetroffenen Antwort nach und überlege, ob <a href="https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788109#m1788109" rel="noopener noreferrer">diese Alternative</a> sinnvoller ist.</p> <p>Ich schreibe dann dort weiter, wo dann auch die Reise hin geht, also entweder wieder hier oder <a href="https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788109#m1788109" rel="noopener noreferrer">dort</a>. ;)</p> <p>Dir vielen Dank für Deine Hilfe! </p> <p>Jörg</p> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 12:54:43 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788115#m1788115 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788115#m1788115 <p>Hallo Rolf,</p> <p>mal ganz zu Anfang eine Rückfrage:</p> <blockquote> <pre><code class="block language-sql"><span class="token keyword">SELECT</span> <span class="token keyword">start</span><span class="token punctuation">,</span> <span class="token keyword">end</span><span class="token punctuation">,</span> blub1<span class="token punctuation">,</span> blub2 <span class="token keyword">FROM</span> sonder s <span class="token keyword">WHERE</span> <span class="token keyword">user</span> <span class="token operator">=</span> $<span class="token keyword">user</span> <span class="token operator">AND</span> <span class="token keyword">start</span> <span class="token operator"><=</span> $bis <span class="token operator">AND</span> <span class="token keyword">end</span> <span class="token operator">>=</span> $von <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> datum </code></pre> </blockquote> <p>Schön wärs, wenn wir hier ein datum hätten, wir haben aber nur Start und End.</p> <blockquote> <p>Im Ergebnis hast Du zwei Arrays. Eins mit den Stunden pro Tag, eins mit den Sonder-Intervallen für den gewünschten Zeitraum. Die Datumsangaben stehen da - meine ich - im Format yyyy-mm-dd drin.</p> </blockquote> <p>Das tun sie.</p> <blockquote> <p>Dazu suchst Du Dir die entsprechenden Einträge aus den Arrays heraus. Das kann man alles ordentlich auf Funktionen verteilen und strukturieren.</p> </blockquote> <p>Bin ich denn wirklich so viel schneller, wenn ich mir zu einem Datum YYYY-mm-dd den Kategorieeintrag aus dem 2.Array heraus suche als in der db selber? Oder sehe ich hier den Trick nicht, wie man das effizient macht?</p> <p>Jörg</p> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 13:20:07 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788118#m1788118 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788118#m1788118 <p>Nochmal ich,</p> <blockquote> <p>Bin ich denn wirklich so viel schneller, wenn ich mir zu einem Datum YYYY-mm-dd den Kategorieeintrag aus dem 2.Array heraus suche als in der db selber? Oder sehe ich hier den Trick nicht, wie man das effizient macht?</p> </blockquote> <p>Ehrlich gesagt weiß ich auch nicht genau, wie ich schnell und direkt auf Einträge meines ersten arrays zugreife, wenn ich über die Tage in php iteriere. ich könnte mir das für das erste Array vorstellen, wenn ich das Ergebnisarray aus sql zuvor entsprechend umkopiere und das Datum als Key verwende.</p> <p>Fpr das zweite Array fällt mir auf Anhieb gar keine schnelle Lösung mit Direktzugriff ein.</p> <p>Oder ist mir einfach nicht bekannt, wie man sowas macht? Bringt ja nichts, für jedes Datum aus php beide Arrays jeweils zu durchlaufen, oder?</p> <p>Jörg</p> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 13:29:30 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788119#m1788119 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788119#m1788119 <p>Hallo Jörg,</p> <blockquote> <p>Schön wärs, wenn wir hier ein datum hätten</p> </blockquote> <p>Kopierfehler meinerseits. Eine Sortierung ist, wenn Du die Einträge im PHP aus dem Array raussuchst und dem Datum zuordnest, vielleicht gar nicht mehr nötig. Das ist jetzt eher die Frage, was man fachlich braucht. Vielleicht nach dem Start-Datum sortieren.</p> <blockquote> <p>Bin ich denn wirklich so viel schneller, wenn ich mir zu einem Datum YYYY-mm-dd den Kategorieeintrag aus dem 2.Array heraus suche</p> </blockquote> <p>Die DB muss es ja auch suchen. Unterm Strich muss der Aufwand also auf jeden Fall getrieben werden.</p> <p>Ein in-memory Search in einem Array ist aber immer schnell genug, sofern Du keinen Blödsinn programmierst. Die Stunden-Einträge kannst Du assoziativ ablegen, d.h. ein Array auf Stufe 1, dessen Schlüssel der Datumsstring ist, und darin ein Array mit den Stunden-Rows für dieses Datum. Das ist sozusagen Direktzugriff. Sowas hast Du ja jetzt schon.</p> <p>Da kannst Du auch so vorgehen, dass Du dieses Array auch als Leitstruktur verwendest. D.h. bevor Du die DB liest, erzeugst Du pro Datum einen Eintrag:</p> <pre><code class="block language-php"><span class="token variable">$stunden</span><span class="token punctuation">[</span><span class="token variable">$cDatum</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">ARRAY</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>und hängst die Stunden-Rows an das passene Datum an, so dass Du nachher nur noch mit <code>foreach ($stunden as $cDatum => $stundenEinträge)</code> drüberlaufen musst.</p> <p>Die Sondereinträge sind da schon schwieriger, weil Du Einträge finden musst, wo das Datum in einem Intervall liegt. D.h. du kannst da nur ein Array aus den Sonder-Rows machen und das sequenziell durchlaufen. Natürlich kann man noch Tricks mit Datenstrukturen einsetzen, um das zu beschleunigen, aber da stellt sich die Frage nach dem Aufwand. Wenn Du nur zehn Sonder-Rows für eine Auswertung hast, lohnt sich das nicht. Das wird eher ab 1000 Sonder-Rows interessant.</p> <p>Beim Programmieren achtet man zuerst auf Verständlichkeit und Einfachheit. Nur, wenn man damit in Zeitprobleme kommt, baut man komplexere Strukturen, die ggf. laufzeiteffizienter sind.</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 13:50:53 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788121#m1788121 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788121#m1788121 <p>Hallo Jörg,</p> <blockquote> <p>Ehrlich gesagt weiß ich auch nicht genau, wie ich schnell und direkt auf Einträge meines ersten arrays zugreife, wenn ich über die Tage in php iteriere.</p> </blockquote> <p>Mach Dir nicht so viel Kopf um drei Millisekunden. Diese Zugriffszeiten sind nur bei richtig großen Arrays relevant, oder wenn Du einen Server hast, der mit vielen Usern an der Leistungsgrenze rennt.</p> <p>Schreib's erstmal so, dass es funktioniert und verständlich ist. Dann miss die Laufzeit. Und überleg Dir das Mengengerüst für die Zugriffe. Wie oft passiert das? Durch wie viele Leute? Davon hängt doch ab, ob der Server deine Last überhaupt spürt oder nicht.</p> <p><em>Rolf</em></p> <div class="signature">-- <br> sumpsi - posui - obstruxi </div> Daten aus DB in Tabelle ausgeben / Programmiertechnik Wed, 05 May 21 16:14:14 Z https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788125#m1788125 https://forum.selfhtml.org/self/2021/may/04/mysql-left-join-an-dieser-stelle/1788125#m1788125 <p>Hallo Rolf,</p> <blockquote> <p>Mach Dir nicht so viel Kopf um drei Millisekunden. Diese Zugriffszeiten sind nur bei richtig großen Arrays relevant, oder wenn Du einen Server hast, der mit vielen Usern an der Leistungsgrenze rennt.</p> <p>Schreib's erstmal so, dass es funktioniert und verständlich ist. Dann miss die Laufzeit. Und überleg Dir das Mengengerüst für die Zugriffe. Wie oft passiert das? Durch wie viele Leute? Davon hängt doch ab, ob der Server deine Last überhaupt spürt oder nicht.</p> </blockquote> <p>Du hast völlig recht. ich habs jetzt mal durchprogrammiert und fertige für jeden Tag 2 Array an:</p> <pre><code class="block">$arrVorgang[$Datum][$VorgangsID]['myKey'] = ... $arrTag[$Datum][myKey] = ... </code></pre> <p>In das erstere packe ich alle Vorgangsdaten (mit vernünftigen Keys), die mir später wichtig sind, in das zweite alle Tagesdaten, die sich über die Vorgänge (oder auch über Abfragedaten) ergeben.</p> <p>Hierbei habe ich Deine beiden Queries umgesetzt.</p> <p>Da ich mir später noch Gedanken über eine sinnvolle Zuordnung der Daten aus der Tabelle "sonder" machen wollte, habe ich diese nun erstmal einfach als function inkl. der Query hinterlegt, anstelle sie in ein php-Array zu packen.</p> <p>Aber selbst so läuft das Script für 1 User in 1 Monat durch, wie nix. Soll heißen, ich klicke und das ergebnis ist da, getestet auf dem Produktivserver mit Produktivdaten. Bin mir inzwischen nicht mal mehr sicher, ob ich das nochmal ändern soll, was die Tabelle "sonder" und die 30 Queries angeht, die ja durch mein Provisorium entstehen.</p> <p>Das Einzige, was ein bischen ungünstig ist, ist, dass auch mehrere Kategorien aus der Tabelle "sonder" für einen Tag gelten können. Aber zum einen läßt sich das hierarchisch deutlich abmildern und die Fälle, die übrig bleiben, sind 4 an der Zahl. Deshalb implodiere ich dann das Rückgabearray der Funktion und werte diese 4 Varianten zusätzlich zu den Einzelvarianten aus.</p> <p>Nochmal vielen dank für Deine Hilfe,</p> <p>Jörg</p>