SQL返回具有最高索引的多个非空值
SQL Server 2008 R2数据库中有以下表格: 客户:SQL返回具有最高索引的多个非空值,sql,sql-server,sql-server-2008-r2,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
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
交易:
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为空,但不能同时为空
我想获得所有客户最近获得的非空发票总额和(这是一个棘手的问题)最近获得的非空忠诚度点数,每个客户的这一信息显示在同一行上:
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
如何在不复制结果中的客户记录的情况下,将其扩展为对忠诚度Intsearned执行相同操作?您可以使用窗口功能 不过,您需要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
你可以使用窗户功能 不过,您需要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
简单的解决方案是使用两个子查询来检索该信息
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
但是,由于子查询可能会严重降低性能,您只需确保在CustID上的事务上有一个多索引,TransID降序,这样这些子查询就会得到优化。简单的解决方案是使用两个子查询检索该信息
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
但是,由于子查询可能会严重降低您的性能,您只需确保在CustID上的事务上有一个多索引,TransID降序,这样子查询就会得到优化。另一对连接似乎可以做到这一点:
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
另一对连接似乎可以做到这一点:
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
使用下面的查询获得所需的结果。。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
输出:
使用以下查询获得所需结果。。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
输出:
这仅返回同时具有至少一个发票值和一个忠诚度积分值的客户。使用上面marc的答案也可以得到空值。这只会返回同时具有至少一个发票值和一个忠诚度积分值的客户。使用上面marc的答案也可以得到空值。这是一种享受,谢谢。我不得不用desc(SQLServer2008R2)替换降序。修复:-)。我仍然习惯于SQL Server的特殊性。这是一种享受,谢谢。我不得不用desc(SQLServer2008R2)替换降序。修复:-)。我仍然习惯于SQL Server的特殊性。