powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Перевод из MS SQL Server в ORACLE
25 сообщений из 120, страница 4 из 5
Перевод из MS SQL Server в ORACLE
    #39223562
tru55
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenНу если это единственный способ, что поделать!
В FAQ написано, как использовать коллекции из пакета, а отнюдь не отдельную таблицу.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39223570
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tru55studierenНу если это единственный способ, что поделать!
В FAQ написано, как использовать коллекции из пакета, а отнюдь не отдельную таблицу.
Не смог осилить. Можете простенький пример показать? Да хоть в примере "контракты" и "платежи".

Мне показалось, что там в FAQ не мой случай.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39223599
eev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenНе смог осилить. Можете простенький пример показать? Да хоть в примере "контракты" и "платежи".

Мне показалось, что там в FAQ не мой случай.

простенький пример из документации
Example 9-10 Compound Trigger Avoids Mutating-Table Error\
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
CREATE OR REPLACE TRIGGER Check_Employee_Salary_Raise
  FOR UPDATE OF Salary ON Employees
COMPOUND TRIGGER
  Ten_Percent                 CONSTANT NUMBER := 0.1;
  TYPE Salaries_t             IS TABLE OF Employees.Salary%TYPE;
  Avg_Salaries                Salaries_t;
  TYPE Department_IDs_t       IS TABLE OF Employees.Department_ID%TYPE;
  Department_IDs              Department_IDs_t;

  -- Declare collection type and variable:

  TYPE Department_Salaries_t  IS TABLE OF Employees.Salary%TYPE
                                INDEX BY VARCHAR2(80);
  Department_Avg_Salaries     Department_Salaries_t;

  BEFORE STATEMENT IS
  BEGIN
    SELECT               AVG(e.Salary), NVL(e.Department_ID, -1)
      BULK COLLECT INTO  Avg_Salaries, Department_IDs
      FROM               Employees e
      GROUP BY           e.Department_ID;
    FOR j IN 1..Department_IDs.COUNT() LOOP
      Department_Avg_Salaries(Department_IDs(j)) := Avg_Salaries(j);
    END LOOP;
  END BEFORE STATEMENT;

  AFTER EACH ROW IS
  BEGIN
    IF :NEW.Salary - :Old.Salary >
      Ten_Percent*Department_Avg_Salaries(:NEW.Department_ID)
    THEN
      Raise_Application_Error(-20000, 'Raise too big');
    END IF;
  END AFTER EACH ROW;
END Check_Employee_Salary_Raise;
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39223608
studieren,

С подходом чтения изменяемой таблицы в триггере этого не решить без блокировки мастер-ключа. У dbms_lock свои недостатки при интенсивном использовании большого количества значений, да еще коммит на аллокейт. Можно, конечно, эксклюзивить всю таблицу.
Посему, в оракле предпочитают использовать более оракловые подходы ограничения агрегатов промеж строк. Или вообще не ограничивать на стороне БД. Мало ли, какие еще нереляционные сложносвязанные бизнес-требования могут применяться в приложении.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39223637
Вячеслав Любомудров
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenВячеслав Любомудров,Не очень понятно, почему ты мне это адресуешь

studierenПрочёл книжку "ORACLE PL/SQL Как писать мощные и гибкие программы на PL/SQL" Кристофер Аллен.Судя по написаному, читать такое не стоит

studierenНу если это единственный способ, что поделать! Буду так. Но я в шоке от корпорации ORACLE.Это самый извращенный способ, мне, честно говоря, и в голову такое прийти не могло (правда, я не разработчик).

По-поводу шока, ты так и не сказал, как нужно вести себя (твое ограничение в 1500 на сумму платежей)
я использую все тот же пример
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
tst> create table payment(id number, contr_id number /* номер контракта */, amount number);

Table created.

tst> insert into payment /* ну вот в таком порядке вводились данные */
  2  select 1 id, 1 contr_id, 1000 amount from dual union all
  3  select 2 id, 1 contr_id, 500 amount from dual union all
  4  select 3 id, 1 contr_id, -1000 amount from dual union all
  5  select rownum + 3 id, trunc(rownum/3)+2, mod(rownum, 3)*500 from dual connect by level <= 10; /* здесь какие-то другие данные */

13 rows created.

