2013-09-15 2 views
-1

Предполагая, что у меня есть следующая таблица:несколько подзапросов к со столом в Oracle

create table Employee 
    (
    ID     VARCHAR2(4 BYTE)   NOT NULL, 
    First_Name   VARCHAR2(10 BYTE), 
    Last_Name   VARCHAR2(10 BYTE), 
    Start_Date   DATE, 
    End_Date   DATE, 
    Salary    Number(8,2), 
    City    VARCHAR2(10 BYTE), 
    Description  VARCHAR2(15 BYTE) 
) 
    ; 
insert into employee (
ID, First_Name, Last_Name, Start_Date,        
End_Date,      Salary, City,  Description) 
select 21 + (level * 2) - 1,'Jason', 'Martin', to_date('19960725','YYYYMMDD'), 
to_date ('20060725','YYYYMMDD'), 1234.56+level/3*5, 'Toronto', 'Programmer' 
from dual 
connect by level < 2501 
; 

Когда я пытаюсь выполнить следующий запрос:

with tt2 as (
select t.*, 
case when rownum = 1 then 1 when rownum = 3 then 3 else null end rfn 

- РФН является примером для сложного случая, который только присваивает числа строкам, которые необходимы. Пожалуйста, не фиксируем на ней

from (select id, first_name, salary from employee) t 
) 

select 
(select id from tt2 where rfn = 3) w 
from dual 

Он возвращает мне все идентификаторы, похожий на тот, где РФН = 3 (2500 строк 26)

А вот объяснить план

"PLAN_TABLE_OUTPUT" 
"Plan hash value: 2716438026" 
" " 
"--------------------------------------------------------------------------------------------------------" 
"| Id | Operation     | Name      | Rows | Bytes | Cost (%CPU)| Time  |" 
"--------------------------------------------------------------------------------------------------------" 
"| 0 | SELECT STATEMENT   |       | 2500 |  | 12 (0)| 00:00:01 |" 
"|* 1 | VIEW      |       | 2500 | 42500 |  4 (0)| 00:00:01 |" 
"| 2 | TABLE ACCESS FULL  | SYS_TEMP_0FD9D6645_8CDDE2 | 2500 | 60000 |  4 (0)| 00:00:01 |" 
"| 3 | TEMP TABLE TRANSFORMATION |       |  |  |   |   |" 
"| 4 | LOAD AS SELECT   | SYS_TEMP_0FD9D6645_8CDDE2 |  |  |   |   |" 
"| 5 | COUNT     |       |  |  |   |   |" 
"| 6 |  TABLE ACCESS FULL  | EMPLOYEE     | 2500 | 60000 |  8 (0)| 00:00:01 |" 
"| 7 | VIEW      |       | 2500 |  |  4 (0)| 00:00:01 |" 
"| 8 | TABLE ACCESS FULL  | SYS_TEMP_0FD9D6645_8CDDE2 | 2500 | 60000 |  4 (0)| 00:00:01 |" 
"--------------------------------------------------------------------------------------------------------" 
" " 
"Predicate Information (identified by operation id):" 
"---------------------------------------------------" 
" " 
" 1 - filter(""RFN""=3)" 
" " 
"Note" 
"-----" 
" - dynamic sampling used for this statement (level=2)" 

--edit--

например у меня есть таблица с использованием:

 
"ID" "FIRST_NAME" "SALARY"  "RFN" 
"22" "Jason"  1236.23   1 
"24" "Jason"  1237.89 
"26" "Jason"  1239.56   3 

Я хочу, чтобы выбрать Зарплату от тех, кто с RFN = 1, что дает мне один номер 1236,23

Но я также хочу в том же запросе, чтобы выбрать Заработную плату enyone с RFN = 3, дает мне один номер 1239.56 ,

И так далее.

Но. Для каждого из этих запросов он делает FULL_TABLE_SCAN из N строк.

with tt2 as (
select t.*, case when rownum = 1 then 1 when rownum = 3 then 3 else null end rfn 
from (select id, first_name, salary from employee) t 
) 
select 
(select salary from tt2 where rfn = 1) w, 
(select salary from tt2 where rfn = 3) w 
from dual 

таблица объяснения:

