frank11
Goto Top

Php mySQL Gruppenwechsel Gruppenbruch, bekomme es einfach nicht hin

Hallo zusammen,

ich habe mich gerade angemeldet, weil ich den php Gruppenwechsel einfach nicht hinbekomme und hoffe dass mir hier jemand helfen kann.

Ich habe eine Datenbanktabelle mit folgender Struktur:

Name         | Typ
-------------+------------
id           | int(11)
created      | datetime
name         | text
text         | text

Es geht um Personen (name) die an zu einem Zeitpunkt (created) einen Eintrag (text) machen.

Die Datensätze würde ich nun als Tabelle pro Person ausgeben, den letzten Datensatz pro Person oben.

Leider bekomme ich es nicht hin.

Bei der ersten Person kommt keine Datensatztabelle, bei der zweiten Person kommt die Datensatztabelle von der ersten Person usw.

<!DOCTYPE html>
<html>
<head>
	<style>
		table, th, td {
		border: 1px solid;
		border-collapse: collapse;
		padding: 5px;
		}
	</style>
</head>
<body>
<?php

include('../db.php');    

$sql = "SELECT id, created, name, text FROM beispieltabelle ORDER BY name ASC, id DESC;" ;  

$erg = $db->query($sql);

$last_entry = null;

while ($row = $erg->fetch_object()) {
	
   if ($last_entry != $row->name) {   
        echo	'<h1>' . $row->name.'</h1>';  
		echo "<table>  
			<thead>
				<tr>
					<th>Datum</th>
					<th>Text</th>
				</tr>
			</thead>
			<tbody>";  
					
        $last_entry = $row->name;
		
    }

		echo "<tr>  
				<td>". date("d.m.Y", strtotime($row->created)) . "</td>  
				<td>". $row->text . "</td>  
			</tr>
		</tbody>
	</table>";  

}

?>
</body>
</html>

Es wäre toll, wenn mir jemand sagen könnte, was ich ändern muss.

Vielen Dank und viele Grüße
Frank11

Content-ID: 4990385676

Url: https://administrator.de/forum/php-mysql-gruppenwechsel-gruppenbruch-bekomme-es-einfach-nicht-hin-4990385676.html

Ausgedruckt am: 22.12.2024 um 11:12 Uhr

LordGurke
LordGurke 16.12.2022 aktualisiert um 23:35:20 Uhr
Goto Top
Was ist ein "Gruppenwechsel"?

Zum Problem mit der Ausgabe:
Du hast einen "Off-by-one"-Fehler, aber ich kann jetzt nicht direkt drauf zeigen, wo er her kommt.
Statt mit While-Schleifen solltest du aber lieber mit foreach() arbeiten, das ist effizienter und deutlich handlicher.
Du benutzt scheinbar mysqli_query(), daher könntest du anstelle der While-Schleife benutzen:

foreach($erg as $row) {
   echo '<h1>' . htmlentities($row->name) . '</h1>';  
   //... und dein weiterer Code
}

Deine ganzen Abfragen auf $last_entry kannst du dann weglassen, da kümmert sich foreach() drum.
frank11
frank11 17.12.2022 aktualisiert um 00:35:42 Uhr
Goto Top
@LordGurke: Vielen Dank für deine Antwort!

Ich dachte "Gruppenbruch" sei das gleiche wie "Gruppenwechsel" > https://php-de.github.io/jumpto/gruppenbruch/

mysqli ist Richtig, meine db.php lautet:
<?php
$db = mysqli_connect(host, benutzer, passwort, name);
mysqli_query($db, "SET NAMES 'utf8'");  
?>

Leider wird mir hier nichts angezeigt, auch nicht der Name:

<?php

include('../db.php');    

$sql = "SELECT id, created, name, text FROM beispieltabelle ORDER BY name ASC, id DESC;" ;  

$erg = $db->query($sql);

foreach($erg as $row) {
   echo '<h1>' . htmlentities($row->name) . '</h1>';  
}

?>

Die Tabelle pro Person habe ich noch garnicht ergänzt, ich wollte schrittweise vorgehen.

Vielen Dank nochmal und viele Grüße
Frank11
MirkoKR
MirkoKR 17.12.2022 um 07:14:06 Uhr
Goto Top
Moin.

