воскресенье, 28 августа 2016 г.

Настройка SSH на Linux

Для проверки, запущен у вас сервер SSH, нужно выполнить:

service sshd status

Если сервер запущен, то появится сообщение:

openssh-daemon (pid 3874) is running

Если серкер не установлен, то это можно сделать с помощью команды:

yum install openssh-server

Для подключения из iOS нужно выполнить следующую командy:

ssh user_name@host_name

или если нам нужно указать специфический потр, то пишем:

ssh -p 22 user_name@host_name

Иногда, нужно узнать, какие же порты открыты. Для этого устанавливаем NMAP:

yum nmap instal

После установки, запускаем следующую команду

nmap -sT -O localhost
которая выводит список открытых портов и кем они используются.

суббота, 30 июля 2016 г.

Запись образа Федоры на флешку

Я столкнулся с проблемой необходимости записи загрузочного образа Федоры на флешку.
Для этого я использовал следующее:

Сначала определил куда примонтирована флешка, с помощью команды:

fdisk -l

Это оказалось /dev/sdс, после этого, ввел следующую команду для записи образа:

dd if=Fedora_24.iso of=/dev/sdс bs=8M

где

Fedora_24.iso - имя образа в текущей папке

/dev/sdс - точка монтирования флешки.


четверг, 7 июля 2016 г.

Логирование работы программы

Следующий скрипт создает пакет и таблицы для записи логов.

Логи пишутся в двух режимах:
1. логи которые откатываются при откате транзакции
2. логи которые коммитятся в автономной транзакции и которые невозможно откатить.

DROP SEQUENCE seq_tbl_system_log
/
DROP SEQUENCE seq_tbl_log
/
DROP TABLE tbl_log
/
DROP TABLE tbl_system_log
/

CREATE SEQUENCE seq_tbl_system_log
/
CREATE TABLE tbl_system_log(
  id                 INTEGER CONSTRAINT pk_tbl_system_log PRIMARY KEY,
  name               VARCHAR2(30) NOT NULL CONSTRAINT un_tbl_system_log UNIQUE
)
/

CREATE SEQUENCE seq_tbl_log
/
CREATE TABLE tbl_log(
  id                 INTEGER CONSTRAINT pk_tbl_log PRIMARY KEY,
  system_log_id      INTEGER        NOT NULL,
  message            VARCHAR2(4000) NOT NULL,
  log_type_id        INTEGER        NOT NULL,
  ts                 TIMESTAMP DEFAULT SYSDATE NOT NULL,
  CONSTRAINT fk_tbl_log_tbl_system_log FOREIGN KEY (system_log_id) REFERENCES tbl_system_log (id)
)
/

CREATE OR REPLACE FORCE VIEW v_log
AS
SELECT tllg.id
     , tslg.name
     , tllg.message
     , DECODE(tllg.log_type_id, 1, 'INFO', 2, 'WARNING', 3, 'ERROR') log_type
     , tllg.ts
  FROM tbl_log tllg
       JOIN
       tbl_system_log tslg
         ON tllg.system_log_id = tslg.id
/
CREATE OR REPLACE PACKAGE pkg_log IS

PROCEDURE reg_system_log
  (p_name               IN VARCHAR2);

FUNCTION get_system_log_id
  (p_name               IN VARCHAR2)
 RETURN NUMBER;

PROCEDURE ins_log_info
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2);

PROCEDURE ins_log_info_autonomous
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2);

PROCEDURE ins_log_warning
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2);

PROCEDURE ins_log_warning_autonomous
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2);

PROCEDURE ins_log_error
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2);

PROCEDURE ins_log_error_autonomous
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2);

PROCEDURE del_log
  (p_id                 IN NUMBER);
PROCEDURE del_log_autonomous
  (p_id                 IN NUMBER);

END pkg_log;
/

CREATE OR REPLACE PACKAGE BODY pkg_log
IS
PROCEDURE reg_system_log
  (p_name               IN VARCHAR2)
IS
BEGIN
  INSERT INTO tbl_system_log
    (id,
     name)
  VALUES(
   seq_tbl_system_log.NEXTVAL,
   p_name);
