140

I am trying to see from an SQL console what is inside an Oracle BLOB.

I know it contains a somewhat large body of text and I want to just see the text, but the following query only indicates that there is a BLOB in that field:

select BLOB_FIELD from TABLE_WITH_BLOB where ID = '<row id>';

the result I'm getting is not quite what I expected:

    BLOB_FIELD
    -----------------------
    oracle.sql.BLOB@1c4ada9

So what kind of magic incantations can I do to turn the BLOB into it's textual representation?

PS: I am just trying to look at the content of the BLOB from an SQL console (Eclipse Data Tools), not use it in code.

Roland Tepp
  • 8,301
  • 11
  • 55
  • 73

12 Answers12

167

First of all, you may want to store text in CLOB/NCLOB columns instead of BLOB, which is designed for binary data (your query would work with a CLOB, by the way).

The following query will let you see the first 32767 characters (at most) of the text inside the blob, provided all the character sets are compatible (original CS of the text stored in the BLOB, CS of the database used for VARCHAR2) :

select utl_raw.cast_to_varchar2(dbms_lob.substr(BLOB_FIELD)) from TABLE_WITH_BLOB where ID = '<row id>';
Mac
  • 8,191
  • 4
  • 40
  • 51
  • 5
    Unfortunately, I do not control the database schema - I just need to peek into the blob... But thanks anyway. – Roland Tepp May 07 '09 at 06:32
  • Thanks Mac, that works fine --- But what is the purpose of that "dbms_lob.substr"? --- Only using "select utl_raw.cast_to_varchar2(BLOB_FIELD) ..." seems to give me the same result...? – Rop Aug 18 '13 at 19:18
  • 5
    cast_to_varchar2 takes a RAW in input (http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/u_raw.htm#autoId18), which is limited to 32767 bytes in length (http://docs.oracle.com/cd/E11882_01/appdev.112/e10472/datatypes.htm#autoId8). A BLOB has no limitation in size, so substr truncates it to a correct size (http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/d_lob.htm#autoId57) if necessary. – Mac Aug 19 '13 at 06:01
  • 44
    Doesn't work for me - I get "ORA-06502: PL/SQL: numeric or value error: raw variable length too long". I can put "2000,1" after BLOB_FIELD to get up to 2000 chars, but nothing beyond that. – Mark Sep 12 '13 at 13:26
  • 3
    if the value is longer than 4000 it will throw errors since that's max value for strings in sql. you need to add substr(BLOB_FIELD, 4000, 1). If yo u need longer field support use PL/SQL (up to 32000 I believe) – Sonic Soul May 13 '14 at 13:29
  • Can LZ_UNCOMPRESS be used with any of these BLOB fields via SQL - or does that strictly require use of the procedural language SQL of Oracle? – Praxiteles Jan 07 '20 at 23:56
  • it gives me "ORA-00904: "URL_RAW"."CAST_TO_VARCHAR2": invalid identifier" error – Line Jun 08 '21 at 14:23
33

SQL Developer provides this functionality too :

Double click the results grid cell, and click edit :

enter image description here

Then on top-right part of the pop up , "View As Text" (You can even see images..)

enter image description here

And that's it!

enter image description here

nullPointer
  • 4,419
  • 1
  • 15
  • 27
18

You can use below SQL to read the BLOB Fields from table.

SELECT DBMS_LOB.SUBSTR(BLOB_FIELD_NAME) FROM TABLE_NAME;
Hemang
  • 26,840
  • 19
  • 119
  • 186
Imran Patel
  • 181
  • 1
  • 2
  • 3
    I have BLOB column and where the XML data is compressed and stored in the table, when I read the data, it shows only some numbers and not actual xml text, what should I do to read the XML text data from table. – BHUVANESH MOHANKUMAR Aug 21 '19 at 15:24
  • 2
    This is not working,raw variable length too long error – Mert Serimer Oct 20 '20 at 09:10
12

Use this SQL to get the first 2000 chars of the BLOB.

SELECT utl_raw.cast_to_varchar2(dbms_lob.substr(<YOUR_BLOB_FIELD>,2000,1)) FROM <YOUR_TABLE>;

Note: This is because, Oracle will not be able to handle the conversion of BLOB that is more than length 2000.

Swapnil Ingle
  • 151
  • 1
  • 4
8

If you want to search inside the text, rather than view it, this works:

with unzipped_text as (
  select
    my_id
    ,utl_compress.lz_uncompress(my_compressed_blob) as my_blob
  from my_table
  where my_id='MY_ID'
)
select * from unzipped_text
where dbms_lob.instr(my_blob, utl_raw.cast_to_raw('MY_SEARCH_STRING'))>0;
Barn
  • 946
  • 12
  • 16
  • what is my_id here ? – anjanb Nov 28 '17 at 15:55
  • This is not working for me, I have BLOB column and where the XML data is compressed and stored in the table, when I read the data, it shows only some numbers and not actual xml text, what should I do to read the XML text data from table. – BHUVANESH MOHANKUMAR Aug 21 '19 at 15:24
7

I can get this to work using TO_CLOB (docs):

select 
  to_clob(BLOB_FIELD)
from 
  TABLE_WITH_BLOB 
where 
  ID = '<row id>';

This works for me in Oracle 19c, with a BLOB field which larger the the VARCHAR limit. I get readable text (from a JSON-holding BLOB)

phhu
  • 1,462
  • 13
  • 33
4

Barn's answer worked for me with modification because my column is not compressed. The quick and dirty solution:

select * from my_table
where dbms_lob.instr(my_UNcompressed_blob, utl_raw.cast_to_raw('MY_SEARCH_STRING'))>0;
Pecos Bill
  • 1,628
  • 1
  • 11
  • 9
3

I struggled with this for a while and implemented the PL/SQL solution, but later realized that in Toad you can simply double click on the results grid cell, and it brings up an editor with contents in text. (i'm on Toad v11)

enter image description here

Sonic Soul
  • 23,855
  • 37
  • 130
  • 196
3

In case your text is compressed inside the blob using DEFLATE algorithm and it's quite large, you can use this function to read it

CREATE OR REPLACE PACKAGE read_gzipped_entity_package AS

FUNCTION read_entity(entity_id IN VARCHAR2)
  RETURN VARCHAR2;

END read_gzipped_entity_package;
/

CREATE OR REPLACE PACKAGE BODY read_gzipped_entity_package IS

FUNCTION read_entity(entity_id IN VARCHAR2) RETURN VARCHAR2
IS
    l_blob              BLOB;
    l_blob_length       NUMBER;
    l_amount            BINARY_INTEGER := 10000; -- must be <= ~32765.
    l_offset            INTEGER := 1;
    l_buffer            RAW(20000);
    l_text_buffer       VARCHAR2(32767);
BEGIN
    -- Get uncompressed BLOB
    SELECT UTL_COMPRESS.LZ_UNCOMPRESS(COMPRESSED_BLOB_COLUMN_NAME)
    INTO   l_blob
    FROM   TABLE_NAME
    WHERE  ID = entity_id;

    -- Figure out how long the BLOB is.
    l_blob_length := DBMS_LOB.GETLENGTH(l_blob);

    -- We'll loop through the BLOB as many times as necessary to
    -- get all its data.
    FOR i IN 1..CEIL(l_blob_length/l_amount) LOOP

        -- Read in the given chunk of the BLOB.
        DBMS_LOB.READ(l_blob
        ,             l_amount
        ,             l_offset
        ,             l_buffer);

        -- The DBMS_LOB.READ procedure dictates that its output be RAW.
        -- This next procedure converts that RAW data to character data.
        l_text_buffer := UTL_RAW.CAST_TO_VARCHAR2(l_buffer);

        -- For the next iteration through the BLOB, bump up your offset
        -- location (i.e., where you start reading from).
        l_offset := l_offset + l_amount;
    END LOOP;
    RETURN l_text_buffer;
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('!ERROR: ' || SUBSTR(SQLERRM,1,247));
END;

END read_gzipped_entity_package;
/

Then run select to get text

SELECT read_gzipped_entity_package.read_entity('entity_id') FROM DUAL;

Hope this will help someone.

1

You can try this:

SELECT TO_CHAR(dbms_lob.substr(BLOB_FIELD, 3900)) FROM TABLE_WITH_BLOB;

However, It would be limited to 4000 byte

Reza Rahimi
  • 583
  • 6
  • 6
-2

Worked for me,

select lcase((insert( insert( insert( insert(hex(BLOB_FIELD),9,0,'-'), 14,0,'-'), 19,0,'-'), 24,0,'-'))) as FIELD_ID from TABLE_WITH_BLOB where ID = 'row id';

  • If this worked for you then you are not using Oracle, which the OP is and that's why the answers need to be valid Oracle syntax. – APC Apr 15 '19 at 09:28
-5

Use TO_CHAR function.

select TO_CHAR(BLOB_FIELD) from TABLE_WITH_BLOB where ID = '<row id>'

Converts NCHAR, NVARCHAR2, CLOB, or NCLOB data to the database character set. The value returned is always VARCHAR2.

Michael Dillon
  • 1,037
  • 6
  • 16
Alex
  • 75
  • 1
  • 4