You are not logged in.

  • Login

1

Thursday, November 1st 2007, 12:07am

Kategorie mit samt allen unterkategorien mit einem SQL-Befehl abfragen

Hallo, Lebende. Ich brauche gerade etwas, was es whahrscheinlich nicht gibt, geschweigedenn in
irgend einem Tutorial zu finden ist. Aber vielleicht ist es doch machbar und jemand hier weiß wie.

Ich habe eine Tabelle 'categories'

SQL Code

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE `categories` (
  `id` int(11) NOT NULL DEFAULT '0',
  `sub` int(11) NOT NULL DEFAULT '0',
  `name` text collate latin1_general_ci NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
 
INSERT INTO `categories` (`id`, `sub`, `name`) VALUES
(1, 0, 'Bücher'),
(2, 1, 'Romane'),
(3, 1, 'Biografien'),
(4, 1, 'Geistiger Abfall'),
(5, 2, 'Krimis');


Und brauche eine Möglichkeit, die 3 Zeilen 'Bücher', 'Romane' und 'Krimis' geliefert zu bekommen.
Dabei geht es darum, via sql die ganze Unterordnungsstange bis zu Krimis abzufragen.
Mit einer Rückverfolgungsschleife ist es leicht möglich, jedenfalls gibt es ab einer Kategorisierung
von 10 subordinierenden Items halt 10 hintereinanderfolgende Datenbankanfragen.
Geht es nicht mit weniger Verkehr?

Hoffe, hier eine Antwort auf mein Problem zu finden.
Bedanke mich.

2

Thursday, November 1st 2007, 8:49am

Hi, die Lösung dazu heißt "Nested Sets". Gut erklärt in der Wikipedia: Nested Sets
Welches DBMS nutzt du denn? Auf MySQL Ebene ist es leider nicht implementiert. Dort müsstest du es selbst coden, oder eben bestehende PHP Klassen (z.B. von PEAR) verwenden.

3

Thursday, November 1st 2007, 3:49pm

Ich will ja nicht den ganzen Baumstamm ab einer Zeile bzw ab der ganzen Wurzel haben.
Ich will anhand einer Zeile den Strang zurückverfolgen. Über dem liegt das, über
dem liegt das und darüber das. Und diese ganzen Zeilen, die drüber liegen in passender
Reihenfolge gesendet haben.

Das Beispiel von Wikipedia vrstehe ich im übrigen nicht

SQL Code

1
2
3
4
SELECT (COUNT(parent.id)-1) AS depth, node.id
FROM tree AS node, tree AS parent
WHERE node.l BETWEEN parent.l AND parent.r
GROUP BY node.id ORDER BY node.l;

Hast du vll. eine resource parat, die das erklärt?
Ja, ich benutze MySQL und nicht postgree oder sonst was.
Wird halt am häufigsten verwendet.

SELECT (COUNT(parent.id)-1) AS depth, node.id
FROM categories AS node, categories AS parent
WHERE node.l BETWEEN parent.l and parent.r
GROUP BY node.id ORDER BY node.l

so klappt das schonmal nicht und ich glaube, dieser
query ist für mysql geeignet.

// edit
Ich glaub, ich hab da was
http://www.php-resource.de/tutorials/read/21/2/

This post has been edited 2 times, last edit by "sjBlack" (Nov 1st 2007, 4:39pm)


4

Thursday, November 1st 2007, 9:01pm

// edit
Ich glaub, ich hab da was

Hast du es denn hinbekommen? Je nach Projekt würd ich dir wirklich eine Klassennutzung empfehlen. Die Pear MDB2 zum Beispiel. Oder eben wie einfach die Beispiele der Wikipedia nutzen,

5

Thursday, November 1st 2007, 9:49pm

Nein. Aber den Strang muss man doch irgendwie mit einem simplen SQL query
bei einer MySQL Datenbank abfragen können?
Das Skript, für das ich das brauche, muss möglichst Hostunabhängig sein.
Ich will die Einträge mit einer Id und einer sub-Spalte.

Wie ich den ganzen Baum abfragen kann, würde ich eventuell auch gerne wissen, aber:
Ihre Subordinierung soll nicht durch eine Nummerierung wie in dem Beispiel, das ich fand, erkannt werden.
Und die Sortierung in seiner Ebene durch eine pos-Spalte durch ORDER BY.

In erster Linie interessiert mich nur der Strang der Eltern-"Elemente".
Verflucht, das muss doch irgendwie simple machbar sein!
Dann verwende ich halt eine Schleife mit einer Anfrage pro Durchlauf...

This post has been edited 1 times, last edit by "sjBlack" (Nov 1st 2007, 10:16pm)


6

Thursday, November 1st 2007, 10:22pm

Ja, Nested Sets sind anstrengend. Das bestreitet keiner *g*

Willst du dein DB Layout behalten, musst du es auf x Ebenen begrenzen. Z.B. so

SQL Code

1
2
3
4
5
6
SELECT * FROM categories A 
LEFT JOIN categories B ON B.id = A.sub 
LEFT JOIN categories C ON C.id = B.sub
LEFT JOIN categories D ON D.id = C.sub
LEFT JOIN categories E ON D.id = E.sub
WHERE A.id = 5;

7

Tuesday, December 25th 2007, 9:49pm

Das ist so hoffnungslos. Ich bekomem es nichteinmal hin, wenn ich es auf 3 Ebenen begrenze.
Jetzt habe ich das Problem wieder in einer Boardsoftware.

SQL Code

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE `sj_forums` (
  `id` int(10) UNSIGNED NOT NULL DEFAULT '0',
  `sub` int(11) NOT NULL DEFAULT '0',
  `pos` int(11) NOT NULL DEFAULT '0',
  `list_subforums` tinyint(1) NOT NULL DEFAULT '1',
  `list_topics` tinyint(1) NOT NULL DEFAULT '1',
  `stat_topics` int(10) UNSIGNED NOT NULL DEFAULT '0',
  `stat_posts` int(10) UNSIGNED NOT NULL DEFAULT '0',
  `title` text collate latin1_general_ci NOT NULL,
  `desc` text collate latin1_general_ci NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;


sub ist der Vaterzeiger auf das übergeordnete Forum.
stat_topics beinhaltet die Anzahl der Themen, die sich
in dem Forum befinden. Relativ, nicht absolut!

Nun versuche ich die ids der Foren eins unter dem Forum der id 0 (wurzelforum)
aufzulisten mit der Anzahl der Themen in absoluter Tiefe abzurufen.

SELECT `id`, SUM(`stat_topics`) AS `sum_stat_topics`, SUM(`stat_posts`) AS `sum_stat_posts`
FROM `sj_forums` A
LEFT JOIN `sj_forums` B ON B.id = A.sub
LEFT JOIN `sj_forums` C ON C.id = B.sub
WHERE A.`sub`=0
GROUP BY `id`

MySQL meldet: Dokumentation
#1052 - Column 'id' in field list is ambiguous

Selbst das bekomme ich nicht hin!
H-E-L-P!!!

8

Tuesday, December 25th 2007, 11:38pm

Hi,
id gibts mehrmals, deswegen musst du sie dir zur Weiterverwendung umbenennen

SQL Code

1
SELECT A.`id` AS aid, B.`id` AS bid, C.`id` AS cid, ....


die weitere logik habe ich mir nicht angeschaut.. probiers erstmal so.

9

Wednesday, December 26th 2007, 12:05am

Source code

1
2
3
4
5
6
7
8
9
SELECT
  A.`id` AS `id`,
  SUM(`stat_topics`) AS `sum_stat_topics`,
  SUM(`stat_posts`) AS `sum_stat_posts`
FROM `sj_forums` A
LEFT JOIN `sj_forums` B ON B.id = A.sub
LEFT JOIN `sj_forums` C ON C.id = B.sub
WHERE A.`sub`=0
GROUP BY `id`

#1052 - Column 'stat_topics' in field list is ambiguous


Ich fasse mein Problem mal so...

Ich habe eine Tabelle categories, wo jede Zeile eine Kategorie darstellt.
Eine Kategorie kann in einer anderen geschachtelt sein.
Jede Kategorie hat eine eindeutige id und eine sub-Spalte, welche angibt,
welcher übergeordneten Kategorie sie unetrgeordnet ist (Vaterzeiger).

Außerdem sind da noch die 2 Spalten 'title', 'text' und 'hits'.
In text ist halt der Text, den man sich anschaut.
hits gibt an, wie oft die ejweilige Kategorie gelesen wurde.

Die Wurzelkategorie hat die id 0 und sub -1.
Nun möchte ich alle Kategorien mit ihrer id abrufen und der absoluten
Anzahl der hits, die der Kategorie der id 0 (Wurzelkategorie)
untergeordnet sind. In einer Gruppierung halt, mit SUM() etc.

Unter absolute Anzahl meine ich die Summe aus der
hits-Spalte einer aufgelisteten Unterkategorie und
denen, die dieser untergeordnet sind.

Der Baum kann auf 3 Ebenen begrenzt sein.
Dann müsste das mit JOINS irgendwie zu machen sein.
Nur weiß ich halt nicht, wie..

So klappt das schonmal nicht:

Source code

1
2
3
4
5
6
SELECT `id`, SUM(B.`hits`)
FROM `categories` A, `categories` B, `categories` C
WHERE A.`sub`=0
LEFT JOIN B.`sub`=A.`id`
LEFT JOIN C.`sub`=B.`id`
GROUP BY `id`


#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LEFT JOIN B. `sub` = A. `id` LEFT JOIN C. `sub` = B. `id` GROUP BY `id`
LIMI' at line 1


Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
-- phpMyAdmin SQL Dump
-- version 2.11.1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Erstellungszeit: 25. Dezember 2007 um 23:59
-- Server Version: 5.0.45
-- PHP-Version: 5.2.4

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--
-- Datenbank: `test`
--

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

--
-- Tabellenstruktur für Tabelle `categories`
--

CREATE TABLE `categories` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `sub` int(11) NOT NULL default '0',
  `hits` int(10) unsigned NOT NULL default '0',
  `title` text collate latin1_general_ci NOT NULL,
  `text` text collate latin1_general_ci NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=3 ;

--
-- Daten für Tabelle `categories`
--

INSERT INTO `categories` (`id`, `sub`, `hits`, `title`, `text`) VALUES
(1, 0, 0, 'Spielen nach Noten', 'Wenn sie bla bla können sie hier ja weitermachen\r\nhier das bla bla usw...'),
(0, -1, 0, 'Gitarrenkurs für Anfänger', 'Hier bla bla Gitarren bla\r\nFahren sie fort mit Spielen nach Noten bla\r\nwenn bla'),
(2, 0, 0, 'Spielen nach Gefühl', 'Ich muss euch ab hier enttäuschen.\r\nIch bin ein lügner, ich kann selbst nicht Gitarre spielen...');



Das hier funtkioniert mit der Ebenenbegrenzung, die ich leider in Kauf nehmen muss.

Source code

1
2
3
4
5
6
7
SELECT
    A.id AS `id`,
    A.title AS `title`,
    SUM(A.stat_posts) + SUM(B.stat_posts) + SUM(C.stat_posts) AS `sum_stat_posts`
FROM `sj_forums` A, `sj_forums` B, `sj_forums` C
WHERE A.sub=0 AND B.sub=A.id AND C.sub=B.id
GROUP BY A.id

Leider aber auch nur auf Unterforen, die selbst mindestens 2 Unterforen haben!

This post has been edited 2 times, last edit by "sjBlack" (Dec 26th 2007, 1:00am)


10

Wednesday, December 26th 2007, 2:17am

AHAHAHAHAHAHA UHIHIHIHI

UHIHIHIHIHIHIHIHIIH ICH HABS GESCHAFFT

UNGLAUBLICH DASS DIESER QUERY FUNKTIONIERT


Source code

1
2
3
4
5
6
SELECT
    `id`, SUM(`stat_posts`) + (
         SELECT SUM(`stat_posts`) FROM `sj_forums` A WHERE A.`sub`=Z.id
    ) AS `sum_stat_posts`
FROM `sj_forums` Z WHERE `sub`=0
GROUP BY `id`


nochn paar einschübe udn ich schaff an die 10 ebenen!!!
UHIHIHI

// edit
VERDAMMTE SCHEISSE!!!
Wenn ich jetzt nichts finde, was NULL in 0 konvertiert, war auch das ein Fehlschlag!

Source code

1
2
3
4
5
6
7
SELECT
    `id`, SUM(`stat_posts`) + (
        SELECT SUM(`stat_posts`) FROM `sj_forums` A WHERE A.`sub`=Z.`id`
    ) AS `absstat_posts`
FROM `sj_forums` Z
WHERE `sub`=1
GROUP BY `id`;

Ich bekomme hier 2x NULL ausgegeben, weil 2 Unterkathegorien keine weiteren Unterkathegorien beinhalten...
Und irgendwas + NULL ist NULL...


Source code

1
2
3
4
5
6
7
SELECT
    `id`, SUM(`stat_posts`) + (IFNULL(
        SELECT SUM(`stat_posts`) FROM `sj_forums` A WHERE A.`sub`=Z.`id`
    ), 0) AS `absstat_posts`
FROM `sj_forums` Z
WHERE `sub`=1
GROUP BY `id`


#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT SUM( `stat_posts` ) FROM `sj_forums` A WHERE A. `sub` = Z. `id` ) , 0 ) ' at line 1

WHYYYYYYYYYYYYY!?!?!?!?!?!?
WHYYYYYYYYYYYYYYYYYYYYY!?!?!!?
ICH WAR SO NAH DRAN ;_; SO VERDAMMT NAH DRAN ;X; ;( ;( ;(

DIESE GOTTVERDAMMTE NULL!!!

This post has been edited 3 times, last edit by "sjBlack" (Dec 26th 2007, 3:10am)


11

Wednesday, December 26th 2007, 11:53am

ich würd ja in der Datenbank alle NULL Werte durch 0 ersetzen. - am besten du ergänzt im Schema einfach ein NOT NULL.
Sonst wird dein SQL Query nur unnötig droß.

btw: Auch wenn man hier für dein Problem nichts nützliches findest, es gibt sogar eine eigene Dokuseite für Probleme mit NULL ;)
http://dev.mysql.com/doc/refman/5.1/de/p…-with-null.html

12

Thursday, December 27th 2007, 12:38am

Hab's schon mit IFNULL() überwunden...
Eine Klammer hatte gefehlt.

13

Thursday, December 27th 2007, 10:25am

Also funktioniert es jetzt?
Wäre für die Lösung dankbar, da ich ein ähnliches Problem hab..

bye

14

Thursday, December 27th 2007, 10:36am

Die null, kann noch sehr viel unangenehmer werden, da eine dreiwertige Logik ensteht. Gibt ganz oft Probleme, wenn man negierte Statements verwendet.

15

Sunday, December 30th 2007, 4:10am

Also funktioniert es jetzt?
Wäre für die Lösung dankbar, da ich ein ähnliches Problem hab..

bye


SQL Code

1
2
3
4
5
6
7
SELECT
    `id`, `stat_posts` + IFNULL(
        (SELECT SUM(`stat_posts`) FROM `sj_forums` A WHERE A.`sub`=Z.`id`)
    , 0) AS `absstat_posts`
FROM `sj_forums` Z
WHERE `sub`=0
GROUP BY `id`

Social bookmarks