END;

FUNCTION get_system_log_id
  (p_name               IN VARCHAR2)
 RETURN NUMBER
IS
  l_id NUMBER;
BEGIN
  SELECT id
    INTO l_id
    FROM tbl_system_log
   WHERE name = p_name;

  RETURN l_id;
END;

PROCEDURE ins_log
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2,
   p_log_type_id        IN NUMBER)
IS
BEGIN
  INSERT INTO tbl_log
    (id,
     system_log_id,
     message,
     log_type_id)
  VALUES(
     seq_tbl_log.NEXTVAL,
     p_system_log_id,
     p_message,
     p_log_type_id);
END;

--- INFO -----------------------------------
PROCEDURE ins_log_info
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2)
IS
BEGIN
  ins_log(p_system_log_id, p_message, 1);
END;

PROCEDURE ins_log_info_autonomous
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2)
IS
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  ins_log(p_system_log_id, p_message, 1);
  COMMIT;
END;

--- WARNING -------------------------------
PROCEDURE ins_log_warning
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2)
IS
BEGIN
  ins_log(p_system_log_id, p_message, 2);
END;

PROCEDURE ins_log_warning_autonomous
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2)
IS
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  ins_log(p_system_log_id, p_message, 2);
  COMMIT;
END;

--- ERROR ---------------------------------
PROCEDURE ins_log_error
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2)
IS
BEGIN
  ins_log(p_system_log_id, p_message, 3);
END;

PROCEDURE ins_log_error_autonomous
  (p_system_log_id      IN NUMBER,
   p_message            IN VARCHAR2)
IS
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  ins_log(p_system_log_id, p_message, 3);
  COMMIT;
END;

--- DELETE -----------------------------
PROCEDURE del_log
  (p_id                 IN NUMBER)
IS
BEGIN

  DELETE FROM tbl_log
    WHERE id = p_id;

END;

PROCEDURE del_log_autonomous
  (p_id                 IN NUMBER)
IS
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN

  del_log(p_id);
  COMMIT;

END;

END pkg_log;
/

Определение размера таблиц

Для определения размера таблиц, я использую следующий SQL

SELECT table_name
     , TRUNC(SUM(table_size)/1024/1024)      AS table_size_meg
     , TRUNC(SUM(index_size)/1024/1024)      AS index_size_meg
     , TRUNC(SUM(lobsegment_size)/1024/1024) AS lobsegment_size_meg
     , TRUNC(SUM(lobindex_size)/1024/1024)   AS lobindex_size_meg
     , TRUNC(SUM(table_size      +
                 index_size      +
                 lobsegment_size +
                 lobindex_size)/1024/1024)   AS sum_meg
  FROM (SELECT segment_name AS table_name
             , bytes as table_size
             , 0     as index_size
             , 0     as lobsegment_size
             , 0     as lobindex_size
          FROM user_segments
         WHERE segment_type = 'TABLE'
         UNION ALL
        SELECT i.table_name
             , 0       as table_size
             , s.bytes as index_size
             , 0       as lobsegment_size
             , 0       as lobindex_size
          FROM user_indexes i
             , user_segments s
         WHERE s.segment_name = i.index_name
           AND s.segment_type = 'INDEX'
         UNION ALL
        SELECT l.table_name
             , 0       as table_size
             , 0       as index_size
             , s.bytes as lobsegment_size
             , 0       as lobindex_size
          FROM user_lobs l
             , user_segments s
         WHERE s.segment_name = l.segment_name
           AND s.segment_type = 'LOBSEGMENT'
         UNION ALL
        SELECT l.table_name
             , 0       as table_size
             , 0       as index_size
             , 0       as lobsegment_size
             , s.bytes as lobindex_size
          FROM user_lobs l
             , user_segments s
         WHERE s.segment_name = l.index_name
           AND s.segment_type = 'LOBINDEX')
 GROUP BY table_name
 ORDER BY sum_meg DESC

файл table_size.sql

пятница, 20 мая 2016 г.

Удаление дубликатов с перебивкой айдишников

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

