2012-01-09 122 views
4

這看起來可能很簡單,但不知怎的,事實並非如此。我有一個名爲TBL_A歷史匯率數據表看起來像這樣:Oracle加入子查詢的第一行

| id | rate | added_date | 
|--------|--------|--------------| 
| bill | 7.50 | 1/24/2011 | 
| joe | 8.50 | 5/3/2011 | 
| ted | 8.50 | 4/17/2011 | 
| bill | 9.00 | 9/29/2011 | 

在TBL_B,我有需要,以獲得成本信息要加入到TBL_A單行小時:

| id | hours | added_date | 
|--------|---------|--------------| 
| bill | 10 | 2/26/2011 | 
| ted | 4  | 7/4/2011 | 
| bill | 9  | 10/14/2011 | 

正如您所看到的,對於比爾,TBL_A有兩種費率,但他們有不同的日期。要在一段時間內正確獲取Bill的成本,您必須將每行TBL_B連接到適合該日期的TBL_A的一行中。

我覺得這很容易;因爲這不需要特別快速的查詢,所以我可以爲成本信息的每一行執行一個單獨的子查詢。但是,加入子查詢顯然不能「看到」他們加入的其他表。這個查詢在具有「H」別名的子查詢上的任何東西拋出一個無效的標識符(ORA-00904):

SELECT h.id, r.rate * h.hours as "COST", h.added_date 
    FROM TBL_B h 
    JOIN (SELECT * FROM (
       SELECT i.id, i.rate 
        FROM TBL_A i 
       WHERE i.id = h.id and i.added_date < h.added_date 
       ORDER BY i.added_date DESC) 
      WHERE rownum = 1) r 
     ON h.id = r.id 

如果問題僅僅是範圍界定,我不知道如果我的做法了以往任何時候都可以工作。但是我想在這裏做的是根據一些標準獲得單行,所以我絕對可以使用其他方法。

編輯:所需的輸出會是這樣:

| id | cost | added_date | 
|--------|---------|--------------| 
| bill | 75 | 2/26/2011 | 
| ted | 34 | 7/4/2011 | 
| bill | 81 | 10/14/2011 | 

注意,比爾在表格中的兩個條目兩個不同的利率。第一行是10 * 7.50 = 75和第二行是9 * 9.00 = 81

+0

什麼是期望的輸出?小時數的總和? – 2012-01-09 17:08:42

+0

我想這是模糊的,我編輯我的問題是更具體。 – monitorjbl 2012-01-09 17:39:16

回答

4

嘗試使用not exists

select 
    b.id, 
    a.rate, 
    b.hours, 
    a.rate*b.hours as "COST", 
    b.added_date, 
    a.added_date 
from 
    tbl_b b 
    inner join tbl_a a on 
     b.id = a.id 
where 
    a.added_date < b.added_date 
    and not exists (
     select 
      1 
     from 
      tbl_a a2 
     where 
      a2.added_date > a.added_date 
      and a2.added_date < b.added_date 
      and a2.id = a.id 
     ) 

如爲什麼發生這種情況的說明:只有相關子都知道的他們正在運行的上下文,因爲它們是針對每一行運行的。連接的子查詢實際上是在連接之前執行的,所以它不知道周圍的表。您需要返回所有標識信息以使聯接處於查詢的頂層,而不是嘗試在子查詢中執行聯接。

+0

謝謝你的解釋,這非常有啓發性,並完全解釋了爲什麼我的代碼不工作。不過,這種方法也行不通。你看,在我的帖子的例子中,Bill有一行需要以「7.50」的價格加入。使用您發佈的代碼,該代碼的row_number()值爲2,因此將被完全排除。除非在WHERE子句中包含某種方法,否則我認爲我需要一些將值注入子查詢本身的方法。「如果這會返回X行數」,那麼這肯定違反了SQL規範。 – monitorjbl 2012-01-09 18:05:49

+0

@monitorjbl - 啊,gotcha。我用'not exists'做了這個,它可以幫助你。這個謂詞是在表格計算完成後完成的,所以你可以使用它們的列。這也相當快。我用臨時表做了這件事,它帶回了預期的結果。 – Eric 2012-01-09 18:28:09

+0

啊哈!這很好,謝謝一堆。我不知道「存在」關鍵字,每天都要學習新東西! – monitorjbl 2012-01-09 19:15:30

1
select id, cost, added_date from (
select 
    h.id, 
    r.rate * h.hours as "COST", 
    h.added_date, 
    -- For each record, assign r=1 for 'newest' rate 
    row_number() over (partition by h.id, h.added_date order by r.added_date desc) r 
from 
    tbl_b h, 
    tbl_a r 
where 
    r.id = h.id and 
    -- Date of rate must be entered before 
    -- hours billed: 
    r.added_date < h.added_date 
) 
where r = 1 
; 
+0

謝謝你的回答,雷內。不幸的是,這是行不通的。 Eric在編輯之前採取了同樣的方法,並且在他的文章中留下了評論,解釋爲什麼它不起作用。 – monitorjbl 2012-01-09 19:11:52

+0

據我所見,這與Eric的走向不一樣,我仍然相信它會按照你的意圖行事。埃裏克在編輯他的答案之前有一個不同的疑問。 – 2012-01-09 19:48:18

+0

Eric的第一個查詢與您的查詢非常相似,他只是使用了不同的連接語法。他原來的查詢(和你的)的問題是,它總是會將TBL_B中的任何**行和TBL_A中的**最新的**行連接起來。我正在尋找的是來自TBL_B的最新的適合行。如果TBL_A和TBL_B中的員工有兩個條目,則連接必須反映TBL_B中的每一行可能需要連接到TBL_A中的不同行(結果可能會爲每行使用不同的費率,而不僅僅是最新的一行) – monitorjbl 2012-01-19 16:51:26