Поиск повторяющихся идентификаторов
Материал из GedeminWiki
Идеология платформы Гедымин требует уникальности идентификаторов объектов в пределах файла базы данных. Дублирующиеся идентификаторы являются следствием физического повреждения базы данных или логических сбоев в программном обеспечении.
Поиск дубликатов с использованием временной таблицы
Для поиска дубликатов создадим временную таблицу TEMP:
CREATE TABLE temp ( id dintkey, relid dintkey )
Заполним ее:
EXECUTE BLOCK AS DECLARE VARIABLE RN CHAR(31); DECLARE VARIABLE RID INTEGER; BEGIN FOR SELECT DISTINCT r.rdb$relation_name, r.rdb$relation_id FROM rdb$relation_fields rf JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name LEFT JOIN ( SELECT relc.rdb$relation_name FROM rdb$relation_constraints relc JOIN rdb$ref_constraints refc ON refc.rdb$constraint_name = relc.rdb$constraint_name JOIN rdb$index_segments iseg ON iseg.rdb$index_name = relc.rdb$index_name AND iseg.rdb$field_name = 'ID' ) constr ON constr.rdb$relation_name = r.rdb$relation_name WHERE rf.rdb$field_name = 'ID' AND r.rdb$relation_name <> 'TEMP' AND r.rdb$relation_name <> 'GD_RUID' AND r.rdb$view_source IS NULL AND constr.rdb$relation_name IS NULL INTO :RN, :RID DO BEGIN EXECUTE STATEMENT 'INSERT INTO TEMP (id, relid) ' || ' SELECT id, ' || :RID || ' FROM ' || :RN || ' WHERE id > 32 ' WITH AUTONOMOUS TRANSACTION; END END
Теперь, получить список ИД, встречающихся более одного раза можно так:
SELECT t.id, COUNT(t.id), list(TRIM(r.rdb$relation_name)) FROM temp t JOIN rdb$relations r ON t.relid = r.rdb$relation_id GROUP BY t.id HAVING COUNT(t.id) > 1
Поиск дубликатов с использованием битовых массивов
На сервере должна быть установлена библиотека GUDF.DLL. Используются два битовых массива. База данных сканируется дважды. На первом проходе, первый массив заполняется всеми ИД из БД, второй -- только повторяющимися. На втором проходе выводится список повторяющихся ИД с именами таблиц.
EXECUTE BLOCK RETURNS(ID INTEGER, RN CHAR(31)) AS DECLARE VARIABLE DUMB INTEGER; BEGIN g_his_create(0, 0); g_his_create(1, 0); FOR SELECT DISTINCT r.rdb$relation_name FROM rdb$relation_fields rf JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name LEFT JOIN ( SELECT relc.rdb$relation_name FROM rdb$relation_constraints relc JOIN rdb$ref_constraints refc ON refc.rdb$constraint_name = relc.rdb$constraint_name JOIN rdb$index_segments iseg ON iseg.rdb$index_name = relc.rdb$index_name AND iseg.rdb$field_name = 'ID' ) constr ON constr.rdb$relation_name = r.rdb$relation_name WHERE rf.rdb$field_name = 'ID' AND r.rdb$relation_name <> 'TEMP' AND r.rdb$relation_name <> 'GD_RUID' AND r.rdb$view_source IS NULL AND constr.rdb$relation_name IS NULL INTO :RN DO BEGIN EXECUTE STATEMENT 'SELECT SUM(g_his_include(1, id)) ' || ' FROM ' || :RN || ' WHERE g_his_has(0, id) <> 0 ' INTO :DUMB; EXECUTE STATEMENT 'SELECT SUM(g_his_include(0, id)) ' || ' FROM ' || :RN INTO :DUMB; END FOR SELECT DISTINCT r.rdb$relation_name FROM rdb$relation_fields rf JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name LEFT JOIN ( SELECT relc.rdb$relation_name FROM rdb$relation_constraints relc JOIN rdb$ref_constraints refc ON refc.rdb$constraint_name = relc.rdb$constraint_name JOIN rdb$index_segments iseg ON iseg.rdb$index_name = relc.rdb$index_name AND iseg.rdb$field_name = 'ID' ) constr ON constr.rdb$relation_name = r.rdb$relation_name WHERE rf.rdb$field_name = 'ID' AND r.rdb$relation_name <> 'TEMP' AND r.rdb$relation_name <> 'GD_RUID' AND r.rdb$view_source IS NULL AND constr.rdb$relation_name IS NULL INTO :RN DO BEGIN FOR EXECUTE STATEMENT 'SELECT id ' || ' FROM ' || :RN || ' WHERE g_his_has(1, id) <> 0 ' INTO :id DO BEGIN SUSPEND; END END g_his_destroy(0); g_his_destroy(1); END