问题
I am using Visual Studio 2010 and SQL Server 2012.
I have searched the net and the stackoverflow archives and found a few others who have had this problem but I could not get their solutions to work for me. The problem involves filtering based on the aggregate value of a dataset using a user definable report parameter.
I have the following report.

The ultimate goal of this report is to filter portfolios that have a user definable % of cash as a percent of total assets. The default will be 30% or greater. So for example if a Portfolios total market value was $100,000 and their cash asset class was $40,000 this would be a cash perent of 40% and this portfolio would appear on the report.
I have been able to select just the cash asset class using a filter on the dataset itself so that is not an issue. I easily added a cash percent parameter to the dataset but soon realized this is filtering on the row detail not the aggregated sum, and sometimes portfolios have multiple cash accounts. I need the sum of all cash accounts so I can truly know if cash is 30% or greater of total market value.
At first I thought the report was working correctly.

But after cross referencing this against another report I realized this portfolio only has 2.66 % total Cash because it has a large negative balance in a second cash account as well. It's the sum of all cash accounts I care about.

I want to filter portfolios that have >= cash based on the total line not the detail lines. I suspect I may need to alter the dataset using the scalar function SUM() then building a parameter off that, but I have not had success writing a query to do that. I also would be very interested to know if somehow this can be done in the .rdl layer rather than at the sql dataset level. The SQL for this is a little complicated because the program that this is reporting on requries the use of SQL functions, stored procedures, and parameters.
If the solution involves altering the query to include sum() in the dataset itself, I suspect it is line 20 that needs to be summed
a.PercentAssets,
Here is the data set for the report.
https://www.dropbox.com/s/bafdo2i6pfvdkk4/CashPercentDataSet.sql
and here is the .rdl file.
https://www.dropbox.com/s/htg09ypyh7f1a98/cashpercent2.rdl
Thank you
回答1:
I would do this in SQL personally. You can use a SUM() aggregate to get the value you're after for each account. You won't want to sum the percents though, you'll want to SUM the values and then create the percent afterwards once you have the totals. A sum of averages isn't the same as an average of sums (except in some circumstances but we can't assume that).
I would do something like this, though you'll probably need to tweak it to get it working correctly for you. (I also may not fully understanding the meaning of all the columns you're using).
SELECT PortfolioBaseCode,totalValue,cashValue,
(CAST(cashValue AS FLOAT)/totalValue) * 100 AS pcntCash
FROM (
SELECT b.PortfolioBaseCode,
SUM(a.MarketValue) AS totalValue
SUM(CASE s.SecuritySymbol WHEN 'CASH' THEN a.MarketValue ELSE 0 END) AS cashValue
FROM APXUser.fAppraisal (@ReportData) a
LEFT JOIN APXUser.vPortfolioBaseSettingEx b ON b.PortfolioBaseID = a.PortfolioBaseID
LEFT JOIN APXUser.vSecurityVariant s ON s.SecurityID = a.SecurityID
AND s.SecTypeCode = a.SecTypeCode
AND s.IsShort = a.IsShortPosition
AND a.PercentAssets >= @PercentAssets
GROUP BY b.PortfolioBaseCode
) AS t
WHERE (CAST(cashValue AS FLOAT)/totalValue)>=@pcntParameter
Alternatively you can use the HAVING clause to filter aggregate functions like a WHERE clause would (though I find this a little less readable):
SELECT b.PortfolioBaseCode,
SUM(a.MarketValue) AS totalValue
SUM(CASE s.SecuritySymbol WHEN 'CASH' THEN a.MarketValue ELSE 0 END) AS cashValue,
(SUM(a.MarketValue)/SUM(CASE s.SecuritySymbol WHEN 'CASH' THEN a.MarketValue ELSE 0 END))*100 AS cashPcnt
FROM APXUser.fAppraisal (@ReportData) a
LEFT JOIN APXUser.vPortfolioBaseSettingEx b ON b.PortfolioBaseID = a.PortfolioBaseID
LEFT JOIN APXUser.vSecurityVariant s ON s.SecurityID = a.SecurityID
AND s.SecTypeCode = a.SecTypeCode
AND s.IsShort = a.IsShortPosition
AND a.PercentAssets >= @PercentAssets
GROUP BY b.PortfolioBaseCode
HAVING (SUM(a.MarketValue)/SUM(CASE s.SecuritySymbol WHEN 'CASH' THEN a.MarketValue ELSE 0 END))>=@pcntParameter
Basically you can use grouping and aggregate functions to get the total value and the cash value for each account and then calculate the proper percentage from that. This will take into account any negatives, etc in other holdings.
Some references for aggregate function and grouping:
MSDN - GROUP BY (TSQL)
MSDN - Aggregate Functions
MSDN - HAVING Clause
If you find you're needing to do some kind of aggregation but you cannot group your results you should look into using the TSQL window functions which are very handy:
Working with Window Functions in SQL Server
MSDN - OVER Clause
来源:https://stackoverflow.com/questions/19173000/filtering-based-on-ssrs-total-sum