2012-08-23 29 views
7

Wielobajtowe postacie spowodowały wiele bólu.WYBIERZ tyle danych od CLOB do VARCHAR2, jak to możliwe, z wielobajtowymi znakami w danych

Wszelkie sugestie dotyczące tego problemu?

Mam pole CLOB że potęga zawiera pewne znaki wielobajtowe, i muszę wybrać w SQL i konwertować to pole do strun procesie przetwórczym, obecnie używam:

SELECT DBMS_LOB.SUBSTR(description, 4000, 1) FROM table 

Ale 4000 w powyższym poleceniu ma długość znaków, a nie bajty. Musiałem więc zmienić na 3000, aby obsłużyć wszystkie wielobajtowe znaki, które mogły wkradnąć się do danych, w przeciwnym razie wystąpi błąd rozmiaru bufora.

Problem dotyczy rekordów, które nie zawierają znaku wielobajtowego, może niepotrzebnie skrócić więcej danych, niż jest to konieczne. (. 4000 jest ograniczenie ciąg możemy/musiała z tym żyć)

Czy istnieje sposób, aby zrobić coś w równowartości:

SELECT DBMS_LOB.SUBSTR(description, 4000bytes, 1) FROM table 

ten sposób mogę uzyskać jak najwięcej danych z jak to możliwe.

Uwaga: Nie wolno mi tworzyć tabele tymczasowe/widoki, nie używając PL/SQL, tylko SQL SELECT ...

Odpowiedz

4

Może obciąć wynikającą varchar2 z SUBSTR:

SELECT SUBSTRB(DBMS_LOB.SUBSTR(description, 4000, 1), 1, 4000) FROM table 
+0

że nie powinno być „... z SUBSTRB”? (SUBSTRB zamiast SUBSTR) –

+1

Ciekawe: czy wiesz, co się stanie, jeśli pierwsze 3999 znaków ma długość jednej bajtu, a 4000 jest wielobajtową? Czy nie zwróci błędnego znaku na pozycji 4000 (ponieważ interpretuje pierwszy bajt wielobajtowego znaku jako jednobajtowego znaku)? –

+2

Żaden Jeffery nie zadziała, jeśli "opis" zawiera znaki wielobajtowe, najgłębszy DBMS_LOB.SUBSTR już trafił w błąd bufora ciągów zanim dotrze do SUBSTRB. – alchn

7

myślenia Jeffreya proces jest w porządku, ale alchn również ma rację. Właśnie wpadł na ten sam problem i oto moje rozwiązanie. Musisz być w stanie utworzyć funkcję, choć:

Create Or Replace Function clob_substr(p_clob In Clob 
             ,p_offset In Pls_Integer 
             ,p_length In Pls_Integer) Return Varchar2 Is 
Begin 
    Return substrb(dbms_lob.substr(p_clob 
           ,p_length 
           ,p_offset) 
       ,1 
       ,p_length); 
End; 
/

Oto demo na jego zastosowanie:

Select c 
     ,clob_substr(c 
        ,1 
        ,4000) 
    From (

     Select xmlelement("t", rpad('é', 4000, 'é'), rpad('é', 4000, 'é')).extract('//text()').getclobval() c 
      From dual 

     ); 
+1

Stworzyłem kompleksowy (mam nadzieję!) Przykład oparty na tej odpowiedzi w https://bitbucket.org/janihur/orasql-ex/src/tip/clob-2.sql – user272735

+0

Przetestowałem i potwierdziłem, że za pomocą tej funkcji działa lepiej niż rozwiązanie Jeffrey'a. Jednak nie rozumiem dlaczego. Czy to nie robi dokładnie tego samego, ale w funkcji zamiast w linii? Dlaczego to robi różnicę? – KStensland

+0

Podejrzewam, że różnica polega na tym, że varchar2 w PL/SQL może wzrosnąć do 32 767 bajtów, podczas gdy w SQL (przynajmniej w 11g i wcześniejszych) maksymalna to 4.000 bajtów. –