Table Structure 在这篇文章中添加表格非常困难,至少我不知道。尝试使用HTML表格标签,但它们看起来不太好。因此将表结构发布为图像。
考虑到图像中看到的3个表,Projects,BC,Actual Spend,作为样本,我正在寻找一个最佳查询,该查询返回Reports作为结果。如您所见,BC有一些计算,实际支出
ActiveForm::begin([
'enableClientScript' => false,
]);
如您所见,BC的SELECT,实际支出运行两次。我有几个其他的表,如BC,实际支出,产生一些计算。有没有办法优化这个。即使我把它们放在一个函数中,它也是一样的,函数需要不止一次调用。 有没有办法优化此查询。
粘贴下面的表格结构:
项目表:
SELECT ProjectId, Name, Budget
, (SELECT b.[BC] FROM [BC] b
WHERE b.[BC] IN
(SELECT SUM(mx.[BC]) FROM [BC] mx
WHERE ProjectId=p.ProjectId)) AS 'BC'
, (SELECT sp.[ActualSpendAmount] FROM [ActualSpend] sp
WHERE sp.[DateSpent] IN
(SELECT MAX(as.[DateSpent]) FROM [ActualSpend] as
WHERE ProjectId=p.ProjectId)) AS 'Actual Spend'
, t.[Budget] - ((SELECT b.[BC] FROM [BC] b
WHERE b.[BC] IN
(SELECT SUM(mx.[BC]) FROM [BC] mx
WHERE ProjectId=p.ProjectId))
+
(SELECT sp.[ActualSpendAmount] FROM [ActualSpend] sp
WHERE sp.[DateSpent] IN
(SELECT MAX(as.[DateSpent]) FROM [ActualSpend] as
WHERE ProjectId=p.ProjectId)))
FROM Projects p;
BC表:实际支出表:
ProjectId Name Budget
1 DeadRock 500000
2 HardRock 300000
报告:
ProjectId BCId BC ApprovalDate ProjectId ActualSpendId ActualSpendAmount DateSpent
1 1 5000 2015/02/01 1 1 " 15000" " 2015/03/01"
1 2 3000 2015/03/10 1 2 " 33000" " 2015/05/12"
1 3 15000 2015/05/01 1 3 " 45000" " 2015/06/03"
1 4 5000 2015/07/01 1 4 " 75000" " 2015/07/11"
2 5 2000 2015/03/19 2 5 " 5000" " 2015/04/20"
2 6 6000 2015/05/20 2 6 " 19000" " 2015/05/29"
2 7 25000 2015/08/01 2 7 " 42000" " 2015/06/23"
2 8 " 85000" " 2015/07/15"
答案 0 :(得分:0)
BC
的相关子查询没有任何意义:
, (SELECT b.[BC] FROM [BC] b
WHERE b.[BC] IN
(SELECT SUM(mx.[BC]) FROM [BC] mx
WHERE ProjectId=p.ProjectId)) AS 'BC'
如果我们专注于projectID 1,你可以在这里获得数据:
ProjectId BCId BC ApprovalDate
--------------------------------------------
1 1 5000 2015/02/01
1 2 3000 2015/03/10
1 3 15000 2015/05/01
1 4 5000 2015/07/01
因此这部分查询:
(SELECT SUM(mx.[BC]) FROM [BC] mx
WHERE ProjectId=p.ProjectId)
将返回28,000。那么你的本质是:
, (SELECT b.[BC] FROM [BC] b
WHERE b.[BC] IN (28000)) AS 'BC'
除非在BC中具有该特定金额的任何项目中的1个且仅有1个记录,否则将返回null。如果存在多个错误,则会出现错误,因为子查询中返回了多个记录。
我怀疑,根据报告数据,您只需要总和,因此您只需使用:
SELECT p.ProjectId,
p.Name,
p.Budget
bc.BC
FROM Projects p
LEFT JOIN
( SELECT bc.ProjectID, SUM(bc.BC) AS bc
FROM BC
GROUP BY bc.ProjectID
) AS bc
ON bc.ProjectID = P.ProjectID;
获取每个项目的BC的总和。
我在此假设您使用的是基于对象名称的方括号和前一个问题中的语法的SQL Server。在这种情况下,我会使用OUTER APPLY
来获取最新的实际支出行,并给出最终查询:
SELECT p.ProjectId,
p.Name,
p.Budget
bc.BC,
sp.ActualSpendAmount AS [Actual Spend],
p.Budget - bc.BC + sp.ActualSpendAmount AS ETC
FROM Projects p
LEFT JOIN
( SELECT bc.ProjectID, SUM(bc.BC) AS bc
FROM BC
GROUP BY bc.ProjectID
) AS bc
ON bc.ProjectID = P.ProjectID
OUTER APPLY
( SELECT TOP 1 sp.ActualSpendAmount
FROM [ActualSpend] AS sp
WHERE sp.ProjectID = p.ProjectID
ORDER BY sp.DateSpent DESC
) AS sp;
答案 1 :(得分:0)
根据您的预期结果,您的查询过于复杂(并且不会在没有错误的情况下运行)。 假设您的DBMS支持Windowed Aggregates:
SELECT p.ProjectId, p.NAME, p.Budget,
BC.BC,
act.ActualSpendAmount,
p.Budget - (BC.BC + act.ActualSpendAmount)
FROM Projects AS p
LEFT JOIN
( -- sum of BC per project
SELECT ProjectId, SUM(BC) AS BC
FROM BC
GROUP BY ProjectId
) AS BC
ON ProjectId=bc.ProjectId
JOIN
( -- latest amount per project
SELECT ProjectId, ActualSpendAmount,
ROW_NUMBER()
OVER (PARTITION BY ProjectId
ORDER BY DateSpent DESC) AS rn
FROM ActualSpend
) AS Act
ON Act.ProjectId=p.ProjectId
AND Act.rn = 1