tst> create trigger paym_trg
  2  for update on payment
  3  compound trigger
  4      type amount_table is table of number;
  5      a_t amount_table;
  6      cur_sum number;
  7  before statement is
  8  begin /* это пример, поэтому мы работаем только с контрактом 1 */
  9      select amount bulk collect into a_t
 10      from payment where contr_id=1 order by id; 
 11      dbms_output.put_line('Before statement');
 12      for i in 1..a_t.count loop /* чтоб не лезть в таблицу -- сохраняем данные в локальную PL/SQL коллекцию перед началом оператора */
 13          dbms_output.put_line('--- id='||i||', a_t(i)='||a_t(i));
 14      end loop;
 15  end before statement;
 16  before each row is
 17  begin
 18      cur_sum := 0;
 19      a_t(:new.id) := a_t(:new.id) - :old.amount + :new.amount; /* и синхронно обновляем запись в локальной коллекции */
 20      dbms_output.put_line('Update row with id='||:new.id);
 21      for i in 1..a_t.count loop
 22          dbms_output.put_line('--- id='||i||', a_t(i)='||a_t(i));
 23          cur_sum := cur_sum + a_t(i); /* подсчитываем сумму для контракта при обновлении каждой строки */
 24      end loop;
 25      dbms_output.put_line('Current sum='||cur_sum);
 26      if cur_sum > 1500 then  /* вот тут нам по-идее нужно генерить ошибку и прерывать оператор */
 27          dbms_output.put_line('!!! ERROR !!!');
 28      end if;
 29  end before each row;
 30  end;
 31  /

Trigger created.

Обновляем несколько строк
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
tst> set serveroutput on
tst> update payment set amount=amount*3 where contr_id=1;
Before statement
--- id=1, a_t(i)=1000
--- id=2, a_t(i)=500
--- id=3, a_t(i)=-1000
Update row with id=1
--- id=1, a_t(i)=3000
--- id=2, a_t(i)=500
--- id=3, a_t(i)=-1000
Current sum=2500
!!! ERROR !!!
Update row with id=2
--- id=1, a_t(i)=3000
--- id=2, a_t(i)=1500
--- id=3, a_t(i)=-1000
Current sum=3500
!!! ERROR !!!
Update row with id=3
--- id=1, a_t(i)=3000
--- id=2, a_t(i)=1500
--- id=3, a_t(i)=-3000
Current sum=1500

3 rows updated.

Просто добавили индекс
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
tst> rollback;

Rollback complete.

tst> create index payment_idx on payment(contr_id, id desc);

Index created.

tst> update payment set amount=amount*3 where contr_id=1;
Before statement
--- id=1, a_t(i)=1000
--- id=2, a_t(i)=500
--- id=3, a_t(i)=-1000
Update row with id=3
--- id=1, a_t(i)=1000
--- id=2, a_t(i)=500
--- id=3, a_t(i)=-3000
Current sum=-1500
Update row with id=2
--- id=1, a_t(i)=1000
--- id=2, a_t(i)=1500
--- id=3, a_t(i)=-3000
Current sum=-500
Update row with id=1
--- id=1, a_t(i)=3000
--- id=2, a_t(i)=1500
--- id=3, a_t(i)=-3000
Current sum=1500

3 rows updated.

Для реляционной БД такое поведение недопустимо

PS. А как себя поведет MS SQL? Точнее, как там разруливаются такие ситуации -- зависимость результата от порядка обработки
Или ты просто никогда не задумывался над этим?
А Оракл за тебя подумал
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39223838
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вячеслав ЛюбомудровstudierenВячеслав Любомудров,Не очень понятно, почему ты мне это адресуешь

Извиняюсь, я просто нажал "Ответить", а т.к. последнее сообщение было Ваше, Ваше имя и осталось. Сорри, не удалил.

Вячеслав ЛюбомудровPS. А как себя поведет MS SQL? Точнее, как там разруливаются такие ситуации -- зависимость результата от порядка обработки
Или ты просто никогда не задумывался над этим?
А Оракл за тебя подумал
Да там Все просто. Когда в одно и то же время меняете 2 и более записей (разумеется и там порядок изменений не имеет значений) и если хотя бы в одной записи "осечка", то сервер не даст сохранить всем изменениям. Поэтому всё работает чётко как запланировано разработчиком БД.
Да, кстати, там триггер не работает по принципу "FOR EACH ROW", там такого нет. Всё целиком, все записи одновременно. Любые изменения будут в логической таблице "Inserted", а удалённые в "Deleted". Если нужно узнать новое и удаленное значение, то выдёргиваем из этих таблиц. Как то так.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39224077
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenКогда в одно и то же время меняете 2 и более записей (разумеется и там
порядок изменений не имеет значений) и если хотя бы в одной записи "осечка", то сервер не
даст сохранить всем изменениям.
Так нет никакой "осечки". Всё отлично вставляется и модифицируется из параллельных
коннектов. Но твоё ограничение при этом - нарушается.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39237877
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Приветствую форумчан!

