2013-03-11 5 views
1

Краткая версия вопроса: Есть ли способ подсчета количества байтов, которое потребуется для хранения символов строки в столбце VARCHAR(n) в базе данных Oracle?Байт-длина строки CLR

Более длинная версия: Следующий сценарий Oracle SQL завершится неудачно в третьем выражении. Он попытается вставить 10 символов в столбец VARCHAR(10); однако одним из этих символов является A с острым акцентом.

CREATE TABLE TESTTABLE (NAME VARCHAR(10) NULL); 

INSERT INTO TESTTABLE (NAME) VALUES ('abcdefghij'); 
--1 rows inserted. 

INSERT INTO TESTTABLE (NAME) VALUES ('ábcdefghij'); 
--ORA-12899: value too large for column "ACME"."TESTTABLE"."NAME" (actual: 11, maximum: 10) 

Моя C# приложение хранит строки в базе данных Oracle, и я не могу просто изменить тип столбца NVARCHAR2(10), который будет работать. Ожидается, что приложение обрезает любую большую строку до предела в 10 символов, поэтому Oracle не будет жаловаться на ее длину. Но обрезка String.Length - это очень наивная стратегия: она будет слепо оставить «ábcdefghij» неповрежденным со всеми его 10 символами CLR.

Как я могу определить, что «а» займет 2 байта в строке базы данных, поэтому я могу обрезать строку «ABCDEFGHI» перед выдачей INSERT заявление?

EDIT: этот вопрос похож на Best way to shorten UTF8 string based on byte length

ответ

4

Это зависит от кодировки вы установили Oracle использовать. Вы преобразовываете экземпляр строки в массив байтов, используя соответствующий пример System.Text.Encoding, такой как System.Text.Encoding.UTF8. (Вы ищете метод «GetBytes»)

+0

Это ответ, который лучше всего подходит для ситуации, потому что я могу сделать так много на стороне базы данных проблемы. Я ограничусь только заменой приложения C#. Спасибо всем! – Humberto

1

Вы можете получить длину в байтах строки, как это:

UTF8Encoding Encoding = new UTF8Encoding(); 
byte[] UTF8String = Encoding.GetBytes("ábcdefghij"); 
int StringLenght = UTF8String.Length 

В самом деле, для примера, она возвращает 11.

+0

+1 для примера кода моего ответа. Хотя вам, вероятно, следует использовать статический экземпляр Encoding.UTF8, а не создавать новые экземпляры UTF8Encoding.(Это приведет к уменьшению количества накладных расходов GC) –

+0

Спасибо за подсказку! – Rafael

5

Функция Oracle length(string) возвращает количество символов, lengthb(string) возвращает количество байтов.

+0

+1 - это единственный ответ, который будет работать независимо от конфигурации кодировки Oracle. –

+0

+1 от меня тоже, но не будет VSIZE тоже работать? –

+0

Я не знал о функции 'lengthb()', спасибо вам большое. – Humberto

4

По умолчанию VARCHAR2(10) выделяет 10 байт памяти, которые могут или не могут равняться 10 символам в зависимости от набора символов базы данных и данных. Вы можете, однако, объявить столбец так, чтобы он всегда сохранял 10 символов.

Когда вы используете набор символов переменной ширины, вы почти всегда хотите объявить столбец семантикой длины символа VARCHAR2(10 CHAR). Затем вы всегда можете сохранить 10 символов, если у вас есть некоторые символы, которым требуется более 1 байт памяти.

Если вы застряли, объявляя столбцы с использованием семантики длины байта по какой-либо причине, вы можете использовать функцию LENGTHB или VSIZE, чтобы вернуть длину строки в байтах.

select lengthb('ábcdefghij'), vsize('ábcdefghij') 
    from dual; 

вернет 11 для обеих столбцов результата.

+0

'+ 1' для' VARCHAR2 (10 CHAR) ' –

+0

' VARCHAR2' было бы очень хорошей идеей, если бы администратор баз данных уже думал о международных символах! И он должен был это сделать, кстати. У нас слишком много акцентированных персонажей на португальском языке. – Humberto

+1

@Humberto - 'VARCHAR' и' VARCHAR2' являются синонимами - вы можете с радостью объявить столбец 'VARCHAR (10 CHAR)', если хотите (или изменить существующий столбец 'VARCHAR (10 BYTE)' на VARCHAR (10 CHAR)). –

Смежные вопросы