Ich lasse mir im Zweifel den Inhalt der Rückgabe als "Debug" unbearbeitet ausgeben, um zu sehen, ob überhaupt was, wie erwartet zurückkommt ...
tk1234
tk1234 17.12.2022 um 09:41:55 Uhr
Goto Top
Zitat von @frank11:

Ich habe eine Datenbanktabelle mit folgender Struktur:

Vielleicht solltest du erstmal die Datenbankstruktur in Ordnung bringen - es geht doch wohl noch um das gleiche Thema wie in dem Thread im Datenbankforum, oder?

Bei der ersten Person kommt keine Datensatztabelle, bei der zweiten Person kommt die Datensatztabelle von der ersten Person usw.

Das Problem dürfte das </tbody> und </table> sein was du nach jedem Datensatz mit ausgibst. Die jeweilige Tabelle darf nur geschlossen werden wenn eine Gruppe abgeschlossen ist - bzw. dann wenn eine neue Gruppe beginnt und das nicht die erste Gruppe ist ($last_entry ist dann nicht null) sowie nach der letzten Gruppe.

mysqli ist Richtig, meine db.php lautet:

Warum quälen sich alle mit MySQLi? PDO ist viel einfacher und dort gibt es auch so praktische Dinge wie die PDO::FETCH_*-Konstanten als Parameter von fetchAll, siehe z.B. Beispiel 4b.

<?php
$db = mysqli_connect(host, benutzer, passwort, name);
mysqli_query($db, "SET NAMES 'utf8'");  
?>

Mal abgesehen davon dass man ?> quasi immer weglassen sollte ist das "SET NAMES" falsch, siehe Handbuch (es muss heißen utf8mb4 und über die Methode set_charset()).

Du benutzt scheinbar mysqli_query(), daher könntest du anstelle der While-Schleife benutzen:

while oder foreach ist ziemlich egal, aber …

echo '<h1>' . htmlentities($row->name) . '</h1>';  

… sowohl h1 als auch htmlentities sind falsch: eine Überschrift erster Ebene kann das rein logisch nicht sein, es muss mindestens die zweite Ebene sein. Und den Kontextwechsel zu behandeln ist zwar grundsätzlich natürlich richtig, die richtige Funktion hierfür ist aber htmlspecialchars, htmlentities macht zu viel.
frank11
frank11 17.12.2022 um 10:19:38 Uhr
Goto Top
@tk1234: Vielen Dank für deine Antwort!

Das stimmt, das Posting aus dem Datenbankforum ist von mir.
Dort habe ich mich gewundert, dass ich keine Benachrichtigungen bei neuen Antworten bekomme und festgestellt, dass ich auf die verwendete Mailadresse keinen Zugriff mehr habe. Daher habe ich eine neue Mailadresse angegeben, das Forum versendet aber keine Verifikations-Mails (mit 2 Providern getestet, auch nicht im Spam-Ordner, ich habe im Roundcube die Spamerkennung auch testweise komplett deaktiviert).
Dann habe mich ganz neu registriert und auch keine Mail erhalten. Daher kann ich dort nicht weiter antworten.
Daher bin ich hier gelandet.
Die Tabelle passt schon so. Das Ganze soll nur ein reines Archiv werden. Die Benutzer und Buchinfos kommen jeweils aus eigenen Tabellen und die Überprüfung ob ein Buch schon weg ist erfolgt auch vorher.

Die db.php habe ich geändert.

Wenn ich </tbody> und </table> testweise komplett weglasse, ändert das leider nichts an dem Problem
"Bei der ersten Person kommt keine Datensatztabelle, bei der zweiten Person kommt die Datensatztabelle von der ersten Person usw."

<?php

include('../db.php');    

$sql = "SELECT id, created, name, text, weiterefelder FROM beispieltabelle ORDER BY name ASC, id DESC;" ;  

$erg = $db->query($sql);

$last_entry = null;

while ($row = $erg->fetch_object()) {
	
   if ($last_entry != $row->name) {   
        echo	'<h2>' . $row->name.'</h2>';  
				echo "	<table>  
					<thead>
						<tr>
							<th>Datum</th>
							<th>Text</th>
							<th>Weiterefelder</th>
						</tr>
					</thead>
					<tbody>";  
					
        $last_entry = $row->name;
		
    }

		echo "<tr>  
				<td>". date("d.m.Y", strtotime($row->created)) . "</td>  
				<td>". $row->text . "</td>  
				<td>". $row->weiterefelder . "</td>  
			</tr>

";  

}

