2016-09-06 2 views
0

나는 SQL Server 2008의 다음 표 R2 데이터베이스 있습니다가장 높은 인덱스 여러 null이 아닌 값을 반환하는 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이 될 수 있지만 둘다는 허용되지 않습니다.

나는 가장 최근의 null 이외의 송장 총을 얻으려면 모든 고객에게 적립 가장 최근의 null 이외의 로열티 포인트 각 고객에 대해 동일한 행에 표시이 정보, (이 까다로운 비트입니다) :

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

다음 쿼리는 최신 송장 총을 제공 :

이이 결과에 고객 기록을 복제하지 않고, LoyaltyPointsEarned에 대해 동일한 작업을 수행하도록 확장 할 수있는 방법
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 

?

답변

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 이상 거래에 여러 인덱스가해야 할, 그래서 그 하위 쿼리가 최적화 될 것이다.

+1

, 덕분에 여기

;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 

테스트 시나리오입니다. 내림차순으로 내림차순으로 바꾸어야했습니다 (SQL Server 2008 R2). – pdm2011

+0

수정 됨 :-). SQL Server의 특성에 익숙해졌습니다. –

0

당신은 창 기능을 사용할 수 있습니다.

당신은 생각이 하위 쿼리가 필요합니다 쉬운 솔루션은 정보를 검색하는 두 개의 서브 쿼리 데

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의 대답을 사용하여 null도 얻으십시오. – pdm2011

1

이 ..() 함수 OVER MAX()가 이러한 상황에서 사용할 수 있습니다 원하는 결과를 얻기 위해 아래 쿼리를 사용합니다.

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

관련 문제