DECLARE
   l_id   NUMBER;

   PROCEDURE sp_merge_ids (p_old          IN INTEGER,
                           p_new          IN INTEGER,
                           p_table_name   IN VARCHAR2)
   IS
      v_str   VARCHAR2 (2000)
                 := 'update table set column = :new where column  = :old';
   BEGIN
      FOR rw
         IN (SELECT urcs2.table_name, uccs.column_name
               FROM user_constraints urcs1
               JOIN user_constraints urcs2
                 ON urcs1.constraint_name = urcs2.r_constraint_name
                AND urcs1.table_name = UPPER (p_table_name)
                AND urcs1.constraint_type = 'P'
               JOIN user_cons_columns uccs
                 ON uccs.constraint_name = urcs2.constraint_name)
      LOOP
         EXECUTE IMMEDIATE REPLACE (REPLACE (v_str, 'table', rw.table_name),
                                    'column',
                                    rw.column_name)
            USING p_new, p_old;
      END LOOP;
   END;
BEGIN
   FOR r IN (SELECT employee_id, employee_name
               FROM tbl_employee
              WHERE ROWID NOT IN (SELECT MAX (ROWID)
                                    FROM tbl_employee
                                   GROUP BY employee_name))
   LOOP
      SELECT employee_id
        INTO l_id
        FROM tbl_employee
       WHERE employee_name = r.employee_name
         AND employee_id <> r.employee_id
         AND ROWNUM = 1;

      sp_merge_ids (r.employee_id, l_id, 'tbl_employee');

      DELETE FROM tbl_employee
            WHERE employee_id = r.employee_id;
   END LOOP;
END;
/

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

понедельник, 16 мая 2016 г.

Ключевое слово PRAGMA

Ключевое слово PRAGMA является директивой, которая передает некоторую управляющую информацию компилятору, но не преобразуется непосредственно в исполняемый код.

PL/SQL поддерживает следующие директивы:

AUTONOMOUS_TRANSACTION — приказывает исполнительному ядру PL/SQL выполнить
сохранение или откат любых изменений, внесенных в базу данных в текущем блоке, без воздействия на главную или внешнюю транзакцию.

EXCEPTION_INIT — приказывает компилятору связать конкретный номер ошибки
с идентификатором, объявленным в программе как исключение. Идентификатор должен соответствовать правилам объявления исключений.

DECLARE
  no_such_sequence EXCEPTION;
  PRAGMA EXCEPTION_INIT (no_such_sequence, –2289);
BEGIN
...
EXCEPTION
  WHEN no_such_sequence
   THEN
      q$error_manager.raise_error ('Sequence not defined');
END;


RESTRICT_REFERENCES — задает для компилятора уровень чистоты программного пакета (отсутствия действий, вызывающих побочные эффекты).

SERIALLY_REUSABLE — сообщает исполнительному ядру PL/SQL, что данные уровни
пакета не должны сохраняться между обращениями к ним.

Команды SQL*Plus

show all -- отображение значений всех переменных
show pagesize --отображение значения переменной pagesize
define x=10 -- присваивание пользовательской переменной Х строкового значения 10
define x -- отображение значения пользовательской переменной Х
select '&x' from dual; -- использование строкового значения переменной Х в запросе
variable x varchar2(10) -- объявление переменной привязки
begin :x := 'hello!'; end; -- присваивание переменной привязки значения
print :x -- вывод значения переменной привязки
spool report -- выходные данные сохраняются в файл report.lst
spool off -- отключение вывода данных в файл
edit -- сохраняет текущее содержимое буфера в файле afiedt.buf и открывает его на редактирование
define _editor = /bin/vi -- установка редактора по умолчанию
SQLPATH -- переменная окружения, в которой можно указать каталоги, где нужно искать скрипты
login.sql -- можно сохранить в нем настройки пользователя и он будет выполняться при каждом подключении к базе, главное чтобы он лежал или в текущем каталоге или в каталоге на который указывает переменная SQLPATH
WHENEVER SQLERROR EXIT SQL.SQLCODE - SQL*Plus прекратит работу, если после выполнения команды сервер базы данных в ответ на команду SQL или PL/SQL вернет сообщение об ошибке
WHENEVER SQLERROR SQL.SQLCODE EXIT ROLLBACK - означает, что перед завершением SQL*Plus будет произведен откат всех не сохраненных изменений данных.