Вопрос № 1.
Есть поле "LastModifiedDate", где необходимо сохранить последнюю дату и время обновления каждой записи.
Если ввести новую запись, то достаточно в значение по умолчанию указать SYSDATE.
А как в триггере надо написать, чтобы ORACLE не ругался на мутирующую таблицу во время обновления записи?
Пробовал разные варианты, но почему то ORACLE ругается.

Вопрос № 2.
В MS SQL Server при обновлении записи я мог использовать CTE, что-то вроде этого:
Код: sql
1.
2.
3.
4.
5.
6.
WITH L AS (SELECT ContractID, MAX(SaleDate) LastSaleDate
    FROM Sale
    GROUP BY ContractID)
UPDATE Sale
SET Last = 1
FROM Sale S INNER JOIN L ON S.ContractID = L.ContractID AND S.SaleDate = L.LastSaleDate


Но как я понимаю, в ORACLE такое не пойдёт.
Пробовал вот так.
Код: plsql
1.
2.
3.
UPDATE Sale Sl
SET Last = 1
WHERE Sl.ContractID IN (SELECT S.ContractID FROM Sale S GROUP BY S.ContractID HAVING MAX(S.SaleDate) = Sl.SaleDate)


Работать то конечно работает, но оооооочень медленно! Разумеется запрос на обновление не самое оптимальное. Но а как ускорить / оптимизировать запрос?
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39237885
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenА как в триггере надо написать, чтобы ORACLE не ругался на мутирующую таблицу во время обновления записи?RTFM DML Triggers: Correlation Names and Pseudorecords (FAQ)
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254001
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день!

Как сделать уникальным все непустые значения поля "А" в таблице "Table1" в Oracle?
В MS SQl Server можно создать уникальный индекс с фильтром. Что-то вроде этого:
Код: sql
1.
CREATE UNIQUE INDEX IX_Table1 ON Table1 (A) WHERE (A Is Not Null);


После этого сервер не позволяет дублировать НЕ пустые значения. А вот если поле "А" не заполнено пользователем, то сервер сколько угодно записей может сохранить без проблем.
Мне нужно тоже самое и в ORACLE. Пожалуйста, подскажите куда рыть.

Спасибо заранее.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254002
studieren,
просто создай уникальный индекс. и всё. работать будет именно так, как ты хочешь:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
create table b$m_test (id number);
-- Table B$M_TEST created.
CREATE UNIQUE INDEX b$m_test_u_indx ON b$m_test (id);
-- Unique index B$M_TEST_U_INDX created.
insert into b$m_test(id) values(1);
-- 1 row inserted.
insert into b$m_test(id) values(2);
-- 1 row inserted.
insert into b$m_test(id) values(null);
-- 1 row inserted.
insert into b$m_test(id) values(null);
-- 1 row inserted.
insert into b$m_test(id) values(null);
-- 1 row inserted.
insert into b$m_test(id) values(1);
ORA-00001: нарушено ограничение уникальности (CDS.B$M_TEST_U_INDX)

select * from b$m_test;

 ID
----
   1
   2
NULL
NULL
NULL

-- 5 row(s) selected
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254009
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый Э - Эх,

Прошу прошения я неправильно написал. У меня в реальной базе индекс состоит из 2 полей.
Код: sql
1.
CREATE UNIQUE INDEX IX_Table1 ON Table1 (A, B) WHERE (A Is Not Null);


Поле "B" обязательное, поэтому там пустое значение не может быть.
Не думал, что ORACLE допускает ввод пустых значений, если индекс состоит из одного поля.
Может мне создать "Function-based index", где конкатенирую 2 поля и полученное значение попробую сделать уникальным?
Сейчас попробую.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254013
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый Э - Эх,

Вроде бы получилось! :)
Спасибо за подсказку.
Правда получился дурацкий индекс, которого не буду использовать в запросах. Он будет служить только как ограничение.

Ну а если у гуру есть более продвинутая идея, буду рад любым подсказкам.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254019
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenболее продвинутая идея
Код: plsql
1.
2.
3.
alter table table1 add b_when_a_is_not_null /*invisible*/ generated always as (nvl2(a, b, null)) virtual;
alter table table1 add unique(a, b_when_a_is_not_null);
select * from table1 where b_when_a_is_not_null = …
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254030
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic,

Thank you very much!
Работает однако! Взял на вооружение. :)
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254135
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenКак сделать уникальным все непустые значения поля "А" в таблице "Table1" в Oracle?
В MS SQl Server можно создать уникальный индекс с фильтром. Что-то вроде этого:
Код: sql
1.
CREATE UNIQUE INDEX IX_Table1 ON Table1 (A) WHERE (A Is Not Null);

