3

Any one can help me to resolve the FIXME ?

-- Task: Get records with given rowid IN STRING from a table.
-- NOTICE: I do not known where the given rowid comes from.

-- OUTPUT 'AAAAB0AABAAAAOhAAA'
SELECT ROWID FROM DUAL; 
-- OK, one record
SELECT * FROM DUAL WHERE ROWID IN ('AAAAB0AABAAAAOhAAA');
-- run with no errors, and no records
SELECT INFO_ID FROM TM_INFO_CATALOG  WHERE ROWID IN (SELECT ROWID FROM DUAL);
-- ERROR: ORA-01410 invalid ROWID, WHY ?????????? (This is my sql statement)
SELECT INFO_ID FROM TM_INFO_CATALOG  WHERE ROWID IN ('AAAAB0AABAAAAOhAAA');  -- FIXME

-- Question: How to check an rowid is exists in a table?

-- The following is my way:
-- FIRST, I need check whether the given rowid is from the table to query.
-- OK, but, low performance, as using function 'ROWIDTOCHAR()' (I think so.)
SELECT 1 FROM TM_INFO_CATALOG WHERE 'AAAAB0AABAAAAOhAAA' IN (SELECT ROWIDTOCHAR(ROWID) FROM TM_INFO_CATALOG);
-- ERROR: ORA-01410 
SELECT 1 FROM TM_INFO_CATALOG WHERE 'AAAAB0AABAAAAOhAAA' IN (SELECT ROWID FROM TM_INFO_CATALOG);

-- THEN, select the record using the exist rowid
-- SELECT * from TM_INFO_CATALOG WHERE ROWID = %theGivenRowIdWhichExistInThisTable%

I think I need to emphasize the point:
I just want select the records from a table(such as TABLE_A), if the rowid matches the given rowid.
When all given rowid comes from TABLE_A (which to query), then it is all right.
But, as long as one given rowid comes from other tables (TABLE_B or DUAL, such as), then "ORA-01410 invalid ROWID" occured. I want to FIX this problem.
I wish someone could run the fouth SQL (or annother SQL with the same pattern), then give me your solution. And, What is the difference between the third and the fourth SQL statement except that one is in SQLID type while the other is in STRING type? HOW TO fix the the fourth SQL's problem?

btpka3
  • 3,720
  • 2
  • 23
  • 26

5 Answers5

4

Assuming you have the ROWID in its "Oracle presented" format, it looks like this:

AAACiZAAFAAAAJEAAA

The Oracle format is a Base64 string encoding. Selecting a ROWID from Oracle will result in a Base64 display of the value.

Four pieces of data are encoded in this structure:

  1. The data object number of the object
  2. The datafile in which the row resides (first file is 1).
  3. The data block in the datafile in which the row resides
  4. The position of the row in the data block (first row is 0)

The format is: OOOOOO.FFF.BBBBBB.RRR

  OOOOOO is the object ID
  FFF is the file number
  BBBBBB is the block number
  RRR is the row number

The datafile number is unique in the database. You can retrieve it from the DBA_DATA_FILES view. Each datafile is broken into blocks, and the dba_extents table will give you a segment_name and segment_type for the record.

Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • 1
    Thanks for explain what ROWID is. But I think is not what I am looking for. I want to figure out the record in a table by given ROWID(it may comes from other table) – btpka3 Mar 04 '11 at 11:07
4

You can use a JOIN

select * 
from TABLE a 
     join (select chartorowid('AAAEqwAAEAAAAD/AAA') rid from dual) b 
         on b.rid=a.rowid;
Gary Myers
  • 34,963
  • 3
  • 49
  • 74
  • This SQL may be used to replace the 5th SQL , and has a better performance. – btpka3 Mar 05 '11 at 03:29
  • 1
    Isn't this equivalent to: `select * from TABLE where rowid = chartorowid('AAAEqwAAEAAAAD/AAA')` ? Why use `dual` and `join`? – DigitalDan Oct 31 '22 at 08:44
3

ROWIDs are a special data type not a string. That's we need to use the ROWIDTOCHAR() function.

As the ROWID identifies a specific row in a specific table why would you expect the ROWID from DUAL to match anything in any other table?

ROWID is the faster way of accessing a row. But it is highly unusual to need to wrangle ROWIDs as strings. The more regular way of doing this would be something like:

declare    
    lv_row_id rowid;
    l_blah t23.whatever%type;
begin
    ....
    select rowid into lv_row_id 
    from t23
    where pk_col = 42;

    do_some_stuff;

    update t23
    set whatever = l_blah
    where rowid = lv_row_id;
    ....

But even more normal would be to use the SELECT ... FOR UPDATE syntax, which implicitly uses ROWID without us having to bother.

So, given that what you are trying to do is a bit unusual I think you should explain a bit more about your goals. That way we can help you find the best way of achieving them.

APC
  • 144,005
  • 19
  • 170
  • 281
3

Just a hint:

You wrote "I do not known where the given rowid comes from.".

Well, DBMS_ROWID.ROWID_OBJECT will give you id of the object (and then you can find the object in ALL_OBJECTS view).

Anyway, it seems that although it is not documented you will get the ORA-01410 error each time when you try to use rowid from one table in query against another table. So instead of trying to force oracle to change its behaviour, you can simply wrap your query with some procedural code like:

BEGIN
   SELECT INFO_ID INTO yourvariable
     FROM TM_INFO_CATALOG  
    WHERE ROWID IN (yourrowid);

   do_something_with_yourvariable;

EXCEPTION
  WHEN invalidrowid THEN
     NULL;
END;
/

or

BEGIN
   IF DBMS_ROWID.ROWID_OBJECT(:yourrowid) = id_of_TM_INFO_CATALOG THEN
      SELECT INFO_ID INTO yourvariable
        FROM TM_INFO_CATALOG  
       WHERE ROWID IN (yourrowid);

      do_something_with_yourvariable;
   END IF;
END;
/
Marcin Wroblewski
  • 3,491
  • 18
  • 27
1

It sounds like you may be trying to use ROWIDs to store references between tables. Perhaps you've stored the ROWIDs from one table in another table?

If this is the case, this approach is not correct. ROWIDs are physical pointers and can change without notification. I'm not aware of any situation where it is useful to store ROWIDs as data in any table.

Referential integrity between tables should be implemented by storing a unique identifier (i.e. the column(s) from the target table that have a UNIQUE constraint defined).

Jeffrey Kemp
  • 59,135
  • 14
  • 106
  • 158
  • Yes, but I have a case to store rowid from many other tables. then I need to pick out the records from these table with the rowid. Since every table's primary key is varing from one to another, so store PK may be a better choice. Updating the new rowid is needed if data is migrated from one to annother, or `TRUNCATE TABLE ...` is executing. – btpka3 Mar 08 '11 at 11:52
  • @btpka3, unfortunately your method will not work. Simple as that. ROWIDs can change, and there's no method by which you can detect that and update all your references. You need to store the value of the primary keys from each table. – Jeffrey Kemp Mar 09 '11 at 01:19