2012-01-05 78 views
0

問題陳述:形成一個SQL查詢,跨行比較結果

選擇所有商店的名字,他們的身份,電話號碼,生效日期 ,其電話號碼從2003年已經被改變,直到當前的日期。

Schema是

store_name,phone number , start_date , status 

示例行

abc 1234 30-DEC-2011 open 
    abc 3433 04-Jan-2012 close 
    bbb 4444 30-Jan-2010 open 
    bbb 4444 31-Jan-2011 open 

輸出

abc 1234 open 30-DEC-3011 till 3-Jan-2012 
    abc 3433 close 04-Jan-2012 till date 

我還具有細等

與排序的開始日期輸出兩行
abc 1234 30-DEC-2011 open 
abc 3433 04-Jan-2012 close 

bbb不應該被報告,因爲電話號碼沒有變化。我們應該只報告那些電話號碼發生變化的商店。

有人可以幫助我在Oracle上進行此查詢嗎?我想通過使用相關的查詢它可以完成,但我不知道如何構建一個。

請注意,我的表有大約3154953條記錄,所以我還需要確保相關查詢不會鎖定整個表的很長時間。這對Oracle來說甚至可能嗎?

謝謝!


APC的答案適用於我,只是我看到了很多重複的結果。

對於輸入:

select store_name,phone_number,start_date, status where store_name=abc; 

回報

STORE_name   Phone number start_date  STATUS 
---------------- ---------------- ----------- ---------- 
abc    122 18-JAN-2011   open 
abc    122 18-JAN-2011   open 
abc    122 18-JAN-2011   close 

運行您的查詢給我下面的輸出。

abc    122 open from 18-JAN-2011 to 17-JAN-2011 
abc    122 open from 18-JAN-2011 to 17-JAN-2011 
abc    122 close from 18-JAN-2011 to date 

你能解釋爲什麼以及在哪裏錯過?

+1

這是MySQL還是Oracle? – 2012-01-05 12:56:32

+0

@ManseUK - 你已經刪除了[mysql]標籤,並忽略了標題中對MySQL的引用。請確保您的更改不會在開始編輯之前扭曲OP的意圖。 – APC 2012-01-05 17:10:01

+0

@APC道歉...這就是2編輯錯誤今天作出了....添加標籤回...雖然我真的不知道爲什麼它在標題或標記? – ManseUK 2012-01-05 17:11:46

回答

2

我假設這是針對Oracle而不是MySQL,因爲我的解決方案使用了一些我相當確定的魔術技巧,它們在MySQL中不可用。首先是公共表表達式來獲得我們可以多次使用的結果集。第二個是使用LEAD()分析函數來「預測」下一行的值。

所以,這裏的查詢:

with a as (select store_name 
      , phone_number 
      , status 
      , start_date 
      , lead (start_date, 1, trunc(sysdate)) over (partition by store_name 
             order by start_date) as next_date 
      , lead (phone_number, 1, null) over (partition by store_name 
             order by start_date) as next_number 
     from your_table 
     where start_date >= date '2003-01-01') 
select a.store_name 
     , a.phone_number 
     , case when a.next_date != trunc(sysdate) then 
        a.status||' from '|| a.start_date ||' to '||to_char(a.next_date - 1) 
       else a.status||' from '||a.start_date ||' to date' 
       end as status_text 
from a 
where a.store_name in (
       select store_name 
       from a 
       where phone_number != next_number) 
order by a.store_name, a.start_date 
/

下面是它的輸出:

SQL> r 
    1 with a as (select store_name 
... 
22 order by a.store_name, a.start_date     
23/

STORE_NAME   PHONE_NUMBER STATUS_TEXT 
-------------------- ------------ -------------------------------- 
abc       1234 open from 30-DEC-11 to 03-JAN-12 
abc       3433 close from 04-JAN-12 to date 

2 rows selected. 

SQL> 

至於這句話:

「,所以我還需要確保相關查詢沒有鎖定 表的整個很多時間「

在Oracle中無關緊要,因爲讀取不會阻止其他讀取。也沒有寫到這一點。

+0

謝謝!它的效果很好。我也有機會閱讀關於鉛的功能。 – TopCoder 2012-01-05 17:58:53

+0

我看到了一些結果問題。我編輯了這個問題,你可以看看它,讓我知道我錯過了什麼嗎? – TopCoder 2012-01-05 18:26:05

0

這將是沿

select * from table0 as q0 join 
(
    select min(date) from table0 as q1 where q1.store_name = q0.store_name 
) as q2 on q2.store_name = q0.store_name 
left join 
(
    select max(date) from table0 as q1 where q1.store_name = q0.store_name 
) as q3 on q3.store_name = q0.store_name 

線那是我沒有的MySQL在我,但它的東西沿着這些路線的前方是不完全正確的東西。