SQL返回多个索引最高的非空值

时间:2016-09-06 10:05:16

标签: sql sql-server sql-server-2008-r2

我在SQL Server 2008 R2数据库中有以下表格:

客户

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中对此进行扩展,而不会在结果中重复客户记录?

4 个答案:

答案 0 :(得分: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

但是,由于子查询可能会严重降低您的性能,因此您必须确保在Transactions over CustID,TransID降序上有多个索引,以便优化这些子查询。

答案 1 :(得分: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

答案 2 :(得分: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

答案 3 :(得分:0)

另一对连接似乎是这样做的:

support library