SELF JOIN oder doch zwei Query´s?

xamunrax

Erfahrenes Mitglied
Hallo,

ich befasse mich immer sehr ungern mit den JOINS da sie in der Anwendung doch meist sehr komplex sind, jedoch sparen sie enorm in der Zeit also muss man sich ja damit beschäftigen :eek:

Nun gut meine Frage lautet ob ich bei folgender Aufgabenstellung um zwei Query´s herum komme und sie doch eher in ein Query Packe, welches meine Stammtabelle mittels SELF JOIN zwei mal aufruft.

Aufgabenstellung:
In einer Forenübersicht sollen die einzelnen Hauptforen (im Beispiel: alle mit der board_sub_id 0) mit dazu passenden unterforen (jeweils die board_sub_id = board_id) aufgelistet werden.

Aktuell löse ich das mit zwei Query´s (erstes erstellt eine Schleife in der wiederum eine neue Abfrage erstellt wird die wiederum durch eine Schleife dargestellt wird).

Meine Frage lautet, ist es mögliche sich das zweite Query zu sparen und es durch ein Query mit hilfe von SELF JOIN zu ersetzen.

Tabelle:
Code:
	  board_id   board_name   board_description   board_icon   board_sub_id
	+----------+------------+-------------------+------------+--------------+
	| 1        | Test1      | BlaBlaBlaBla      | ICON 5     | 0            |
	+----------+------------+-------------------+------------+--------------+
	| 2        | Test2      | BlaBlaBlaBla      | ICON 5     | 0            |
	+----------+------------+-------------------+------------+--------------+
	| 3        | Test1_1    | BlaBlaBlaBla      | ICON 5     | 1            |
	+----------+------------+-------------------+------------+--------------+
	| 4        | Test1_2    | BlaBlaBlaBla      | ICON 5     | 1            |
	+----------+------------+-------------------+------------+--------------+
	| 5        | Test1_3    | BlaBlaBlaBla      | ICON 5     | 1            |
	+----------+------------+-------------------+------------+--------------+
	| 6        | Test3      | BlaBlaBlaBla      | ICON 5     | 0            |
	+----------+------------+-------------------+------------+--------------+
	| 7        | Test2_1    | BlaBlaBlaBla      | ICON 5     | 2            |
	+----------+------------+-------------------+------------+--------------+
	| 8        | Test4      | BlaBlaBlaBla      | ICON 5     | 0            |
	+----------+------------+-------------------+------------+--------------+

mein aktueller PHP-Code:
(Bitte ignoriert die MySQL-Classe mit der ich arbeite, ich denke aber vom Sinn her ist es trotzdem verständlich.
PHP:
	$db_board->query("SELECT board_name, board_description, board_icon, board_id FROM ".DB_BOARDS." WHERE board_level >= '".$_SESSION['user_lvl']."' AND board_sub_id = '".$_GET['bid']."' ORDER BY board_sort");
	
	for ($i=0; $i < $db_board->num_rows; $i++) { 
		
		$db_board->next_record(); 
		
		$db_sboard->query("SELECT board_id, board_name, board_sub_id FROM ".DB_BOARDS." WHERE board_sub_id = '".$db_board->f('board_id')."' AND board_level >= '".$_SESSION['user_lvl']."' LIMIT 4");
		
		if($db_sboard->num_rows()>0){
			
			for ($i=0; $i < ; $i++) { 
				
				$db_sboard->next_record();
				
				$tmp_sub_boards[] = array('SUBBOARD_NAME' => $db_sboard->f('asd'), 'SUBBOARD_LINK' => GCMS_LINK('board&bid='.$db_sboard->f('board_id'))); 
			
			}
		}
		
		if(strlen($db_board->f('board_description'))>111){ $tmp_text = substr($db_board->f('board_description'),0,111).'...'; }
		
		$tmp_icon = '<img src="img/board/'.$db_board->f('board_icon').'" width="125" height="122" alt="'.$db_board->f('board_name').'" />';
		
		$tmp_boards[] = array(	'BOARD_ID' => $db_board->f('board_id')),
								
								'BOARD_NAME' => $db_board->f('board_name'), 
								'BOARD_ICON' => $tmp_icon, 
								'BOARD_DESCRIPTION' => $tmp_text);
		
	}
 
Bin ein wenig verwirrt. Das feld heist board_sub_id und beinhaltet die id des Parents?