?>

Auch ist die Überschrift nun testweise h1, eigentlich soll das ja irgenwann mal ein Accordion werden.
Aber als Anfänger wollte ich schrittweise vorgehen.

Vielen Dank auf jeden Fall bis hierher und viele Grüße
Frank11
tk1234
tk1234 17.12.2022 um 10:40:46 Uhr
Goto Top
Zitat von @frank11:

Wenn ich </tbody> und </table> testweise komplett weglasse, ändert das leider nichts an dem Problem
"Bei der ersten Person kommt keine Datensatztabelle, bei der zweiten Person kommt die Datensatztabelle von der ersten Person usw."

Einfach weglassen darfst du </tbody> und </table> natürlich nicht einfach, das Ergebnis muss schon gültiges HTML sein. Wenn das Problem auch mit validem HTML nicht behoben ist solltest du mal Datenbankstruktur und Testdaten (als CREATE-TABLE- und INSERT-Querys!) posten damit sich das Problem nachstellen lässt.

Auch ist die Überschrift nun testweise h1, eigentlich soll das ja irgenwann mal ein Accordion werden.

Tipp: Bootstrap und besonders sowas überflüssiges wie jQuery braucht es da garnicht, <details> existiert.
frank11
frank11 18.12.2022 aktualisiert um 22:14:07 Uhr
Goto Top
@tk1234: Vielen Dank für deine Antwort und für den Tipp mit <details>. Das kannte ich tatsächlich noch gar nicht. Das würde die Sache sehr vereinfachen.

Die Tabellenstruktur ist folgendermaßen:

Name         | Typ
-------------+------------
id           | int(11)
created      | datetime
name         | text
text         | text
Ich hoffe es ist das was du meinst.

Ich könnte die Tabelle exportieren als sql-Datei hier zur Verfügung stellen, wäre das hilfreich?


Vielen Dank schonmal bis hierhin und viele Grüße
Frank11
tk1234
tk1234 19.12.2022 um 07:44:21 Uhr
Goto Top
Zitat von @frank11:

Ich hoffe es ist das was du meinst.

Nein, so lässt sich die Tabelle nicht zum Testen einfach importieren - dafür braucht es einen CREATE-TABLE-Query wie er üblicherweise von Admin-Tools (z.B. Adminer oder phpMyadmin) erzeugt wird.

Ich könnte die Tabelle exportieren als sql-Datei hier zur Verfügung stellen, wäre das hilfreich?

Jein. Ein Export der Daten ist schon richtig und hilfreich - aber nicht einfach alles sondern nur eine handvoll Daten mit denen sich das Problem nachvollziehen lässt. Die hier natürlich als INSERT-Query hier posten (nicht als Datei anhängen soweit das hier überhaupt ginge) und nicht vergessen ggf. persönliche Daten zu entfernen.
frank11
frank11 19.12.2022 um 09:13:04 Uhr
Goto Top
Hallo @tk1234,

ich habe die Tabelle auf 50 Datensätze gekürzt und anonymisiert.
Ein Testimport in eine andere Datenbank hat funktioniert.
Die Datei habe ich hier hochgeladen: https://my.hidrive.com/lnk/gYSyLEvn

Dankeschön!


Viele Grüße
Frank11
tk1234
tk1234 20.12.2022 um 18:06:41 Uhr
Goto Top
Zitat von @frank11:

ich habe die Tabelle auf 50 Datensätze gekürzt und anonymisiert.
Ein Testimport in eine andere Datenbank hat funktioniert.

Nein, der Import funktioniert nicht fehlerfrei, beim Anlegen des primary-Keys kracht es da es mehrere Datensätze mit der gleichen ID gibt.
Ist aber egal, testen lässt es sich auch so und es ist genau wie ich schon schrieb: du musst valides HTML erzeugen. Wenn ich </tbody> und </table> korrekt einfüge so das jede Tabelle wieder geschlossen wird (siehe oben), wird auch jede Tabelle bei dem dazugehörigen Benutzer angezeigt.
frank11
frank11 20.12.2022 aktualisiert um 20:41:46 Uhr
Goto Top
Hallo @tk1234,

