|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Есть 2 таблицы (очень упрощенные): catalogs - каталог вещей и catalog_volume - сборник каталогов. В catalogs - данные по разным категорям (книги, видео, аудио, машины и т.д.). Вот код создания таблиц с данными на SQLite : Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74.
Помощь нужна в следующем: Нужно написать триггер, который, при удалении в таблице catalogs записей с p arent_id=NULL (корни деревьев), определял всех потомков этих корней (атрибуты catalog_id ) и в таблице catalog_volume в ЭТИХ ЖЕ атрибутах catalog_id ставил значение - 1 (т.е. таких вещей в каталоге больше нет). Я написал триггер, но что-то он не срабатывает. Подозреваю, что код не срабатывает где-то в условии WHERE catalog_volume.catalog_id = ( Код фрагмента SELECT root_children.catalog_id FROM ( работает корректно - проверял в простом SQL запросе, заменив OLD на catalogs , а в строку WHERE catalogs.catalog_id = OLD.catalog_id немного изменяем на WHERE catalogs.catalog_id = 1 (для примера удаляем 1-ю запись корня дерева). Вот проверочный код: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
Подскажите, пожалуйста, где я недоделал код триггера? В чем ошибка? Благодарен за любые наводки и советы. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.08.2012, 12:22 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Полная каша... Смотрим текст триггера, видим: Код: sql 1. 2. 3. 4. 5.
1. Если обновляем набор потомков, то нужно не "=", а "in", ИМХО. 2. OLD.* - это набор удаляемых строк (только их!), с вполне конкретными значениями. Потомки в него не входят. "SELECT OLD.catalog_id FROM catalogs" - это мы что и где ищем? Если поставить опцию "FOR EACH ROW", то в запросе это будет одна строка с конретным набором значений полей. Найти ее потомков - можно без вложенного SELECT'а: Код: sql 1. 2. 3.
Маска '_%' исключает саму удаляемую запись, что нужно, поскольку триггер '_bd' (запись в catalog_volume, соответствующую удаляемой из catalogs, логично удалять, но это - по вкусу). 3. Отсутсвует проверка то, что удаляемый элемент - корневой. Ее нужно просто сделать. Ну, и в довесок: сомнительна необходимость появления в таблице catalog_volume группы записей (some_catalog_volume_id, -1). Я бы просто удалял. А обновление поля "path_id TEXT" - судя по всему, в другом триггере? ... |
|||
:
Нравится:
Не нравится:
|
|||
09.08.2012, 14:45 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Serg_GapПолная каша... Согласен. Это - моя первая попытка использования триггеров (раньше как-то без них обходился, потом понял, что легче написать триггер, чем программировать на С++ логику обработки строк. Хотя, как оказалось, последнее для меня было легче, чем понять принципы работы CASE, WHEN и т.д., применительно к группе записей в триггере :) ). Поэтому и нуждаюсь в помощи. Serg_Gap Ну, и в довесок: сомнительна необходимость появления в таблице catalog_volume группы записей (some_catalog_volume_id, -1). Я бы просто удалял. Как я писал выше - код - очень урезанный кусок базы. В приводимом коде не все поля включены в таблицы (для простоты). Поэтому мне нужно, чтобы, при удалении строк в catalogs, строки в catalog_volume оставались, только catalog_id становился равным -1. Serg_GapА обновление поля "path_id TEXT" - судя по всему, в другом триггере? Именно так :) Где-то в сети увидел пример триггера по обработке деревьев в базе (есть же талантливые головы) - понял, что много терял, игнорируя триггеры. Адаптировал тот код под свои нужды, в смысле - обновления поля "path_id TEXT" - очень удобно - не надо на С++ делать массу проверок.. Serg_Gap , не могли бы вы написать пример триггера для моего случая? Если не сложно. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.08.2012, 16:06 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Уточнение: идея работы . 1. В таблице catalogs удаляем запись, у которой parent_id. Все ее потомки удаляются автоматом за счет " parent_id INTEGER REFERENCES catalogs (catalog_id) ON DELETE CASCADE ON UPDATE CASCAD ". Вместе с "корнем" удалятся и его потомками - 12 записей (из приведенного примера). В таблице catalog_volume только для этих 12-ти атрибутов catalog_id нужно задать значение -1. 2. Если удаляется не корень, а како-то его потомок, то удаляется и он, и его потомки, например 5 записей. Опять же - за счет " parent_id INTEGER REFERENCES catalogs (catalog_id) ON DELETE CASCADE ON UPDATE CASCAD ". В таблице catalog_volume только для этих 5-ти атрибутов catalog_id нужно задать значение -1. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.08.2012, 16:19 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Опечатался, а правки - нет. Заново напишу исправленный текст. Уточнение: идея работы. 1. В таблице catalogs удаляем запись, у которой parent_id = NULL . Все ее потомки удаляются автоматом за счет " parent_id INTEGER REFERENCES catalogs (catalog_id) ON DELETE CASCADE ON UPDATE CASCAD ". Вместе с "корнем" удалятся и его потомками - 12 записей (из приведенного примера). В таблице catalog_volume только для этих 12-ти атрибутов catalog_id нужно задать значение -1. 2. Если удаляется не корень, а какой-то его потомок (у которой parent_id != NULL .) , то удаляется и он, и его потомки, например 5 записей. Опять же - за счет " parent_id INTEGER REFERENCES catalogs (catalog_id) ON DELETE CASCADE ON UPDATE CASCAD ". В таблице catalog_volume только для этих 5-ти атрибутов catalog_id нужно задать значение -1. Я 2-ю задачу вынес у себя в отдельный триггер - все прекрасно работает. Застопорился на 1-й задаче. Если можете, помогите написать триггер, выполняющий только 1-ю задачу. Если же поможете написать триггер, объединяющий обе эти 2 задачи в одну - буду очень вам признателен. Спасибо. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.08.2012, 16:26 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
kvesda Serg_Gap , не могли бы вы написать пример триггера для моего случая? Если не сложно. Не сложно, и не лень. Но все уже описано, только ручками - собрать в одно и вставить... Не в насмешку, - это просто полезно сделать самомУ; будет дальше легче жить. Единственная поправка - для не-корневого элемента маска будет не '_%', а '%' (см.описание масок). А проверка - в формулировке триггера (я в SQLite - новичок, и другой возможности для проверки не нашел). Я создал 2 триггера, оба - с условием WHEN (инструмент SQLite Expert Personal 3.4.21.2243; при создании триггера в нижней части "шапки", в последнам выпадающем списке можно его выбрать): Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
Работает, проверял. Хотя в другом триггере - получилось сделать ветвление внутри триггера: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.
(при необходимости - и строку "else" можно добавить). Пробовал добавить вместо RAISE запрос на update ... , но получал каждый раз ошибку (хоть в кавычки брал запрос, хоть писал без них). Но на этот счет - вопросы к специалистам более грамотным и опытным, чем я. Удачи. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.08.2012, 17:39 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
kvesda, а без триггеров не пробовали ? Код: sql 1. 2. 3. 4. 5.
... |
|||
:
Нравится:
Не нравится:
|
|||
10.08.2012, 01:33 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Serg_Gap , Спасибо за помощь. Я тоже - новичок в SQLite :) . Ранее использовал MySQL - многого не хватает оттуда в SQLite. Ну и триггеры никогда не использовал. С другой стороны, мне легче учиться на готовых примерах... ... |
|||
:
Нравится:
Не нравится:
|
|||
10.08.2012, 08:08 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Stupid_BOTkvesda, а без триггеров не пробовали ? Код: sql 1. 2. 3. 4. 5.
Такая идея не приходила в голову :). Спасибо, попробую и этот вариант. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.08.2012, 08:10 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Stupid_BOT , Идея "ON DELETE SET DEFAULT" привлекательная, но здесь возникает проблема: Для моих таблиц (catalog_volume сделана по вашему коду): Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
боюсь, такая идея не пройдет. Мне надо удалять строки в catalogs. Но из-за FOREIGN KEY(catalog_id) REFERENCES catalogs(catalog_id) ON DELETE SET DEFAULT ON UPDATE CASCADE удаление невозможно - ограничения FOREIGN KEY. Удалять строки можно в catalog_volume, но это как раз мне и не надо :). Я поэтому и не задавал связь FK от catalog_volume к catalogs. Возможно я что-то упускаю. Подскажите, пожалуйста, в таком случае. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.08.2012, 08:47 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
Все гениальное - просто! ( (с) не помню кто ) Сделал все-таки триггер, который работает даже лучше, чем первоначально планировал: Если удаляется корень дерева в catalog, то все записи в catalog_volume, соответствующие этому корню и его потомкам в атрибуте catalog_id получают значение -1 (данного вида каталога - нет). Если же удаляется не корень, а какой-то его потомок, то все записи в catalog_volume, соответствующие этому потомку и его потомкам получают значение вышестоящего узла (parent_id из catalog) - т.е. все книги, или видео, или аудио и т.д. для удаляемого узла "переносятся" на вышестоящий узел. Вот полный код тестовой базы (но главное - триггер ): Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64.
Например, удаляем в catalogs узел /Книги/Программирование/ Все нижестоящие ветки-потомки удаляются каскадно. А в catalog_volume все записи этих удаленных ветвей в атрибуте catalog_id принимают значение 1 - эти книги "перенеслись" в категорию /Книги/ Так даже универсальней получилось. Спасибо всем, кто откликнулся... ... |
|||
:
Нравится:
Не нравится:
|
|||
10.08.2012, 09:54 |
|
Не срабатывает триггер, как должен (где-то ошибка)
|
|||
---|---|---|---|
#18+
> kvesda, > удаление невозможно - ограничения FOREIGN KEY. Возможно. Если добавить в catalogs запись с catalog_id = -1. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.08.2012, 20:09 |
|
|
start [/forum/topic.php?fid=54&fpage=18&tid=2008994]: |
0ms |
get settings: |
10ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
24ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
54ms |
get tp. blocked users: |
2ms |
others: | 16ms |
total: | 142ms |
0 / 0 |