Autor Zpráva
shmoula
Profil
Ahoj,
narazil jsem na zajímavý problém. Nevím, jestli je to chyba nebo fíčura, ale rád bych, kdyby mi to někdo vysvětlil.
Mám tabulku 240 lidí (ke které joinuju další tabulky) a potřebuju vytvořit rank (automaticky číslovaný sloupec). Nejdřív jsem to řešil přes temporary table s auto_incrementem, ale pak jsem tady v často kladených dotazech narazil na rychlejší a elegantnější řešení přes @proměnnou. S úžasem jsem ale zjistil, že rank nabývá hodnot 241 až 480 místo 1 až 240. Trochu jsem to zkoumal a tady je výsledek (místo lidí jsem dal barvy).

Je to PHP skript, připravený ke spuštění.
Nejdřív zahodí a vytvoří tabulku barvy_pokus (tak bacha na vaše případné stejnojmenné tabulky :o)
Pak do ní vloží 3 testovací řádky (pro tento účel stačí).
Potom se složí a provede 5 skoro stejných mysql dotazů. (Jejich výstup ja na konci.) První čtyři jsou správně, pořadí počítají od 1 do 3. Poslední ho počítá od 4 do 6. V komentáři v kódu dotazu je k tomu ještě dodatek.

Pokud je to známá fíčura tak se omlouvám, hledat na webu jakž takž umím, ale v tomto případě nemám ponětí, jak bych to hledal.

Pokud je to chyba, je možné, že se v jiných verzích MySQL bude chovat jinak. Mám verzi 5.0.22 (pro Windows). Nikde jinde jsem to nezkoušel.

Děkuju za váš čas.


function show_colours($sql)
{
$result = mysql_query($sql);
echo "<pre>poradi id nazev\n-------------------\n";
while ($row = mysql_fetch_row($result))
echo "$row[0] $row[1] $row[2]\n";
echo '</pre><br>';
}

mysql_query("DROP TABLE IF EXISTS barvy_pokus");

mysql_query("CREATE TABLE barvy_pokus (
id INT AUTO_INCREMENT PRIMARY KEY,
nazev VARCHAR(20) )");

mysql_query("INSERT INTO barvy_pokus (nazev) VALUES ('cervena'), ('zelena'), ('modra')");

//bez razeni, zakladni select, ke kteremu se prida razeni a vnejsi select
$sql0 =
"SELECT (@counter := @counter + 1) AS poradi, id, nazev
FROM (SELECT @counter := 0) AS initCounter
JOIN (SELECT id FROM barvy_pokus) AS a /* To jsem jenom potreboval nasimulovat join z jine tabulky. Pokud tam je id, nazev, funguje to spravne. */
LEFT JOIN barvy_pokus USING (id)"; /* Bez LEFT to taky funguje spravne, ale v moji skutecne aplikaci LEFT potrebuju. */

//podle id
$sql1 = "$sql0 ORDER BY id";

//podle id a nazvu
$sql2 = "$sql0 ORDER BY id, nazev";

//podle id, s vnejsim selectem
$sql3 = "SELECT * FROM ( $sql1 ) AS b";

//podle id a nazvu, s vnejsim selectem
$sql4 = "SELECT * FROM ( $sql2 ) AS b";

show_colours($sql0);
show_colours($sql1);
show_colours($sql2);
show_colours($sql3);
show_colours($sql4);

/*
Vystup:

poradi id nazev
-------------------
1 1 cervena
2 2 zelena
3 3 modra


poradi id nazev
-------------------
1 1 cervena
2 2 zelena
3 3 modra


poradi id nazev
-------------------
1 1 cervena
2 2 zelena
3 3 modra


poradi id nazev
-------------------
1 1 cervena
2 2 zelena
3 3 modra


poradi id nazev
-------------------
4 1 cervena
5 2 zelena
6 3 modra

*/

Kajman_
Profil *
Vypadá to, že se to pořadí totiž udělá v tom vnitřním dotazu a pak ještě jednou pro celek.

Pokud má pořadí odpovídat, nedávejte ho do poddotazu ale rovnou do konečného dotazu.
shmoula
Profil
Ahoj, děkuju za odpověď. V tom příkladu s barvami je ten vnější select samozřejmě zbytečný, ale co kdybych to celé, i s pořadím, chtěl seřadit podle názvu barvy? Pak ten výpočet pořadí nemůže být v posledním dotazu.
Konkretně já vytvářím tabulku hráčů, jejich ratingů (jako šachové ELO) a statistik, řadím je podle rating, name, id, podle toho počítám pořadí, a nakonec to celé potřebuju seřadit podle sloupce, který si uživatel vybere na stránce kliknutím na záhlaví.

Ještě to budu zkoumat, třeba to nějak oblafnu, ale vadí mi, že tomu nerozumím. Proč když seřadím jen podle ratingu, spočítá se pořadí správně, když k tomu přidám řazení podle jména (nebo pokusně řadím jenom podle jména), spočítá se špatně? Co když tam udělám nějakou kličku, a v příští setinkové verzi MySQL se toto chování změní? Proto mě zajímá, jestli je to chyba, nebo jestli je to schválně, nebo třeba ne úplně schválně, ale má to tak být.
Kajman_
Profil *
V tomhle případě bych šupnul pořadí asi přímo do tabulky s hráči a jejich elem... a po každém turnaji, nebo kdy se to pořadí mění, tak bych ho přepočítal pomocí update a té proměnné v normální tabulce.


Asi se častěji bude na pořadí dotazovat, než ho měnit, tak mi to přijde jako rychlejší řešení.
shmoula
Profil
:o(
Já jsem to zase nechtěl komplikovat, ve skutečnosti ale celou tu tabulku ratingu netahám rovnou z DB, ale nejdřív ji musím sestavit (tabulka statistik má mj. sloupce id_turnaje, id_hrace, rating_pred, rating_potom, tammusím najít pro každého hráče příslušný řádek, kdy na turnaji hrál naposledy), vypočítat aktivitu hráče (jestli hrál aspoň jednou za poslední rok) a to řazení pro pořadí ve skutečnosti nejdřív vezme aktivní hráče podle ratingu a pak neaktivní hráče podle ratingu. Navíc je tam možost listování v archívu žebříčků. Ostatně původní (ne moje) verze je na http://www.hrejsi.cz/othello/cfo/zebricky/zebricek.php

Uznávám, že se to dá řešit všelijak, i v tomhle případě by šlo ty tabulky celé ukládat do databáze, ale jako řešení mi to moc sympatické není. Prostě jsem chtěl vyřešit to počítadlo.
Toto téma je uzamčeno. Odpověď nelze zaslat.

0