Проверка на дубликаты уникальных идентификаторов
Материал из GedeminWiki
(Различия между версиями)
SYSDBA (обсуждение | вклад) |
SYSDBA (обсуждение | вклад) |
||
| Строка 77: | Строка 77: | ||
g_his_destroy(0); | g_his_destroy(0); | ||
END | END | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | Процедура выводит все ИД из базы данных в привязке к ИД таблицы: | ||
| + | |||
| + | <syntaxhighlight lang="SQL"> | ||
| + | CREATE OR ALTER PROCEDURE gd_p_find_dupl_id | ||
| + | RETURNS(id INTEGER, relationkey INTEGER) | ||
| + | AS | ||
| + | DECLARE VARIABLE rn VARCHAR(31); | ||
| + | DECLARE VARIABLE fn VARCHAR(31); | ||
| + | DECLARE VARIABLE rid INTEGER; | ||
| + | BEGIN | ||
| + | FOR | ||
| + | SELECT | ||
| + | rf.rdb$relation_name, atr.id, LIST(TRIM(rf.rdb$field_name)) | ||
| + | FROM | ||
| + | rdb$relation_fields rf | ||
| + | JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name | ||
| + | JOIN rdb$index_segments idxs ON idxs.rdb$field_name = rf.rdb$field_name | ||
| + | JOIN rdb$indices idx ON idx.rdb$index_name = idxs.rdb$index_name | ||
| + | JOIN rdb$relation_constraints rc ON rc.rdb$index_name = idx.rdb$index_name | ||
| + | AND rc.rdb$relation_name = rf.rdb$relation_name | ||
| + | JOIN at_relations atr ON atr.relationname = r.rdb$relation_name | ||
| + | WHERE | ||
| + | rc.rdb$constraint_type = 'PRIMARY KEY' | ||
| + | AND | ||
| + | rf.rdb$relation_name <> 'GD_RUID' | ||
| + | /* | ||
| + | |||
| + | Тут должно быть условие на таблицы, в которых не соблюдается | ||
| + | условие уникальности ИД. | ||
| + | |||
| + | */ | ||
| + | AND | ||
| + | r.rdb$system_flag = 0 | ||
| + | AND | ||
| + | COALESCE(r.rdb$relation_type, 0) = 0 | ||
| + | AND | ||
| + | NOT EXISTS( | ||
| + | SELECT * | ||
| + | FROM | ||
| + | rdb$index_segments idxs_fk | ||
| + | JOIN rdb$indices idx_fk ON idxs_fk.rdb$index_name = idx_fk.rdb$index_name | ||
| + | WHERE | ||
| + | idxs_fk.rdb$field_name = rf.rdb$field_name | ||
| + | AND | ||
| + | idx_fk.rdb$relation_name = rf.rdb$relation_name | ||
| + | AND | ||
| + | idx_fk.rdb$index_name <> idx.rdb$index_name | ||
| + | ) | ||
| + | GROUP BY | ||
| + | 1, 2 | ||
| + | HAVING | ||
| + | LIST(TRIM(rf.rdb$field_name)) = 'ID' | ||
| + | INTO | ||
| + | :rn, :rid, :fn | ||
| + | DO BEGIN | ||
| + | relationkey = :rid; | ||
| + | FOR | ||
| + | EXECUTE STATEMENT 'SELECT id FROM ' || :rn | ||
| + | INTO :id | ||
| + | DO | ||
| + | SUSPEND; | ||
| + | END | ||
| + | END | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | Используется для поиска дубликатов с помощью запроса: | ||
| + | |||
| + | <syntaxhighlight lang="SQL"> | ||
| + | select | ||
| + | id, list(relationkey), count(*) | ||
| + | from | ||
| + | gd_p_find_dupl_id | ||
| + | group by | ||
| + | 1 | ||
| + | having | ||
| + | count(*) > 1 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
[[Category:База данных]] | [[Category:База данных]] | ||
Текущая версия на 20:37, 22 декабря 2017
Идеология платформы требует чтобы у каждого бизнес-объекта был свой уникальный в пределах базы данных целочисленный идентификатор. Данное правило достигается с помощью использования единого генератора GD_G_UNIQUE. Однако, в результате программных сбоев могут возникнуть дубликаты ИД. Для их отыскания следует использовать запрос, приведенный ниже. Запрос выводит название таблицы и количество записей с ИД, встречающимся в других таблицах, в данной базе данных.
EXECUTE BLOCK RETURNS(tbl VARCHAR(31), cnt INTEGER) AS DECLARE VARIABLE rn VARCHAR(31); DECLARE VARIABLE fn VARCHAR(31); DECLARE VARIABLE id INTEGER; DECLARE VARIABLE s INTEGER; DECLARE VARIABLE c INTEGER; BEGIN IF (g_his_create(0, 0) = 0) THEN EXCEPTION gd_e_exception 'Can''t create huge array'; FOR SELECT rf.rdb$relation_name, LIST(TRIM(rf.rdb$field_name)) FROM rdb$relation_fields rf JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name JOIN rdb$index_segments idxs ON idxs.rdb$field_name = rf.rdb$field_name JOIN rdb$indices idx ON idx.rdb$index_name = idxs.rdb$index_name JOIN rdb$relation_constraints rc ON rc.rdb$index_name = idx.rdb$index_name AND rc.rdb$relation_name = rf.rdb$relation_name WHERE rc.rdb$constraint_type = 'PRIMARY KEY' AND rf.rdb$relation_name <> 'GD_RUID' /* Тут должно быть условие на таблицы, в которых не соблюдается условие уникальности ИД. */ AND r.rdb$system_flag = 0 AND COALESCE(r.rdb$relation_type, 0) = 0 AND NOT EXISTS( SELECT * FROM rdb$index_segments idxs_fk JOIN rdb$indices idx_fk ON idxs_fk.rdb$index_name = idx_fk.rdb$index_name WHERE idxs_fk.rdb$field_name = rf.rdb$field_name AND idx_fk.rdb$relation_name = rf.rdb$relation_name AND idx_fk.rdb$index_name <> idx.rdb$index_name ) GROUP BY 1 HAVING LIST(TRIM(rf.rdb$field_name)) = 'ID' INTO :rn, :fn DO BEGIN s = 0; c = 0; EXECUTE STATEMENT 'SELECT SUM(g_his_include(0, id)), COUNT(*) FROM ' || :rn || ' WHERE id > 147000000' INTO :s, :c; s = COALESCE(:s, 0); c = COALESCE(:c, 0); IF (:c <> :s) THEN BEGIN tbl = :rn; cnt = :c - :s; SUSPEND; END END g_his_destroy(0); END
Процедура выводит все ИД из базы данных в привязке к ИД таблицы:
CREATE OR ALTER PROCEDURE gd_p_find_dupl_id RETURNS(id INTEGER, relationkey INTEGER) AS DECLARE VARIABLE rn VARCHAR(31); DECLARE VARIABLE fn VARCHAR(31); DECLARE VARIABLE rid INTEGER; BEGIN FOR SELECT rf.rdb$relation_name, atr.id, LIST(TRIM(rf.rdb$field_name)) FROM rdb$relation_fields rf JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name JOIN rdb$index_segments idxs ON idxs.rdb$field_name = rf.rdb$field_name JOIN rdb$indices idx ON idx.rdb$index_name = idxs.rdb$index_name JOIN rdb$relation_constraints rc ON rc.rdb$index_name = idx.rdb$index_name AND rc.rdb$relation_name = rf.rdb$relation_name JOIN at_relations atr ON atr.relationname = r.rdb$relation_name WHERE rc.rdb$constraint_type = 'PRIMARY KEY' AND rf.rdb$relation_name <> 'GD_RUID' /* Тут должно быть условие на таблицы, в которых не соблюдается условие уникальности ИД. */ AND r.rdb$system_flag = 0 AND COALESCE(r.rdb$relation_type, 0) = 0 AND NOT EXISTS( SELECT * FROM rdb$index_segments idxs_fk JOIN rdb$indices idx_fk ON idxs_fk.rdb$index_name = idx_fk.rdb$index_name WHERE idxs_fk.rdb$field_name = rf.rdb$field_name AND idx_fk.rdb$relation_name = rf.rdb$relation_name AND idx_fk.rdb$index_name <> idx.rdb$index_name ) GROUP BY 1, 2 HAVING LIST(TRIM(rf.rdb$field_name)) = 'ID' INTO :rn, :rid, :fn DO BEGIN relationkey = :rid; FOR EXECUTE STATEMENT 'SELECT id FROM ' || :rn INTO :id DO SUSPEND; END END
Используется для поиска дубликатов с помощью запроса:
SELECT id, list(relationkey), COUNT(*) FROM gd_p_find_dupl_id GROUP BY 1 HAVING COUNT(*) > 1