problem mit Baum durchsuchen

Kalma

Erfahrenes Mitglied
Guten Morgen,

ich habe eine kleine Kategorie verwaltung geschrieben, die eine wiefolgt aussehende MySQL Tabelle hat
kat_id | auto_increment | primary_key
kat_is_root
kat_top_kategorie
kat_name

Kat_is_root gibt an, ob die Kategorie eine TopKategorie ist, also z.b.

Musik kat_is_root = 1
-- Schlagzeug
--- Becken
Auto kat_is_root = 1
-- Opel
-- Mercedes

Das Level zeigt immer die Einrückung an und kat_top_kategorie die Kategorie in der die Kategorie gespeichert ist
(ID 1) Musik
(ID 2) -- Schlagzeug kat_level = 1 / kat_top_kategorie = 1 (Musik)
(ID 3) --- Becken kat_level = 2 / kat_top_kategorie = 2 (Schlagzeug)
(ID 4) Auto
(ID 5) -- Opel kat_level = 1 / kat_top_kategorie = 4
(ID 6) -- Mercedes kat_level = 1 / kat_top_kategorie = 4

So, soweit klappt das ganz gut auch mit der PHP Ausgabe.
Jetzt habe ich jedoch noch eine Benutzer und eine Schlagwort Tabelle.
Benutzer:
benutzer_id
benutzer_name

Schlagwoerter
schlagwort_id
schlagwort_besitzer
schlagwort_inhalt

Dort kann der Benutzer eintragen, er möchte z.B zu "Becken" gefunden werden.
Das ist soweit kein Problem, jedoch soll er auch gefunden werden, wenn man auf Musik klickt, da "Becken" in "Musik" ist.
Ich kriegs nicht hin.

Wie würdet ihr das machen?
 
Ich würde statt "kat_is_root" eher die "parent_id" speichern und wenn es auf höchster Ebene ist einfach "NULL" als Wert nutzen. Dann hast du die Zuordnung Musik zu Becken.
 
Hi
Danke für die fixe Antwort.
wie meinst du das genau?

Ich habe bis jetzt soein paar Testeinträge inner Datenbank:
Code:
-- phpMyAdmin SQL Dump
-- version 2.11.7
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Jul 15, 2008 at 10:48 AM
-- Server version: 5.0.51
-- PHP Version: 5.2.4-2ubuntu5.2

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--
-- Database: `me_test`
--

-- --------------------------------------------------------

--
-- Table structure for table `kategorien`
--

