2017-06-18 43 views
2

所以我有兩個SQL表,一個是客戶通訊錄,另一個是購買日誌。SQL按日期加入和排序個別科目

客戶表

Cust ID  Cust Name 
1   Adam 
2   Brian 
3   Charles 
4   Dave 
... 

購買歷史

Customer ID   Price   Date 
1     $100   1996-01-20 
1     $200   1995-01-01 
2     $70   1999-05-22 
... 

我想看到的是客戶的名字和最近購買的價格。 所以這個表應該是這樣的:

Customer Name  Price  
Adam    $100 
Brian    $70 
... 

我覺得我有什麼功能,使用總體思路(通過,限制,如訂單,並加入),但我無法把他們放在一起。

更糟糕的是,我需要找出處理關係的方法,這意味着如果客戶在同一天進行多次採購。默認情況下,我認爲它會列出第一個價格,但是如何製作它才能列出當天的最高價格?還是平均價格?

+0

我寧願PostgreSQL的。 – Vic

回答

2

您可以使用Postgres的distinct on()操作:

SELECT distinct on (c.cust_id) c.cust_name, p.price, p.purchase_date 
from customer c 
    join purchase p ON c.cust_id = c.customer_id 
order by c.cust_id, p.date desc, p.price desc; 

通過在該price descorder by如果一天有兩個價格,Postgres將選擇最高價格。

另一種選擇是加入一個派生表(可能更快)

select c.cust_id, c.cust_name, p.price, p.purchase_date 
from customer c 
    join (
    select distinct on (customer_id) customer_id, price, purchase_date 
    from purchase 
    order by customer_id, purchase_date desc, p.price desc 
) p on c.cust_id = p.customer_id; 
+0

謝謝。你知不知道這個解決方案(使用'不同on')如何與下面使用窗函數的一個比較? – Vic

+0

@Vic:通常在()上的'distinct是比使用窗口函數的等價解決方案更快的。通過窗口函數,您可以更好地控制「distinct」的定義,以查詢您是如何處理關係的。 –

0

讓我們暫時擱置一下你寫的關係問題,首先從基礎入手,將名字寫入購買表。這是一個簡單的連接:

SELECT c.name, p.price, p.date from purchase as p inner join customer as c 
ON c.cust_id = c.customer_id; 

這會給你一個包含所有購買一張桌子,用的名字。
現在,這個你可以添加平均,總和,最大值或任何聚集你想要的,例如:

SELECT name, date, MAX(price) from (
    SELECT c.name, p.price, p.date from purchase as p inner join customer as c 
    ON c.cust_id = c.customer_id 
) group by name, date; 
+0

但我希望它只返回最近一次購買的價格。 – Vic

+0

這不會對答案返回最新日期和價格(只有_highest_價格爲每臺日期) –

1

標準SQL的方式來記錄排序是RANKDENSE_RANK(考慮兩者的關係)或ROW_NUMBER(不) 。

下面的查詢需要的最後一天購買,如果有幾個購買它挑選具有較高的性價比記錄。 (和幸福,如果有兩個採購具有相同的最高價,記錄一個任意挑選,但這並不重要。)

select 
    customer.cust_name, 
    ranked.price 
from customer 
join 
(
    select 
    customer_id, 
    price, 
    row_number() over (partition by customer_id order by date desc, price desc) as rnk 
    from purchase_history 
) ranked on ranked.customer_id = customer.cust_id and ranked.rnk = 1; 

下面的查詢需要最後購買日的採購,並計算avarage這些的價格。

select 
    customer.cust_name, 
    avg(ranked.price) 
from customer 
join 
(
    select 
    customer_id, 
    price, 
    rank() over (partition by customer_id order by date desc) as rnk 
    from purchase_history 
) ranked on ranked.customer_id = customer.cust_id and ranked.rnk = 1 
group by customer.cust_id, customer.cust_name; 
+0

最後一行中的'customer.cust_id'是否必要? – Vic

+0

不,這只是當你有兩個同名客戶時,爲了得到兩個單獨的行而不是一個。如果你對名稱有一個獨特的限制或者只是不在乎,那麼這是沒有必要的。 –