替换循环查询
Replacing a loop query
我设置了以下 table:
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
前 table 包含客户在特定日期提出申请的数据。
第二个 table 包含这些客户的发票详细信息、发票发送时间和付款(清算)时间。
我想知道客户在申请日期未结清的发票金额。
如果发票已支付,则 ClearedDate 列中将有一个日期。如果发票从未支付过,它将为 NULL。
我考虑过的唯一方法是通过一个循环,我一次只将一个 AppDate 传递给 WHERE
子句。但我希望我可以取消它。
如有任何帮助,我们将不胜感激。
您可以使用 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
它 returns 对我来说是正确的结果,在我从你的测试数据中删除了两个重复的行之后(17.56
和 48.40
都有两个条目)。
这不是一个特别有效的方法 - 它会导致 table 对 [=15] 中的每一行进行 inv_detail
的扫描(或者可能是索引扫描,如果您有适当的索引) =].但是,我认为在这种情况下没有办法解决这个问题 - 它不是一个简单的聚合,因为来自 inv_detail
的一行可能涉及 app_detail
.[=19 的许多行的计算=]
借用 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
我设置了以下 table:
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
前 table 包含客户在特定日期提出申请的数据。 第二个 table 包含这些客户的发票详细信息、发票发送时间和付款(清算)时间。 我想知道客户在申请日期未结清的发票金额。 如果发票已支付,则 ClearedDate 列中将有一个日期。如果发票从未支付过,它将为 NULL。
我考虑过的唯一方法是通过一个循环,我一次只将一个 AppDate 传递给 WHERE
子句。但我希望我可以取消它。
如有任何帮助,我们将不胜感激。
您可以使用 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
它 returns 对我来说是正确的结果,在我从你的测试数据中删除了两个重复的行之后(17.56
和 48.40
都有两个条目)。
这不是一个特别有效的方法 - 它会导致 table 对 [=15] 中的每一行进行 inv_detail
的扫描(或者可能是索引扫描,如果您有适当的索引) =].但是,我认为在这种情况下没有办法解决这个问题 - 它不是一个简单的聚合,因为来自 inv_detail
的一行可能涉及 app_detail
.[=19 的许多行的计算=]
借用 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