Oracle считает пустые строки NULL, а SQL Server нет - как это лучше всего обрабатывать? - PullRequest
20 голосов
/ 02 октября 2008

Мне нужно написать компонент, который воссоздает таблицы SQL Server (структуру и данные) в базе данных Oracle. Этот компонент также должен принимать новые данные, введенные в базу данных Oracle, и копировать их обратно в SQL Server.

Перевод типов данных из SQL Server в Oracle не является проблемой. Однако критическое различие между Oracle и SQL Server вызывает серьезную головную боль. SQL Server считает, что пустая строка ("") отличается от значения NULL, поэтому столбец char можно определить как NOT NULL, но при этом все еще включать в данные пустые строки.

Oracle считает пустую строку такой же, как значение NULL, поэтому, если столбец char определен как NOT NULL, вы не можете вставить пустую строку. Это приводит к тому, что мой компонент ломается всякий раз, когда столбец NOT NULL char содержит пустую строку в исходных данных SQL Server.

До сих пор моим решением было не использовать NOT NULL ни в одном из моих зеркальных определений таблиц Oracle, но мне нужно более надежное решение. Это должно быть решение кода, поэтому ответом не может быть «использовать такой-то продукт SQL2Oracle».

Как бы вы решили эту проблему?

Редактировать: вот единственное решение, которое я нашел до сих пор, и оно может помочь проиллюстрировать проблему. Поскольку Oracle не допускает "" в столбце NOT NULL, мой компонент может перехватить любое такое значение, поступающее от SQL Server, и заменить его на "@" (например, только).

Когда я добавляю новую запись в свою таблицу Oracle, мой код должен написать «@», если я действительно хочу вставить «», а когда мой код копирует новую строку обратно в SQL Server, он должен перехватить "@" и вместо этого напишите "".

Я надеюсь, что есть более элегантный способ.

Редактировать 2: Возможно ли, что есть более простое решение, например, некоторые настройки в Oracle, которые заставляют его обрабатывать пустые строки так же, как и все другие основные базы данных? И будет ли этот параметр также доступен в Oracle Lite?

Ответы [ 11 ]

10 голосов
/ 02 октября 2008

Я не вижу простого решения для этого.

Может быть, вы можете сохранить свои значения в виде одного или нескольких пробелов -> ' ', которые не равны NULLS в Oracle, или отслеживать этот особый случай через дополнительные поля / таблицы и слой адаптера.

9 голосов
/ 02 октября 2008

Мое типичное решение было бы добавить ограничение в SQL Server, заставляя все строковые значения в соответствующих столбцах иметь длину больше 0:

CREATE TABLE Example (StringColumn VARCHAR(10) NOT NULL)

ALTER TABLE Example
ADD CONSTRAINT CK_Example_StringColumn CHECK (LEN(StringColumn) > 0)

Однако, как вы заявили, у вас нет контроля над базой данных SQL. Таким образом, у вас действительно есть четыре варианта (на мой взгляд):

  1. Обрабатывать пустые строковые значения как недействительные, пропускать эти записи, предупреждать оператора и каким-либо образом регистрировать записи, что упрощает ручное исправление / повторный ввод.
  2. Преобразование пустых строковых значений в пробелы.
  3. Преобразование пустых строковых значений в код (т. Е. "LEGACY" или "EMPTY").
  4. Откат переносов, в которых встречаются пустые строковые значения в этих столбцах, а затем давление на владельца базы данных SQL Server для исправления их данных.

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

ПРИМЕЧАНИЕ: Я полагаю, что в этом случае SQL Server действительно демонстрирует "правильное" поведение.

3 голосов
/ 25 октября 2011

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

Я думаю, вы должны просто разрешить NULLS в любом столбце Oracle, который отражает столбец SqlServer, который, как известно, содержит пустые строки.

Если в базе данных SqlServer есть логическое различие между NULL и пустой строкой, вам понадобится что-то дополнительное для моделирования этой разницы в Oracle.

3 голосов
/ 02 октября 2008

Это неприятно и может иметь неожиданные побочные эффекты ... но вы можете просто вставить "chr (0)" вместо "".

drop table x

drop table x succeeded.
create table x ( id number, my_varchar varchar2(10))

create table succeeded.
insert into x values (1, chr(0))

1 rows inserted
insert into x values (2, null)

1 rows inserted
select id,length(my_varchar) from x

ID                     LENGTH(MY_VARCHAR)     
---------------------- ---------------------- 
1                      1                      
2                                             

2 rows selected

select * from x where my_varchar is not null

ID                     MY_VARCHAR 
---------------------- ---------- 
1                      
3 голосов
/ 02 октября 2008