После этого сервер не позволяет дублировать НЕ пустые значения. А вот если поле "А" не заполнено пользователем, то сервер сколько угодно записей может сохранить без проблем.null, он даже в mssql null. Неужели без этого условия mssql запрещает вставлять несколько null?
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254372
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
-2-studierenКак сделать уникальным все непустые значения поля "А" в таблице "Table1" в Oracle?
В MS SQl Server можно создать уникальный индекс с фильтром. Что-то вроде этого:
Код: sql
1.
CREATE UNIQUE INDEX IX_Table1 ON Table1 (A) WHERE (A Is Not Null);

После этого сервер не позволяет дублировать НЕ пустые значения. А вот если поле "А" не заполнено пользователем, то сервер сколько угодно записей может сохранить без проблем.null, он даже в mssql null. Неужели без этого условия mssql запрещает вставлять несколько null?
Да, запрещает. В принципе я согласен с таким положением дел.
Вот к примеру ORACLE также запрещает, но только если уникальный индекс состоит как минимум из 2 полей.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39254400
Фотография orawish
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren,

ну и в оракле вы можете и над одной колонкой сделать fbi, который обеспечит желаемое.
другое дело, что обычно атрибут такой создают обязательным и проблемы нет в принципе
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39255438
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Приветствую всех.
Очередной вопрос.
Разве в Oracle нет пустой строки ''?
Код: plsql
1.
2.
3.
select case when replace('a', 'a', '') is null then 'is null' else 'is not null' end,
    case when '' is null then 1 else 0 end
from dual;


Получается проверять длину строки на 0 не имеет смысла?
Я имею ввиду вот такое сравнение:
Код: sql
1.
IF LENGTH(A) = 0 THEN
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39255448
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Читай документацию - узнаешь гораздо больше, чем методом тыка или форумяния.
RTFM Nulls (FAQ)
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39255819
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenПолучается проверять длину строки на 0 не имеет смысла?
Я имею ввиду вот такое сравнение:
Код: sql
1.
IF LENGTH(A) = 0 THEN



Примите в расчет - здесь вам не BSTR.
Проблема не там, где length вернет Null вместо ожидавшегося вами 0,
а, наоборот, вовсе там, где он трудолюбиво займется вычислениями ее длины для непустой строки.

В отличии от BSTR, где length просто читает префикс строки, здесь вы наступаете на алгоритм сложности порядка длины строки,
с коэффициентом на алгоритм определения длины следующего символа для кодировок типа utf8.

Просто выбросьте из головы length до тех пор, пока он вам жизненно не понадобится.
А в оставшихся случаях пользуйтесь им предельно экономно, т.к. вы точно знаете, что вы за рамками BSTR.

studierenПриветствую всех.
Очередной вопрос.
Разве в Oracle нет пустой строки ''?
Код: plsql
1.
2.
3.
select case when replace('a', 'a', '') is null then 'is null' else 'is not null' end,
    case when '' is null then 1 else 0 end
from dual;



Нет в том смысле, в каком ее длина ожидается равной нулю.
Так же, как симметрично, нет строкового +, обращающего в Null результат, если один из операндов Null.
Конкатенация всегда работает как &.

В документации тщательно оговаривается возможность изменения поведения в будущем.
Имхо, даже если так, то будущая вероятная "опасность" подстерегает только злоупотребляющих ANSI-формулировками для имен типов.
Не могу сказать, что таких борцов за переносимость не может быть, но своими глазами не только видел,
но искренне надеюсь уже и не увидеть.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39257200
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Очередная проблема.

Есть поле в SQL Server varchar(8000). Т.к. в ORACLE максимальная длина 4000, пришлось мне создать 2 поля с типом данных Varchar2(4000). Далее, создал виртуальное поле, которое соединяет эти поля.
Но не тут то было. Оказывается при конкатенации ORACLE всё равно ругается, если общая длина строк превышает 4000.
Как мне быть? Есть способ как то обойти данное ограничение?

Спасибо заранее.
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39257209
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studierenКак мне быть?
Use CLOB, Luke!
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39257212
Фотография orawish
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren,

на 12c нет лимита 4000 байт на varchar2 столбцах
на серверах < 12с есть, например, тип CLOB

короче, Как мне быть? читайте..
...
Рейтинг: 0 / 0
Перевод из MS SQL Server в ORACLE
    #39257213
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry Sibiryakov,

Спасибки! Вроде бы получилось.
...
Рейтинг: 0 / 0
25 сообщений из 120, страница 4 из 5
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Перевод из MS SQL Server в ORACLE
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]