С помощью SQL*Plus можно запускать пакетные программы, задавая в командной
строке аргументы и обращаясь к ним по ссылкам вида &1 (первый аргумент), &2
(второй аргумент) и т. д.

show errors -- отображает список последних ошибок
SHOW ERRORS категория [схема.]объект -- отображение списка последних ошибок по объекту. Например, чтобы просмотреть информацию о последних ошибках в процедуре
wordcount, выполните такую команду: SHOW ERRORS FUNCTION wordcount

Полный список категорий, поддерживаемых этой командой, зависит от версии СУБД,
но в него как минимум входят следующие категории:
DIMENSION
FUNCTION
JAVA SOURCE
JAVA CLASS
PACKAGE
PACKAGE BODY
PROCEDURE
TRIGGER
TYPE
TYPE BODY
VIEW

Вызов функции и присваивание значения переменной привязки:

VARIABLE words NUMBER
CALL wordcount('некоторый_ текст') INTO :words;
PRINT :words

DESCRIBE wordcount -- вывод описания объекта. В нашем случае, это функция wordcount 

Удаление дубликатов строк

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

DELETE
    FROM t_emp
     WHERE rowid NOT IN (SELECT MAX(rowid)
                                                 FROM t_emp
                                               GROUP BY emp_no)

среда, 27 апреля 2016 г.

Создание ридонли админского аккаунта

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

CREATE ROLE USER_ADMIN_ROLE
/
GRANT CREATE SESSION TO USER_ADMIN_ROLE
/
GRANT SELECT_CATALOG_ROLE TO USER_ADMIN_ROLE
/
CREATE USER USER_ADMIN IDENTIFIED BY user_admin
/
GRANT USER_ADMIN_ROLE TO USER_ADMIN
/

После этого, можно настроить админский коннекшен в SQL Developer и мониторить состояние базы данных:


Проверка переноса всех строк при экспорте/импорте дампа

Если у вас есть возможность перед сворачиванием дампа, подсчитать количество строк в каждой таблице и типов объектов, то можно использовать следующий скрипт:

DECLARE
  l_cnt NUMBER;
BEGIN
  FOR rw IN (SELECT object_type, count(*) cnt
               FROM user_objects
              GROUP BY object_type
              ORDER BY object_type)
  LOOP
    dbms_output.put_line(rw.object_type || '=' || rw.cnt);
  END LOOP;
  FOR rw IN (SELECT table_name
               FROM user_tables
              ORDER BY table_name)
  LOOP
    EXECUTE IMMEDIATE 'SELECT COUNT(*) l_cnt FROM ' || rw.table_name INTO l_cnt;
    dbms_output.put_line(rw.table_name || '=' || l_cnt);
  END LOOP;
END;
/

После импорта дампа, запускаем данный скрипт на схеме и сверяем с предыдущем запуском.
Конечно результаты можно было бы сохранить в таблицы и проводить сравнение с помощью SQL, но на данном этапе я остановился на текущем варианте и сохраняю результаты в текстовые файлы, а потом сравниваю их обычным компаратором файлов.

Сбор статистики по таблицам

После разворачивания дампа, я использую следующий скрипт для сбора статистики по таблицам:

begin
  for r in (select table_name from user_tables)
  loop
        dbms_stats.unlock_table_stats(user, r.table_name);
        dbms_stats.gather_table_stats(
          ownname => user,
          tabname => r.table_name,
          estimate_percent => 100);
  end loop;
end;

/

вторник, 26 апреля 2016 г.

Проверка правильности переноса дампа

Очень часто сталкиваюсь с проблемой, когда администраторы разворачивают дамп с неконсистентными данными, при этом теряются констрейнты, форенкеи.......
Для проверки о том что был ли дамп перенесен консистентно, я создал таблицу a$schema_statistics:

declare
  v_table_name   varchar2(30)   := 'a$schema_statistics';
  v_create_table varchar2(2000) := 'create table ' || v_table_name || ' '
                                || '(object_type varchar2(30)'
                                || ',object_name varchar2(4000)'
                                || ',status      varchar2(20))'
                                || 'tablespace itap_data01';
  v_trunc_table  varchar2(200)  := 'truncate table ' || v_table_name;
  v_cnt integer;
begin
  select count(*)
    into v_cnt
    from user_tables
    where table_name = upper(v_table_name);

  execute immediate case v_cnt
                      when 0 then v_create_table
                      else v_trunc_table
                    end;
end;

/

И два представления:

CREATE OR REPLACE FORCE VIEW v_schema_statistics
AS
WITH cons_columns AS
  (SELECT table_name
       || '#'
       || listagg(column_name, ':') WITHIN GROUP (ORDER BY position) cons_name, constraint_name
     FROM user_cons_columns uccs
    GROUP BY table_name
            , constraint_name)
SELECT 'CONSTRAINTS' AS object_type
     , CASE
         WHEN constraint_name LIKE 'SYS%'
         THEN CASE urcs.constraint_type
                 WHEN 'R' THEN urcs.constraint_type
                            || '='
                            || (SELECT cons_name FROM cons_columns cscs WHERE cscs.constraint_name = urcs.constraint_name)
                            || '&'
                            || (SELECT cons_name FROM cons_columns cscs WHERE cscs.constraint_name = urcs.r_constraint_name)
                 WHEN 'P' THEN urcs.constraint_type
                            || '='
                            || (SELECT cons_name FROM cons_columns cscs WHERE cscs.constraint_name = urcs.constraint_name)
                 WHEN 'U' THEN urcs.constraint_type
                            || '='
                            || (SELECT cons_name from cons_columns cscs WHERE cscs.constraint_name = urcs.constraint_name)
                 WHEN 'C' THEN urcs.constraint_type
                            || '='
                            || (SELECT cons_name from cons_columns cscs WHERE cscs.constraint_name = urcs.constraint_name)
               END
         ELSE urcs.constraint_name
       END object_name
     , urcs.status
  FROM user_constraints urcs
UNION ALL
SELECT 'INDEX' as object_type
     , CASE
         WHEN index_name LIKE 'SYS%'
         THEN CASE index_type
                WHEN 'LOB' then index_type || '=' || uris.table_name
                ELSE (SELECT table_name
                          || '#'
                          || LISTAGG(column_name || '&' || descend, ':') WITHIN GROUP (ORDER BY column_position) index_name
                        FROM user_ind_columns uics
                       WHERE uics.index_name = uris.index_name
                       GROUP BY table_name)
              END
         ELSE index_name
       END object_name
     , uris.status
  FROM user_indexes uris
WHERE uris.index_type <> 'LOB'
UNION ALL
SELECT object_type
     , object_name
     , status
  FROM user_objects
WHERE object_type not in ('LOB', 'INDEX')
   AND ((object_type <> 'TYPE') OR (object_name not LIKE 'SYS%'))
/
CREATE OR REPLACE FORCE VIEW v_schema_statistics_compare
AS
SELECT *
  FROM (SELECT CASE
                 WHEN sass.object_name IS NULL
                   OR vsss.object_name IS NULL   THEN 'NOT MATCHED'
                 WHEN sass.status <> vsss.status THEN 'DIFF STATUS'
                 ELSE 'OK'
               END compare_result
             , sass.object_type AS a$_object_type
             , sass.object_name AS a$_object_name
             , sass.status      AS a$_status
             , vsss.object_type AS sh_object_type
             , vsss.object_name AS sh_object_name
             , vsss.status      AS sh_status
          FROM a$schema_statistics sass
          FULL OUTER JOIN
               v_schema_statistics vsss
            ON sass.object_type = vsss.object_type
           AND sass.object_name = vsss.object_name)