PHP:
$sql ="
    SELECT 
        parent.board_name AS PARENT_NAME,
        parent.board_description AS PARENT_DESC,
        parent.board_icon AS PARENT_ICON,
        sub.* 
    FROM
        ".DB_BOARDS." AS parent
        LEFT JOIN ( 
                SELECT
                    *
                FROM
                    ".DB_BOARDS." 
                WHERE
                    board_level >= '{$_SESSION['user_lvl']}') AS sub
            ON sub.board_sub_id = parent.board_id
    WHERE
        parent.board_sub_id = 0;";
 
Ich frage mich gerade, wieso da überhaupt ein Join rein sollte. Würde es nicht reichen, eine einfache Anfrage auf die Tabelle zu richen und eine "passende" Sortierung zu verlangen? (Gut, die Sortierung ist vielleicht ein bisschen trickreich, wenn man so was nie benötigt hat, aber es könnte z.B. in Richtung "CASE board_sub_id WHEN 0 THEN board_id * 10000 ELSE board_sub_id * 10000 + board_id END" gehen (unter der noch zu verifizierenden Annahme, dass es nicht mehr als 10000 Boards geben wird).
 
Bin ein wenig verwirrt. Das feld heist board_sub_id und beinhaltet die id des Parents?

ich gebe zu bei genauerem hinsehen ist die Wahl des Namens leicht irreführend... :D
Umso deutlicher aber deine Lösung!

Vielen Dank genau das hab ich so gesucht! :D



@benjava
Deine Lösung hat mich erstmal völlig fertig gemacht, sie bringt mich jedoch auch nicht zum gewünschten Ergebnis, dort würde die Tabellen mit folgendem Result kommen:
Code:
	  board_id   board_name   board_description   board_icon   board_sub_id
	+----------+------------+-------------------+------------+--------------+
	| 10000    | Test1      | BlaBlaBlaBla      | ICON 5     | 0            |
	+----------+------------+-------------------+------------+--------------+
	| 20000    | Test2      | BlaBlaBlaBla      | ICON 5     | 0            |
	+----------+------------+-------------------+------------+--------------+
	| 3        | Test1_1    | BlaBlaBlaBla      | ICON 5     | 10003        |
	+----------+------------+-------------------+------------+--------------+
	| 4        | Test1_2    | BlaBlaBlaBla      | ICON 5     | 10004        |
	+----------+------------+-------------------+------------+--------------+
	| 5        | Test1_3    | BlaBlaBlaBla      | ICON 5     | 10005        |
	+----------+------------+-------------------+------------+--------------+
	| 60000    | Test3      | BlaBlaBlaBla      | ICON 5     | 0            |
	+----------+------------+-------------------+------------+--------------+
	| 7        | Test2_1    | BlaBlaBlaBla      | ICON 5     | 20007        |
	+----------+------------+-------------------+------------+--------------+
	| 80000    | Test4      | BlaBlaBlaBla      | ICON 5     | 0            |
	+----------+------------+-------------------+------------+--------------+

dort liese sie sich dann nur nach folgendem sortieren:

Test1_1, Test1_2, Test1_3, Test2_1, Test1, Test2, Test3, Test4

oder

Test1, Test2, Test3, Test4, Test1_1, Test1_2, Test1_3, Test2_1

das gewünschte Endergebnis wäre jedoch

Test1, Test1_1, Test1_2, Test1_3, Test2, Test2_1, Test3, Test4

danke aber trotzdem für die Mühe!
 
Die Idee mit dem Sortieren ist nicht schlecht. Falls die IDs wirklich ein gutes Sortierkriterium sind, würde der folgende ORDER BY ev. weiterhelfen
SQL:
 ORDER BY CAST(IF(board_sub_id = 0, board_id, CONCAT_WS('.', board_sub_id, board_sub)) AS DECIMAL)

Falls du aber nach Namen sortieren willst, wirds ein wenig komplizierter
SQL:
SELECT
	board_name,
	board_description,
	board_icon,
	TRUE AS is_parent,
	board_name AS order_by_parent,
	'' AS order_by_sub,
FROM
	[table]
WHERE 
	board_sub_id = 0
UNION SELECT
	sub.board_name,
	sub.board_description,
	sub.board_icon,
	FALSE AS is_parent,
	parent.parent_name AS order_by_parent,
	sub.board_name AS order_by_sub,
FROM
	(	SELECT 
			* 
		FROM 
			[table] 
		WHERE 
			board_sub_id != 0
	) AS sub,
	(	SELECT 
			board_id AS parent_id, 
			board_name AS parent_name 
		FROM 
			[table] 
		WHERE 
			board_sub_id = 0
	) as parent
WHERE 
	sub.board_sub_id = parent.parent_id	
ORDER BY order_by_parent, order_by_sub
 
Zuletzt bearbeitet von einem Moderator:
Zurück