2011-03-04 94 views
1

任何人都可以帮我解决FIXME吗?如何从表(Oracle)中获取给定rowid列表中的记录IN STRING?

-- 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% 

我想我需要强调点:
我只是想从一个表(如TABLE_A)选择的记录,如果rowid给定rowid的匹配。
当所有给定的rowid来自TABLE_A(要查询)时,那么它是正确的。
但是,只要给出一个rowid来自其他表(如TABLE_B或DUAL等),则会发生“ORA-01410无效的ROWID”。我想修正这个问题。
我希望有人可以运行第四个SQL(或使用相同模式的其他SQL),然后给我你的解决方案。 而且,第三个和第四个SQL语句除了一个是SQLID类型而另一个是STRING类型之外还有什么区别?如何解决第四个SQL的问题?

+0

您使用的是哪个版本的Oracle?我没有在11.2.0.1.0上运行您的代码时出现任何错误。 – 2011-03-05 02:25:03

回答

2

ROWID是一种特殊的数据类型,不是字符串。这是我们需要使用ROWIDTOCHAR()函数。

由于ROWID标识特定表中的特定行,您为什么期望来自DUAL的ROWID匹配任何其他表中的任何内容?

ROWID是访问行的更快方式。但是,需要将ROWID作为字符串进行争吵是非常不寻常的。这样做的更经常的方法是这样的:

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; 
    .... 

但更正常的是使用the SELECT ... FOR UPDATE syntax,其中隐含使用ROWID没有我们不必理会。

所以,鉴于你想要做的事情有点不寻常,我想你应该多解释一下你的目标。这样我们可以帮助您找到实现它们的最佳方式。

2

只是一个提示:

你写了“我不知道在给定的ROWID来的。”。

那么,DBMS_ROWID.ROWID_OBJECT会给你对象的id(然后你可以在ALL_OBJECTS视图中找到对象)。

无论如何,它似乎虽然没有记录,但您每次尝试在查询中使用一个表中的rowid时,都会得到ORA-01410错误。因此,而不是试图迫使甲骨文改变自己的行为,你可以简单地用一些程序代码包装你的查询,如:

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

    do_something_with_yourvariable; 

EXCEPTION 
    WHEN invalidrowid THEN 
    NULL; 
END; 
/

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; 
/
+0

好吧,实际上,我并不关心给定的ROWID来自何处。反正, – btpka3 2011-03-04 10:34:33

+0

,谢谢。 – btpka3 2011-03-04 11:34:16

3

假设你有ROWID在其“甲骨文提出了”格式,它看起来像这样:

AAACiZAAFAAAAJEAAA 

Oracle格式是Base64字符串编码。从Oracle中选择ROWID将导致Base64显示该值。

四件数据被编码在这样的结构:

  1. 对象
  2. 的数据文件,其中所述行驻留的数据对象号(第一文件为1)。
  3. 在其中行所在
  4. 在数据块的行的位置数据文件的数据块(第一行是0)

的格式是:OOOOOO.FFF.BBBBBB.RRR

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

数据文件号在数据库中是唯一的。您可以从DBA_DATA_FILES视图中检索它。每个数据文件都分成块,dba_extents表将为您提供记录的segment_name和segment_type。

+0

感谢您解释ROWID是什么。但我认为不是我正在寻找的东西。我想通过给定的ROWID(可能来自其他表)计算表中的记录 – btpka3 2011-03-04 11:07:09

1

您可以使用JOIN

select * 
from TABLE a 
    join (select chartorowid('AAAEqwAAEAAAAD/AAA') rid from dual) b 
     on b.rid=a.rowid; 
+0

此SQL可用于替换第5个SQL,并具有更好的性能。 – btpka3 2011-03-05 03:29:02

1

这听起来像你可能会试图使用的ROWID存储表之间的引用。也许你已经从另一个表中的一个表中存储了ROWID?

如果是这种情况,这种方法是不正确的。 ROWID是物理指针,可以在没有通知的情况下更改。我没有意识到将ROWIDs作为数据存储在任何表中的情况。

表之间的参照完整性应该通过存储一个唯一标识符(即来自目标表的已定义约束条件的一列或多列)来实现。

+0

是的,但我有一个案例来存储许多其他表中的rowid。那么我需要用rowid从这些表中挑出记录。由于每个表的主键都是不同的,因此存储PK可能是更好的选择。如果数据从一个迁移到另一个,或者正在执行'TRUNCATE TABLE ...',则需要更新新的rowid。 – btpka3 2011-03-08 11:52:57

+0

@ btpka3,不幸的是你的方法不起作用。就那么简单。 ROWID可以改变,并且没有方法可以检测到并更新所有的引用。您需要存储每个表中主键的值。 – 2011-03-09 01:19:07

相关问题