Использование SELECT в операторе SELECT в ORACLE

У меня есть имя таблицы SAMPLETABLE, оно содержит имена таблиц, которые мне нужны, в столбце TABLENAMES. Допустим, имена таблиц TABLEA, TABLEB и TABLEC.

По запросу

SELECT TABLENAMES FROM SAMPLETABLE WHERE ROWNUM = 1

Я получаю вывод столбца TABLENAMES со значением TABLEA.

Моя проблема в том, что теперь я хочу использовать это выбранное значение в операторе выбора. То есть,

SELECT * FROM (SELECT TABLENAMES FROM SAMPLETABLE WHERE ROWNUM = 1) 

Моя идея состоит в том, что он вернет содержимое TABLEA, потому что, когда вложенный SELECT возвращает TABLEA, внешний SELECT должен захватить и отобразить его.

Наоборот, я получаю вывод только внутреннего оператора, то есть

SELECT TABLENAMES FROM SAMPLETABLE WHERE ROWNUM = 1

и

SELECT * FROM (SELECT TABLENAMES FROM SAMPLETABLE WHERE ROWNUM = 1) 

вернуть тот же вывод.

Я хочу, чтобы первый оператор SELECT извлекал возвращаемое значение второго оператора SELECT и отображал таблицу. Приведенный выше запрос этого не делает, так как мне это сделать? А что не так с моей идеей?

Я на Oracle 10g, любая помощь приветствуется.


person iMan    schedule 11.09.2013    source источник
comment
Вы забыли задать вопрос   -  person zerkms    schedule 11.09.2013
comment
Это потому, что вы ничего не делаете с результатом внутреннего запроса.   -  person Vaibhav Desai    schedule 11.09.2013
comment
@Vaibhav Desai, как мне сделать «что-то» с внутренним запросом? Я попытался сохранить переменную, но SELECT * FROM varname возвращает неверное имя таблицы, как мне обойти это. Все, что я хочу, это внутренний результат, который будет использоваться во внешнем SELECT.   -  person iMan    schedule 11.09.2013
comment
Поскольку имя таблицы неизвестно во время компиляции, вам нужно использовать динамический SQL (например, execute immediate, собственный динамический SQL), чтобы иметь возможность выбирать из таблицы, имя которой хранится в виде строкового литерала - вы не можете сделать это со статическим SQL.   -  person Nick Krasnov    schedule 11.09.2013
comment
Как уже указывал Николас, вам нужен динамический sql. Посмотрите на процедуры/функции.   -  person Vaibhav Desai    schedule 11.09.2013
comment
@NicholasKrasnov, не могли бы вы просветить меня? Ссылка, которая может помочь, я нашел ее в OracleDocs, где я могу использовать EXECUTE IMMEDIATE?   -  person iMan    schedule 11.09.2013
comment
@VaibhavDesai, как мне сохранить имя таблицы в переменной? DECLARE tabe1 varchar(20) BEGIN tabe1 := (SELECT query) ? EXEC IMM внешний SELECT? КОНЕЦ;   -  person iMan    schedule 11.09.2013


Ответы (2)


Поскольку имя таблицы неизвестно во время компиляции, вам необходимо использовать динамический SQL (выполнить немедленно, например, собственный динамический SQL), чтобы иметь возможность выбирать из таблицы, имя которой хранится в виде строкового литерала - вы не можете выполнить это со статическим SQL

Вот пример:

-- table which contains names of other tables
-- in the table_name column
SQL> create table Table_Names as
  2    select 'employees' as table_name
  3      from dual
  4  ;
Table created


SQL> set serveroutput on;

