КАК получить записи с заданным списком строк IN STRING из таблицы (Oracle)? - PullRequest
2 голосов
/ 04 марта 2011

Кто-нибудь может помочь мне решить 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%

Я думаю, мне нужно подчеркнуть точку:
Я просто хочу выбрать записи из таблицы (например, TABLE_A), если rowid соответствует заданному rowid.
Когда все данные rowid поступают из TABLE_A (для запроса), тогда все в порядке.
Но если один данный идентификатор строки поступает из других таблиц (TABLE_B или DUAL ,, например), то "ORA-01410 invalid ROWID" происходит. Я хочу исправить эту проблему.
Я хотел бы, чтобы кто-то мог запустить полный SQL (или другой SQL с тем же шаблоном), а затем дать мне ваше решение. И в чем разница между третьим и четвертым оператором SQL, за исключением того, что один тип SQLID, а другой тип STRING? КАК исправить проблему с четвертым SQL?

Ответы [ 5 ]

3 голосов
/ 04 марта 2011

Вы можете использовать JOIN

select * 
from TABLE a 
     join (select chartorowid('AAAEqwAAEAAAAD/AAA') rid from dual) b 
         on b.rid=a.rowid;
3 голосов
/ 04 марта 2011

Предполагая, что у вас есть ROWID в формате «представленный Oracle», он выглядит следующим образом:

AAACiZAAFAAAAJEAAA

Формат Oracle - это строковое кодирование Base64.Выбор ROWID в Oracle приведет к отображению значения 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 предоставит вам имя сегмента и тип сегмента для записи.

3 голосов
/ 04 марта 2011

ROWID - это специальный тип данных, а не строка. Вот и нам нужно использовать функцию ROWIDTOCHAR().

Поскольку ROWID идентифицирует конкретную строку в конкретной таблице, почему вы ожидаете, что ROWID из DUAL будет совпадать с чем-либо в любой другой таблице?

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

Но еще более нормальным было бы использование синтаксиса SELECT ... FOR UPDATE , который неявно использует ROWID без нас.

Итак, учитывая, что то, что вы пытаетесь сделать, немного необычно, я думаю, вам следует немного подробнее рассказать о своих целях. Таким образом, мы можем помочь вам найти лучший способ их достижения.

2 голосов
/ 04 марта 2011

Просто намек:

Вы написали: «Я не знаю, откуда взялся данный rowid».

Хорошо, DBMS_ROWID.ROWID_OBJECT даст вам идентификатор объекта (а затем вы сможете найти объект в представлении ALL_OBJECTS).

В любом случае, кажется, что, хотя это не задокументировано, вы будете получать ошибку ORA-01410 каждый раз, когда пытаетесь использовать rowid из одной таблицы в запросе к другой таблице. Таким образом, вместо того, чтобы пытаться заставить oracle изменить свое поведение, вы можете просто обернуть ваш запрос некоторым процедурным кодом, например:

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;
/
1 голос
/ 07 марта 2011

Похоже, вы пытаетесь использовать ROWID для хранения ссылок между таблицами. Возможно, вы сохранили ROWID из одной таблицы в другой таблице?

Если это так, такой подход не верен. ROWID являются физическими указателями и могут изменяться без уведомления. Я не знаю ни одной ситуации, когда было бы полезно хранить ROWID как данные в любой таблице.

Ссылочная целостность между таблицами должна быть реализована путем сохранения уникального идентификатора (то есть столбца (столбцов) из целевой таблицы, для которых определено ограничение UNIQUE).

...