WITH RECURSIVE ns_tree AS ( SELECT f.filename, CAST((f.xid || '_' || f.dbid) AS VARCHAR(1024)) AS path, l2.uses_xid, l2.uses_dbid FROM at_namespace_file f JOIN at_namespace_file_link l ON l.uses_xid = f.xid AND l.uses_dbid = f.dbid LEFT JOIN at_namespace_file_link l2 ON l2.filename = f.filename WHERE l.filename = :filename UNION ALL SELECT f.filename, (t.path || '-' || f.xid || '_' || f.dbid) AS path, l.uses_xid, l.uses_dbid FROM ns_tree t JOIN at_namespace_file f ON t.uses_xid = f.xid AND t.uses_dbid = f.dbid JOIN at_namespace_file_link l ON l.filename = f.filename WHERE POSITION ((f.xid || '_' || f.dbid) IN t.path) = 0) SELECT t.filename FROM ns_tree t UNION SELECT f.filename FROM ns_tree t JOIN at_namespace_file f ON f.xid = t.uses_xid AND f.dbid = t.uses_dbid LEFT JOIN at_namespace_file_link l ON l.filename = f.filename WHERE l.filename IS NULL
28 сент. 2013 г.
Неприятное ограничение рекурсивных CTE
Простейший способ заехать в дурдом -- это отладка рекурсивных запросов в уме. В предыдущем примере у нас закралась ошибка. Объекты, которые ни от кого не зависят, не попадут в итоговую выборку. Но, только в том случае, если глубина уровня их вложенности больше единицы. Всему виной JOIN at_namespace_file_link l ON l.filename = f.filename во второй части CTE. По логике вещей, тут должен быть LEFT JOIN, но рекурсивное CTE внутри себя не может участвовать во внешних объединениях. C'est la vie. И никакой возможности разрулить данную ситуацию внутри самого CTE не просматривается. Остается городить огород с объединением двух выборок.
14 сент. 2013 г.
Список объектов в соответствии с заданными зависимостями
Если в предыдущем примере мы ранжировали заданный список объектов, то следующий пример возвращает упорядоченный в соответствии с иерархией зависимости список объектов, от которых зависит указанный объект.
WITH RECURSIVE ns_tree AS ( SELECT f.filename, CAST((f.xid || '_' || f.dbid) AS VARCHAR(1024)) AS path, l2.uses_xid, l2.uses_dbid FROM at_namespace_file f JOIN at_namespace_file_link l ON l.uses_xid = f.xid AND l.uses_dbid = f.dbid LEFT JOIN at_namespace_file_link l2 ON l2.filename = f.filename WHERE l.filename = :filename UNION ALL SELECT f.filename, (t.path || '-' || f.xid || '_' || f.dbid) AS path, l.uses_xid, l.uses_dbid FROM ns_tree t JOIN at_namespace_file f ON t.uses_xid = f.xid AND t.uses_dbid = f.dbid JOIN at_namespace_file_link l ON l.filename = f.filename WHERE POSITION ((f.xid || '_' || f.dbid) IN t.path) = 0) SELECT * FROM ns_treeТаблица at_namespace_file содержит список объектов, а at_namespace_file_link -- связи между ними. Вычисление пути (path) и дополнительная проверка через функцию POSITION позволяют избежать зацикливания на кольцевых ссылках, если такие попадутся в исходных данных.
Labels:
SQL
7 сент. 2013 г.
Firebird 2013 Tour
Firebird Project is glad to announce Firebird 2013 Tour – series of seminars around the world, devoted to Firebird, with members of Firebird Project as speakers. The first seminar will be in Siegburg (North Rhine-Westphalia, Germany), November 22, 2013.
Labels:
Firebird
2 сент. 2013 г.
Удаление гланд автогеном...
Таблицу со строковым первичным ключем подключить к визуальным контролам Гедымина нельзя, так как все они поголовно спроектированы для работы с целочисленными идентификаторами. Выход -- добавить вычисляемую колонку в запрос, которую заполнять хэшем от строкового значения. Встроенная функция Firebird HASH() возвращает 64-х битное целое (тип BIGINT), которое следует сдвигать вправо, пока значение не войдет в допустимый для 32-х битных целых диапазон.
В следующем примере мы генерируем ключи типа INTEGER по наименованиям контактов (что не совсем корректно, так как сами наименования у нас могут быть неуникальными).
select cast(iif(log(2, hash(name)) > 30, bin_shr(hash(name), cast(log(2, hash(name)) as integer) - 30), hash(name)) as integer), name from gd_contactВ некоторых случаях может подойти и заполнение колонки последовательными значениями генератора:
select gen_id(my_gen, 1), name from gd_contact
Labels:
SQL
1 сент. 2013 г.
Построение списка зависимых объектов
Замечательная задача для проверки программиста на знание SQL и реляционных БД. Пусть в одной таблице хранится список объектов. Объекты могут зависеть друг от друга. Связи хранятся в другой таблице ввиде пар ключей: объект - объект, от которого зависит данный объект. Требуется построить упорядоченный список, чтобы для любого объекта в нем, все объекты, от которых он зависит, располагались перед ним.
Решение с использованием рекурсивного CTE:
WITH RECURSIVE ns_tree AS ( SELECT n.filename AS headname, 0 AS usescount, CAST((n.xid || '_' || n.dbid) AS VARCHAR(1024)) AS path, n.filename FROM at_namespace_file n UNION ALL SELECT t.headname, (t.usescount + 1) AS usescount, (t.path || '-' || n.xid || '_' || n.dbid) AS path, n.filename FROM ns_tree t JOIN at_namespace_file_link l ON l.filename = t.filename JOIN at_namespace_file n ON l.uses_xid = n.xid and l.uses_dbid = n.dbid WHERE POSITION ((n.xid || '_' || n.dbid) IN t.path) = 0 ) SELECT t.headname, sum(t.usescount) FROM ns_tree t GROUP BY 1 ORDER BY 2В приведенном запросе at_namespace -- список объектов, а at_namespace_link -- связи между ними. Вычисление пути (path) и дополнительная проверка через функцию POSITION позволяют избежать зацикливания на кольцевых ссылках, если такие попадутся в исходных данных.
Labels:
исходный код,
программирование,
школа,
SQL
Предупрежден -- значит вооружен!
Контроллеры Marvell 88SE91xx и HDD > 2.2TB (3TB, 4TB).
Labels:
цікава
Подписаться на:
Сообщения (Atom)