das tut mir leid, sorry. Jetzt sehe ich das auch... face-sad

Der Import bei all-inkl.com hat problemlos funktioniert, dort wurde einfach ein neuer, aufsteigender Primärschlüssel vergeben.

Ich habe die Datenbanktabelle nun korrigiert und hier hochgeladen: https://my.hidrive.com/lnk/gYSyLEvn

Ich habe jetzt die ganze Zeit versucht, </tbody> und </table> korrekt einzusetzen, aber es nicht geschafft.
In meiner Not habe ich es stumpf vor <h2> gesetzt. Die Seite wird jetzt zwar "korrekt" angezeigt, aber valide ist das naürlich nicht.

<?php

include('../db.php');    

$sql = "SELECT id, created, name, text, weiterefelder FROM beispieltabelle ORDER BY name ASC, id DESC;" ;  

$erg = $db->query($sql);

$last_entry = null;

while ($row = $erg->fetch_object()) {
	
   if ($last_entry != $row->name) {   
        echo	'</tbody></table><h2>' . $row->name.'</h2>';  
				echo "	<table>  
					<thead>
						<tr>
							<th>Datum</th>
							<th>Text</th>
							<th>Weiterefelder</th>
						</tr>
					</thead>
					<tbody>";  
					
        $last_entry = $row->name;
		
    }

		echo "<tr>  
				<td>". date("d.m.Y", strtotime($row->created)) . "</td>  
				<td>". $row->text . "</td>  
				<td>". $row->weiterefelder . "</td>  
			</tr>";  

}

?>

Würdest du mir verraten, wie und wo ich </tbody> und </table> korrekt einsetze?

Das ganze funktioniert so stumpf auch nur mit <table>, mit <details> schon nicht mehr.

Das wäre wirklich sehr nett. face-smile


Vielen Dank und viele Grüße
Frank11
tk1234
Lösung tk1234 20.12.2022 um 22:00:09 Uhr
Goto Top
Zitat von @frank11:

Würdest du mir verraten, wie und wo ich </tbody> und </table> korrekt einsetze?

Das hab ich doch oben bereits: vor <h2> (nur wenn $last_entry nicht null ist) sowie nach der while-Schleife - du musst dir einfach das anschauen was der Browser an Quelltext geliefert bekommt, da müssen die Elemente richtig verschachtelt sein (ob die Zeilenumbrüche im Quelltext "richtig" sind oder nicht ist egal).
frank11
frank11 20.12.2022 um 23:32:20 Uhr
Goto Top
@tk1234: Vielen Dank für deine Antwort! Es funktioniert!

Es mag eine elegantere Lösung geben, aber falls das ganze nochmal jemand braucht:

