2015-04-06 80 views
1

我有2個表,客戶和CustomerActivity如下面的圖片中顯示,獲得通過日期最新行:計數行並從多個表

enter image description here

我想輸出表:

  • 具有來自Customer表的CustomerType ='Existing Customer'的所有列,再加上2列:
  • totalActivity(count activityID) - 顯示每個客戶的總活動數。
  • latestActivity(最大checkinTime) - 顯示在最近一次活動的日期時間

到目前爲止,我有這2個查詢,但我不知道如何組合/加入和過濾它們以獲得我所需要的。任何人都可以用1個查詢幫助(有些解釋是完美的)

SELECT customerId, firstName, birthDate, customerType 
FROM Customer 
WHERE Customer.customerType = 'Existing Customer' 

SELECT t1.activityId, t1.checkinTime, t1.customerId 
FROM CustomerActivity t1 
inner join (
    SELECT customerId, max(checkinTime) as Lastest 
    FROM CustomerActivity 
    group by customerId 
) t2 on t1.customerId = t2.customerId and t1.checkinTime = t2.Lastest 

回答

2

你實際上關閉。這是您的查詢應該是什麼樣子:

SELECT 
    c.customerId, 
    c.firstName, 
    c.lastName, 
    c.birthDate, 
    c.customerType, 
    ca.totalActivity, 
    ca.latestActivity 
FROM Customer c 
INNER JOIN(
    SELECT 
     customerId, 
     latestActivity = MAX(checkinTime), 
     totalActivity = COUNT(*) 
    FROM CustomerActivity 
    GROUP BY customerId 
) ca 
    ON ca.customerId = c.customerId 
WHERE 
    c.customerType = 'Existing Customer' 

子查詢(在INNER JOIN內部)使用COUNT(*),並使用每個客戶的MAX(checkinTime)最新活動獲取活動的總數。之後,您需要將其加入customerIdCustomer表。然後,您只需添加WHERE子句即可篩選'Existing Customer'

+0

它完美的作品! – 2015-04-06 02:19:27

+1

正如我在回答的評論中指出的那樣,我相信由於子查詢,這種方法效率會降低。我建議看看兩者的執行計劃,但我願意打賭,這種方法將彙總每個客戶的總體活動和最新活動,而直接加入表格會顯示您僅針對「現有「 顧客。唯一我不確定的是,如果這將被優化,但我不認爲它會。如果您有200萬客戶,其中只有20萬客戶是現有客戶,這可能會在性能上產生巨大差異。 – 2015-04-06 02:31:18

+0

@ScottSmith,同意。我不知道優化器是否足夠聰明以優化它,只有現有的客戶纔會被聚合。我建議OP應該看執行計劃。 – 2015-04-06 02:36:13

1

我還沒有根據實際模式對其進行測試,但類似這樣的情況應該可以工作(即使沒有活動,這種方法也會顯示客戶,如果您只希望客戶有活動,只需將左連接更改爲內連接):使用row_number()和窗口福而不是

SELECT c.CustomerID 
    , c.FirstName 
    , c.BirthDate 
    , c.CustomerType 
    , COUNT(ca.ActivityID) AS TotalActivity 
    , MAX(ca.CheckinTime) AS MostRecentActivity 
FROM Customer c 
LEFT JOIN CustomerActivity ca ON c.CustomerID = ca.CustomerID 
WHERE c.CustomerType = 'Existing Customer' 
GROUP BY c.CustomerID 
    , c.FirstName 
    , c.BirthDate 
    , c.CustomerType 
+0

我相信提議的其他解決方案由於加入中的子查詢會計算系統中每個客戶的兩個活動聚合,然後再將它們過濾到現有客戶。而採用這種方法,只會招致現有客戶記錄的計算開銷。 – 2015-04-06 02:18:16

1

你可以得到你想要的東西,而不group by,:

SELECT c.*, ca.numActivities, ca.activityId as LastActivity 
FROM Customer c JOIN 
    (select ca.*, 
      count(*) over (partition by ca.CustomerId) as numActivities 
      row_number() over (partition by ca.CustomerId order by checkinTime desc) as seqnum 
     from CustomerActivity ca 
    ) ca 
    on c.customerId = ca.customerId and ca.seqnum = 1 
WHERE c.customerType = 'Existing Customer'; 

這個版本將讓你得到你從最近的活動排喜歡的任何列。

編輯:

在你原來的問題,我想你想的最新活動。如果你只是想在最新的日期時間,然後彙總工作:

SELECT c.*, ca.numActivities, ca.lastActivityDateTime 
FROM Customer c JOIN 
    (select ca.*, 
      count(*) as numActivities 
      max(checkinTime) as lastActivityDateTime 
     from CustomerActivity ca 
    ) ca 
    on c.customerId = ca.customerId 
WHERE c.customerType = 'Existing Customer'; 
+0

感謝這兩個版本,真的很有幫助!是的,我想要datetime的最新版本,但是可以更詳細地解釋一下'over(ca.CustomerId分區)'部分,它有什麼作用? – 2015-04-06 02:18:50

+0

這些是窗口功能。開始的好地方是文檔:https://msdn.microsoft.com/en-us/library/ms189461.aspx。 – 2015-04-06 02:24:06

0
Select c.customerId, c.firstName, c.lastName, c.birthDate, c.customerType, gca.latestCheckIn, gca.count 
from customer as c, 
    (select ca.customerId, max(ca.checkInTime) as latestCheckIn, count(*) as checkinCount 
    from customerActivity as ca 
    group by ca.customerId) as gca 
where gca.customerId = c.customerId AND c.customerType = 'Existing Customer' 

如果你澄清更多的客戶沒有活動,就可以查詢改爲使用左連接