('Plan hash value: 1823688231'); 
(' '); 
('--------------------------------------------------------------------------------------------------------'); 
('| Id | Operation     | Name      | Rows | Bytes | Cost (%CPU)| Time  |'); 
('--------------------------------------------------------------------------------------------------------'); 
('| 0 | SELECT STATEMENT   |       | 2500 |  | 12 (0)| 00:00:01 |'); 
('|* 1 | VIEW      |       | 2500 | 40000 |  4 (0)| 00:00:01 |'); 
('| 2 | TABLE ACCESS FULL  | SYS_TEMP_0FD9D6651_8CDDE2 | 2500 | 60000 |  4 (0)| 00:00:01 |'); 
('|* 3 | VIEW      |       | 2500 | 40000 |  4 (0)| 00:00:01 |'); 
('| 4 | TABLE ACCESS FULL  | SYS_TEMP_0FD9D6651_8CDDE2 | 2500 | 60000 |  4 (0)| 00:00:01 |'); 
('| 5 | TEMP TABLE TRANSFORMATION |       |  |  |   |   |'); 
('| 6 | LOAD AS SELECT   | SYS_TEMP_0FD9D6651_8CDDE2 |  |  |   |   |'); 
('| 7 | COUNT     |       |  |  |   |   |'); 
('| 8 |  TABLE ACCESS FULL  | EMPLOYEE     | 2500 | 60000 |  8 (0)| 00:00:01 |'); 
('| 9 | VIEW      |       | 2500 |  |  4 (0)| 00:00:01 |'); 
('| 10 | TABLE ACCESS FULL  | SYS_TEMP_0FD9D6651_8CDDE2 | 2500 | 60000 |  4 (0)| 00:00:01 |'); 
('--------------------------------------------------------------------------------------------------------'); 
(' '); 
('Predicate Information (identified by operation id):'); 
('---------------------------------------------------'); 
(' '); 
(' 1 - filter("RFN"=1)'); 
(' 3 - filter("RFN"=3)'); 
(' '); 
('Note'); 
('-----'); 
(' - dynamic sampling used for this statement (level=2)'); 

--edited для более clarification--

Ожидаемый результат от:

 
"ID" "FIRST_NAME" "SALARY"  "RFN" 
"22" "Jason"  1236.23   1 
"24" "Jason"  1237.89 
"26" "Jason"  1239.56   3 
"26" "Jack"   1249.56   6 
"26" "Wiki"   119.56   8 
 
salary salary1 salary2 name name2 
1236.23 1249.56 119.56 Wiki Jack 

из ~ следующего утверждения:

with tt2 as (
select t.*, case when row_number() over (order by id) = 1 then 1 when row_number() over  (order by id) = 3 then 3 else null end rfn 
from (select id, first_name, salary from employee) t 
) 
select 
(select salary from tt2 where rfn = 1) salary, 
(select salary from tt2 where rfn = 6) salary1, 
(select salary from tt2 where rfn = 8) salary2, 
(select first_name from tt2 where rfn = 8) name, 
(select first_name from tt2 where rfn = 6) name2 

from dual 

без 5 полных таблиц развертки 2500 строк

+0

Этот код очень трудно следовать, возможно, потому что смысл его полностью скрыт абстракции, который вы используете. Оператор case, основанный на rownum, который вы комментируете как «Только пример», ничего не значит в контексте запроса, который вы выбираете.Можете ли вы объяснить смысл всего этого и какую проблему вы на самом деле пытаетесь решить здесь? –

+0

Я создаю временную таблицу в WITH. Затем через CASE я назначаю конкретные разные числа для каждой строки в этой таблице. Чем я хочу выбрать определенные значения из этой таблицы. По вновь приобретенному номеру. – Fate

+1

Вы все еще не объяснили, что вы на самом деле пытаетесь сделать. И почему ROW_NUMBER не работает, это рекомендуется для ROWNUM. Btw, «странная причина» не странная, это именно то, что вы написали: верните одинаковый идентификатор для всех строк. – dnoeth

ответ

0

Вы спрашивающие для всех строк, вы должны изменить на:

with tt2 as (
select t.*, case when rownum = 1 then 1 when rownum = 3 then 3 else null end rfn 
from (select id, first_name, salary from employee) t 
) 
select salary from tt2 where rfn in (1,3) 

Но почему хотите этот результат? ROWNUM не является детерминированным без ORDER BY, у него не гарантируется одинаковый порядок каждый раз. Вы probablly должны использовать ROW_NUMBER как:

WITH tt2 AS (SELECT t.*, ROW_NUMBER() OVER (ORDER BY ID) rn) 
SELECT salary 
FROM tt2 
WHERE rn IN (1,3) 
+0

Это абсолютно не то, что я хочу. И «случай, когда row_number() over (order by id) = 1, а затем 1, когда row_number() over (order by id) = 3, тогда 3 else null end rfn 'не будет иметь никакого значения ни в моем случае. Это пример сложного случая, который только делает номера строк необходимыми. Пожалуйста, не исправляйте это. – Fate

+0

CASE WHEN не уменьшит количество обработанных строк. это просто сложнее для оптимизатора. И вы никогда не должны судить о плане для небольшого стола, лучше проверьте его на большой стол, тогда оптимизатор может приложить больше усилий в этом плане. – dnoeth

+0

Это просто пример. Мой основной запрос занимает ~ 15-30 секунд для запуска, а таблица WITH в этом запросе занимает всего 1,3 секунды. И у него было намного больше 2,5 тыс. Строк. – Fate

Смежные вопросы