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