WHERE compare_result <> 'OK'
/
Первое представление v_schema_statistics отображает статистику по текущей схеме, а второе v_schema_statistics_compare сравнивает сохраненную статистику в таблице  a$schema_statistics с текущей статистикой. При каждом обновлении схемы, я запускаю следующий скрипт;

truncate table a$schema_statistics
/
insert
  into a$schema_statistics
     ( object_type
     , object_name
     , status
     )
select object_type
     , object_name
     , status
  from v_schema_statistics
/
commit
/
Он собирает статистику по схеме и сохраняет в таблице a$schema_statistics.
Если мне нужно узнать, целостность перенесенного дампа, я выполняю запрос 

select * from v_schema_statistics_compare

Колонки с префиксом A$ отображают сохраненную статистику, а с префиксом SH текущую статистику по схеме.

среда, 20 апреля 2016 г.

Конкантенация строк в Oracle

В Оракле можно конкантенировать строки следующим способом:

select cast(wm_concat(a) as varchar2(255)) x
  from (select '1' a from dual
        union all
        select '2' a from dual
        union all
        select '3' a from dual
        union all
        select '4' a from dual)
/

или начиная с Оракла 11

select LISTAGG(a, ', ') WITHIN GROUP (ORDER BY a) x
  from (select '1' a from dual
        union all
        select '2' a from dual
        union all
        select '3' a from dual
        union all
        select '4' a from dual)
/

Удаление записи и всех связанных данных из других таблиц

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

create table list_of_constraints as
select ddl_constraint
     , substr(replace(ddl_constraint, ' ADD ', ' DROP '), 1, instr(ddl_constraint, ' FOREIGN KEY ')) as drop_constraint
     , replace(ddl_constraint, ' ENABLE', ' ON DELETE CASCADE ENABLE') as cascade_constraint
from (select lpad(' ', 2*(level-1)) || table_name as table_name
             , id
             , parent_id
             , constraint_name
             , delete_rule
             , r_constraint_name
             , decode(constraint_type, 'R', dbms_metadata.get_ddl('REF_CONSTRAINT', constraint_name)) ddl_constraint
          from (select case
                         when constraint_type = 'R' then (select constraint_name
                                                            from user_constraints urco
                                                           where urco.table_name = urcs.table_name
                                                             and urco.constraint_type = 'P')
                         else urcs.constraint_name
                       end as id
                     , urcs.r_constraint_name as parent_id
                     , urcs.table_name
                     , urcs.constraint_type
                     , urcs.constraint_name
                     , urcs.r_constraint_name
                     , urcs.delete_rule
                  from user_constraints urcs
                 where constraint_type in ('P', 'U', 'R')) obtr
        connect by nocycle prior obtr.id = obtr.parent_id
          start with obtr.table_name = 'AAAA'
                 and obtr.constraint_type in ('P'))
where ddl_constraint is not null
  and delete_rule = 'NO ACTION'
/
---
begin
  for r in (select drop_constraint, cascade_constraint from list_of_constraints)
  loop
    execute immediate r.drop_constraint;
    execute immediate r.cascade_constraint;
  end loop;
end;
/
--- DELETE ---------------------------------------------------------------------
delete from AAAA where name = 'bbbb'
/
--------------------------------------------------------------------------------
---
begin
  for r in (select drop_constraint, ddl_constraint from list_of_constraints)
  loop
    execute immediate r.drop_constraint;
    execute immediate r.ddl_constraint;
  end loop;
end;
/
drop table list_of_constraints

/
В этом скрипте, мы вычисляем все подчиненные таблицы для таблице АААА. При этом во временную таблицу list_of_constraints  мы записываем скрипты для пересоздания уже существующих форенкеев на форенкеи с каскадным удалением.
После пересоздания форенкеев, мы удаляем запись из таблицы АААА и потом восстанавливаем первоначальное состояние форенкеев.

вторник, 19 апреля 2016 г.

Получение значениий параметров для v$sql

Значение параметров для запросов из v$sql можно найти в представлении v$sql_bind_capture.

 select *
   from v$sql vsql
   join v$sql_bind_capture vbce
     on vsql.sql_id = vbce.sql_id
/