Как я могу узнать, какие строки были удалены? - PullRequest
1 голос
/ 30 марта 2011

Informix-SQL 7.32 с механизмом SE:

У меня есть клиент, который удалил несколько строк из таблицы SE.(Я не использую протоколирование транзакций или аудит).Таблица имеет последовательный столбец.Я хотел бы создать отчет Ace для печати отсутствующих серийных столбцов.Я попробовал следующий быстрый и грязный отчет, но он не сработал! .. Вы можете предложить лучший способ?

define
variable next_id integer
end

  select tbl_id 
    from tbl
order by tbl_id {I'm ordering tbl_id because all the rows are periodically re-clustered}
     end        {by an fk_id in order to group all rows belonging to the same customer}

format
on every row
let next_id = tbl_id + 1  

after group of tbl_id
if tbl_id + 1 <> next_id then
print column 1, tbl_id + 1 using "######"

end

или, возможно, создать временную таблицу со столбцом INT, содержащим последовательные числа от 1 до5000 и выполните оператор выбора, например:

   SELECT tbl_id 
     FROM tbl
    WHERE tbl_id NOT IN
                 (SELECT tmp_int
                    FROM tmp);

или оператор выбора с HAVING, OUTER и т. Д.

Ответы [ 2 ]

1 голос
/ 31 марта 2011

Поскольку это SE, мы должны использовать старомодные нотации, а не нотации SQL-92 JOIN.

Четыре следующих запроса являются общей основой для двух возможных ответов:

SELECT t1.tbl_id AS tbl_id, t2.tbl_id AS ind
  FROM tbl AS t1, OUTER tbl AS t2
 WHERE t1.tbl_id + 1 = t2.tbl_id
  INTO TEMP x1;

SELECT t1.tbl_id AS tbl_id, t2.tbl_id AS ind
  FROM tbl AS t1, OUTER tbl AS t2
 WHERE t1.tbl_id - 1 = t2.tbl_id
  INTO TEMP x2;

SELECT tbl_id AS hi_range
  FROM x1
 WHERE ind IS NULL
  INTO TEMP x3;

SELECT tbl_id AS lo_range
  FROM x2
 WHERE ind IS NULL
  INTO TEMP x4;

Таблицы x3 и x4 теперь содержат (соответственно) значения для tbl_id, которые не имеют непосредственного преемника и непосредственного предшественника.Каждое значение является началом или концом смежных диапазонов значений tbl_id.В IDS вместо SE вы можете использовать стандартную нотацию SQL OUTER JOIN и фильтровать результаты объединения в двух запросах вместо четырех;у вас нет такой роскоши в SE.

Нерешение с квадратичным (или хуже) поведением

Теперь вам просто нужно разобраться, как объединить две таблицы:

SELECT t1.lo_range, t2.hi_range
  FROM x4 AS t1, x3 AS t2
 WHERE t1.lo_range <= t2.hi_range
   AND NOT EXISTS
       (SELECT t3.lo_range, t4.hi_range
          FROM x4 AS t3, x3 AS t4
         WHERE t3.lo_range <= t4.hi_range
           AND t1.lo_range =  t3.lo_range
           AND t2.hi_range >  t4.hi_range
       );

Основная часть этого запроса выполняется дважды и генерирует все пары строк, в которых начало диапазона меньше или равно концу диапазона (равный учитывает «диапазоны», состоящие из одного значения самостоятельно,с удаленными рядами с обеих сторон).Предложение NOT EXISTS гарантирует отсутствие другой пары с таким же начальным значением и меньшим конечным значением.

Запросы к временным таблицам могут быть не очень быстрыми, если в данных много пробелов;если пропусков очень мало, они должны быть в порядке.

Последний запрос демонстрирует квадратичное поведение с точки зрения количества диапазонов.Когда у меня было всего дюжина диапазонов, это было нормально (время отклика менее секунды);когда у меня было 1200 диапазонов, это было не в порядке - не завершилось за разумное время.

Избегание квадратичного поведения

Поскольку квадратичное поведение не является хорошим, как мы можем перефразировать запрос ...

Для каждого нижнего конца диапазона найдите минимальный верхний предел диапазона, который больше или равен нижнему концу, или в SQL:

SELECT t1.lo_range, MIN(t2.hi_range) AS hi_range
  FROM x4 AS t1, x3 AS t2
 WHERE t2.hi_range >= t1.lo_range
 GROUP BY t1.lo_range;

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

Синхронизация

Это хорошо работает на таблице с 22100 строками, содержащими 1200 пробелов в данных.Использование (my) программы SQLCMD в режиме тестирования (-B) и отправка вывода SELECT в / dev / null, а также использование IDS 11.70.FC1 для MacOS X 10.6.7 (MacBook Pro, Intel Core 2 Duo на частоте 3 ГГц и4 ГБ ОЗУ), результаты были:

$ sqlcmd -d stores -B -f gaps.sql
+ CLOCK START;
2011-03-31 18:44:39
+ BEGIN;
Time: 0.000588
2011-03-31 18:44:39
+ SELECT t1.tbl_id AS tbl_id, t2.tbl_id AS ind
  FROM tbl AS t1, OUTER tbl AS t2
 WHERE t1.tbl_id + 1 = t2.tbl_id
  INTO TEMP x1;
Time: 0.437521
2011-03-31 18:44:39
+ SELECT t1.tbl_id AS tbl_id, t2.tbl_id AS ind
   FROM tbl AS t1, OUTER tbl AS t2
  WHERE t1.tbl_id - 1 = t2.tbl_id
   INTO TEMP x2;
Time: 0.315050
2011-03-31 18:44:39
+ SELECT tbl_id AS hi_range
  FROM x1
 WHERE ind IS NULL
  INTO TEMP x3;
Time: 0.012510
2011-03-31 18:44:39
+ SELECT tbl_id AS lo_range
  FROM x2
 WHERE ind IS NULL
  INTO TEMP x4;
Time: 0.008754
+ output "/dev/null";
2011-03-31 18:44:39
+ SELECT t1.lo_range, MIN(t2.hi_range) AS hi_range
  FROM x4 AS t1, x3 AS t2
 WHERE t2.hi_range >= t1.lo_range
 GROUP BY t1.lo_range;
Time: 0.561935
+ output "/dev/stdout";
2011-03-31 18:44:40
+ SELECT COUNT(*) FROM x1;
22100
Time: 0.001171
2011-03-31 18:44:40
+ SELECT COUNT(*) FROM x2;
22100
Time: 0.000685
2011-03-31 18:44:40
+ SELECT COUNT(*) FROM x3;
1200
Time: 0.000590
2011-03-31 18:44:40
+ SELECT COUNT(*) FROM x4;
1200
Time: 0.000768
2011-03-31 18:44:40
+ SELECT t1.lo_range, MIN(t2.hi_range) AS hi_range
  FROM x4 AS t1, x3 AS t2
 WHERE t2.hi_range >= t1.lo_range
 GROUP BY t1.lo_range
 INTO TEMP x5;
Time: 0.529420
2011-03-31 18:44:40
+ SELECT COUNT(*) FROM x5;
1200
Time: 0.001155
2011-03-31 18:44:40
+ ROLLBACK;
Time: 0.329379
+ CLOCK STOP;
Time: 2.202523
$ 

Будет делать;время обработки меньше пары секунд.

0 голосов
/ 31 марта 2011
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...