Нужно ли разрешать пустые строки в системе SQL Server? Если вы можете добавить в систему SQL Server ограничение, запрещающее пустые строки, это, вероятно, самое простое решение.

2 голосов
/ 30 января 2015

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

2 голосов
/ 27 января 2015

Для тех, кто думает, что Null и пустая строка должны считаться одинаковыми. Ноль имеет значение, отличное от пустой строки. Он фиксирует разницу между «неопределенным» и «известным как пустой». В качестве примера, запись может быть создана автоматически, но никогда не подтверждена пользовательским вводом, и, таким образом, получить «ноль» в расчете на то, что, когда пользователь ее проверяет, она будет установлена ​​пустой. Практически мы можем не захотеть запускать логику для нуля, но можем захотеть пустую строку. Это аналогично случаю для флажка 3 состояния Да / Нет / Не определено.

И SQL, и Oracle не совсем правильно поняли. Пробел не должен удовлетворять ограничению «not null», и необходимо обрабатывать пустую строку иначе, чем обрабатывается null.

1 голос
/ 02 октября 2008

Если вы переносите данные, вам, возможно, придется заменить пробел пустой строкой. Не очень элегантно, но выполнимо. Это неприятная «особенность» Oracle.

0 голосов
/ 03 февраля 2015

Хотя, по большей части, я согласен с большинством других ответов (не собираюсь спорить о том, с чем я не согласен - не место для этого :))

Я заметил, что OP упомянул следующее:

"Oracle считает пустую строку такой же, как значение NULL, поэтому, если столбец char определен как NOT NULL, вы не можете вставить пустую строку."

Специально вызывая CHAR, а не VARCHAR2. Следовательно, говорить о «пустой строке» длина 0 (т.е. «») является спорным. Если он объявил CHAR как, например, CHAR (5), то просто добавьте пробел в пустую строку, входящую в систему, Oracle все равно ее дополнит. Вы получите строку из 5 пробелов.

Теперь, если OP означает VARCHAR2, ну да, это совсем другой зверь, и да, разница между пустой строкой и NULL становится существенной.

  SQL> drop table junk;

  Table dropped.

  SQL>
  SQL> create table junk ( c1     char(5) not null );

  Table created.

  SQL>
  SQL> insert into junk values ( 'hi' );

  1 row created.

  SQL>
  SQL> insert into junk values ( ' ' );

  1 row created.

  SQL>
  SQL> insert into junk values ( '' );
  insert into junk values ( '' )
                            *
  ERROR at line 1:
  ORA-01400: cannot insert NULL into ("GREGS"."JUNK"."C1")


  SQL>
  SQL> insert into junk values ( rpad('', 5, ' ') );
  insert into junk values ( rpad('', 5, ' ') )
                            *
  ERROR at line 1:
  ORA-01400: cannot insert NULL into ("GREGS"."JUNK"."C1")


  SQL>
  SQL> declare
    2    lv_in   varchar2(5) := '';
    3  begin
    4     insert into junk values ( rpad(lv_in||' ', 5) );
    5  end;
    6  /

  PL/SQL procedure successfully completed.

  SQL>
0 голосов
/ 29 января 2015

Ну, главное, что я хотел бы рассмотреть, это отсутствие задач, когда какое-то поле может быть пустым, это же поле может быть пустой строкой, и бизнес-логика требует различать эти значения. Так что я бы сделал эту логику:

  • проверка MSSQL, если столбец имеет ограничение NOT NULL
  • проверка MSSQL, если столбец имеет CHECK (столбец <> '') или подобное ограничение

Если оба значения верны, сделать столбец Oracle NOT NULL. Если любое из них истинно, установите для столбца Oracle значение NULL. Если ни один из них не соответствует истине, вызовите исключение INVALID DESIGN (или, возможно, проигнорируйте его, если это допустимо этим приложением).

При отправке данных из MSSQL в Oracle, просто не делайте ничего особенного, все данные будут переданы правильно. При извлечении данных в MSSQL любые ненулевые данные должны отправляться как есть. Для нулевых строк вы должны решить, будет ли она вставлена ​​как нулевая или как пустая строка. Чтобы сделать это, вы должны снова проверить дизайн таблицы (или вспомнить предыдущий результат) и посмотреть, имеет ли оно ограничение NOT NULL. Если имеет - используйте пустую строку, если нет - используйте NULL. Просто и умно.

Иногда, если вы работаете с неизвестным и непредсказуемым приложением, вы не можете проверить наличие ограничения {не пустая строка} из-за различных его форм. Если это так, вы можете использовать упрощенную логику (сделать столбцы Oracle всегда обнуляемыми) или проверить, можете ли вы вставить пустую строку в таблицу MSSQL без ошибок.

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