2016-09-06 89 views
0

我在SQL Server 2008中的以下表R2數據庫:SQL返回多非空值與最高的指數

客戶

CustID CustName 
====== ======== 
1  A 
2  B 
3  C 
4  D 

交易

TransID CustID InvoiceTotal LoyaltyPointsEarned 
======= ====== ============ =================== 
1  1  300   25 
2  2  NULL   10 
3  3  100   10 
4  2  200   25 
5  1  NULL   100 
6  3  120   NULL 

交易按時間順序插入(更高的ID =更新的訂單);事務允許InvoiceTotal或LoyaltyPointsEarned爲NULL,但不能同時爲兩者。

我想獲得最新的非空發票總額AND(這是有點棘手)贏得了所有客戶最近的非空的忠誠點,在同一行上爲每個客戶顯示以下信息:

CustID CustName LatestInvoiceTotal LatestLoyaltyPointsEarned 
1  A   300     100 
2  B   200     25 
3  C   120     10 

下面的查詢提供了最新的發票總額:

SELECT DISTINCT 
    CustID, CustName, LatestInvoiceTotal, LatestLoyaltyPointsEarned 
FROM 
    Customers 
INNER JOIN 
    (SELECT 
     CustID, InvoiceTotal AS LatestInvoiceTotal, TransID 
    FROM 
     Transactions 
    GROUP BY 
     CustID, InvoiceTotal, TransID) CustomerTransactions ON Customers.CustID = CustomerTransactions.CustID 
INNER JOIN 
    (SELECT 
     CustID, MAX(TransID) AS MaxTransID 
    FROM 
     Transactions 
    WHERE 
     InvoiceTotal IS NOT NULL 
    GROUP BY 
     CustID) MaxTransactionIDs ON Customers.CustID = MaxTransactionIDs.CustID AND CustomerTransactions.TransID = MaxTransactionIDs.MaxTransID 

這怎麼可能擴展到做LoyaltyPointsEarned一樣,沒有結果複製客戶記錄?

回答

1

最簡單的辦法是有兩個子查詢中檢索信息。

select CustID, CustName, 
     (select top 1 InvoiceTotal 
     from Transactions 
     where Transactions.CustID = Customers.CustID and InvoiceTotal is not null 
     order by TransID desc) as LatestInvoiceTotal, 
     (select top 1 LoyaltyPointsEarned 
     from Transactions 
     where Transactions.CustID = Customers.CustID and LoyaltyPointsEarnedis not null 
     order by TransID desc) as LatestLoyaltyPointsEarned    
from Customers 

但作爲子查詢可以降低重要你的表現,你只需要確保有超過客戶ID,TRANSID交易降多索引,因此這些子查詢將被優化。

+1

此作品一種享受,謝謝。我不得不用desc替換降序(SQL Server 2008 R2)。 – pdm2011

+0

修正:-)。我仍然習慣於SQL Server特性。 –

0

你可以使用窗口功能。

您將需要2子查詢,但:

with tmp as (
select custId, 
    InvoiceTotal, 
    row_number() over(partition by custId order by TransId desc) as rnk 
from Transactions 
where InvoiceTotal is not null) 
select * 
from tmp 
where rnk = 1 
0

另一對加入似乎做到這一點:

SELECT DISTINCT 
    CustID, CustName, LatestInvoiceTotal, LatestLoyaltyPointsEarned 
FROM 
    Customers 
INNER JOIN 
    (SELECT 
     CustID, InvoiceTotal AS LatestInvoiceTotal, TransID 
    FROM 
     Transactions 
    GROUP BY 
     CustID, InvoiceTotal, TransID) CustomerTransactions ON Customers.CustID = CustomerTransactions.CustID 
INNER JOIN 
    (SELECT 
     CustID, MAX(TransID) AS MaxTransID 
    FROM 
     Transactions 
    WHERE 
     InvoiceTotal IS NOT NULL 
    GROUP BY 
     CustID) MaxTransactionIDs ON Customers.CustID = MaxTransactionIDs.CustID AND CustomerTransactions.TransID = MaxTransactionIDs.MaxTransID 
INNER JOIN 
    (SELECT 
     CustID, LoyaltyPointsEarned AS LatestLoyaltyPointsEarned, TransID 
    FROM 
     Transactions 
    GROUP BY 
     CustID, LoyaltyPointsEarned, TransID) CustomerTransactions2 ON Customers.CustID = CustomerTransactions2.CustID 
INNER JOIN 
    (SELECT 
     CustID, MAX(TransID) AS MaxTransID 
    FROM 
     Transactions 
    WHERE 
     LoyaltyPointsEarned IS NOT NULL 
    GROUP BY 
     CustID) MaxTransactionIDs2 ON Customers.CustID = MaxTransactionIDs2.CustID AND CustomerTransactions2.TransID = MaxTransactionIDs2.MaxTransID 
+1

這隻會返回至少有一個發票值和一個忠誠點值的客戶。使用marc的答案也可以得到空值。 – pdm2011

1

使用下面的查詢來獲取想要的結果.. MAX()OVER()函數可以在這樣的情況下使用。

;WITH cte_1 
AS 
(SELECT a.CustID ,a.CustName,MAX(InvoiceTotal) OVER(Partition by a.CustID Order by TransID desc)LatestInvoiceTotal 
     ,MAX(LoyaltyPointsEarned) OVER(Partition by a.CustID Order by TransID desc)LatestLoyaltyPointsEarned 
     FROM Customers a 
      JOIN Transactions b 
       ON a.CustID =b.CustID) 
SELECT DISTINCT * 
FROM cte_1 
WHERE LatestInvoiceTotal IS NOT NULL AND LatestLoyaltyPointsEarned is NOT NULL 

下面是測試場景:

DROP TABLE #Customers 

DROP TABLE #Transactions 


CREATE TABLE #Customers 
(
CustId INT, 
CustName VARCHAR(50) 
) 

    CREATE TABLE #Transactions 
(
TransID INT, 
CustID INT, 
InvoiceTotal INT, 
LoyaltyPointsEarned INT 
) 

INSERT INTO #Customers 
VALUES (1,'A'),(2,'B'),(3,'C'),(4,'D') 

INSERT INTO #Transactions 
VALUES (1,1,300,25),(2,2,NULL,10),(3,3,100,10),(4,2,200,25),(5,1,NULL,100),(6,3,120,NULL) 


;WITH cte_1 
AS 
(SELECT a.CustID ,a.CustName,MAX(InvoiceTotal) OVER(Partition by a.CustID Order by TransID desc)LatestInvoiceTotal 
     ,MAX(LoyaltyPointsEarned) OVER(Partition by a.CustID Order by TransID desc)LatestLoyaltyPointsEarned 
     FROM #Customers a 
      JOIN #Transactions b 
       ON a.CustID =b.CustID) 
SELECT DISTINCT * 
FROM cte_1 
WHERE LatestInvoiceTotal IS NOT NULL AND LatestLoyaltyPointsEarned is NOT NULL 

輸出:

enter image description here