Recursive DBDirlisting (pgSQL)

Door Jens V, 14 jaar geleden, 2.489x bekeken

Met deze functie is het mogelijk om door een fictieve mappenstructuur in een database te bladeren. Ik heb de functie enkel voor PostgreSQL gemaakt, maar het aanpassen ervan zou makkelijk moeten zijn.
De werking zou voor zich moeten spreken.

Voor de eenvoudigheid voeg ik de database-class die ik gemaakt heb erbij. Deze stelt niet heel veel voor, maar daar draait dit script dan ook niet rond.

Het script zou ook bij snippets kunnen staan, maar daar vind ik het te groot voor.

Voorbeeld: Helaas niet, nog geen pgSQL op mijn host. Iemand met een host waar pgSQL op staat, het zou fijn zijn als je een voorbeeldje online kan zetten :)

Als je de code bekijkt zal je zien dat er wordt gecontroleerd of parent_id -1 is. Moest je hiervoor een betere methode hebben mag je die altijd laten weten.

Een toepassing van dit script zou kunnen zijn om door categorien van een webwinkel te bladeren. Je kan makkelijk je producten per categorie laten zien door juist onder regel 41 een query toe te voegen die je producten uit de database haalt.
Een mogelijke toevoeging daar zou dit kunnen zijn:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$aProducts
= $DB->fetchDB("
    SELECT
        *
    FROM
        products
    WHERE
        category_id = $1
    ORDER BY
        name
"
, array($aCats[$i]['id']));

if($aProducts)
{

    for($p = 0; $p < count($aProducts); $p++)
    {

        echo $aProducts[$p]['name'] . '<br />';
    }
}

?>

Gesponsorde koppelingen

PHP script bestanden

  1. recursive-dbdirlisting-pgsql

 

Er zijn 13 reacties op 'Recursive dbdirlisting pgsql'

PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
- -
- -
14 jaar geleden
 
0 +1 -0 -1
Ik heb wel PostgreSQL bij mijn host, moet ik even een voorbeeld online plaatsen?
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Grappig scriptje, alleen het datamodel rammelt. Je hebt een parent_id, maar dat is niet altijd een parent_id en dankzij het ontbreken van een foreign key heb je de garantie dat je vroeg of laat een corrupte database oploopt. Want wat ga je doen als je een parent verwijdert, maar de children per ongeluk als eenzame weesjes achterlaat?

Zet dus een foreign key op het parent_id die naar het id verwijst en zorg er voor dat deze ook NULL mag zijn. Wanneer er geen parent is, is er geen parent en heeft het geen enkele zin om een -1 parent te verzinnen. Die is er niet!

Het script zul je dus ook iets moeten aanpassen, je krijgt nu een NULL (ontbreken van een waarde) en geen -1 als waarde retour.
Jens V
Jens V
14 jaar geleden
 
0 +1 -0 -1
Bedankt Frank voor de tip, de database heb ik ondertussen aangepast. Ik wist niet dat dat ging, een FK op dezelfde tabel.
Maar voor het script zit ik nu wel even vast. Hoe moet ik dat nu doen, aangezien die 'NULL' die er nu staat niet werkt...

Jens

EDIT: 't Zou moeten werken zo, en ik denk dat het datamodel nu ook juist is :)
@Jonathan, je mag altijd wel een voorbeeldje online zetten ja, zou fijn zijn :)
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Je kunt in de SELECT de NULL vervangen door de jou gewenste -1 door COALESCE te gebruiken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
SELECT
  id,
  COALESCE(parent_id, '-1') AS my_parent_id,
  name,
  description
FROM
  directories
WHERE
  COALESCE(parent_id, '-1') = $1
ORDER BY
  id

Edit: query even iets aangepast.
Jens V
Jens V
14 jaar geleden
 
0 +1 -0 -1
En wat doet dan dan? :D Ik ben hier nu echt al vijf minuten op aan't kijken... Ik heb geen idee waarom je dat zou doen op de products tabel?
De werking van die COALESCE snap ik wel, die staat mooi op de pgSQL site...
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
9.13.2. COALESCE

COALESCE(value [, ...])

The COALESCE function returns the first of its arguments that is not null. Null is returned only if all arguments are null. It is often used to substitute a default value for null values when data is retrieved for display, for example:

SELECT COALESCE(description, short_description, '(none)') ...

Like a CASE expression, COALESCE will not evaluate arguments that are not needed to determine the result; that is, arguments to the right of the first non-null argument are not evaluated. This SQL-standard function provides capabilities similar to NVL and IFNULL, which are used in some other database systems.


Maar ik snap echt niet waarom dat op de products tabel toe te passen.... :)
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Omdat ik met copy-paste lukraak een query heb gecopieerd....

Je moet uiteraard directories hebben. Zal de boel even editen.
Jens V
Jens V
14 jaar geleden
 
0 +1 -0 -1
Dus ik moet dit doen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$aCats
= $DB->fetchDB("
        SELECT
            id,
            COALESCE(parent_id, '-1') AS my_parent_id,
            name,
            description
        FROM
            directories
        WHERE
            COALESCE(parent_id, '-1') = $1
        ORDER BY
            id
    "
, array($parent_id));
?>

