Поиск дублированных документов в Interbase


Если документ организован по принципу “заголовок–строки” (мастер–деталь), то как найти в базе номер(а) документов, набор строк в которых в точности совпадает с заданным ?

Проблема возникла из следующей задачи: имеется база данных по компьютерам и их комплектующим. Пользователь в виртуальной таблице создает новую конфигурацию. Если такая конфигурация уже зарегистрирована в базе – необходимо найти ее номер, если нет – зарегистрировать новую конфигурацию. После длительных проб и ошибок я остановился на следующей структуре базы:

таблица наименований товаров (компьютеров и комплектующих):
CREATE TABLE WARES (

WARENUM INTEGER,
NAME VARCHAR(128),
...,
PRIMARY KEY(WARENUM));

состав компьютеров описывается таблицей:
CREATE TABLE WCONF (

WARENUM INTEGER, /* номер компьютера */
WAREREF INTEGER, /* номер комплектующего */
AMOUNT INTEGER,  /* количество */
PRIMARY KEY(WARENUM, WAREREF));

Для простоты на уровне триггеров было запрещено использовать в качестве комплектующего товар, который сам состоит из других комплектующих, а структура PK таблицы WCONF запрещала указывать одну деталь в составе компьютера дважды.

Вероятно кто-то кинет в меня камень за циклическую связь между таблицами, но на том этапе она мне казалась удачной идеей, т.к. комплектующие и готовые компьютеры на складе выглядели совершенно одинаково.

Проблем с формированием виртуальной таблицы и вставкой новой конфигурации в БД не возникало, оставалась только задача поиска: не перебирать же всю базу! Решение в конце концов было найдено: в таблицу WARES было добавлено поле NITEMS INTEGER, в котором указывалось количество комплектующих в компьютере. Далее, по указанным пользователем комплектующим строился запрос:

select c.WareNum, Count(*) from wconf c, wares w
where (w.WareNum=c.WareNum and w.NItems=?NItems)
    and (%S1)
group by c.WareNum
having count(*)=?NItems

где ?Nitems = количество комплектующих в конфигурации, указанной пользователем, а %S1 – строка вида

(c.WareRef=?N1 and c.Amount=?A1) or (c.WareRef=?N2 and c.Amount=?A2) or ...
где (Ni, Ai – номер детали и ее количество соответственно)

Смысл во всем этом следующий. Допустим, пользователь указал 3 детали (количество для простоты опустим), назовем их A, B, C. Среди товаров, состоящих ровно из трех комплектующих, в WCONF ищутся строки, содержащие номера A, B или C и пересчитывается их количество для каждого из компьютеров. Теперь внимание: результат подсчета будет равен 3 только в том случае, если в состав компьютера входят все 3 детали. Т.е. получается, что мы нашли компьютер, в который входят A, B и C, и в котором ровно 3 детали – а это то, что нам нужно!


P.S. Позднее мне пришла в голову еще одна идея: собрать все номера + количества комплектующих в одну длинную строку (типа 2х18/1х231/...), сделать для нее hash (например, MD5) и хранить его в заголовке документа, тогда с хорошей вероятностью по этому hash-коду можно будет найти нужный товар. Но это уже совсем другой метод... :-)

(c) Konstantin Beliaev, 2001

Comments