Autor Zpráva
Sylar
Profil
Zdravím,
mám takovéto pole

(
    [0] => Array
        (
            [id] => Array
                (
                    [orig] => 1171
                )
            [par_id] => Array
                (
                    [orig] => 0
                )
            [nazev] => Array
                (
                    [orig] => "Položka 1"
                )
        )
 [1] => Array
        (
            [id] => Array
                (
                    [orig] => 2000
                )
            [par_id] => Array
                (
                    [orig] => 0
                )
            [nazev] => Array
                (
                    [orig] => "Položka 2"
                )
        )
   [2] => Array
        (
            [id] => Array
                (
                    [orig] => 1190
                )
            [par_id] => Array
                (
                    [orig] => 1171
                )
            [nazev] => Array
                (
                    [orig] => "Položka 3"
                )
        )
)

Potřeboval bych seřadit položky, které mají nenulový údaj [par_id][orig] a zařadit je tak, aby byly ihned za polem, které odpovídá [par_id][orig] == [id][orig] . Jedná se o strom položek, kdy údaj [par_id][orig] nese ID rodičovské položky a já bych potřeboval pole seřadit tak, aby byla hlavní položka a ihned za ní, aby byly její dceřiné (jsou-li nějaké), za nimi další hlavní položka a za ní opět (má-li nějaké) dceřiné položky. Pořadí hlavních položek (tedy těch, které mají [par_id][orig] == 0) musí zůstat nezměněné (vůči ostatním hlavním položkám) .

Ukázkové pole výše by tedy mělo po seřazení být v pořadí [Položka 1], [Položka 3], [Položka 2]
mzk
Profil *
Sylar:
Zdravím,
mám takovéto pole
otázkou je, kde se to pole bere? nešlo by to pole už rovnou vytvářet dle tvých požadavků, než ho pak seřazovat?
Sylar
Profil
mzk:
beru jej z databáze, kde jsou všechny položky uloženy v jedné tabulce se sloupci [ID] [PAR_ID] [NAZEV] , provázanost mezi ID a PAR_ID je stejná jako popisuji výše. Přemýšlel jsem nad tím, ale pokud lze takto seřadit pole pomocí sql dotazu, je to bohužel nad mé znalosti. Osobně si myslím, že to ale asi nepůjde.
Tori
Profil
Řešila bych to určitě na úrovni databáze. Pro větší objem dat to bude IMHO i rychlejší, než přeskládávat pole v PHP.
SELECT id, par_id, IF(par_id == 0, id, par_id) ref, nazev
FROM tabulka
ORDER BY ref, (par_id == 0) DESC, nazev
V té označené části si vyberete ID skupiny (tj. rodic.id anebo potomek.par_id), potom to můžete použít při řazení. Nevýhoda je, že takhle sice potomci budou seřazení podle názvu, ale rodiče/vlákna budou podle svých ID.

Pokud byste tedy chtěl řadit i rodiče podle názvu, bude potřeba poddotaz, něco jako
SELECT r.id, r.nazev, p.id AS idPotomka, p.nazev AS nazevPotomka
FROM 
   (SELECT id, nazev FROM tabulka 
    WHERE par_id = 0
    ORDER BY nazev) r
LEFT JOIN tabulka p ON r.id = p.par_id
ORDER BY r.nazev, r.id, p.nazev
(píšu z hlavy, možná to bude potřeba opravit). Pokud je na sloupci nazev unikátní klíč, stačí řadit podle ORDER BY r.nazev, p.nazev.

edit: Předpokládám, že je to jen dvouúrovňová struktura.
Sylar
Profil
Tori:
díky za nápad, jen tam moc nechápu ten poddotaz, opravdu má být v klauzuli FROM? Mohla bys mi prosím spíše popsat myšlenku toho druhého řešení s podvýrazem, asi mi něco důležitého uniká a nevidím tam to řešení.
Tori
Profil
Sylar:
opravdu má být v klauzuli FROM?
Ano. Zkusil jste to, jaká data vám ten dotaz vrátí?
Princip je ten, že mám (dejme tomu na nějakém fóru) tabulku r s tématy (= rodiče, r.par_id == 0), a k ní připojím druhou tabulku p s příspěvky (= potomci, p.par_id == rodič.id). Akorát tu první tabulku nemáte samostatně, tak si ji musíte vytvořit poddotazem.
Sylar
Profil
Tori:
zkoušel, ale hodilo mi to chybu, že tabulka "r" neexistuje, resp. že neexistuje sloupec "r.id" .