in plaats van
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
if($parent_id == -1)
    {

        $aCats = $DB->fetchDB("
            SELECT
                *
            FROM
                categorien
            WHERE
                id = 0
        "
, array());
    }

    else
    {
        $aCats = $DB->fetchDB("
            SELECT
                *
            FROM
                categorien
            WHERE
                parent_id = $1
            ORDER BY
                id
        "
, array($parent_id));
    }

?>
?

Heb dat hier op men localhost geprobeerd en dat werkt niet.. :-/ Ik snap de werking wel, maar hij doet het gewoon niet....
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Met COALESCE(parent_id, '-1') vervang je een NULL in parent_id door de waarde -1. Dat is wat jij graag in je php-code wilt gaan verwerken, vraag het dan ook zo op. Dit heeft ook als voordeel dat je dan een vergelijking kan maken zonder dat je de WHERE hoeft aan te passen. = NULL of <> NULL kan niet, dan moet je met IS NULL of IS NOT NULL gaan werken.

Let er wel op dat je de queries niet doorelkaar gaat gooien, zoals ik ook al deed, de tabel directories is heel wat anders dan de tabel categorien. Ga dus even op je gemak de juiste queries uitschrijven en zet ze dan pas in je PHP-code. pgAdmin kan je hier uitstekend bij helpen.
Jens V
Jens V
14 jaar geleden
 
0 +1 -0 -1
Dat van directories en categorien is gewoon een foutje van mij. Ik had dit script gemaakt om door categorien te bladeren. De originele tabel in mijn database noemt catogorien. Dat was dus ook duidelijk de fout;) Ik pas het script zodadelijk aan...
Bedankt Frank!
(ohja, ook nog eens bedankt om die pgSQL in mijn hoofd te drammen... Die is echt wel véél beter dan MySQL;) )
Jesper Diovo
Jesper Diovo
14 jaar geleden
 
0 +1 -0 -1
Ziet er wel leuk uit. Maar, kan dit niet korter:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
INSERT INTO directories (id, parent_id, name, description) VALUES (1, 0, 'Cat 1', 'cat1');
INSERT INTO directories (id, parent_id, name, description) VALUES (2, 0, 'Cat 2', 'cat2');
INSERT INTO directories (id, parent_id, name, description) VALUES (3, 1, 'Cat 3', 'cat3');
INSERT INTO directories (id, parent_id, name, description) VALUES (5, 1, 'Cat 5', 'cat5');
INSERT INTO directories (id, parent_id, name, description) VALUES (4, 3, 'Cat 4', 'cat4');
INSERT INTO directories (id, parent_id, name, description) VALUES (0, '', 'Hoofd map', 'Dit is de hoofdmap');


Zo:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
INSERT INTO directories (id, parent_id, name, description) VALUES (1, 0, 'Cat 1', 'cat1'), (2, 0, 'Cat 2', 'cat2'), (3, 1, 'Cat 3', 'cat3'), (5, 1, 'Cat 5', 'cat5'), (4, 3, 'Cat 4', 'cat4'), (0, '', 'Hoofd map', 'Dit is de hoofdmap');


Overigens, waarom een insert van het id? Dat is toch auto_increment, die hoef je toch eigenlijk niet te inserten?


Edit: het is 1st, hè :-P.
Jens V
Jens V
14 jaar geleden
 
0 +1 -0 -1
@Jezpur
Bedankt voor de commentaar, maar ze is totaal irrelevant. Hoe dit INSERT-queries eruit zien doet er toch helemaal niet toe... In pgSQL noemt het daarbij ook nog eens niet auto_increment. Geef liever eens een reactie op het script...
Jens
Frank -
Frank -
14 jaar geleden
 
0 +1 -0 -1
Jezpur heeft wel een punt dat hij aandacht vraagt voor de INSERT-queries, die zijn namelijk niet goed.

Wanneer jij een NULL wilt behouden bij de hoofdmap, moet je een NULL opgeven en niet een '' (lege string). Dat is niet handig, dat is echt wat anders.

Daarnaast is zul je nu op de INSERT een foutmelding krijgen doordat je eerst de children probeert in te voeren en dán pas de parent. Hoe wil je dan de foreign keys afdwingen? Die leveren dus fraaie en geheel correcte foutmeldingen op. Zelf de id's toekennen terwijl je net een SERIAL hebt aangemaakt, is niet handig. Ook dat gaat foutmeldingen opleveren omdat de SEQUENCE die bij de SERIAL hoort, nog de teller op 1 heeft staan. Die gaat dus de waardes 1 t/m 5 uitgeven, wat niet kan. Wederom een aantal foutmeldingen. De waarde 0 die jij opgeeft voor het id van de hoofdmap, zal een foutje zijn, dat moet 1 zijn. Gebruik NEXTVAL() en LASTVAL() om de juiste id's aan te maken en op te vragen.
PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Jens V
Jens V
14 jaar geleden
 
0 +1 -0 -1
Daar heb je wel een punt Frank (en Jezpur; bij deze mijn excuses). 't Is juist, dit is gewone output van mijn pgAdmin (een backup van de data gemaakt). Heb voor de rest eigenlijk niet naar de data gekeken :)

Jens

Om te reageren heb je een account nodig en je moet ingelogd zijn.

Inhoudsopgave

  1. recursive-dbdirlisting-pgsql

Labels

  • Geen tags toegevoegd.

Navigatie

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.