-- example of an anonymous PL/SQL block
-- where native dynamic SQL (execute immediate statement)
-- is used to execute a dynamically formed select statement  
SQL> declare
  2    type T_record is record(   -- example of record for fetched data
  3      f_name varchar2(123),    
  4      l_name varchar2(123)
  5    );  
  6  
  7    l_table_name varchar2(123);  -- variable that will contain table name
  8    l_select     varchar2(201);   
  9    l_record     T_Record;       -- record we are going to fetch data into
 10  begin
 11    select table_name
 12      into l_table_name          -- querying a name of a table
 13     from table_names            -- and storing it in the l_table_name variable
 14    where rownum = 1;
 15  
 16    l_select := 'select first_name, last_name from ' ||
 17                 dbms_assert.simple_sql_name(l_table_name) ||   
 18                ' where rownum = 1';   -- forming a query              
 19  
 20    execute immediate l_select    -- executing the query
 21       into l_record;
 22    -- simple output of data just for the sake of demonstration
 23    dbms_output.put_line('First_name: ' || l_record.f_name || chr(10) ||
 24                         'Last name:  ' || l_record.l_name);
 25  exception
 26    when no_data_found
 27    then dbms_output.put_line('Nothing is found');
 28  end;
 29  /

First_name: Steven
Last name:  King

PL/SQL procedure successfully completed

В качестве второго варианта вы можете использовать слабо типизированные курсоры — refcursors для выполнения динамически формируемого оператора select:

SQL> variable refcur refcursor;
SQL> declare
  2    l_table_name varchar2(123);
  3    l_select     varchar2(201);
  4  begin
  5    select table_name
  6      into l_table_name
  7     from table_names
  8    where rownum = 1;
  9  
 10    l_select := 'select first_name, last_name from ' ||
 11                 dbms_assert.simple_sql_name(l_table_name) ||
 12                ' where rownum = 1';
 13  
 14    open :refcur
 15     for l_select;
 16  
 17  exception
 18    when no_data_found
 19    then dbms_output.put_line('Nothing is found');
 20  end;
 21  /

PL/SQL procedure successfully completed.

SQL> print refcur;

FIRST_NAME           LAST_NAME                                                  
-------------------- -------------------------                                  
Steven               King                                                       

SQL> spool off;

Подробнее о курсорах и курсорных переменных

person Nick Krasnov    schedule 11.09.2013
comment
Когда я использую приведенный выше пример (refcursor) в Oracle 10g, я получаю всплывающее окно с предложением ввести значение :REFCUR, что бы я ни вводил, или даже если я оставлю его пустым, оно показывает (неверный оператор SQL), почему это? И почему это утверждение OPEN :REFCUR FOR l_select ? Спасибо - person iMan; 12.09.2013
comment
Всплывающее окно @iMan? Используйте SQLPLUS — интерфейс командной строки. В последнем примере используется SQLPlus. - person Nick Krasnov; 12.09.2013

Вы можете сделать это с помощью динамического sql. Поскольку имя таблицы получается во время выполнения, вам необходимо динамически формировать запрос и запускать его.

Declare
Tab_Name Varchar2(30);
Begin

  SELECT TABLENAMES into Tab_Name FROM SAMPLETABLE WHERE ROWNUM = 1;

  Execute Immediate 'Select * into (Collection Variable) from ' || Tab_Name;

End
/

Я просто привел это как пример. Вы объявляете переменную для получения данных или чего-то еще, что вам нужно. Но когда вы пытаетесь использовать немедленное выполнение с входным параметром, прочитайте о внедрении sql, а затем напишите свой код.

person DB_learner    schedule 11.09.2013
comment
Спасибо за наводку, я посмотрю на это и вернусь, если я застрял в другом месте. - person iMan; 11.09.2013
comment
Я знаю, что это всего лишь пример, но когда я запускаю это в ORA10g, я получаю «Выписка обработана», вы упомянули, что я должен динамически формировать запрос, разве это не то, что делает EXECUTE IMMEDIATE? Если да, то почему бы не работать. При поиске SQL Injection я только теряюсь в более глубоком океане. Любая помощь приветствуется. - person iMan; 12.09.2013
comment
Место, которое я упомянул * в (коллекцию), не является синтаксисом. Я дал это как идею. Вы не можете сделать выбор внутри PL/SQL. Вы должны назначить его коллекции/переменной и распечатать. Ищите немедленное выполнение в синтаксисе коллекции. Вы получите представление о том, как действовать. По этой ссылке есть несколько примеров. docs.oracle.com/cd/B13789_01/appdev.101/ b10807/13_elems017.htm - person DB_learner; 12.09.2013
comment
И для инъекции sql я упоминал об этом, если и когда вы получаете входной параметр и используете его в своем динамическом sql. - person DB_learner; 12.09.2013