Nejste přihlášen(a)
Stránky: 1
Ahoj vsem,
snad je nadpis odpovidajici tomu na co chci zeptat ;o)
Resim aktualizaci poradi pro zobrazeni, tj. mam v MySQL tabulku napr. XXX se
sloupci primary_index(id), unique(poradi) a text.
Mam tam rekneme 1000 radku (zatim je poradi shodne s id) a ted mi uzivatel
skrze fomular rekne, ze id=999 majici do ted poradi 999 bude mit nove poradi 10
→ tj. potrebuji vygenerovat dotaz/dotazy na zmenu id v intervalu
10 az 999.
Jak to nejlepe udelat?
1.) vytvorit pro kazde ID update->execute() → to je asi trochu .. ehm … nestastne reseni
2.) vygenerovat pro kazde ID update, ale pouze je kumulovat a pak naraz provest ->execute() → to je asi vhodnejsi, ale napada Vas nekoho jako to udelat pres DibiFluent ?
3.) existuje nejaka lepsi treti cesta?
Diky za info.
Radek
Editoval ras (23. 11. 2011 22:29)
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.
Existuje několik dalších cest. Vše musí proběhnout uzavřené v transakci, zkráceně zapsáno takto:
poradi = poradi + 1 atd.poradi_newUPDATE poradi_new = poradiporadi_newUPDATE poradi = NULLUPDATE poradi = poradi_new$max = SELECT MAX(poradi)poradi = poradi + $max + 1 WHERE ... atd.Vše má svoje výhody i nevýhody, záleží i na počtu řádků v tabulce. Já používám variantu c)
@ras: a na základě čeho má být pořadí změněno? nepřijde mi nijak užitečné určovat ad hoc pořadí u 1000 záznamů. pokud se pořadí řídí podle nějakého parametru záznamu, možná by bylo lepší využít toho
Doma jsem našel kus kódu k řešení c)
$old = 999;
$new = 10;
try{
$db->begin();
$limits = $db->query('SELECT MAX(poradi) AS max, MIN(poradi) AS min FROM tab')->fetch();
$k = $limits->max - $limits->min + 1;
$old = min(max($old, $limits->min), $limits->max);
$new = min(max($new, $limits->min), $limits->max);
if ($old < $new) {
$db->query('UPDATE tab SET poradi = poradi + %i', $k, 'WHERE poradi > %i', $old, 'AND poradi <= %i', $new);
$db->query('UPDATE tab SET poradi = %i', $new, 'WHERE poradi = %i', $old);
$db->query('UPDATE tab SET poradi = poradi - %i - 1', $k, 'WHERE poradi > %i', ($old + $k), 'AND poradi <= %i', ($new + $k));
} else {
$db->query('UPDATE tab SET poradi = poradi + %i', $k, 'WHERE poradi < %i', $old, 'AND poradi >= %i', $new);
$db->query('UPDATE tab SET poradi = %i', $new, 'WHERE poradi = %i', $old);
$db->query('UPDATE tab SET poradi = poradi - %i + 1', $k, 'WHERE poradi < %i', ($old + $k), 'AND poradi >= %i', ($new + $k));
}
$db->commit();
} catch (Exception $e) {
$db->rollback();
throw $e;
}
Milo: Diky moc za zpusoby reseni … je to sice neco uplne jineho nez co jsem mel v planu, ale proc ne.
Kazdopadne muj puvodni plan bylo to provest nejak takto
$sql = "UPDATE XXX SET 'poradi' = 0 WHERE 'poradi' = 999";
<nejaky cyklus v PHP>
$sql .= "UPDATE XXX SET 'poradi' = 999 WHERE 'poradi' = 998";
$sql .= "UPDATE XXX SET 'poradi' = 998 WHERE 'poradi' = 997";
.
.
.
$sql .= "UPDATE XXX SET 'poradi' = 12 WHERE 'poradi' = 11";
$sql .= "UPDATE XXX SET 'poradi' = 11 WHERE 'poradi' = 10";
</nejaky cyklus v PHP>
$sql .= "UPDATE XXX SET 'poradi' = 10 WHERE 'poradi' = 0";
// V tuto chvili mam "kvanta" SQL prikazu v 1 promenne a zbyva udelat jeden hromadny EXECUTE()
$sql->execute();
Akorat neutisim, zda to, co je obsazeno v to cyklu, je mozne provest v DibiFluent, tj. jak tam naplnit tu promennou?
paranoiq: poradi je na libovuli uzivatele ;o), takze me jina cesta nenapada, nez menit ty kvanta zaznamu, resp. cesta by asi byla pres vytvoreni nejake vlastni logiky zapisu poradi, ale to se mi nechce resit ;o)
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.
Myslím, že to co jsem poslal bude rychlejší. Ale pokud to chceš dělat
UPDATE ....; UPDATE ....; UPDATE ....;, poskládat se to dá.
Jenže MySQL driver nepodporuje multiquery, takže to přes něj neproleze.
Můžeš si upravit MySQLi, psal
jsem tu jak cca na to. A další věcí je maximální délka SQL dotazu
(nevím jestli je u MySQL nějak omezená), protože pro 1000 řádků to bude
román. Takže bych to tak vůbec nedělal :)
$fluent = dibi::command();
for ($i = 10; $i > 0; $i--) {
$f = dibi::update('XXX', array('poradi' => $i))->where(array('poradi' => $i - 1));
$fluent->{''}((string) $f . ';');
}
$fluent->test();
Diky za info.
Ja to ted resim nad tabulkou o par radcich … takze vykon neni problem … ale umyslne jsem napsal tisic, protoze tam uz vykon je neco, co se musi resit. Tady u tech par radku je to fuk.
Jeste jednou diky.
Radek
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.
Rozhodně není dobré psát 1000 dotazů pro 1000 řádků, lepší je nastavit to pomocí intervalů.
Ty musíš změnit ty dva konrétní řádky, prohodit je, posunout je… A pak ty zbývající, pokud je potřeba je posouvat, posuneš pomocí
UPDATE xxx SET `order` = `order` + 1 /* nebo -1 */ WHERE `order` <= $x AND `order` > $y
Neptej se, jestli se můžeš ptát | Blog | Twitter | GitHub | CMS Kdyby
Nette Jabber Room – nette@conf.netlab.cz , všichni jste vítáni
Super, ja uplne vedel, ze neco je … ale fakt jsem to nedokazal vymyslet. ;o) To je tak, kdyz ma nekdo Filipa ;o)
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.
@HosipLan: Jenže on má na tom sloupci unikátní klíč.
Takže order = order + 1 nemusí proběhnout. Je vhodnější daný
interval přesunout nad maximum a pak zpět o jedno větší/menší. Viz. kód
k řešení c).
Milo …ja to jeste nezkousel → pak dam vedet, ale podle toho HosipLanova popisu bych rekl (logickym usudkem), ze to musi fungovat … az to vyzkousim, tak dam vedet.
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.
Takze vyzkouseno → a vysledek jsou 3 dotazy do DB bez ohledu na to, kolik radku se ma menit a UNIQUE index na danem sloupci … klidne to zvladne tech 1000 radku.
id / poradi / text 1 / 1 / aaa 2 / 2 / bbb 3 / 3 / ccc 4 / 4 / ddd 5 / 5 / eee
**Vzdy je nutne rozlisit, zda je novePoradi vetsi/mensi nez puvodniPoradi → podle toho se pak upravuje update
→ eee ma byt prvni → poradi 5 ⇒ 1
// zmenim docasne poradi u radku, ktery se ma primarne zmeni, tj. u poradi c. 5
UPDATE XXX SET `poradi` = 0 WHERE `poradi` = 5
// ted posuneme vsechny radky, kterych se pozadavek na zmenu poradi dotyka, tj. radky v intervalu <nova pozadovana hodnota> az <puvodni hodnota - 1>
// DULEZITE je zde provest to ORDER BY .. jinak by to narazilo na UNIQUE() index
UPDATE XXX SET `poradi` = `poradi` + 1 WHERE `poradi` >= 1 AND `poradi` < 5 ORDER BY poradi DESC;
// nastavime pro radek, ktereho se zmena primarne tyka novou, tj. pozadovanou, hodnotu
UPDATE XXX SET `poradi` = 1 WHERE `poradi` = 0
a ted ukazka opacneho postupu
v navaznosti na predchozi pozadavk → eee ma byt ve finale treti → poradi 1 ⇒ 3
// zmenim docasne poradi u radku, ktery se ma primarne zmeni, tj. u poradi c. 1
UPDATE XXX SET `poradi` = 0 WHERE `poradi` = 1
// ted posuneme vsechny radky, kterych se pozadavek na zmenu poradi dotyka, tj. radky v intervalu <puvodni hodnota +1> az <nova pozadovana hodnota>
// DULEZITE je zde provest to ORDER BY .. jinak by to narazilo na UNIQUE() index
UPDATE XXX SET `poradi` = `poradi` - 1 WHERE `poradi` > 1 AND `poradi` <= 3 ORDER BY poradi ASC;
// nastavime pro radek, ktereho se zmena primarne tyka novou, tj. pozadovanou, hodnotu
UPDATE XXX SET `poradi` = 1 WHERE `poradi` = 0
id / poradi / text 1 / 1 / aaa 2 / 2 / bbb 3 / 4 / ccc 4 / 5 / ddd 5 / 3 / eee
= 6 SQL dotazu → mene to myslim ani nejde
Diky vsem za pomoc → pokud nekdo ma v rukavu jeste neco efektivnejsiho, tak sem s tim ;o)
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.
Wow! Tak s tím ORDER BY u mě MySQL dost zabodovalo. To jsem
netušil. V tom případě HosipLanovo řešení je to
nejsnazší.
Editoval Milo (25. 11. 2011 12:07)
Ja taky ne, ale resil jsem, jak je donutit, aby mi to precislovavalo v poradi jak je potreba, jinak to porad narazelo na ten UNIQUE() index → tak jsem to zkusil ;O)
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.
ras napsal(a):
paranoiq: poradi je na libovuli uzivatele ;o), takze me jina cesta nenapada, nez menit ty kvanta zaznamu, resp. cesta by asi byla pres vytvoreni nejake vlastni logiky zapisu poradi, ale to se mi nechce resit ;o)
u 20–50 položek bych to ještě chápal. ale v 1000 už se ten chudák přeci musí sám ztrácet. tohle je případ, kdy bych já uživateli vysvětloval, že to co potřebuje asi není to co chce…
Ted jeste zkoumam jak to v DibiFluent zapsat
UPDATE XXX SET `poradi` = `poradi` + 1 WHERE `poradi` >= 1 AND `poradi` < 5 ORDER BY poradi DESC;
protoze kdyz napisu
$this->db->update($tabulka, array('poradi' => 'poradi + 1'))->/....
tak je vysledny SQL
UPDATE XXX SET 'poradi' = 'poradi + 1' WHERE ...
a ja potrebuji
UPDATE XXX SET 'poradi' = poradi + 1 WHERE ...
Nejaky navrh by byl, resp. jiny nez to resit pres dibi::query ci dibi::command?
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.
Už se tu několikrát řešilo…
$this->db->update($tabulka, array('poradi%sql' => '[poradi] + 1'))...
MILO Pres dibi::command jsem na to vcera prisel …
$this->db->command()->update($tabulka)->where("poradi >= %i", $novePoradi)->AND("poradi < %i", $puvodniPoradi)->orderBy("poradi")->desc()->set("poradi = poradi + 1")->execute();
… ale, protoze jsem vcera musel od PC, tak jsem se k procitani fora nedostal, takze diky za usetreny cas. Tvoje reseni se mi libi vice.
DIKY za vse v tomto vlaknu !
Shánění zakázek je pro mě jednodušší než samotná tvorba webů ⇒ hledám partnera především na dlouhodobou spolupráci.