2016-03-08 48 views
3

對於所有人「OMG!他正在使用圖像:O:O:O」人(原文發表於此):SQL(ORACLE):使用2個或更多相關/配對容器查詢「指針」的內部查詢

我有一個表:

date1 | id1 | value 
date1 | id2 | value 
date1 | id3 | value 
date1 | id4 | value 
------------------- 
date2 | id1 | value 
date2 | id2 | value 
date2 | id5 | value 
date2 | id7 | value 
------------------- 
date3 | id4 | value 
date3 | id5 | value 
date3 | id10 | value 
date3 | id11 | value 
------------------- 
... 
------------------- 
dateN | id1 | value 
dateN | id2 | value 
dateN | id3 | value 
dateN | id4 | value 

,如被輸入:

date: X - ids: 2, 3 
date: Y - ids: 4 
date: Z - ids: 2, 4, 5 
... 

需要一個單一的查詢(非PL,非條件語句,變量或光標......)帶來對於每一個日期d它自己的每一個ID,日期的一行以及具有VALUE的ID。如果日期沒有其特定ID的值,則必須找到最近的日期。

即:

date: 06/03/2016 - ids: 5, 6 

結果:

06/03/2016|5|value 
04/03/2016|6|value 

第二結果行具有不同的日期,因爲還沒有發現日期2016年6月3日和ID = 6的記錄。這就是爲什麼帶來最匹配的日期。噢!和最接近我的意思是,之前。不是在約會之後。因此,如果日期不匹配,則指定的日期日期或最近的日期。

我可以爲每一行輸入創建一個查詢,最後從all'em創建一個UNION。但這不是一個解決問題的優雅方法。並且在每個循環上拋出查詢都會啓用PHP並不是一個選項。




原來的線程:

早上好,首先,請原諒我的英語請,因爲我來自西班牙。

說,我要儘量簡明,並在最後這個問題,但首先,讓我暴露environtment:

  • 我有一個tipical日期/數據類型/值表。

enter image description here

  • 我用紅線去日期變更塊劃分視覺。藍色箭頭標記「數據類型」ID(來自另一個表)列,另一個藍色箭頭標記與這些值相關的日期。 所以你有不同的type-id的日期塊,每一個你有一個變化值(CAMBIO):綠色箭頭。

現在,我能做什麼?這給我的坎比奧值某些特定日期的查詢:

enter image description here

注意:GRUPO是表中存在的另一列,我總是需要從這個GRUPO型,1的值。這是必要的。

下一步是,可能發生的情況是,對於指定的DATE,不存在表記錄上的值。所以我必須找到最接近的一個。

我可以做這樣的查詢:

enter image description here

你可以第一個圖像上看到,有對3月6日和3月5日沒有記錄,所以通過這個查詢,我可以去最現有的最接近的價值,在這種情況下,與3月4日相同

與查詢的問題是,我需要指定DIVISA_C柱爲特定值,假設5和10。然後我colud經歷這樣的:

enter image description here

這對於作品不錯現有的DIVISA_C ids上的結果,但如果我需要一個不包含在「日期塊」(即:2016-03-04)中的ID,我們說6,那麼我得不到這個DIVISA_C ID的結果,並且我需要才能得到它的結果,具體地說,就是我之前展示的最接近的日期。

如果我做的:

enter image description here

沒有談到這6 ID。與上次查詢結果相同。 在這種情況下,我知道如何解決過的東西:

enter image description here

你看,我已經從內部查詢到自DIVISA_C ID的WHERE增加了一個「指針」,基本上分從ourtsider/container查詢到DIVISA_C。這會導致對於內部查詢中的指定DATE,容器查詢「IN列表」中的每個單個ID都會按預期方式帶來最可能的關聯行。因此,如果內部查詢可以爲指定的DIVISA_C標識解析指定的日期,它會帶來記錄。否則,爲DIVISA_C id值帶來最接近的日期。這是我所需要的。

NOTE:我在內部查詢中添加了一些額外的過濾器,以與外部/容器查詢保持一致。根本不是問題或變化。現在

,解釋說,來這裏的真正的問題:

- 現在我已經日期列表,併爲每一個這些日期的,DIVISA_C ID的列表。我需要做一個查詢,沒有PL-SQL(所以沒有FOR,沒有IF,沒有CURSORS等等),只是一個SELECT組合,它帶給我預期的結果,基本上這是最後一個我已經向你展示了結果,但是與他們相關的DIVISA_C ID列表有很多日期。

要和榜樣,我已經表現出了最後的查詢可以像這樣解釋:

date: 06/03/2016 - divisa_c ids: 5, 6, 10 

,這給我帶來了3排,aproximated日期爲每個ID在這種情況下,3月6日不有任何DIVISA_C ID的記錄。

現在,我認爲必須只用一個單一的查詢需要解決的一個完整的輸入列表,即:

date: 06/03/2016 - divisa_c ids: 5, 6, 10 
date: 05/02/2016 - divisa_c ids: 5 
date: 03/02/2016 - divisa_c ids: 5, 6 
date: 01/01/2016 - divisa_c ids: 6, 10 
date: 31/12/2015 - divisa_c ids: 4, 6, 10, 12 
date: 24/10/2015 - divisa_c ids: 3, 4, 5, 11 
... 

當然,我可以拍在每個PHP迴路轉單查詢多達輸入列表具有的行。

