2016-12-06 77 views
2

我有以下的表格設置:更換循環查詢

CREATE TABLE app_detail 
(
CustID1 int, 
CustID2 int, 
AppDate datetime 
) 

CREATE TABLE inv_detail 
(
CustID1 int, 
CustID2 int, 
PostDate datetime, 
ClearDate datetime, 
Amt float 
) 

INSERT INTO app_detail 
VALUES(583,246,'2013-04-30 00:00:00.000') 
INSERT INTO app_detail 
VALUES(583,246,'2015-06-17 00:00:00.000') 

INSERT INTO inv_detail 
VALUES(583,246,'2013-04-05 00:00:00.000',NULL,17.56) 
INSERT INTO inv_detail 
VALUES(583,246,'2013-04-05 00:00:00.000','2013-12-31 00:00:00.000',667.97) 
INSERT INTO inv_detail 
VALUES(583,246,'2013-04-05 00:00:00.000','2014-10-05 00:00:00.000',3.96) 
INSERT INTO inv_detail 
VALUES(583,246,'2013-04-05 00:00:00.000',NULL,48.40) 
INSERT INTO inv_detail 
VALUES(583,246,'2013-01-08 00:00:00.000','2013-12-31 00:00:00.000',332.03) 
INSERT INTO inv_detail 
VALUES(583,246,'2013-01-08 00:00:00.000','2013-12-31 00:00:00.000',63.10) 


INSERT INTO inv_detail 
VALUES(583,246,'2013-07-09 00:00:00.000',NULL,1062.29) 
INSERT INTO inv_detail 
VALUES(583,246,'2013-04-05 00:00:00.000',NULL,17.56) 
INSERT INTO inv_detail 
VALUES(583,246,'2013-04-05 00:00:00.000',NULL,48.40) 

select * from app_detail 
select * from inv_detail 

我想獲得以下輸出:

SELECT 
'583' AS CustID1 
,'246' AS CustID2 
,'2013-04-30 00:00:00.000' AS AppDate 
,'1133.02' AS TotalAmount 

UNION 
SELECT 
'583' 
,'246' 
,'2015-06-17 00:00:00.000' 
,'1128.25' 

CustID1 CustID2 AppDate TotalAmount 
583  246 2013-04-30 1133.02 
583  246 2015-06-17 1128.25 

第一個表包含客戶製作上的應用程序數據特定日期。 第二個表格包含這些客戶的發票詳細信息,發票已發送時以及付款(已清除)的時間。 我想知道客戶在申​​請日期的未清發票金額。 如果已經支付了發票,那麼ClearedDate列中會有一個日期。如果發票從未付款,則它將爲空。

我曾經想過這樣做的唯一方法是通過一個循環,我只是一次將一個AppDate傳遞給WHERE子句。但我希望我可以做到無效。

任何幫助,將不勝感激。

+2

你如何計算總金額?我無法跟隨。抱歉。 –

回答

2

從Blorgbeard的答案中借用來顯示如何在沒有子查詢的情況下完成此操作。

DECLARE @app_detail TABLE (CustID1 int,CustID2 int,AppDate datetime) 
DECLARE @inv_detail TABLE(CustID1 int,CustID2 int,PostDate datetime,ClearDate datetime,Amt float) 

INSERT INTO @app_detail VALUES(583,246,'2013-04-30 00:00:00.000') 
INSERT INTO @app_detail VALUES(583,246,'2015-06-17 00:00:00.000') 

INSERT INTO @inv_detail VALUES(583,246,'2013-04-05 00:00:00.000',NULL,17.56) 
INSERT INTO @inv_detail VALUES(583,246,'2013-04-05 00:00:00.000','2013-12-31 00:00:00.000',667.97) 
INSERT INTO @inv_detail VALUES(583,246,'2013-04-05 00:00:00.000','2014-10-05 00:00:00.000',3.96) 
INSERT INTO @inv_detail VALUES(583,246,'2013-04-05 00:00:00.000',NULL,48.40) 
INSERT INTO @inv_detail VALUES(583,246,'2013-01-08 00:00:00.000','2013-12-31 00:00:00.000',332.03) 
INSERT INTO @inv_detail VALUES(583,246,'2013-01-08 00:00:00.000','2013-12-31 00:00:00.000',63.10) 
INSERT INTO @inv_detail VALUES(583,246,'2013-07-09 00:00:00.000',NULL,1062.29) 
INSERT INTO @inv_detail VALUES(583,246,'2013-04-05 00:00:00.000',NULL,17.56) 
INSERT INTO @inv_detail VALUES(583,246,'2013-04-05 00:00:00.000',NULL,48.40) 

select a.*, sum(Amt) AS [Total] 
from @app_detail a 
LEFT JOIN @inv_detail i ON i.CustID1=a.CustID1 
    AND i.CustID2=a.CustID2 
    AND i.PostDate <= a.AppDate 
    AND (i.ClearDate is null or i.ClearDate > a.AppDate) 
GROUP BY a.CustID1,a.CustID2,a.AppDate 
+0

這看起來不錯,而且更簡單 - 但OP可能希望根據我對他真實數據的回答來測試其性能。我對最小測試數據的測試表明,這實際上比較慢 - 它進行嵌套循環連接加上排序,而「outer apply」只進行嵌套循環連接。 – Blorgbeard

+0

@Blorgbeard如果我爲自己重寫它,我會使用聯合並擺脫OR。我一直髮現,要更高效。基準測試後,只有當OR實施速度不夠快當然:) – UnhandledExcepSean

2

可以使用outer apply代替人工循環做到這一點:

select a.*, due.Total 
from app_detail a 
outer apply (
    select sum(Amt) [Total] 
    from inv_detail i 
    where 
     i.CustID1=a.CustID1 and i.CustID2=a.CustID2 and 
     i.PostDate <= a.AppDate and (i.ClearDate is null or i.ClearDate > a.AppDate) 
) due 

它返回給我正確的結果,之後我刪除從測試數據的兩個重複的行(17.5648.40兩個有兩個條目) 。

這不是一個特別有效的方法 - 它將導致對app_detail中的每一行都進行表掃描(或可能是索引掃描,如果您有適當的索引)爲inv_detail。然而,我不相信在這種情況下有一種解決方法 - 這不是一個簡單的聚合,因爲inv_detail中的一行可能涉及許多行app_detail的計算。