Autor | Zpráva | ||
---|---|---|---|
qteck Profil |
#1 · Zasláno: 30. 5. 2015, 12:10:53
Ahoj,
mám tři tabulky article, tags a ref.tags přidám článek, vyfiltruju tagy, a pak přidávám tag a hned za ním referenci jeden po jednom dokud tam nejsou všechny. probém nastane když vkládám dva nebo více stejných tagů. v tabulce tags je na jednom sloupci (name) nastavený unique key. pracouje to celé nazávislosti z last insert id a tak když vložim duplicitu a unique key to potlačí, dostanu prostě jenom ten nejvyšší id z tags kterej není správný. Následně se mi do ref.tags uloží odkaz na článek s odkazem na tag který neexistuje. Řešením by bylo odebrat unique key to by ale zpomalilo celej systém a zkrátka se to nehodí. Jak toto vyřešit? Možná nějaký trigger? Pro zpracování používám takový kód: $tags = array('boobs','blueberries','food','boobs') function hashTagInsert($tags) { /// commit this as a transaction $lastInsertId = $this->db->lastId(); // last insert id of article foreach ($tags as $val) { $sql = 'INSERT INTO tags (tag, added) VALUES (:tag, NOW()) ON DUPLICATE KEY UPDATE occurrence = occurrence + 1'; $this->db->boolQuery($sql, array(':tag' => $val)); $sql2 = 'INSERT INTO tags_refs (article_id, tag_id) VALUES (:lastInsertId, LAST_INSERT_ID())'; $this->db->boolQuery($sql2, array(':lastInsertId' => $lastInsertId)); } } a po tomto dostanu v db toto: CREATE TABLE `tags` ( `id` int(11) NOT NULL AUTO_INCREMENT, `tag` varchar(100) NOT NULL, `occurrence` int(11) NOT NULL, `added` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `tag` (`tag`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `tags` (`id`, `tag`, `occurrence`, `added`) VALUES (18, 'boobs', 1, '2015-05-29 16:46:44'), (20, 'food', 0, '2015-05-29 16:46:44'), (19, 'blueberries', 0, '2015-05-29 16:46:44'); and the reference one: CREATE TABLE `tags_refs` ( `id` int(11) NOT NULL AUTO_INCREMENT, `article_id` int(11) NOT NULL, `tag_id` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `tags_refs` (`id`, `article_id`, `tag_id`) VALUES (24, 31, 18), (25, 31, 19), (26, 31, 20), (27, 31, 26); -- 2015-05-29 14:49:55 |
||
yFang Profil |
#2 · Zasláno: 30. 5. 2015, 12:26:14
qteck:
Nepomohlo by použít před uložením na pole těch tagů array_unique? |
||
Alphard Profil |
Doporučoval bych trochu předělat tu strukturu. Nesnažil bych se nové tagy automaticky vkládat (protože očekávám, že k jednomu tagu bude existovat mnoho článků), ale zkusil bych je prvně najít a teprve když se nenajde, vložit nový. Tohle by bylo v samostatné funkci, která by vracela id správného tagu, řekněme
function getTagId($tag) { if ($dbTag = $db->select($tag)) { return $dbTag->id; } else { $db->insert($tag); return $db->last_id } } Tohle celé by možná šlo řešit na úrovní db nastavením vrácení správného id při updatu, ale návrhově mi tam ten on duplicate key nesedí. yFang [#2]: V tomto ukázkovém případě ano, ale obecně ne (tagy se sdílejí mezi články). Doplňuji, že z pohledu konkurenčního přístupu by dávalo smysl prvně zkusit provést insert na tabulku s unikátním klíčem a teprve při selhání kvůli duplicitě hledat starší záznam. Výše popsaný postup je myslím srozumitelnější na vysvětlení, jako oprava stačí prohodit if a else větev v navržené funkci.
|
||
qteck Profil |
ale jo to byi dávalo smysl kdyby šlo vyloženě o to jedno pole. článků muže být vloženo více a paki když to pole s tagama nemá duplicity v databázi na ty duplicity narazit můžea pak se zase odehraje scénář který jsem popsal výše.
klíčem bybylo zjistit pokud je v db duplicita jaké řádky byly změněny. Teď si nejsem jistej, ale napadlo mě, že byse možná dal použít affected rows ----- affacted rows vrací jenom počet ovlivněných řádků, žádné další detaily. :( Alphard: moje představa je taková, že někdo napíše článek a pod něj pak napíše jenom tagy #tag1 #tag2 #tag3 a nebo přímo někde v toku textu toho článku. Já je z toho vytáhnu a pak uložím do db. Ty k teré neexistují vložím a ty které existují v db zvýrazním připočtením occurrence + 1 abych je potom mohl řadit podle četnosti. Chtěl jsemse vyhnout jakémukoliv testování v phpku bo se trochu obávám rychlosti, pravděpodobně to ale udělám jakříkáš, něják mi došli inspirace :-). |
||
qteck Profil |
#5 · Zasláno: 30. 5. 2015, 13:38:30
Pro tentokrát vyřešeno takto:
function hashTagInsert($tags) { /// commit this as a transaction $lastInsertId = $this->db->lastId(); foreach ($tags as $val) { $sql = 'INSERT INTO tags (tag, added) VALUES (:tag, NOW()) ON DUPLICATE KEY UPDATE occurrence = occurrence + 1, last_article_id = :lastInsertId'; $stmt = $this->db->boolQuery($sql, array(':tag' => $val, ':lastInsertId' => $lastInsertId)); if(!$stmt) { $sql3 = 'SELECT id FROM tags WHERE tag = :tag'; $existingTagId = $this->db->queryFetch($sql3, array(':tag' => $val)); } $tagId = (isset($existingTagId)? $existingTagId : $this->db->lastId()); $sql2 = 'INSERT INTO tags_refs (article_id, tag_id) VALUES (:lastInsertId, :tagId)'; $this->db->boolQuery($sql2, array(':lastInsertId' => $lastInsertId, ':tagId' => $tagId)); unset($existingTagId); } } |
||
Alphard Profil |
#6 · Zasláno: 30. 5. 2015, 14:05:16
Můj návrh je přiměřeně efektivní, přidávání článků není tak časté, aby bylo třeba to řešit. Navíc často má přehlednost kódů přednost; ta vaše podmínka založená na testování existence proměnné vytvořené v podmínce není vůbec hezká.
„a ty které existují v db zvýrazním připočtením occurrence + 1“ Tohle je podle mě zbytečná denormalizace, už jste řešil update článku? Počet použití tagu lze snadno spočítat z tabulky tags_refs .
|
||
Časová prodleva: 9 let
|
0