Поиск повторяющихся идентификаторов
Материал из GedeminWiki
(Различия между версиями)
SYSDBA (обсуждение | вклад) |
SYSDBA (обсуждение | вклад) (→Поиск дубликатов с использованием битовых массивов) |
||
| Строка 68: | Строка 68: | ||
===Поиск дубликатов с использованием битовых массивов=== | ===Поиск дубликатов с использованием битовых массивов=== | ||
| − | На сервере должна быть установлена библиотека GUDF.DLL. | + | На сервере должна быть установлена библиотека GUDF.DLL. Используются два битовых массива. База данных сканируется дважды. На первом проходе, первый массив заполняется всеми ИД из БД, второй -- только повторяющимися. На втором проходе выводится список повторяющихся ИД с именами таблиц. |
<syntaxhighlight lang="SQL"> | <syntaxhighlight lang="SQL"> | ||
| Строка 75: | Строка 75: | ||
AS | AS | ||
BEGIN | BEGIN | ||
| − | g_his_create(0); | + | g_his_create(0, 0); |
| − | g_his_create(1); | + | g_his_create(1, 0); |
FOR | FOR | ||
Версия 20:32, 24 июля 2014
Идеология платформы Гедымин требует уникальности идентификаторов объектов в пределах файла базы данных. Дублирующиеся идентификаторы являются следствием физического повреждения базы данных или логических сбоев в программном обеспечении.
Поиск дубликатов с использованием временной таблицы
Для поиска дубликатов создадим временную таблицу 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 DINTKEY, RN CHAR(31)) AS 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 '; EXECUTE STATEMENT 'SELECT SUM(g_his_include(0, id)) ' || ' FROM ' || :RN; 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