或者我可以創建每個單一的查詢與列表上的輸入行,並作出所有的聯合國教育,以創建一個masive長字符串查詢將給我精確的結果,我需要,但這不是選項。 我需要一個更更高雅的方式來解決這個問題,在這裏我卡住了... :(

我雖然已經像這樣的東西:

enter image description here

你看,在外部WHERE上的某種「鏈接」數據包,這會導致內部查詢爲每個關聯日期解析DIVISA_C IN列表中的所有行,而在內部查詢中,DATE也是一個指針......但是就你而言可以想象這不起作用,因爲內部查詢通過FECHA =(子查詢...)在哪裏鏈接,並且沒有意義在此之後我寫的數據包...

我以爲創建一個INNER連接上的異常查詢到同一個表,所以表反對自己有2個指針不知何故,並結合他們的情況......但我不知道該怎麼辦它正確...

你能給我點亮這個嗎?

感謝所有人,對於長篇文章感到抱歉!但我認爲通過圖像解釋它更加舒適。

Greetings,

Mark。

+0

http://meta.stackoverflow.com/questions/285551/why-may-i-not上傳圖片的代碼時,要求提問/ 285557#285557 –

+0

@a_horse_with_no_name來吧。在這個特殊情況下,圖片只是爲了展示。沒有用的其他任何東西。問題可以直接拋出,根本不顯示任何示例。是帖子中最後一條粗體文字。那些在這裏可以直觀地證明我在問什麼。 – Lightworker

+0

@Lightworker不是所有人都能看到圖像(例如,它們被防火牆阻擋),所以通過使用它們,您可以在格式化文本中提供相同信息,從而防止某些人能夠幫助您。 – Boneist

回答

2

使用row_number()可以查找最近幾天的值。在with子句中定義了輸入參數,在我使用的測試數據中('2016-03-04',(5)),('2016-03-06',(5)),('2016-03-07' (5,6,10))。不需要Id,我說這爲清楚:

with t as ( 
    select 1 id, date '2016-03-04' fecha, 5 divisa from dual union all 
    select 2 id, date '2016-03-06' fecha, 5 divisa from dual union all 
    select 3 id, date '2016-03-07' fecha, 5 divisa from dual union all 
    select 3 id, date '2016-03-07' fecha, 6 divisa from dual union all 
    select 3 id, date '2016-03-07' fecha,10 divisa from dual) 
select * from (
    select cd.*, t.fecha input_fecha, t.divisa input_divisa, 
     row_number() over (partition by t.fecha, t.divisa order by t.fecha-cd.fecha) rn 
    from cotizaciones_div cd 
    join t on cd.divisa_c = t.divisa and cd.grupo = 1 and cd.fecha<=t.fecha) 
    where rn=1 order by input_fecha, input_divisa 

定義輸入參數,你也可以使用類型sys.odcinumberlist,如果你更舒適的(它可以縮短語法時帝維名單很長),喜歡這裏:

select 1 id, date '2016-03-04' fecha, column_value as divisa 
    from table(sys.odcinumberlist(5)) union all 
    select 2 id, date '2016-03-06' fecha, column_value as divisa 
    from table(sys.odcinumberlist(5)) union all 
    select 3 id, date '2016-03-07' fecha, column_value as divisa 
    from table(sys.odcinumberlist(5, 6, 10)) 

測試數據和輸出:

create table cotizaciones_div (codigo number(8), divisa_o number(3), divisa_c number(3), 
    fecha date, cambio number(12, 4), grupo number(3)); 

insert into cotizaciones_div values (1000, 4, 11, date '2016-01-01', 0.5123, 8); 
insert into cotizaciones_div values (2273, 15, 6, date '1998-12-31', 0,  1); 
insert into cotizaciones_div values (63289, 4, 5, date '2016-03-04', 1.0998, 1); 
insert into cotizaciones_div values (63297, 4, 10, date '2016-03-04', 7.4622, 1); 
insert into cotizaciones_div values (63290, 4, 11, date '2016-03-04', 0.7738, 1); 
insert into cotizaciones_div values (63309, 4, 5, date '2016-03-07', 1.1016, 1); 
insert into cotizaciones_div values (63317, 4, 10, date '2016-03-07', 7.4619, 1); 
insert into cotizaciones_div values (63310, 4, 11, date '2016-03-07', 0.7724, 1); 

    CODIGO DIVISA_O DIVISA_C FECHA    CAMBIO GRUPO INPUT_FECHA INPUT_DIVISA 
--------- -------- -------- ----------- -------------- ----- ----------- ------------ 
    63289  4  5 2016-03-04   1,0998  1 2016-03-04    5 
    63289  4  5 2016-03-04   1,0998  1 2016-03-06    5 
    63309  4  5 2016-03-07   1,1016  1 2016-03-07    5 
    2273  15  6 1998-12-31   0,0000  1 2016-03-07    6 
    63317  4  10 2016-03-07   7,4619  1 2016-03-07   10 
+0

男人......你太棒了!你真的有一個很棒的Oracle級別,就像你真正在這裏展示的那樣。請您花一點時間來解釋一下它的工作原理和原理?也許編輯帖子並添加一些額外的信息/提示?我很想真正理解哪個是超越它的魔法...... :)也許row_number()部分,你如何命令它,以及正在做什麼。還有你怎麼做INNER JOIN呢。再次感謝!! – Lightworker

+1

對於每個元組(input_date,divisa),我正在檢查日期的差異(input_date和fecha)。 Row_number()使用'partition by'子句「組織」這些差異,並用'order by'子句對這些行進行「排序」,因此與input_date最接近的日期的值最小。我們只對RN = 1的行感興趣。鏈接到[rownumber()](https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions137.htm)文檔,也請查看其他分析功能和例子。 –