2013-10-10 60 views
0

對於Oracle數據庫,假設我這裏有兩個表(類似的結構,但更大的數據量)的定義如下:的Oracle SQL:表中加入

create table payments(
    record_no INTEGER; 
    cust_no INTEGER; 
    amount NUMBER; 
    date_entered DATE; 
); 
insert into payments values(1,3,34.5,sysdate-1); 
insert into payments values(2,2,34.5,sysdate-2); 
insert into payments values(3,3,34.5,sysdate-18/1440); 
insert into payments values(4,1,34.5,sysdate-1); 
insert into payments values(5,2,34.5,sysdate-2/24); 
insert into payments values(6,3,34.5,sysdate-56/1440); 
insert into payments values(7,4,34.5,sysdate-2); 
insert into payments values(8,2,34.5,sysdate-1); 

create table customer(
    cust_no INTEGER; 
    name VARCHAR2; 
    zip VARCHAR2; 
); 
insert into customer values(1,'Tom',90001); 
insert into customer values(2,'Bob',90001); 
insert into customer values(3,'Jack',90001); 
insert into customer values(4,'Jay',90001); 

現在,我要生成與列的報告(獲得每個客戶訂單由paydate前兩種付款金額和日期):

Cust_no | pay_amount1 | pay_date1 |pay_amount2 | pay_date2

報告示例我想

CUST_NO PAYMENT1 PAYDATE1  PAYMENT2  PAYDATE2 
1 34.5 October, 09 2013  0    null 
2 34.5 October, 08 2013  34.5  October, 09 2013 
3 34.5 October, 09 2013  34.5  October, 10 2013 
4 34.5 October, 08 2013  0    null 

任何人都可以做出正確而有效的查詢嗎?提前致謝。

+1

不僅它慢,你查詢中使用的rownum謂詞會給你一個隨機的行。請查閱文檔,瞭解使用rownum的正確方式 - Oracle Rownum的Google搜索可能只會引發大量示例。 –

+0

這個查詢是錯誤的(在Oracle上),最後兩個子查詢給出錯誤'c.cust_no - 無效標識符 - - 看看這個演示:http://www.sqlfiddle.com/#!4/bf6e1/ 5 – krokodilko

+0

@kordirko我注意到並修改了我的問題,謝謝指出,那麼你的解決方案是什麼? – Frank

回答

3

首先你需要讓你的創建腳本正確。 ;終止聲明聲明中不是一行。其次,varchar2數據類型需要長度規範:name VARCHAR2(20)而不是name VARCHAR2。字符文字也需要用單引號括起來。 是一個字符文字,90001是一個數字。這是兩回事。

所以這導致了下面的腳本:

create table payments(
    record_no INTEGER, 
    cust_no INTEGER, 
    amount NUMBER, 
    date_entered DATE 
); 

insert into payments values(1,3,34.5,sysdate-1); 
insert into payments values(2,2,34.5,sysdate-2); 
insert into payments values(3,3,34.5,sysdate-18/1440); 
insert into payments values(4,1,34.5,sysdate-1); 
insert into payments values(5,2,34.5,sysdate-2/24); 
insert into payments values(6,3,34.5,sysdate-56/1440); 
insert into payments values(7,4,34.5,sysdate-2); 
insert into payments values(8,2,34.5,sysdate-1); 

create table customer(
    cust_no INTEGER, 
    name VARCHAR2(20), 
    zip VARCHAR2(20) 
); 

insert into customer values(1,'Tom','90001'); 
insert into customer values(2,'Bob','90001'); 
insert into customer values(3,'Jack','90001'); 
insert into customer values(4,'Jay','90001'); 

請注意,這是不好的編碼習慣在INSERT聲明中未指定的列。它應該是insert into customer (cust_no, name, zip) values(1,'Tom','90001');而不是insert into customer values(1,'Tom','90001');


現在爲您查詢,以下應該做你需要wnat:

with numbered_payments as (
    select cust_no, 
     amount, 
     date_entered, 
     row_number() over (partition by cust_no order by date_entered) as rn 
    from payments 
) 
select c.cust_no, 
     c.name, 
     p1.amount as pay_amount1, 
     p1.date_entered as pay_date1, 
     p2.amount as pay_amount2, 
     p2.date_entered as pay_date2 
from customer c 
    left join numbered_payments p1 
     on p1.cust_no = c.cust_no 
     and p1.rn = 1 
    left join numbered_payments p2 
     on p2.cust_no = c.cust_no 
     and p2.rn = 2; 

請注意,我用了一個外部聯接,以確保每一個客戶甚至返回如果沒有或只有一次付款。

這裏是所有的改正和查詢的SQLFiddle:http://sqlfiddle.com/#!4/74349/3

0

的解析函數ROW_NUMBER可以幫你給一個數字,每一筆支出:

select cust_no, amount, date_entered, 
    row_number() over(partition by cust_no order by date_entered) rn 
from payments ; 

使用這個我認爲我們可以得到你想要的要尋找的,是這樣的:

With ordered_payments as (
    select cust_no, amount, date_entered, 
     row_number() over(partition by cust_no order by date_entered) rn 
     from payments) 
select customer.cust_no, p1.amount, p1.date_entered, p2.amount, p2.date_entered 
from customer left join ordered_payments p1 
        on customer.cust_no = p1.cust_no and p1.rn = 1 
       left join ordered_payments p2 
        on customer.cust_no = p2.cust_no and p2.rn = 2 ; 
1
SELECT * FROM (
    SELECT 
     c.cust_no, 
     p.amount as payment, 
     p.date_entered as paydate, 
     ROW_NUMBER() OVER (PARTITION BY cust_no ORDER BY p.record_no ASC) AS rn 
    FROM customer c 
     JOIN payments p ON p.cust_no = c.cust_no 
    ) t 
WHERE 
    rn <= 2 
ORDER BY cust_no, rn; 

將分兩行顯示每個客戶需要的2條記錄。如果你喜歡把它放在同一行,那麼用下面的查詢:

SELECT 
    cust_no, 
    payment1, 
    paydate1, 
    CASE WHEN nextcli <> cust_no THEN 0 ELSE payment2 END AS payment2, 
    CASE WHEN nextcli <> cust_no THEN SYSDATE ELSE paydate2 END AS paydate2 
FROM (
    SELECT 
     c.cust_no, 
     p.amount as payment1, 
     p.date_entered as paydate1, 
     ROW_NUMBER() OVER (PARTITION BY c.cust_no ORDER BY p.record_no ASC) AS rn, 
     LEAD(c.cust_no, 1, -1) OVER (ORDER BY c.cust_no ASC) as nextcli, 
     LEAD(p.amount, 1, 0) OVER (ORDER BY c.cust_no ASC) as payment2, 
     LEAD(p.date_entered, 1, NULL) OVER (ORDER BY c.cust_no ASC) as paydate2 
    FROM customer c 
     JOIN payments p ON p.cust_no = c.cust_no 
    ) t 
WHERE 
    rn <= 1 
ORDER BY cust_no, rn;