| 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: 11 let
|
|||
0