Princip je ten, že mám (dejme tomu na nějakém fóru) tabulku r s tématy (= rodiče, r.par_id == 0), a k ní připojím druhou tabulku p s příspěvky (= potomci, p.par_id == rodič.id).
Tomuhle rozumím, ale nebude potíž v tom, že v klauzuli FROM vybíráme sloupce "id" a "název" a dotaz tam očekává pouze jméno té tabulky?

Edit:
Ještě jsem zde nezmínil, možná, že to není důležité, že data si uživatel může řadit i podle dalších sloupců (např. cena apod. - další sloupce jsem do tohoto příkladu neuváděl kvůli zjednodušení), takže při selectu by se měla nejprve podle konkrétního sloupce (např. cena) seřadit nejprve rodiče a k nim poté vybrat děti (ty by se v ideálním případě také mohli řadit dle ceny, ale to už za každou cenu být nemusí).
Tori
Profil
Sylar:
hodilo mi to chybu, že tabulka "r" neexistuje, resp. že neexistuje sloupec "r.id" .
Udělala jsem si pokusnou tabulku, dotaz mi chybu neháže. Jak vypadá váš dotaz, se správnými názvy tabulek atd.?
edit: A v tom poddotazu je řazení zbytečné, stačí řadit až výsledek spojení tabulek (nemůžu to už opravit ve [#4].)
Sylar
Profil
Tori:
tak ta chyba byla způsobena zřejmě něčím jiným, omluva - moje chyba.

Nyní mi dotaz vyhodí pouze potomky:
SELECT r.id AS par_id, r.nazev AS par_nazev, p.id, p.nazev FROM 
(SELECT id, nazev FROM udaje WHERE par_id = '0') r
LEFT JOIN udaje p ON r.id = p.par_id ORDER BY r.nazev, r.id, p.nazev

Array
(
    [0] => Array
        (
            [par_id] => 310
            [par_nazev] => Název
            [id] => 311
            [nazev] => Název
        )

    [1] => Array
        (
            [par_id] => 310
            [par_nazev] => Název
            [id] => 812
            [nazev] => Název
        )

    [2] => Array
        (
            [par_id] => 310
            [par_nazev] => Na skok do Paříže
            [id] => 800
            [nazev] => Na skok do Paříže
        )

)

Neukáže se rodič [ID = 310] a několik dalších rodičů bez potomků.
Tori
Profil
No, mě totiž nenapadlo, jak udělat to "za rodičem následují jeho potomci" - možná s tím počítáte při čtení z DB? Můj dotaz vrací vždycky ve stejném řádku s rodičem i jeho prvního potomka, takže tady by to mělo vyhodit něco jako:
par_id | par_nazev | id | nazev |
310 | Název | 311 | Název |     -- tady začíná rodič ID 310 + zároveň jeho první potomek.
310 | Název | 812 | Název |     -- další potomek rodiče ID 310
310 | Název | 800 | Na skok... |   -- dtto
123 | Něco  | NULL | NULL |     -- tady začíná rodič ID 123, který nemá žádného potomka
456 | Nadpis | NULL | NULL |    -- další rodič, s ID 456, taky bez potomka
Sylar
Profil
Tori:
tak nakonec jsem to vyřešil ještě jinak, přeskládáním pole.

Script prochází celé pole a zjistí zda-li je prvek dítě nebo rodič. Pokud dítě, projde znova celé pole a najde rodiče. Poté posune všechny položky vzad či vpřed (záleží jestli se dítě nachází před nebo za rodičem) a na volné místo umístí dítě. Pokud rodiče nenajde, nechá dítě tam kde je.

$last_id = 0;
for($i = 0; $i < count($data); $i++) {
      $item = $data[$i];

      if ($item['par_id'] == 0) {
        $last_id = $item['id'];
        continue;
      }
      if ($last_id == $item['par_id']) {
        continue;
      }

      foreach($data as $d => $dat) {
        if ($item['par_id'] == $dat['id']) {

          if ($i < $d) {
            for($j = $i; $j < $d; $j++) { $data[$j] = $data[$j + 1]; }
            $empty = $d;
            $i -= 1;
          } else {
            for($j = $i; $j > $d; $j--) { $data[$j] = $data[$j - 1]; }
            $empty = $d + 1;
          }

          $data = $item;
    } } }

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: