我想要与费率及其差异作为保证金的相关合同
我想在SQL Server中执行此操作,而无需在子查询中自行加入表。
我的架构设置如下:
合同
ContractId relatedContractId Discriminator
-----------------------------------------------------
8041 8040 VendorContract
8040 8041 CustomerContract
8042 NULL CustomerContract
8043 8044 CustomerContract
8044 8043 VendorContract
价格
RateId RatePerUnit ContractId
---------------------------------
8052 120.00 8041
8053 123.00 8041
8050 121.00 8040
8051 127.00 8040
8052 120.00 8042
8053 137.00 8042
8054 102.00 8043
8055 100.00 8044
预期输出
CContract VContract Marging
------------------------------------
8040 8041 5.00
8042 Null 257.00
8043 8044 2.00
我使用下面的查询获得了正确的结果,该查询使用了一个子查询,但我需要在不使用子查询的情况下执行此操作。
SELECT cts.ContractId,
cts.RelatedContractId,
(ISNULL(SUM(r.RatePerUnit),0) - ISNULL(vr.VendorContractRate,0)) AS Margin
FROM Contracts cts
LEFT OUTER JOIN Contracts vcts
ON cts.RelatedContractId = vcts.ContractId
LEFT OUTER JOIN Rates r
ON cts.ContractId = r.ContractId
LEFT OUTER JOIN
( SELECT c.ContractId,
ISNULL(SUM(r.RatePerUnit),0) VendorContractRate
FROM Contracts c
LEFT OUTER JOIN Rates r
ON r.ContractId = c.contractId
WHERE c.Discriminator = 'VendorContract'
GROUP BY c.ContractId
) vr
ON cts.RelatedContractId = vr.ContractId
WHERE cts.Discriminator = 'CustomerContract'
GROUP BY cts.ContractId, cts.RelatedContractId, vr.VendorContractRate;
我试图在不使用子查询的情况下重写此查询,如下所示:
SELECT vc.ContractId,
SUM(r.RatePerUnit),
SUM(vr.RatePerUnit)
FROM Contracts c
LEFT OUTER JOIN Contracts vc
ON c.RelatedContractId = vc.ContractId
LEFT OUTER JOIN Rates r
ON r.ContractId= c.ContractId
INNER JOIN Rates vr
ON vr.ContractId = vc.ContractId
WHERE c.Discriminator = 'CustomerContract'
AND c.ContractStatus = 0
GROUP BY vc.ContractId;
不幸的是,这会重复我的结果,所以这是不正确的。对于多种费率,它将费率乘以存在的费率数。所以我得到了结果:
CContract VContract Marging
------------------------------------
8040 8041 10.00 ---- in this case 496-486(248-243)
8042 Null 514.00
8043 8044 2.00
答案 0 :(得分:1)
在没有某种子查询的情况下,我无法看到一种简单的方法,但也没有理由尝试避免子查询。你已经引用了想要避免子查询的性能原因,但这不是一个正当的理由,SQL是一种声明性语言,即你告诉优化器你想要什么而不是如何获取它,所以仅仅因为你使用了一个子查询并不意味着你必须改变计划。
虽然不需要删除子查询来提高性能,但这并不是说查询的性能仍然无法提高。这可以通过删除不必要的连接来完成。以下应该会有更好的表现:
WITH SummedRates AS
( SELECT ContractID, RatePerUnit = SUM(RatePerUnit)
FROM Rates
GROUP BY ContractID
)
SELECT c.ContractID,
c.RelatedContractID,
Margin = ISNULL(r.RatePerUnit, 0) - ISNULL(r2.RatePerUnit, 0)
FROM Contracts AS c
LEFT JOIN SummedRates AS r
ON r.ContractId = c.ContractId
LEFT JOIN SummedRates AS r2
ON r2.ContractId = c.RelatedContractId
WHERE c.Discriminator = 'CustomerContract'
完整的工作演示
DECLARE @Contracts TABLE (ContractId INT, relatedContractId INT, Discriminator VARCHAR(20));
INSERT @Contracts (ContractId, relatedContractId, Discriminator)
VALUES
(8041, 8040, 'VendorContract'),
(8040, 8041, 'CustomerContract'),
(8042, NULL, 'CustomerContract'),
(8043, 8044, 'CustomerContract'),
(8044, 8043, 'VendorContract');
DECLARE @Rates TABLE (RateId INT, RatePerUnit DECIMAL(5, 2), ContractId INT);
INSERT @Rates (RateId, RatePerUnit, ContractId)
VALUES
(8052, 120.00, 8041),
(8053, 123.00, 8041),
(8050, 121.00, 8040),
(8051, 127.00, 8040),
(8052, 120.00, 8042),
(8053, 137.00, 8042),
(8054, 102.00, 8043),
(8055, 100.00, 8044);
WITH SummedRates AS
( SELECT ContractID, RatePerUnit = SUM(RatePerUnit)
FROM @Rates
GROUP BY ContractID
)
SELECT c.ContractID,
c.RelatedContractID,
Margin = ISNULL(r.RatePerUnit, 0) - ISNULL(r2.RatePerUnit, 0)
FROM @Contracts AS c
LEFT JOIN SummedRates AS r
ON r.ContractId = c.ContractId
LEFT JOIN SummedRates AS r2
ON r2.ContractId = c.RelatedContractId
WHERE c.Discriminator = 'CustomerContract';