Autor Zpráva
Ondra456
Profil *
Pěkný den, zasekl jsem se a nevím jak dál.
Potřebuji vymyslet jak se udělá následující:

- Mám data seřazeny dle ID od nejvyššího po nejmenší.
- Každá položka má také čístelnou hodnotu ve sloupci "hodnota".
- Vyberu si třeba ID 50, které má hodnotu 3.
- Potřebuji zjistit, který řádek je poslední (při sestupném řazení), který má hodnotu stejnou, nebo menší než je 3

Pro jednoduchost dám příklad:
Mám data:
ID 51 - hodnota: 5
ID 50 - hodnota: 3 // mám vybrán tento řádek
ID 49 - hodnota: 4
ID 48 - hodnota: 7
ID 47 - hodnota: 5 // toto je poslední řádek který má hodnotu stejnou, nebo větší než je hodnota řádku s ID 50
ID 46 - hodnota: 2
ID 45 - hodnota: 6 // toto už neberu v potaz, protože na předchozím řádku je hodnota menší než 3

Řádek který potřebuju zjistit je řádek číslo 47.

Bohužel na to ne a ne přijít. Předpokládám že to jde čistě MYSQL dotazem.


Našel jsem tento dotaz:
// zjisti první následující s menší nebo stejnou hloubkou jako rodič (určen $row[poradi])
$row = mysql_fetch_row(mysql_query("SELECT MIN(poradi) - 1, $row[hloubka] + 1 FROM diskuse WHERE poradi > $row[poradi] AND hloubka <= $row[hloubka]"));

Já bych potřeboval něco podobného, akorát s trochu jiným zněním, tedy zjisti poslední následující s větší nebo stejnou hodnotou jako rodič.
Ale nevím jak ten dotaz předělat.
Tori
Profil
Pokud už znáte ID a hodnotu před tímto dotazem, tak asi:
SELECT * FROM tabulka
WHERE ID > 50 AND hodnota >= 3
ORDER BY ID
LIMIT 1
Anebo pokud znáte jen ID, tak si poddotazem dohledejte hodnotu z toho řádku:
SELECT t.* FROM tabulka t
INNER JOIN (SELECT ID, hodnota FROM tabulka WHERE ID = 50) ref USING (ID, hodnota)
WHERE t.ID > ref.ID AND t.hodnota >= ref.hodnota
ORDER BY t.ID
LIMIT 1
Joker
Profil
Ondra456:
Vyberu si třeba ID 50, které má hodnotu 3.
To by mělo být jednoduché. Když znám ID a hodnotu řádku proti kterému porovnávám:
SELECT id, hodnota FROM tabulka WHERE id = (SELECT MAX(id) FROM tabulka WHERE hodnota >= hodnota AND id < id řádku)
edit: Řešení od Tori je lepší.

Ale podle dotazu odhaduji, že jde o vypisování nějakého stromu diskusí, na to jsou efektivnější metody.
Kajman
Profil
Možná něco takového
SELECT t.*
FROM   tabulka t
       CROSS JOIN (SELECT Coalesce(Min(id), 18446744073709551615) hranice
                   FROM   tabulka
                   WHERE  id > 50
                          AND hodnota < 3) h
WHERE  t.id > 50
       AND t.hodnota >= 3
       AND t.id < h.hranice
ORDER  BY t.id DESC
LIMIT  1       

A souhlasím, že se stromy se dá nakládat lépe.
Ondra456
Profil *
Mám tento dotaz:
(výpis z Nette debuggeru)
SELECT `id`
FROM `comment`
WHERE (`item_id` = 2) AND (`poradi` < 11) AND (`hloubka` >= 2)
ORDER BY `poradi`
LIMIT 1

Tedy to co psal Tori, což dělá bohužel to co jsem čekal že bude dělat. Problém je, že to funguje tak, že to vybere ID, které je poslední z celé tabulky s větší, nebo stejnou hloubkou. Jenže to je to co právě nechci.

Vrátím se k předchozímu příkladu a trochu ho rozšířím:
ID 51 - hodnota: 5
ID 50 - hodnota: 3 // mám vybrán tento řádek s hodnotou 3
ID 49 - hodnota: 4
ID 48 - hodnota: 7
ID 47 - hodnota: 5 // Tento potřebuji zjistit, protože následující řádek už má hodnotu menší než 3
ID 46 - hodnota: 2
ID 45 - hodnota: 3
ID 44 - hodnota: 4
ID 43 - hodnota: 5 // Dotaz mi ale vybere tento řádek
ID 42 - hodnota: 1
ID 41 a menší neexistují

RE: Joker, Kajman:
Toto slouží k tomu, abych zjistil na jakou pozici ve stromu mám umístnit nový příspěvek. Jaká je lepší metoda? Googlil jsem a tohle byl nejlepší způsob co jsem našel (tedy určování pozice a hlouby příspěvku při ukládání).
Kajman
Profil
Ondra456:
Mrkněte na "traverzování kolem stromu". Nějaké ukázky práce s touto strukturou a odkazy na úvodní články naleznete např. u Jakuba.
Joker
Profil
Ondra456:
Řekl bych, že řešení od Tori by mělo fungovat, jen to má opačně formulovanou podmínku a řazení.
SELECT * FROM tabulka
WHERE ID < 50 AND hodnota >= 3
ORDER BY ID DESC
LIMIT 1

Problematikou se zabývá třeba tento článek:
http://interval.cz/clanky/metody-ukladani-stromovych-dat-v-relacnich-databazich/
Kajman
Profil
Joker:
To taky fungovat nebude. Ale i já tam mám blbě řazení...

SELECT t.*
FROM   tabulka t
       CROSS JOIN (SELECT Coalesce(Max(id), 0) hranice
                   FROM   tabulka
                   WHERE  id < 50
                          AND hodnota < 3) h
WHERE  t.id < 50
       AND t.id > h.hranice
ORDER  BY t.id
LIMIT  1
Ondra456
Profil *
Kajman:
Ano, toto řešení vypadá že je funkční. Díky moc.


Teď se ještě potýkám s hláškou "Table 'comment' was not locked with LOCK TABLES", i když jasně provádím "LOCK TABLES comment WRITE" ale to je asi jiný problém.
Předpokládám že se mi to z nějakého důvodu pere s Nette.
Tori
Profil
Joker:
Díky, přehlédla jsem chybu.

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:

0