Die Test-Datenbank-Tabelle:

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";  
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";  
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
CREATE TABLE `beispieltabelle` (
  `id` int(11) NOT NULL,
  `created` datetime DEFAULT NULL,
  `name` text DEFAULT NULL,
  `text` text DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `beispieltabelle` (`id`, `created`, `name`, `text`) VALUES
(1, '2022-01-01 11:08:15', 'Nicole', 'Spülmittel'),  
(2, '2022-01-01 12:34:44', 'Martin', 'Tisch'),  
(3, '2022-01-01 13:00:55', 'Mirko', 'Dose'),  
(4, '2022-01-01 13:01:27', 'Mirko', 'Gürtel'),  
(5, '2022-01-02 07:42:51', 'Mirko', 'Kiste'),  
(6, '2022-01-02 07:59:40', 'Nicole', 'Batterie'),  
(7, '2022-01-02 08:34:54', 'Martin', 'Öl'),  
(8, '2022-01-02 09:39:01', 'Monika', 'Stift'),  
(9, '2022-01-22 06:43:50', 'Mirko', 'Holz'),  
(10, '2022-01-03 08:46:01', 'Jana', 'Käse'),  
(11, '2022-01-03 09:52:09', 'Anja', 'Fenster'),  
(12, '2022-01-03 12:50:44', 'Jutta', 'Schuh'),  
(13, '2022-01-03 13:32:10', 'Hartmut', 'Computer'),  
(14, '2022-01-03 14:44:10', 'Dirk', 'Film'),  
(15, '2022-01-04 07:05:02', 'Birgit', 'Gitarre'),  
(16, '2022-01-04 07:27:20', 'Bernhard', 'Hülle'),  
(17, '2022-01-04 09:05:02', 'Werner', 'Halter'),  
(18, '2022-01-04 11:21:09', 'Bernhard', 'Kleber'),  
(19, '2022-01-05 08:47:08', 'Jennifer', 'Karton'),  
(20, '2022-01-05 09:01:08', 'Armin', 'Auto'),  
(21, '2022-01-05 09:32:07', 'Frank', 'Rolle'),  
(22, '2022-01-05 09:57:16', 'Diane', 'Boot'),  
(23, '2022-01-05 09:59:09', 'Patrick', 'Wohnmobil'),  
(24, '2022-01-05 13:03:44', 'Monika', 'Rolle'),  
(25, '2022-01-06 06:10:02', 'Mirko', 'Atlas'),  
(26, '2022-01-06 07:03:45', 'Hartmut', 'Baum'),  
(27, '2022-01-06 07:05:32', 'Hartmut', 'Schale'),  
(28, '2022-01-06 07:49:16', 'Oliver', 'Sack'),  
(29, '2022-01-06 07:50:51', 'Oliver', 'Eimer'),  
(30, '2022-01-06 09:48:58', 'Martin', 'Säge'),  
(31, '2022-01-06 09:49:47', 'Martin', 'Papier'),  
(32, '2022-01-06 10:08:02', 'Dirk', 'Klammern'),  
(33, '2022-01-06 12:42:21', 'Jutta', 'Gel'),  
(34, '2022-01-07 07:53:07', 'Michael', 'Band'),  
(35, '2022-01-07 08:02:53', 'Werner', 'Blume'),  
(36, '2022-01-07 09:27:10', 'Oliver', 'Wand'),  
(37, '2022-01-08 07:32:04', 'Oliver', 'Haus'),  
(38, '2022-01-08 07:33:11', 'Fabian', 'Text'),  
(39, '2022-01-08 08:04:08', 'Klaus', 'Buch'),  
(40, '2022-01-08 08:39:44', 'Fabian', 'Spiel'),  
(41, '2022-01-08 10:39:09', 'Werner', 'Kugel'),  
(42, '2022-01-09 06:59:27', 'Oliver', 'Farbe'),  
(43, '2022-01-09 06:59:52', 'Oliver', 'Mehl'),  
(44, '2022-01-09 07:00:08', 'Oliver', 'Sand'),  
(45, '2022-01-09 11:05:27', 'Monika', 'Eisen'),  
(46, '2022-01-10 10:45:21', 'Marion', 'Hut'),  
(47, '2022-01-10 10:51:12', 'Birgit', 'Schere'),  
(48, '2022-01-10 11:39:14', 'Werner', 'Hammer'),  
(49, '2022-01-11 06:04:12', 'Klaus', 'Regal'),  
(50, '2022-01-11 06:50:02', 'Nicole', 'Katze');  
ALTER TABLE `beispieltabelle`
  ADD PRIMARY KEY (`id`);
ALTER TABLE `beispieltabelle`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2168;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;


Das Script:
<?php

$db = mysqli_connect(host, benutzer, passwort, name); 

$sql = 'SELECT id, created, name, text FROM beispieltabelle ORDER BY name ASC, id DESC;' ;  

$erg = $db->query($sql);

$last_entry = null;

while ($row = $erg->fetch_object()) {
	
   if ($last_entry != $row->name) { 

		if ($last_entry != 0) {
			echo '</tbody></table></details>';  
		}
   
        echo '<details><summary>' . $row->name.'</summary>';  
				echo '<table>  
					<thead>
						<tr>
							<th>Datum</th>
							<th>Name</th>
							<th>Text</th>
						</tr>
					</thead>
					<tbody>';  
					
        $last_entry = $row->name;
		
    }

		echo '<tr>  
				<td>'. date('d.m.Y', strtotime($row->created)) . '</td>  
				<td>'. $row->name . '</td>  
				<td>'. $row->text . '</td>  
			</tr>';  

}

echo '</tbody></table></details>';  

?>

Vielen, vielen Dank nochmal @tk1234 für deine Geduld mit mir!

Schöne Weihnachten und viele Grüße
Frank11