CREATE TABLE IF NOT EXISTS `kategorien` (
  `kat_id` int(11) NOT NULL auto_increment,
  `kat_is_root` tinyint(4) NOT NULL,
  `kat_top_kategorie` int(11) NOT NULL,
  `kat_level` int(11) NOT NULL,
  `kat_name` varchar(50) NOT NULL,
  PRIMARY KEY  (`kat_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=24 ;

--
-- Dumping data for table `kategorien`
--

INSERT INTO `kategorien` (`kat_id`, `kat_is_root`, `kat_top_kategorie`, `kat_level`, `kat_name`) VALUES
(1, 1, 0, 0, 'Musik'),
(2, 1, 0, 0, 'Auto'),
(3, 1, 0, 0, 'Politik'),
(4, 1, 0, 0, 'Gesundheit'),
(5, 0, 2, 1, 'Opel'),
(6, 0, 2, 1, 'Porsche'),
(7, 0, 2, 1, 'Mercedes'),
(8, 0, 2, 1, 'Ford'),
(9, 0, 1, 1, 'Schlagzeug'),
(10, 0, 1, 1, 'Gitarre'),
(11, 0, 1, 1, 'Bass'),
(12, 0, 1, 1, 'Blasinstrumente'),
(13, 0, 9, 2, 'Becken'),
(14, 0, 9, 2, 'Felle'),
(15, 0, 9, 2, 'Sticks'),
(16, 0, 9, 2, 'Snares'),
(17, 0, 13, 3, 'Zildjian'),
(18, 0, 13, 3, 'Ufip'),
(19, 0, 17, 4, 'Avedis'),
(20, 0, 17, 4, 'ZHT'),
(21, 0, 17, 4, 'ZBT'),
(22, 0, 17, 4, 'K-Custom'),
(23, 0, 17, 4, 'Constantinople');


Könnt ihr ja mal anschauen wenn ihr grad Zeit habt.

Mein Code zu folgender Ausgabe sieht so aus:
PHP:
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<style type="text/css" rel="stylesheet">
			body {
				font-size:small;
			}
			
			a:link, a:visited, a:hover {
				color:#000000;
				text-decoration:none;
			}
		</style>
		<?php
			require_once 'mysql.php';
		?>
	</head>
<body>
	<h1>Kategorien</h1>
	
	<?php
		$query		=	'SELECT
								*
							FROM
								kategorien
							WHERE
								`kat_is_root` = "1"
							ORDER BY
								`kat_name` ASC';
		$result		=	mysql_query($query) or die(mysql_error());
		$count		= mysql_num_rows($result);
		
		if($count == 0) {
			echo '<p>Keine Root Kategorien gefunden!</p>';
		} else {
			// Funktion zum Auslesen der Kategorien
			function getkat($current_id, $level)
			{
				// Weitere Kategorien auslesen
				$sub_query		=	'SELECT
												*
											FROM
												kategorien
											WHERE
												`kat_top_kategorie` = "'.$current_id.'"
											ORDER BY
												`kat_name` ASC';
				$sub_result		=	mysql_query($sub_query) or die(mysql_error());
				$sub_count		= mysql_num_rows($sub_result);
				
				while($selectsub = mysql_fetch_array($sub_result))
				{
					$id			= $selectsub['kat_id'];
					$level		= $selectsub['kat_level'];
					$name		= $selectsub['kat_name'];
					$ruecken	= '--';
					
					if($level == 1) {
						$ruecken = '--';
					} elseif ($level == 2) {
						$ruecken = '----';	
					} elseif ($level == 3) {
						$ruecken = '------';
					} elseif ($level == 4) {
						$ruecken = '--------';
					}
					
					echo $ruecken.' <a href="viewcat.php?id='.$id.'" title="Finde Leute in der Kategorie '.$name.'">'.$name.'</a><br />';
					
					getkat($id, $level);
				}
			}
			
			
			while($select = mysql_fetch_array($result))
			{
				$id			= $select['kat_id'];
				$is_root	= $select['kat_is_root'];
				$name		= $select['kat_name'];
				
				// Namen ausgeben
				echo '<h2>'.$id.' <a href="viewcat.php?id='.$id.'" title="Finde Leute in der Kategorie '.$name.'">'.$name.'</a></h2>';
				
				getkat($id, 1);
			}
		}
	?>
</body>
</html>

Wenn jemand noch Verbesserungsvorschläge zur Performance-Verbesserung des Scriptes hat, die ich noch nicht gesehen hab, bitte her damit ;)
 
Ich versuchs mal als Beispiel:

Code:
kat_id | auto_increment | primary_key
kat_name
parent_id | DEFAULT NULL

Code:
kat_id | kat_name | parent_id
1 | Musik | NULL
2 | Auto | NULL
3 | Politik | NULL
4 | Gesundheit | NULL
5 | Opel | 2
6 | Porsche | 2
7 | Mercedes | 2
8 | Ford | 2
9 | Schlagzeug | 1

Das bedeutet, das jedes Kind-Element seinen Vater kennt (parent_id). Also eine einfache Vater-Kind-Beziehung.

Meistens will man ja auch noch pro Ebene die Sortierreihenfolge selber bestimmen. Daher würde ich eine Tabelle wie folgt aufbauen:

Code:
kat_id | auto_increment | primary_key
kat_name
sort_order (UNSINGED INT)
parent_id | DEFAULT NULL

Ich schau mal ob ich des auch aus dem Kopf in SQL hinkriege:
PHP:
CREATE TABLE IF NOT EXISTS `kategorien` (
  `kat_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `kat_name` VARCHAR(50) NOT NULL,
  `sort_order` INT UNSIGNED NOT NULL DEFAULT 0,
  `parent_id` int(11) DEFAULT NULL,
  PRIMARY KEY  (`kat_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;
PS: pass bloß auf, dass alles, was du machst in Latin1 bzw. ISO-8859-1 / ISO-8859-15 codiert ist! Falls du zukünftig UTF-8 einsetzen willst, solltest du am besten sofort alle Datenbanken / Tabellen in UTF-8 anlegen!
 
Guten Morgen,

ich habe eine kleine Kategorie verwaltung geschrieben, die eine wiefolgt aussehende MySQL Tabelle hat
kat_id | auto_increment | primary_key
kat_is_root
kat_top_kategorie
kat_name

Kat_is_root gibt an, ob die Kategorie eine TopKategorie ist, also z.b.

Musik kat_is_root = 1
-- Schlagzeug
--- Becken
Auto kat_is_root = 1
-- Opel
-- Mercedes

Das Level zeigt immer die Einrückung an und kat_top_kategorie die Kategorie in der die Kategorie gespeichert ist
(ID 1) Musik
(ID 2) -- Schlagzeug kat_level = 1 / kat_top_kategorie = 1 (Musik)
(ID 3) --- Becken kat_level = 2 / kat_top_kategorie = 2 (Schlagzeug)
(ID 4) Auto
(ID 5) -- Opel kat_level = 1 / kat_top_kategorie = 4
(ID 6) -- Mercedes kat_level = 1 / kat_top_kategorie = 4

Also du hast in der ersten tabelle unötiger weise eine Spalte zuviel was das nur unötig komplizierter macht. Die spalte kat_top_kategorie könntes du weglassen.
Alle Haupt und unter Gruppen kanst du allein mit der einen Spalte kat_is_root steuern.

Bsp.
ID 1) Musik /kat_is_root=1
(ID 2) -- Schlagzeug /kat_is_root=1 (Musik) // untergruppe von Musik
(ID 3) --- Becken /kat_is_root = 2 (Schlagzeug) // untergruppe von Schlagzeug
(ID 4) Auto / kat_is_root=4 // Hauptgruppe da verweis auf sich selbst
(ID 5) -- Opel / kat_is_root = 4 // untergruppe von Auto
(ID 6) -- Mercedes /kat_is_root=4 // untergruppe von Auto

Wie du siehst läst sich das viel leichter über eine Spalte lösen als 2.
Jede Id die auf sich verweist ist eine Hauptgruppe. Nach dem Schema kanste beliebig vieler unterkategorien machen.

So, soweit klappt das ganz gut auch mit der PHP Ausgabe.
Jetzt habe ich jedoch noch eine Benutzer und eine Schlagwort Tabelle.
Benutzer:
benutzer_id
benutzer_name

Schlagwoerter
schlagwort_id
schlagwort_besitzer
schlagwort_inhalt

Dort kann der Benutzer eintragen, er möchte z.B zu "Becken" gefunden werden.
Das ist soweit kein Problem, jedoch soll er auch gefunden werden, wenn man auf Musik klickt, da "Becken" in "Musik" ist.
Ich kriegs nicht hin.

Die lösung ist nun einfach wenn du wie oben beschrieben die Spalte wegelassen hast und und die Struktur daran angepasst hast.
Nun brauchst nur mehr in der Tabelle die Id speichern die Zugeordnet werden sollen.
Dazu gibst nun 2 Möglichkeiten.

1.) Du Ordnes generrel nur Hauptgruppen zu so werden sie dann in jeder unter gruppe davon gefunden.

2.) oder du specherst expliziept nun nur die Gruppen Id getrennt mit komma ab
Bsb Benutzer_eintrag=3,6 Dann würde er gefunden werden unter Becken und Mercedes

Mfg Splasch
 
Zuletzt bearbeitet:
Danke schonmal für die vielen Antworten.

Ich denke ich werde mich Radhads Beispiel anschließen.

Allerdings hab ich ne Frage.
Ich lese die Kategorien mit einer rekursiven Funktion aus.

PHP:
function getkat($current)
{
// Auslesen und neue $current - ID bestimmen

getkat($current);
}

Wie kann ich das realisieren, dass er automatisch pro neue Ebene -- Striche für die Einrückung einfügt?

Musik
-- Schlagzeug
---- Becken
------ Ufip


Vielen Dank schonmal
 
In dem du in deiner Rekusiven Funktion folgendes einfügst:

PHP:
echo str_repeat("-",$ebene); // $ebene gibt die Anzahl der unter ebene als int an

Mfg Splasch
 
Hi nocheinmal.


Ich verzweifle grad wieder.

Habe jetzt folgende Datenbank:
kat_id
kat_parent_id
kat_name

Und folgenden Code:
PHP:
	// hautpkategorien auslesen
	// kat_parent == NULL
	$query		=	'SELECT
						*
					FROM
						kategorien
					WHERE
						`kat_parent_id` = "NULL"
					ORDER BY
						`kat_name` ASC';
	$result		=	@mysql_query($query);
	
	if($result == false) {
		$kat_fehler		= true;
	} else {
		$kat_fehler		= false;
		
		
		$i				= 1;
		$kategorien		= array();
		$subkats		= array();
		while($select = mysql_fetch_assoc($result))
		{
			$kat_id		= $select['kat_id'];
			$kat_name	= $select['kat_name'];
			
			$select['i']		= $i;
			$select['kat_id']	= $kat_id;
			$select['kat_name']	= $kat_name;
			
			// subkategorien auslesen
			$subkat			=	'SELECT
									*
								FROM
									kategorien
								WHERE
									`kat_parent_id` = "'.$kat_id.'"
								ORDER BY
									`kat_name` ASC';
			$subkat_res		=	@mysql_query($subkat);
			$subkat_count	=	@mysql_num_rows($subkat_res);
			
			if($subkat_count != 0) {
				while($fetch = mysql_fetch_assoc($subkat_res))
				{
					$skat_id		= $fetch['kat_id'];
					$skat_parent	= $fetch['kat_parent_id'];
					$skat_name		= $fetch['kat_name'];
					
					$fetch['subkat_id']		= $skat_id;
					$fetch['subkat_parent']	= $skat_parent;
					$fetch['subkat_name']	= $skat_name;
					
					$subkats[]	= $fetch;
				}
			}			
			
			$kategorien[]		= $select;
		
			$i++;
		}
	}

Und im Template:
HTML:
			<?php foreach($kategorien as $select) { ?>
				<b><a href="katetgorien.php?show=<?php echo $select['kat_id']; ?>"><?php echo $select['kat_name']; ?></a></b> <br />
				
				<?php foreach($subkats as $fetch) { ?>
					<?php if($fetch['subkat_parent'] == $select['kat_id']) { ?>
						&nbsp; &nbsp; <a href="kategorien.php?show=<?php echo $fetch['subkat_id']; ?>"><?php echo $fetch['subkat_name']; ?></a> <br />
					<?php } ?>
				<?php } ?>
			<?php } ?>


Jetzt hab ich aber das Problem dass ich nur eine Ebene hab.
Wenn ich mehrere will muss ich wieder für jede Ebene einen Query manuell durchführen. Finde keine Lösung.

Danke für die Hilfe schonmal im Voraus
 
Du wirst da nicht um eine Rekusive funktion rum kommen. Da helfen dir alle schleifen nicht.
Doch vorsicht bei rekusiven Funktionen ist die gefahr hoch das man eine endlos Routine Programmiert.

Mfg Splasch
 
Zurück